[cig-commits] r6939 - in vendor: . elsa elsa/current elsa/current/ast elsa/current/elkhound elsa/current/elkhound/asfsdf elsa/current/elkhound/c elsa/current/elkhound/c.in elsa/current/elkhound/cc elsa/current/elkhound/cc.in elsa/current/elkhound/cc2 elsa/current/elkhound/examples elsa/current/elkhound/examples/arith elsa/current/elkhound/examples/cdecl elsa/current/elkhound/examples/cexp elsa/current/elkhound/examples/gcom elsa/current/elkhound/examples/gcom1 elsa/current/elkhound/examples/gcom2 elsa/current/elkhound/examples/gcom3 elsa/current/elkhound/examples/gcom4 elsa/current/elkhound/examples/gcom5 elsa/current/elkhound/examples/gcom7 elsa/current/elkhound/examples/scannerless elsa/current/elkhound/in elsa/current/elkhound/ocaml elsa/current/elkhound/ocaml/occ2 elsa/current/elkhound/out elsa/current/elkhound/perftest elsa/current/elkhound/tcheck elsa/current/elkhound/toplevel elsa/current/elkhound/triv elsa/current/elsa elsa/current/elsa/buildint elsa/current/elsa/doc elsa/current/elsa/in elsa/current/elsa/in/big elsa/current/elsa/in/big/gz elsa/current/elsa/in/c elsa/current/elsa/in/c99 elsa/current/elsa/in/gnu elsa/current/elsa/in/gnu/bugs elsa/current/elsa/in/gnu/cil elsa/current/elsa/in/kandr elsa/current/elsa/in/msvc elsa/current/elsa/in/std elsa/current/elsa/include elsa/current/elsa/toplevel elsa/current/smbase elsa/current/www

leif at geodynamics.org leif at geodynamics.org
Tue May 22 15:09:28 PDT 2007


Author: leif
Date: 2007-05-22 15:09:08 -0700 (Tue, 22 May 2007)
New Revision: 6939

Added:
   vendor/elsa/
   vendor/elsa/current/
   vendor/elsa/current/ast/
   vendor/elsa/current/ast/.gdbinit
   vendor/elsa/current/ast/agramlex.lex
   vendor/elsa/current/ast/agrampar.cc
   vendor/elsa/current/ast/agrampar.codes.h
   vendor/elsa/current/ast/agrampar.h
   vendor/elsa/current/ast/agrampar.tab.cc
   vendor/elsa/current/ast/agrampar.tab.h
   vendor/elsa/current/ast/agrampar.y
   vendor/elsa/current/ast/ast.ast
   vendor/elsa/current/ast/ast.ast.cc
   vendor/elsa/current/ast/ast.ast.h
   vendor/elsa/current/ast/ast.hand.cc
   vendor/elsa/current/ast/ast.hand.h
   vendor/elsa/current/ast/astgen.cc
   vendor/elsa/current/ast/asthelp.cc
   vendor/elsa/current/ast/asthelp.h
   vendor/elsa/current/ast/ccsstr.cc
   vendor/elsa/current/ast/ccsstr.h
   vendor/elsa/current/ast/configure.pl
   vendor/elsa/current/ast/demo.ast
   vendor/elsa/current/ast/embedded.cc
   vendor/elsa/current/ast/embedded.h
   vendor/elsa/current/ast/example.ast
   vendor/elsa/current/ast/exampletest.cc
   vendor/elsa/current/ast/ext1.ast
   vendor/elsa/current/ast/fakelist.h
   vendor/elsa/current/ast/fileloc.cc
   vendor/elsa/current/ast/fileloc.h
   vendor/elsa/current/ast/gramlex.cc
   vendor/elsa/current/ast/gramlex.h
   vendor/elsa/current/ast/index.html
   vendor/elsa/current/ast/license.txt
   vendor/elsa/current/ast/locstr.cc
   vendor/elsa/current/ast/locstr.h
   vendor/elsa/current/ast/manual.html
   vendor/elsa/current/ast/readme.txt
   vendor/elsa/current/ast/reporterr.cc
   vendor/elsa/current/ast/reporterr.h
   vendor/elsa/current/ast/tiny.ast
   vendor/elsa/current/ast/towner.cc
   vendor/elsa/current/ast/xmlhelp.cc
   vendor/elsa/current/ast/xmlhelp.h
   vendor/elsa/current/elkhound/
   vendor/elsa/current/elkhound/algorithm.html
   vendor/elsa/current/elkhound/asfsdf/
   vendor/elsa/current/elkhound/asfsdf/DeclExpr.sdf
   vendor/elsa/current/elkhound/asfsdf/EEb.sdf
   vendor/elsa/current/elkhound/asfsdf/EFa.sdf
   vendor/elsa/current/elkhound/asfsdf/SSSx.sdf
   vendor/elsa/current/elkhound/asfsdf/SSx.sdf
   vendor/elsa/current/elkhound/asfsdf/eeb.notree.perf.txt
   vendor/elsa/current/elkhound/asfsdf/eeb.perf.txt
   vendor/elsa/current/elkhound/asfsdf/efa.notree.perf.csv
   vendor/elsa/current/elkhound/asfsdf/efa.notree.perf.txt
   vendor/elsa/current/elkhound/asfsdf/efa.perf.csv
   vendor/elsa/current/elkhound/asfsdf/efa.perf.txt
   vendor/elsa/current/elkhound/asfsdf/sssx.notree.perf.txt
   vendor/elsa/current/elkhound/asfsdf/sssx.perf.txt
   vendor/elsa/current/elkhound/asfsdf/ssx.notree.perf.txt
   vendor/elsa/current/elkhound/asfsdf/ssx.perf.txt
   vendor/elsa/current/elkhound/asockind.cc
   vendor/elsa/current/elkhound/asockind.h
   vendor/elsa/current/elkhound/c.in/
   vendor/elsa/current/elkhound/c.in/c.in0
   vendor/elsa/current/elkhound/c.in/c.in1
   vendor/elsa/current/elkhound/c.in/c.in10
   vendor/elsa/current/elkhound/c.in/c.in11
   vendor/elsa/current/elkhound/c.in/c.in12
   vendor/elsa/current/elkhound/c.in/c.in2
   vendor/elsa/current/elkhound/c.in/c.in2.c
   vendor/elsa/current/elkhound/c.in/c.in3
   vendor/elsa/current/elkhound/c.in/c.in4
   vendor/elsa/current/elkhound/c.in/c.in4b
   vendor/elsa/current/elkhound/c.in/c.in5
   vendor/elsa/current/elkhound/c.in/c.in6
   vendor/elsa/current/elkhound/c.in/c.in7
   vendor/elsa/current/elkhound/c.in/c.in8
   vendor/elsa/current/elkhound/c.in/c.in9
   vendor/elsa/current/elkhound/c/
   vendor/elsa/current/elkhound/c/bcparse.cc
   vendor/elsa/current/elkhound/c/bcparse.h
   vendor/elsa/current/elkhound/c/c.ast
   vendor/elsa/current/elkhound/c/c.gr
   vendor/elsa/current/elkhound/c/c_env.cc
   vendor/elsa/current/elkhound/c/c_env.h
   vendor/elsa/current/elkhound/c/c_type.cc
   vendor/elsa/current/elkhound/c/c_type.h
   vendor/elsa/current/elkhound/c/c_variable.cc
   vendor/elsa/current/elkhound/c/c_variable.h
   vendor/elsa/current/elkhound/c/cc_flags.cc
   vendor/elsa/current/elkhound/c/cc_flags.h
   vendor/elsa/current/elkhound/c/cc_lang.cc
   vendor/elsa/current/elkhound/c/cc_lang.h
   vendor/elsa/current/elkhound/c/configure.pl
   vendor/elsa/current/elkhound/c/cparse.cc
   vendor/elsa/current/elkhound/c/cparse.h
   vendor/elsa/current/elkhound/c/exprequal.cc
   vendor/elsa/current/elkhound/c/exprequal.h
   vendor/elsa/current/elkhound/c/exprvisit.cc
   vendor/elsa/current/elkhound/c/exprvisit.h
   vendor/elsa/current/elkhound/c/lexer1.cc
   vendor/elsa/current/elkhound/c/lexer1.h
   vendor/elsa/current/elkhound/c/lexer1.lex
   vendor/elsa/current/elkhound/c/lexer1yy.cc
   vendor/elsa/current/elkhound/c/lexer2.cc
   vendor/elsa/current/elkhound/c/lexer2.h
   vendor/elsa/current/elkhound/c/main.cc
   vendor/elsa/current/elkhound/c/parssppt.cc
   vendor/elsa/current/elkhound/c/parssppt.h
   vendor/elsa/current/elkhound/c/paths.cc
   vendor/elsa/current/elkhound/c/paths.h
   vendor/elsa/current/elkhound/c/postorder.cc
   vendor/elsa/current/elkhound/c/stubs.cc
   vendor/elsa/current/elkhound/c/tcheck.cc
   vendor/elsa/current/elkhound/c/treeout.cc
   vendor/elsa/current/elkhound/c/treeout.h
   vendor/elsa/current/elkhound/cc.in/
   vendor/elsa/current/elkhound/cc.in/big/
   vendor/elsa/current/elkhound/cc/
   vendor/elsa/current/elkhound/cc/outdir/
   vendor/elsa/current/elkhound/cc2/
   vendor/elsa/current/elkhound/cc2/cc2.gr
   vendor/elsa/current/elkhound/cc2/cc2main.cc
   vendor/elsa/current/elkhound/cc2/license.txt
   vendor/elsa/current/elkhound/cc2/test.cc
   vendor/elsa/current/elkhound/cc2/testprog.cc
   vendor/elsa/current/elkhound/cdecl2.gr
   vendor/elsa/current/elkhound/configure.pl
   vendor/elsa/current/elkhound/cyctimer.cc
   vendor/elsa/current/elkhound/cyctimer.h
   vendor/elsa/current/elkhound/doc/
   vendor/elsa/current/elkhound/emitcode.cc
   vendor/elsa/current/elkhound/emitcode.h
   vendor/elsa/current/elkhound/examples/
   vendor/elsa/current/elkhound/examples/arith/
   vendor/elsa/current/elkhound/examples/arith/arith.cc
   vendor/elsa/current/elkhound/examples/arith/arith.gr
   vendor/elsa/current/elkhound/examples/arith/arith.h
   vendor/elsa/current/elkhound/examples/arith/arith.lex
   vendor/elsa/current/elkhound/examples/arith/arithyy.cc
   vendor/elsa/current/elkhound/examples/arith/configure.pl
   vendor/elsa/current/elkhound/examples/asu419.gr
   vendor/elsa/current/elkhound/examples/cc_eeb.cc
   vendor/elsa/current/elkhound/examples/cc_eeb.gr
   vendor/elsa/current/elkhound/examples/cc_eeb.h
   vendor/elsa/current/elkhound/examples/cdecl/
   vendor/elsa/current/elkhound/examples/cdecl/cdecl.gr
   vendor/elsa/current/elkhound/examples/cexp/
   vendor/elsa/current/elkhound/examples/cexp/cexp3.gr
   vendor/elsa/current/elkhound/examples/cexp/cexp3ast.ast
   vendor/elsa/current/elkhound/examples/cexp/cexp3mrg.cc
   vendor/elsa/current/elkhound/examples/crash1.gr
   vendor/elsa/current/elkhound/examples/gcom/
   vendor/elsa/current/elkhound/examples/gcom/eval.cc
   vendor/elsa/current/elkhound/examples/gcom/eval.h
   vendor/elsa/current/elkhound/examples/gcom/gcom.ast
   vendor/elsa/current/elkhound/examples/gcom/gcom.gr
   vendor/elsa/current/elkhound/examples/gcom/in1
   vendor/elsa/current/elkhound/examples/gcom/in2
   vendor/elsa/current/elkhound/examples/gcom/in3
   vendor/elsa/current/elkhound/examples/gcom/lexer.cc
   vendor/elsa/current/elkhound/examples/gcom/lexer.h
   vendor/elsa/current/elkhound/examples/gcom/parser.cc
   vendor/elsa/current/elkhound/examples/gcom1/
   vendor/elsa/current/elkhound/examples/gcom1/gcom.gr
   vendor/elsa/current/elkhound/examples/gcom1/lexer.cc
   vendor/elsa/current/elkhound/examples/gcom1/lexer.h
   vendor/elsa/current/elkhound/examples/gcom1/parser.cc
   vendor/elsa/current/elkhound/examples/gcom2/
   vendor/elsa/current/elkhound/examples/gcom2/parser.cc
   vendor/elsa/current/elkhound/examples/gcom3/
   vendor/elsa/current/elkhound/examples/gcom3/gcom.gr
   vendor/elsa/current/elkhound/examples/gcom4/
   vendor/elsa/current/elkhound/examples/gcom4/gcom.gr
   vendor/elsa/current/elkhound/examples/gcom4/lexer.cc
   vendor/elsa/current/elkhound/examples/gcom4/lexer.h
   vendor/elsa/current/elkhound/examples/gcom4/parser.cc
   vendor/elsa/current/elkhound/examples/gcom5/
   vendor/elsa/current/elkhound/examples/gcom5/gcom.gr
   vendor/elsa/current/elkhound/examples/gcom5/lexer.cc
   vendor/elsa/current/elkhound/examples/gcom5/lexer.h
   vendor/elsa/current/elkhound/examples/gcom5/parser.cc
   vendor/elsa/current/elkhound/examples/gcom7/
   vendor/elsa/current/elkhound/examples/gcom7/eval.cc
   vendor/elsa/current/elkhound/examples/gcom7/eval.h
   vendor/elsa/current/elkhound/examples/gcom7/gcom.ast
   vendor/elsa/current/elkhound/examples/gcom7/gcom.gr
   vendor/elsa/current/elkhound/examples/gcom7/lexer.cc
   vendor/elsa/current/elkhound/examples/gcom7/lexer.h
   vendor/elsa/current/elkhound/examples/gcom7/parser.cc
   vendor/elsa/current/elkhound/examples/scannerless/
   vendor/elsa/current/elkhound/examples/scannerless/main.cc
   vendor/elsa/current/elkhound/examples/scannerless/sless.gr
   vendor/elsa/current/elkhound/extradep.mk
   vendor/elsa/current/elkhound/faq.html
   vendor/elsa/current/elkhound/ffollow.gr
   vendor/elsa/current/elkhound/ffollow_ext.gr
   vendor/elsa/current/elkhound/find-extra-deps
   vendor/elsa/current/elkhound/flatutil.h
   vendor/elsa/current/elkhound/forbid.gr
   vendor/elsa/current/elkhound/genml.cc
   vendor/elsa/current/elkhound/genml.h
   vendor/elsa/current/elkhound/glr.cc
   vendor/elsa/current/elkhound/glr.h
   vendor/elsa/current/elkhound/glrconfig.h.in
   vendor/elsa/current/elkhound/glrmain.cc
   vendor/elsa/current/elkhound/gramanl.cc
   vendor/elsa/current/elkhound/gramanl.h
   vendor/elsa/current/elkhound/gramast.ast
   vendor/elsa/current/elkhound/gramast.cc
   vendor/elsa/current/elkhound/gramast.h
   vendor/elsa/current/elkhound/gramexpl.cc
   vendor/elsa/current/elkhound/gramlex.lex
   vendor/elsa/current/elkhound/grammar.cc
   vendor/elsa/current/elkhound/grammar.h
   vendor/elsa/current/elkhound/grammar.txt
   vendor/elsa/current/elkhound/grampar.cc
   vendor/elsa/current/elkhound/grampar.codes.h
   vendor/elsa/current/elkhound/grampar.h
   vendor/elsa/current/elkhound/grampar.tab.cc
   vendor/elsa/current/elkhound/grampar.tab.h
   vendor/elsa/current/elkhound/grampar.y
   vendor/elsa/current/elkhound/in/
   vendor/elsa/current/elkhound/in/L1.in1
   vendor/elsa/current/elkhound/in/asu419.in
   vendor/elsa/current/elkhound/in/bb10.c
   vendor/elsa/current/elkhound/in/bb100.c
   vendor/elsa/current/elkhound/in/bb1000.c
   vendor/elsa/current/elkhound/in/bb12.c
   vendor/elsa/current/elkhound/in/bb14.c
   vendor/elsa/current/elkhound/in/bb16.c
   vendor/elsa/current/elkhound/in/bb18.c
   vendor/elsa/current/elkhound/in/bb20.c
   vendor/elsa/current/elkhound/in/bb200.c
   vendor/elsa/current/elkhound/in/bb300.c
   vendor/elsa/current/elkhound/in/bb400.c
   vendor/elsa/current/elkhound/in/bb5.c
   vendor/elsa/current/elkhound/in/bb50.c
   vendor/elsa/current/elkhound/in/bb500.c
   vendor/elsa/current/elkhound/in/bb6.c
   vendor/elsa/current/elkhound/in/bb7.c
   vendor/elsa/current/elkhound/in/bb8.c
   vendor/elsa/current/elkhound/in/bb9.c
   vendor/elsa/current/elkhound/in/bsort.c.in4
   vendor/elsa/current/elkhound/in/castprob.in1
   vendor/elsa/current/elkhound/in/castprob.in2
   vendor/elsa/current/elkhound/in/cc.in1
   vendor/elsa/current/elkhound/in/cc.in2
   vendor/elsa/current/elkhound/in/cc.in3
   vendor/elsa/current/elkhound/in/cc.in4
   vendor/elsa/current/elkhound/in/cc.in5
   vendor/elsa/current/elkhound/in/cc.in6
   vendor/elsa/current/elkhound/in/cdecl.in1
   vendor/elsa/current/elkhound/in/cexp.in1
   vendor/elsa/current/elkhound/in/cexp2.in2
   vendor/elsa/current/elkhound/in/cexp3.in1
   vendor/elsa/current/elkhound/in/cexp3.in2
   vendor/elsa/current/elkhound/in/expr.in1
   vendor/elsa/current/elkhound/in/ffollow.in1
   vendor/elsa/current/elkhound/in/gramlex.in1
   vendor/elsa/current/elkhound/in/gramlex.in2
   vendor/elsa/current/elkhound/in/gramlex.in3
   vendor/elsa/current/elkhound/in/lexer2.in1
   vendor/elsa/current/elkhound/in/mem.in1
   vendor/elsa/current/elkhound/in/mem.in2
   vendor/elsa/current/elkhound/in/mem.in3
   vendor/elsa/current/elkhound/in/pc_keyb.i
   vendor/elsa/current/elkhound/in/qpsmall.i
   vendor/elsa/current/elkhound/in/qsort.c.in5
   vendor/elsa/current/elkhound/in/ssh-add2.c
   vendor/elsa/current/elkhound/index.html
   vendor/elsa/current/elkhound/lexerint.h
   vendor/elsa/current/elkhound/license.txt
   vendor/elsa/current/elkhound/make-lrtable-graph
   vendor/elsa/current/elkhound/make-tok
   vendor/elsa/current/elkhound/make-trivparser.pl
   vendor/elsa/current/elkhound/manual.html
   vendor/elsa/current/elkhound/mkdist
   vendor/elsa/current/elkhound/mlsstr.cc
   vendor/elsa/current/elkhound/mlsstr.h
   vendor/elsa/current/elkhound/ocaml/
   vendor/elsa/current/elkhound/ocaml/arith.gr
   vendor/elsa/current/elkhound/ocaml/arraystack.ml
   vendor/elsa/current/elkhound/ocaml/een.gr
   vendor/elsa/current/elkhound/ocaml/glr.ml
   vendor/elsa/current/elkhound/ocaml/lexer.mll
   vendor/elsa/current/elkhound/ocaml/lexerint.ml
   vendor/elsa/current/elkhound/ocaml/lrparse.ml
   vendor/elsa/current/elkhound/ocaml/main.ml
   vendor/elsa/current/elkhound/ocaml/objpool.ml
   vendor/elsa/current/elkhound/ocaml/oc_arith.mly
   vendor/elsa/current/elkhound/ocaml/occ2/
   vendor/elsa/current/elkhound/ocaml/occ2/lexer.mll
   vendor/elsa/current/elkhound/ocaml/occ2/occ2.gr
   vendor/elsa/current/elkhound/ocaml/occ2/tokens.h
   vendor/elsa/current/elkhound/ocaml/parsetables.ml
   vendor/elsa/current/elkhound/ocaml/ptreeact.ml
   vendor/elsa/current/elkhound/ocaml/ptreenode.ml
   vendor/elsa/current/elkhound/ocaml/smutil.ml
   vendor/elsa/current/elkhound/ocaml/tobjpool.ml
   vendor/elsa/current/elkhound/ocaml/useract.ml
   vendor/elsa/current/elkhound/out/
   vendor/elsa/current/elkhound/out/c.out1
   vendor/elsa/current/elkhound/out/c.out2
   vendor/elsa/current/elkhound/out/c.out3
   vendor/elsa/current/elkhound/out/castprob.out1
   vendor/elsa/current/elkhound/out/cdecl.out1
   vendor/elsa/current/elkhound/out/expr.out1
   vendor/elsa/current/elkhound/out/ffollow.out1
   vendor/elsa/current/elkhound/ownerspec.h
   vendor/elsa/current/elkhound/parse-linux
   vendor/elsa/current/elkhound/parse-tests
   vendor/elsa/current/elkhound/parser.files
   vendor/elsa/current/elkhound/parsetables.cc
   vendor/elsa/current/elkhound/parsetables.h
   vendor/elsa/current/elkhound/parsgen.txt
   vendor/elsa/current/elkhound/parsstub.cc
   vendor/elsa/current/elkhound/perf
   vendor/elsa/current/elkhound/perftest/
   vendor/elsa/current/elkhound/perftest/history
   vendor/elsa/current/elkhound/perftest/test-all
   vendor/elsa/current/elkhound/perftest/test-ver
   vendor/elsa/current/elkhound/ptreeact.cc
   vendor/elsa/current/elkhound/ptreeact.h
   vendor/elsa/current/elkhound/ptreenode.cc
   vendor/elsa/current/elkhound/ptreenode.h
   vendor/elsa/current/elkhound/rcptr.h
   vendor/elsa/current/elkhound/readme.txt
   vendor/elsa/current/elkhound/regrtest
   vendor/elsa/current/elkhound/skeleton.gr
   vendor/elsa/current/elkhound/ssxmain.cc
   vendor/elsa/current/elkhound/ssxnode.h
   vendor/elsa/current/elkhound/tcheck/
   vendor/elsa/current/elkhound/tcheck/addrglob.c
   vendor/elsa/current/elkhound/tcheck/exprpath.c
   vendor/elsa/current/elkhound/tcheck/init.c
   vendor/elsa/current/elkhound/tcheck/loops.c
   vendor/elsa/current/elkhound/tcheck/morepaths.c
   vendor/elsa/current/elkhound/test-all-config
   vendor/elsa/current/elkhound/test-ambig-perf
   vendor/elsa/current/elkhound/test-bad
   vendor/elsa/current/elkhound/test-mlsstr-on-many
   vendor/elsa/current/elkhound/toplevel/
   vendor/elsa/current/elkhound/toplevel/license.txt
   vendor/elsa/current/elkhound/toplevel/readme.txt
   vendor/elsa/current/elkhound/trcptr.cc
   vendor/elsa/current/elkhound/triv/
   vendor/elsa/current/elkhound/triv/AdB.gr.in
   vendor/elsa/current/elkhound/triv/AdB.in1
   vendor/elsa/current/elkhound/triv/CAdB.gr.in
   vendor/elsa/current/elkhound/triv/CAdB.in1
   vendor/elsa/current/elkhound/triv/CNI.gr.in
   vendor/elsa/current/elkhound/triv/CNI.in1
   vendor/elsa/current/elkhound/triv/DeclExpr.gr.in
   vendor/elsa/current/elkhound/triv/DeclExpr.in1
   vendor/elsa/current/elkhound/triv/DeclExpr.in10
   vendor/elsa/current/elkhound/triv/DeclExpr.in100
   vendor/elsa/current/elkhound/triv/DeclExpr.in1000
   vendor/elsa/current/elkhound/triv/DeclExpr.in10000
   vendor/elsa/current/elkhound/triv/DeclExpr.in5
   vendor/elsa/current/elkhound/triv/DeclExpr.perf.txt
   vendor/elsa/current/elkhound/triv/EEb.gr.in
   vendor/elsa/current/elkhound/triv/EEb.in1
   vendor/elsa/current/elkhound/triv/EEb.in2
   vendor/elsa/current/elkhound/triv/EEb.in3
   vendor/elsa/current/elkhound/triv/EFa.gr.in
   vendor/elsa/current/elkhound/triv/ESb.gr.in
   vendor/elsa/current/elkhound/triv/ESb.in1
   vendor/elsa/current/elkhound/triv/SSSx.gr.in
   vendor/elsa/current/elkhound/triv/SSx.gr.in
   vendor/elsa/current/elkhound/triv/aSEb.gr.in
   vendor/elsa/current/elkhound/triv/aSEb.in1
   vendor/elsa/current/elkhound/triv/angle.gr.in
   vendor/elsa/current/elkhound/triv/angle.in1
   vendor/elsa/current/elkhound/triv/angle.in2
   vendor/elsa/current/elkhound/triv/angle.in3
   vendor/elsa/current/elkhound/triv/angle.in4
   vendor/elsa/current/elkhound/triv/angle.in5
   vendor/elsa/current/elkhound/triv/eeb.notree.perf.txt
   vendor/elsa/current/elkhound/triv/eeb.perf.txt
   vendor/elsa/current/elkhound/triv/efa.bison.notree.perf.csv
   vendor/elsa/current/elkhound/triv/efa.bison.notree.perf.txt
   vendor/elsa/current/elkhound/triv/efa.bison.tree.perf.csv
   vendor/elsa/current/elkhound/triv/efa.bison.tree.perf.txt
   vendor/elsa/current/elkhound/triv/efa.glronly.notree.perf.csv
   vendor/elsa/current/elkhound/triv/efa.glronly.notree.perf.txt
   vendor/elsa/current/elkhound/triv/efa.glronly.perf.csv
   vendor/elsa/current/elkhound/triv/efa.glronly.perf.txt
   vendor/elsa/current/elkhound/triv/efa.nohybrid.notree.perf.csv
   vendor/elsa/current/elkhound/triv/efa.nohybrid.notree.perf.txt
   vendor/elsa/current/elkhound/triv/efa.nohybrid.perf.csv
   vendor/elsa/current/elkhound/triv/efa.nohybrid.perf.txt
   vendor/elsa/current/elkhound/triv/efa.notree.perf.csv
   vendor/elsa/current/elkhound/triv/efa.notree.perf.txt
   vendor/elsa/current/elkhound/triv/efa.perf.csv
   vendor/elsa/current/elkhound/triv/efa.perf.txt
   vendor/elsa/current/elkhound/triv/ite.gr.in
   vendor/elsa/current/elkhound/triv/ite.in1
   vendor/elsa/current/elkhound/triv/ite.in2
   vendor/elsa/current/elkhound/triv/ite.in3
   vendor/elsa/current/elkhound/triv/ite.in4
   vendor/elsa/current/elkhound/triv/ite.in5
   vendor/elsa/current/elkhound/triv/sssx.notree.perf.txt
   vendor/elsa/current/elkhound/triv/sssx.perf.txt
   vendor/elsa/current/elkhound/triv/ssx.notree.perf.txt
   vendor/elsa/current/elkhound/triv/ssx.perf.txt
   vendor/elsa/current/elkhound/triv/testRR.gr.in
   vendor/elsa/current/elkhound/triv/testRR.in1
   vendor/elsa/current/elkhound/triv/testRR.in2
   vendor/elsa/current/elkhound/trivbison.cc
   vendor/elsa/current/elkhound/trivbison.h
   vendor/elsa/current/elkhound/trivlex.cc
   vendor/elsa/current/elkhound/trivlex.h
   vendor/elsa/current/elkhound/trivmain.cc
   vendor/elsa/current/elkhound/tutorial.html
   vendor/elsa/current/elkhound/useract.cc
   vendor/elsa/current/elkhound/useract.h
   vendor/elsa/current/elkhound/util.h
   vendor/elsa/current/elsa/
   vendor/elsa/current/elsa/ast_build.cc
   vendor/elsa/current/elsa/ast_build.h
   vendor/elsa/current/elsa/astvisit.cc
   vendor/elsa/current/elsa/astvisit.h
   vendor/elsa/current/elsa/astxml_check
   vendor/elsa/current/elsa/baselexer.cc
   vendor/elsa/current/elsa/baselexer.h
   vendor/elsa/current/elsa/bitstrmap.h
   vendor/elsa/current/elsa/buildint/
   vendor/elsa/current/elsa/buildint/extract_section.pl
   vendor/elsa/current/elsa/buildint/install
   vendor/elsa/current/elsa/buildint/interceptor.pl
   vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-2
   vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-3
   vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-3.4
   vendor/elsa/current/elsa/buildint/reconstruct-exec.pl
   vendor/elsa/current/elsa/builtin-declarations.h
   vendor/elsa/current/elsa/builtin-t.h
   vendor/elsa/current/elsa/builtinops.cc
   vendor/elsa/current/elsa/builtinops.h
   vendor/elsa/current/elsa/cc.ast
   vendor/elsa/current/elsa/cc.gr
   vendor/elsa/current/elsa/cc.lex
   vendor/elsa/current/elsa/cc_ast.h
   vendor/elsa/current/elsa/cc_ast_aux.cc
   vendor/elsa/current/elsa/cc_ast_aux.h
   vendor/elsa/current/elsa/cc_elaborate.ast
   vendor/elsa/current/elsa/cc_elaborate.cc
   vendor/elsa/current/elsa/cc_elaborate.h
   vendor/elsa/current/elsa/cc_env.cc
   vendor/elsa/current/elsa/cc_env.h
   vendor/elsa/current/elsa/cc_err.cc
   vendor/elsa/current/elsa/cc_err.h
   vendor/elsa/current/elsa/cc_flags.cc
   vendor/elsa/current/elsa/cc_flags.h
   vendor/elsa/current/elsa/cc_lang.cc
   vendor/elsa/current/elsa/cc_lang.h
   vendor/elsa/current/elsa/cc_print.ast
   vendor/elsa/current/elsa/cc_print.cc
   vendor/elsa/current/elsa/cc_print.h
   vendor/elsa/current/elsa/cc_scope.cc
   vendor/elsa/current/elsa/cc_scope.h
   vendor/elsa/current/elsa/cc_tcheck.ast
   vendor/elsa/current/elsa/cc_tcheck.cc
   vendor/elsa/current/elsa/cc_tokens.tok
   vendor/elsa/current/elsa/cc_type.cc
   vendor/elsa/current/elsa/cc_type.h
   vendor/elsa/current/elsa/ccparse.cc
   vendor/elsa/current/elsa/ccparse.h
   vendor/elsa/current/elsa/cfg.ast
   vendor/elsa/current/elsa/cfg.cc
   vendor/elsa/current/elsa/cfg.h
   vendor/elsa/current/elsa/chop_out
   vendor/elsa/current/elsa/cipart.lex
   vendor/elsa/current/elsa/configure.pl
   vendor/elsa/current/elsa/const_eval.cc
   vendor/elsa/current/elsa/const_eval.h
   vendor/elsa/current/elsa/crlf.txt
   vendor/elsa/current/elsa/doc/
   vendor/elsa/current/elsa/doc/ambiguous_ast.png
   vendor/elsa/current/elsa/doc/anon-structs.txt
   vendor/elsa/current/elsa/doc/ast_build.dot
   vendor/elsa/current/elsa/doc/ast_build.png
   vendor/elsa/current/elsa/doc/atomic_types.png
   vendor/elsa/current/elsa/doc/block_diagram.fig
   vendor/elsa/current/elsa/doc/block_diagram.png
   vendor/elsa/current/elsa/doc/cc.ast.html
   vendor/elsa/current/elsa/doc/cc_type.html
   vendor/elsa/current/elsa/doc/class_templates.png
   vendor/elsa/current/elsa/doc/coloncolon.txt
   vendor/elsa/current/elsa/doc/complex.txt
   vendor/elsa/current/elsa/doc/constructed_types.png
   vendor/elsa/current/elsa/doc/contributors.html
   vendor/elsa/current/elsa/doc/convertibility.txt
   vendor/elsa/current/elsa/doc/cpp_er.html
   vendor/elsa/current/elsa/doc/declarator.fig
   vendor/elsa/current/elsa/doc/declarator.html
   vendor/elsa/current/elsa/doc/declarator.png
   vendor/elsa/current/elsa/doc/design.html
   vendor/elsa/current/elsa/doc/er.fig
   vendor/elsa/current/elsa/doc/er.png
   vendor/elsa/current/elsa/doc/er.ps
   vendor/elsa/current/elsa/doc/faq.html
   vendor/elsa/current/elsa/doc/function_templates.png
   vendor/elsa/current/elsa/doc/gv-xwd-convert-png
   vendor/elsa/current/elsa/doc/hex_float_lit.dot
   vendor/elsa/current/elsa/doc/index.html
   vendor/elsa/current/elsa/doc/lexer_build.dot
   vendor/elsa/current/elsa/doc/lexer_build.png
   vendor/elsa/current/elsa/doc/lookup.txt
   vendor/elsa/current/elsa/doc/parser_build.dot
   vendor/elsa/current/elsa/doc/parser_build.png
   vendor/elsa/current/elsa/doc/permissive.txt
   vendor/elsa/current/elsa/doc/serialization.txt
   vendor/elsa/current/elsa/doc/template_er.fig
   vendor/elsa/current/elsa/doc/template_er.png
   vendor/elsa/current/elsa/doc/template_er.ps
   vendor/elsa/current/elsa/doc/tutorial.html
   vendor/elsa/current/elsa/doc/tutorial_part2.html
   vendor/elsa/current/elsa/doc/valid-html401.png
   vendor/elsa/current/elsa/doc/variables.png
   vendor/elsa/current/elsa/extradep.mk
   vendor/elsa/current/elsa/filter_elsa_noise
   vendor/elsa/current/elsa/five-errors
   vendor/elsa/current/elsa/generic_amb.h
   vendor/elsa/current/elsa/generic_aux.h
   vendor/elsa/current/elsa/gnu.ast
   vendor/elsa/current/elsa/gnu.cc
   vendor/elsa/current/elsa/gnu.gr
   vendor/elsa/current/elsa/gnu.lex
   vendor/elsa/current/elsa/gnu_ext.tok
   vendor/elsa/current/elsa/id_obj_dict.cc
   vendor/elsa/current/elsa/id_obj_dict.h
   vendor/elsa/current/elsa/idemcheck
   vendor/elsa/current/elsa/implconv.cc
   vendor/elsa/current/elsa/implconv.h
   vendor/elsa/current/elsa/implint.cc
   vendor/elsa/current/elsa/implint.h
   vendor/elsa/current/elsa/in/
   vendor/elsa/current/elsa/in/big/
   vendor/elsa/current/elsa/in/big/gz/
   vendor/elsa/current/elsa/in/big/gz/nonport.i.gz
   vendor/elsa/current/elsa/in/big/gz/nsAtomTable.i.gz
   vendor/elsa/current/elsa/in/big/gz/nsCLiveconnectFactory.i.gz
   vendor/elsa/current/elsa/in/big/gz/nsHTMLEditRules.i.gz
   vendor/elsa/current/elsa/in/big/gz/nsMsgServiceProvider.i.gz
   vendor/elsa/current/elsa/in/big/gz/nsSOAPPropertyBag.i.gz
   vendor/elsa/current/elsa/in/big/gz/nsUnicodeToTeXCMRt1.i.gz
   vendor/elsa/current/elsa/in/big/gz/ostream.i.gz
   vendor/elsa/current/elsa/in/c/
   vendor/elsa/current/elsa/in/c/d0124b.c
   vendor/elsa/current/elsa/in/c/dC0010.c
   vendor/elsa/current/elsa/in/c/dC0011.c
   vendor/elsa/current/elsa/in/c/dC0012.c
   vendor/elsa/current/elsa/in/c/dC0013.c
   vendor/elsa/current/elsa/in/c/dC0017.c
   vendor/elsa/current/elsa/in/c/dC0018.c
   vendor/elsa/current/elsa/in/c/dC0019.c
   vendor/elsa/current/elsa/in/c/dC0020.c
   vendor/elsa/current/elsa/in/c/dC0021.c
   vendor/elsa/current/elsa/in/c/dC0022.c
   vendor/elsa/current/elsa/in/c/dC0023.c
   vendor/elsa/current/elsa/in/c/dC0024.c
   vendor/elsa/current/elsa/in/c/dC0025.c
   vendor/elsa/current/elsa/in/c/dC0026.c
   vendor/elsa/current/elsa/in/c/dC0027.c
   vendor/elsa/current/elsa/in/c/dC0028.c
   vendor/elsa/current/elsa/in/c/dC0029.c
   vendor/elsa/current/elsa/in/c/dC0030.c
   vendor/elsa/current/elsa/in/c/dC0031.c
   vendor/elsa/current/elsa/in/c/dC0032.c
   vendor/elsa/current/elsa/in/c/k0001.c
   vendor/elsa/current/elsa/in/c/k0002.c
   vendor/elsa/current/elsa/in/c/k0003.c
   vendor/elsa/current/elsa/in/c/k0003a.c
   vendor/elsa/current/elsa/in/c/k0004.c
   vendor/elsa/current/elsa/in/c/k0005.c
   vendor/elsa/current/elsa/in/c/k0006.c
   vendor/elsa/current/elsa/in/c/k0006a.c
   vendor/elsa/current/elsa/in/c/k0007.c
   vendor/elsa/current/elsa/in/c/k0008.c
   vendor/elsa/current/elsa/in/c/k0009.c
   vendor/elsa/current/elsa/in/c/k0010.c
   vendor/elsa/current/elsa/in/c/k0011.c
   vendor/elsa/current/elsa/in/c/k0012.c
   vendor/elsa/current/elsa/in/c/k0013.c
   vendor/elsa/current/elsa/in/c/k0014.c
   vendor/elsa/current/elsa/in/c/k0015.c
   vendor/elsa/current/elsa/in/c/k0016.c
   vendor/elsa/current/elsa/in/c/k0017.c
   vendor/elsa/current/elsa/in/c/t0001.c
   vendor/elsa/current/elsa/in/c/t0002.c
   vendor/elsa/current/elsa/in/c/t0003.c
   vendor/elsa/current/elsa/in/c/t0004.c
   vendor/elsa/current/elsa/in/c/t0005.c
   vendor/elsa/current/elsa/in/c/t0006.c
   vendor/elsa/current/elsa/in/c/t0007.c
   vendor/elsa/current/elsa/in/c/t0008.c
   vendor/elsa/current/elsa/in/c/t0009.c
   vendor/elsa/current/elsa/in/c/t0010.c
   vendor/elsa/current/elsa/in/c/t0011.c
   vendor/elsa/current/elsa/in/c/t0012.c
   vendor/elsa/current/elsa/in/c/t0013.c
   vendor/elsa/current/elsa/in/c/t0014.c
   vendor/elsa/current/elsa/in/c/t0015.c
   vendor/elsa/current/elsa/in/c/t0016.c
   vendor/elsa/current/elsa/in/c/t0017.c
   vendor/elsa/current/elsa/in/c/t0018.c
   vendor/elsa/current/elsa/in/c/t0019.c
   vendor/elsa/current/elsa/in/c/t0020.c
   vendor/elsa/current/elsa/in/c/t0021.c
   vendor/elsa/current/elsa/in/c/t0022.c
   vendor/elsa/current/elsa/in/c/t0023.c
   vendor/elsa/current/elsa/in/c/t0024.c
   vendor/elsa/current/elsa/in/c/t0025.c
   vendor/elsa/current/elsa/in/c/t0026.c
   vendor/elsa/current/elsa/in/c/t0027.c
   vendor/elsa/current/elsa/in/c99/
   vendor/elsa/current/elsa/in/c99/d0077.c
   vendor/elsa/current/elsa/in/c99/n0001.c
   vendor/elsa/current/elsa/in/c99/n0002.c
   vendor/elsa/current/elsa/in/c99/t0133.c
   vendor/elsa/current/elsa/in/d0001.cc
   vendor/elsa/current/elsa/in/d0002.cc
   vendor/elsa/current/elsa/in/d0003.cc
   vendor/elsa/current/elsa/in/d0004.cc
   vendor/elsa/current/elsa/in/d0005.cc
   vendor/elsa/current/elsa/in/d0006.cc
   vendor/elsa/current/elsa/in/d0007.cc
   vendor/elsa/current/elsa/in/d0008.cc
   vendor/elsa/current/elsa/in/d0009.cc
   vendor/elsa/current/elsa/in/d0010.cc
   vendor/elsa/current/elsa/in/d0011.cc
   vendor/elsa/current/elsa/in/d0012.cc
   vendor/elsa/current/elsa/in/d0013.cc
   vendor/elsa/current/elsa/in/d0014.cc
   vendor/elsa/current/elsa/in/d0015.cc
   vendor/elsa/current/elsa/in/d0016.cc
   vendor/elsa/current/elsa/in/d0017.cc
   vendor/elsa/current/elsa/in/d0018.cc
   vendor/elsa/current/elsa/in/d0019.cc
   vendor/elsa/current/elsa/in/d0020.cc
   vendor/elsa/current/elsa/in/d0021.cc
   vendor/elsa/current/elsa/in/d0022.cc
   vendor/elsa/current/elsa/in/d0023.cc
   vendor/elsa/current/elsa/in/d0024.cc
   vendor/elsa/current/elsa/in/d0025.cc
   vendor/elsa/current/elsa/in/d0026.cc
   vendor/elsa/current/elsa/in/d0027.cc
   vendor/elsa/current/elsa/in/d0028.cc
   vendor/elsa/current/elsa/in/d0029.cc
   vendor/elsa/current/elsa/in/d0030.cc
   vendor/elsa/current/elsa/in/d0031.cc
   vendor/elsa/current/elsa/in/d0032.cc
   vendor/elsa/current/elsa/in/d0034.cc
   vendor/elsa/current/elsa/in/d0035.cc
   vendor/elsa/current/elsa/in/d0036.cc
   vendor/elsa/current/elsa/in/d0037.cc
   vendor/elsa/current/elsa/in/d0038.cc
   vendor/elsa/current/elsa/in/d0039.cc
   vendor/elsa/current/elsa/in/d0040.cc
   vendor/elsa/current/elsa/in/d0041.cc
   vendor/elsa/current/elsa/in/d0046.cc
   vendor/elsa/current/elsa/in/d0046elab.cc
   vendor/elsa/current/elsa/in/d0047.cc
   vendor/elsa/current/elsa/in/d0048.cc
   vendor/elsa/current/elsa/in/d0048elab.cc
   vendor/elsa/current/elsa/in/d0049.cc
   vendor/elsa/current/elsa/in/d0050.cc
   vendor/elsa/current/elsa/in/d0050elab.cc
   vendor/elsa/current/elsa/in/d0051.cc
   vendor/elsa/current/elsa/in/d0051elab.cc
   vendor/elsa/current/elsa/in/d0052.cc
   vendor/elsa/current/elsa/in/d0053.cc
   vendor/elsa/current/elsa/in/d0054.cc
   vendor/elsa/current/elsa/in/d0055.cc
   vendor/elsa/current/elsa/in/d0056.cc
   vendor/elsa/current/elsa/in/d0057.cc
   vendor/elsa/current/elsa/in/d0058.cc
   vendor/elsa/current/elsa/in/d0059.cc
   vendor/elsa/current/elsa/in/d0060.cc
   vendor/elsa/current/elsa/in/d0061.cc
   vendor/elsa/current/elsa/in/d0062.cc
   vendor/elsa/current/elsa/in/d0063.cc
   vendor/elsa/current/elsa/in/d0064.cc
   vendor/elsa/current/elsa/in/d0065.cc
   vendor/elsa/current/elsa/in/d0066.cc
   vendor/elsa/current/elsa/in/d0067.cc
   vendor/elsa/current/elsa/in/d0068.cc
   vendor/elsa/current/elsa/in/d0069.cc
   vendor/elsa/current/elsa/in/d0070.cc
   vendor/elsa/current/elsa/in/d0071.cc
   vendor/elsa/current/elsa/in/d0072.cc
   vendor/elsa/current/elsa/in/d0073.cc
   vendor/elsa/current/elsa/in/d0074.cc
   vendor/elsa/current/elsa/in/d0075.cc
   vendor/elsa/current/elsa/in/d0079.cc
   vendor/elsa/current/elsa/in/d0080.cc
   vendor/elsa/current/elsa/in/d0084.cc
   vendor/elsa/current/elsa/in/d0087.cc
   vendor/elsa/current/elsa/in/d0088.cc
   vendor/elsa/current/elsa/in/d0089.cc
   vendor/elsa/current/elsa/in/d0090.cc
   vendor/elsa/current/elsa/in/d0091.cc
   vendor/elsa/current/elsa/in/d0097.cc
   vendor/elsa/current/elsa/in/d0098.cc
   vendor/elsa/current/elsa/in/d0099.cc
   vendor/elsa/current/elsa/in/d0100.cc
   vendor/elsa/current/elsa/in/d0101.cc
   vendor/elsa/current/elsa/in/d0102.cc
   vendor/elsa/current/elsa/in/d0103.cc
   vendor/elsa/current/elsa/in/d0104.cc
   vendor/elsa/current/elsa/in/d0105.cc
   vendor/elsa/current/elsa/in/d0106.cc
   vendor/elsa/current/elsa/in/d0107.cc
   vendor/elsa/current/elsa/in/d0108.cc
   vendor/elsa/current/elsa/in/d0109.cc
   vendor/elsa/current/elsa/in/d0110.cc
   vendor/elsa/current/elsa/in/d0111.cc
   vendor/elsa/current/elsa/in/d0112.cc
   vendor/elsa/current/elsa/in/d0113.cc
   vendor/elsa/current/elsa/in/d0114.cc
   vendor/elsa/current/elsa/in/d0115.cc
   vendor/elsa/current/elsa/in/d0116.cc
   vendor/elsa/current/elsa/in/d0117.cc
   vendor/elsa/current/elsa/in/d0118.cc
   vendor/elsa/current/elsa/in/d0119.cc
   vendor/elsa/current/elsa/in/d0120.cc
   vendor/elsa/current/elsa/in/d0121.cc
   vendor/elsa/current/elsa/in/d0123.cc
   vendor/elsa/current/elsa/in/d0124.cc
   vendor/elsa/current/elsa/in/d0125.cc
   vendor/elsa/current/elsa/in/d0126.cc
   vendor/elsa/current/elsa/in/d0128.cc
   vendor/elsa/current/elsa/in/d0129.cc
   vendor/elsa/current/elsa/in/dk0127.cc
   vendor/elsa/current/elsa/in/gnu/
   vendor/elsa/current/elsa/in/gnu/asm01.c
   vendor/elsa/current/elsa/in/gnu/attr01.c
   vendor/elsa/current/elsa/in/gnu/attr02.c
   vendor/elsa/current/elsa/in/gnu/bugs/
   vendor/elsa/current/elsa/in/gnu/bugs/d0106.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0001.c
   vendor/elsa/current/elsa/in/gnu/bugs/gb0002.c
   vendor/elsa/current/elsa/in/gnu/bugs/gb0003.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0004.c
   vendor/elsa/current/elsa/in/gnu/bugs/gb0005.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0006.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0007.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0008.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0009.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0010.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0011.cc
   vendor/elsa/current/elsa/in/gnu/bugs/gb0012.cc
   vendor/elsa/current/elsa/in/gnu/c0001.c
   vendor/elsa/current/elsa/in/gnu/c0002.c
   vendor/elsa/current/elsa/in/gnu/cil/
   vendor/elsa/current/elsa/in/gnu/cil/align1.i
   vendor/elsa/current/elsa/in/gnu/cil/align2.i
   vendor/elsa/current/elsa/in/gnu/cil/attr2.i
   vendor/elsa/current/elsa/in/gnu/cil/attr3.i
   vendor/elsa/current/elsa/in/gnu/cil/attr4.i
   vendor/elsa/current/elsa/in/gnu/cil/attr5.i
   vendor/elsa/current/elsa/in/gnu/cil/attr6.i
   vendor/elsa/current/elsa/in/gnu/cil/bind-zero.i
   vendor/elsa/current/elsa/in/gnu/cil/combine_samefn_1.i
   vendor/elsa/current/elsa/in/gnu/cil/decl1.i
   vendor/elsa/current/elsa/in/gnu/cil/enumattr.i
   vendor/elsa/current/elsa/in/gnu/cil/globalprob.i
   vendor/elsa/current/elsa/in/gnu/cil/init8.i
   vendor/elsa/current/elsa/in/gnu/cil/invalredef.i
   vendor/elsa/current/elsa/in/gnu/cil/mode_sizes.i
   vendor/elsa/current/elsa/in/gnu/cil/regparm0.i
   vendor/elsa/current/elsa/in/gnu/cil/rmtmps-attr.i
   vendor/elsa/current/elsa/in/gnu/cil/rmtmps2.i
   vendor/elsa/current/elsa/in/gnu/cil/sockaddr.i
   vendor/elsa/current/elsa/in/gnu/cil/structattr.i
   vendor/elsa/current/elsa/in/gnu/cil/structattr2.i
   vendor/elsa/current/elsa/in/gnu/cil/structattr3.i
   vendor/elsa/current/elsa/in/gnu/cil/transpunion.i
   vendor/elsa/current/elsa/in/gnu/cil/typeof1.i
   vendor/elsa/current/elsa/in/gnu/cil/warnings-noreturn.i
   vendor/elsa/current/elsa/in/gnu/d0076.cc
   vendor/elsa/current/elsa/in/gnu/d0078.cc
   vendor/elsa/current/elsa/in/gnu/d0081.cc
   vendor/elsa/current/elsa/in/gnu/d0082.cc
   vendor/elsa/current/elsa/in/gnu/d0083.c
   vendor/elsa/current/elsa/in/gnu/d0085.cc
   vendor/elsa/current/elsa/in/gnu/d0086.cc
   vendor/elsa/current/elsa/in/gnu/d0089.cc
   vendor/elsa/current/elsa/in/gnu/d0092.cc
   vendor/elsa/current/elsa/in/gnu/d0093.cc
   vendor/elsa/current/elsa/in/gnu/d0094.cc
   vendor/elsa/current/elsa/in/gnu/d0095.c
   vendor/elsa/current/elsa/in/gnu/d0096.c
   vendor/elsa/current/elsa/in/gnu/d0099.c
   vendor/elsa/current/elsa/in/gnu/d0122.c
   vendor/elsa/current/elsa/in/gnu/d0130.cc
   vendor/elsa/current/elsa/in/gnu/dC0001.c
   vendor/elsa/current/elsa/in/gnu/dC0002.c
   vendor/elsa/current/elsa/in/gnu/dC0003.c
   vendor/elsa/current/elsa/in/gnu/dC0004.c
   vendor/elsa/current/elsa/in/gnu/dC0005.c
   vendor/elsa/current/elsa/in/gnu/dC0006.c
   vendor/elsa/current/elsa/in/gnu/dC0007.c
   vendor/elsa/current/elsa/in/gnu/dC0008.c
   vendor/elsa/current/elsa/in/gnu/dC0009.c
   vendor/elsa/current/elsa/in/gnu/dC0014.c
   vendor/elsa/current/elsa/in/gnu/dC0015.c
   vendor/elsa/current/elsa/in/gnu/dC0016.c
   vendor/elsa/current/elsa/in/gnu/dC0017.c
   vendor/elsa/current/elsa/in/gnu/g0001.cc
   vendor/elsa/current/elsa/in/gnu/g0002.cc
   vendor/elsa/current/elsa/in/gnu/g0003.cc
   vendor/elsa/current/elsa/in/gnu/g0004.cc
   vendor/elsa/current/elsa/in/gnu/g0005.cc
   vendor/elsa/current/elsa/in/gnu/g0006.cc
   vendor/elsa/current/elsa/in/gnu/g0007.cc
   vendor/elsa/current/elsa/in/gnu/g0008.cc
   vendor/elsa/current/elsa/in/gnu/g0009.c
   vendor/elsa/current/elsa/in/gnu/g0010.cc
   vendor/elsa/current/elsa/in/gnu/g0011.cc
   vendor/elsa/current/elsa/in/gnu/g0012.cc
   vendor/elsa/current/elsa/in/gnu/g0013.cc
   vendor/elsa/current/elsa/in/gnu/g0014.cc
   vendor/elsa/current/elsa/in/gnu/g0015.cc
   vendor/elsa/current/elsa/in/gnu/g0016.cc
   vendor/elsa/current/elsa/in/gnu/g0017.cc
   vendor/elsa/current/elsa/in/gnu/g0018.cc
   vendor/elsa/current/elsa/in/gnu/g0019.cc
   vendor/elsa/current/elsa/in/gnu/g0020.cc
   vendor/elsa/current/elsa/in/gnu/g0021.cc
   vendor/elsa/current/elsa/in/gnu/g0022.cc
   vendor/elsa/current/elsa/in/gnu/g0023.cc
   vendor/elsa/current/elsa/in/gnu/g0024.cc
   vendor/elsa/current/elsa/in/gnu/g0025.cc
   vendor/elsa/current/elsa/in/gnu/g0026.cc
   vendor/elsa/current/elsa/in/gnu/g0027.cc
   vendor/elsa/current/elsa/in/gnu/g0028.cc
   vendor/elsa/current/elsa/in/gnu/g0029.cc
   vendor/elsa/current/elsa/in/gnu/g0030.cc
   vendor/elsa/current/elsa/in/gnu/g0031.cc
   vendor/elsa/current/elsa/in/gnu/g0032.cc
   vendor/elsa/current/elsa/in/gnu/g0033.cc
   vendor/elsa/current/elsa/in/gnu/k0001.cc
   vendor/elsa/current/elsa/in/gnu/k0002.cc
   vendor/elsa/current/elsa/in/gnu/k0003.cc
   vendor/elsa/current/elsa/in/gnu/k0004.cc
   vendor/elsa/current/elsa/in/gnu/k0005.cc
   vendor/elsa/current/elsa/in/gnu/k0006.cc
   vendor/elsa/current/elsa/in/gnu/k0006a.cc
   vendor/elsa/current/elsa/in/gnu/k0007.cc
   vendor/elsa/current/elsa/in/gnu/k0008.c
   vendor/elsa/current/elsa/in/gnu/k0009.cc
   vendor/elsa/current/elsa/in/gnu/k0010.c
   vendor/elsa/current/elsa/in/gnu/t0124.cc
   vendor/elsa/current/elsa/in/gnu/t0125.cc
   vendor/elsa/current/elsa/in/gnu/t0126.c
   vendor/elsa/current/elsa/in/gnu/t0126.c.da_cor
   vendor/elsa/current/elsa/in/gnu/t0127.cc
   vendor/elsa/current/elsa/in/gnu/t0128.cc
   vendor/elsa/current/elsa/in/gnu/t0129.cc
   vendor/elsa/current/elsa/in/gnu/t0130.cc
   vendor/elsa/current/elsa/in/gnu/t0131.cc
   vendor/elsa/current/elsa/in/gnu/t0132.cc
   vendor/elsa/current/elsa/in/gnu/t0133.c
   vendor/elsa/current/elsa/in/gnu/t0134.c
   vendor/elsa/current/elsa/in/gnu/t0135.c
   vendor/elsa/current/elsa/in/gnu/t0136.c
   vendor/elsa/current/elsa/in/gnu/t0137.c
   vendor/elsa/current/elsa/in/k0001.cc
   vendor/elsa/current/elsa/in/k0002.cc
   vendor/elsa/current/elsa/in/k0003.cc
   vendor/elsa/current/elsa/in/k0004.cc
   vendor/elsa/current/elsa/in/k0005.cc
   vendor/elsa/current/elsa/in/k0005a.cc
   vendor/elsa/current/elsa/in/k0006.cc
   vendor/elsa/current/elsa/in/k0007.cc
   vendor/elsa/current/elsa/in/k0008.cc
   vendor/elsa/current/elsa/in/k0009.cc
   vendor/elsa/current/elsa/in/k0010.cc
   vendor/elsa/current/elsa/in/k0010a.cc
   vendor/elsa/current/elsa/in/k0011.cc
   vendor/elsa/current/elsa/in/k0012.cc
   vendor/elsa/current/elsa/in/k0013.cc
   vendor/elsa/current/elsa/in/k0014.cc
   vendor/elsa/current/elsa/in/k0015.cc
   vendor/elsa/current/elsa/in/k0016.cc
   vendor/elsa/current/elsa/in/k0017.cc
   vendor/elsa/current/elsa/in/k0018.cc
   vendor/elsa/current/elsa/in/k0019.cc
   vendor/elsa/current/elsa/in/k0020.cc
   vendor/elsa/current/elsa/in/k0021.cc
   vendor/elsa/current/elsa/in/k0022.cc
   vendor/elsa/current/elsa/in/k0023.cc
   vendor/elsa/current/elsa/in/k0024.cc
   vendor/elsa/current/elsa/in/k0025.cc
   vendor/elsa/current/elsa/in/k0026.cc
   vendor/elsa/current/elsa/in/k0027.cc
   vendor/elsa/current/elsa/in/k0028.cc
   vendor/elsa/current/elsa/in/k0029.cc
   vendor/elsa/current/elsa/in/k0030.cc
   vendor/elsa/current/elsa/in/k0031.cc
   vendor/elsa/current/elsa/in/k0032.cc
   vendor/elsa/current/elsa/in/k0033.cc
   vendor/elsa/current/elsa/in/k0034.cc
   vendor/elsa/current/elsa/in/k0035.cc
   vendor/elsa/current/elsa/in/k0036.cc
   vendor/elsa/current/elsa/in/k0037.cc
   vendor/elsa/current/elsa/in/k0038.cc
   vendor/elsa/current/elsa/in/k0039.cc
   vendor/elsa/current/elsa/in/k0040.cc
   vendor/elsa/current/elsa/in/k0041.cc
   vendor/elsa/current/elsa/in/k0042.cc
   vendor/elsa/current/elsa/in/k0043.cc
   vendor/elsa/current/elsa/in/k0044.cc
   vendor/elsa/current/elsa/in/k0045.cc
   vendor/elsa/current/elsa/in/k0046.cc
   vendor/elsa/current/elsa/in/k0046a.cc
   vendor/elsa/current/elsa/in/k0046b.cc
   vendor/elsa/current/elsa/in/k0047.cc
   vendor/elsa/current/elsa/in/k0048.cc
   vendor/elsa/current/elsa/in/k0049.cc
   vendor/elsa/current/elsa/in/k0050.cc
   vendor/elsa/current/elsa/in/k0051.cc
   vendor/elsa/current/elsa/in/k0052.cc
   vendor/elsa/current/elsa/in/k0053.cc
   vendor/elsa/current/elsa/in/k0054.cc
   vendor/elsa/current/elsa/in/k0055.cc
   vendor/elsa/current/elsa/in/k0056.cc
   vendor/elsa/current/elsa/in/k0057.cc
   vendor/elsa/current/elsa/in/k0058.cc
   vendor/elsa/current/elsa/in/k0059.cc
   vendor/elsa/current/elsa/in/k0060.cc
   vendor/elsa/current/elsa/in/k0061.cc
   vendor/elsa/current/elsa/in/k0062.cc
   vendor/elsa/current/elsa/in/k0063.cc
   vendor/elsa/current/elsa/in/k0064.cc
   vendor/elsa/current/elsa/in/k0065.cc
   vendor/elsa/current/elsa/in/k0066.cc
   vendor/elsa/current/elsa/in/k0067.cc
   vendor/elsa/current/elsa/in/k0068.cc
   vendor/elsa/current/elsa/in/k0069.cc
   vendor/elsa/current/elsa/in/k0070.cc
   vendor/elsa/current/elsa/in/k0071.cc
   vendor/elsa/current/elsa/in/k0072.cc
   vendor/elsa/current/elsa/in/k0073.cc
   vendor/elsa/current/elsa/in/k0074.cc
   vendor/elsa/current/elsa/in/k0075.cc
   vendor/elsa/current/elsa/in/k0076.cc
   vendor/elsa/current/elsa/in/k0077.cc
   vendor/elsa/current/elsa/in/k0078.cc
   vendor/elsa/current/elsa/in/k0078a.cc
   vendor/elsa/current/elsa/in/k0079.cc
   vendor/elsa/current/elsa/in/k0080.cc
   vendor/elsa/current/elsa/in/k0081.cc
   vendor/elsa/current/elsa/in/k0082.cc
   vendor/elsa/current/elsa/in/k0083.cc
   vendor/elsa/current/elsa/in/k0084.cc
   vendor/elsa/current/elsa/in/k0085.cc
   vendor/elsa/current/elsa/in/k0086.cc
   vendor/elsa/current/elsa/in/k0087.cc
   vendor/elsa/current/elsa/in/k0088.cc
   vendor/elsa/current/elsa/in/k0089.cc
   vendor/elsa/current/elsa/in/k0090.cc
   vendor/elsa/current/elsa/in/k0090a.cc
   vendor/elsa/current/elsa/in/k0091.cc
   vendor/elsa/current/elsa/in/k0092.cc
   vendor/elsa/current/elsa/in/k0093.cc
   vendor/elsa/current/elsa/in/k0094.cc
   vendor/elsa/current/elsa/in/k0095.cc
   vendor/elsa/current/elsa/in/k0096.cc
   vendor/elsa/current/elsa/in/k0097.cc
   vendor/elsa/current/elsa/in/k0098.cc
   vendor/elsa/current/elsa/in/k0099.cc
   vendor/elsa/current/elsa/in/k0100.cc
   vendor/elsa/current/elsa/in/k0101.cc
   vendor/elsa/current/elsa/in/k0102.cc
   vendor/elsa/current/elsa/in/k0103.cc
   vendor/elsa/current/elsa/in/k0104.cc
   vendor/elsa/current/elsa/in/k0105.cc
   vendor/elsa/current/elsa/in/k0105a.cc
   vendor/elsa/current/elsa/in/k0106.cc
   vendor/elsa/current/elsa/in/k0107.cc
   vendor/elsa/current/elsa/in/k0108.cc
   vendor/elsa/current/elsa/in/k0109.cc
   vendor/elsa/current/elsa/in/k0110.cc
   vendor/elsa/current/elsa/in/k0111.cc
   vendor/elsa/current/elsa/in/k0112.cc
   vendor/elsa/current/elsa/in/k0113.cc
   vendor/elsa/current/elsa/in/k0114.cc
   vendor/elsa/current/elsa/in/k0115.cc
   vendor/elsa/current/elsa/in/k0116.cc
   vendor/elsa/current/elsa/in/k0117.cc
   vendor/elsa/current/elsa/in/k0118.cc
   vendor/elsa/current/elsa/in/k0119.cc
   vendor/elsa/current/elsa/in/k0120.cc
   vendor/elsa/current/elsa/in/k0121.cc
   vendor/elsa/current/elsa/in/k0122.cc
   vendor/elsa/current/elsa/in/kandr/
   vendor/elsa/current/elsa/in/kandr/t0001.c
   vendor/elsa/current/elsa/in/kandr/t0002.c
   vendor/elsa/current/elsa/in/kandr/t0003.c
   vendor/elsa/current/elsa/in/kandr/t0004.c
   vendor/elsa/current/elsa/in/msvc/
   vendor/elsa/current/elsa/in/msvc/m0001.cc
   vendor/elsa/current/elsa/in/sg0001.cc
   vendor/elsa/current/elsa/in/std/
   vendor/elsa/current/elsa/in/std/12.3.2c.cc
   vendor/elsa/current/elsa/in/std/12.6.2.2a.cc
   vendor/elsa/current/elsa/in/std/12.6.2.2b.cc
   vendor/elsa/current/elsa/in/std/13.1a.cc
   vendor/elsa/current/elsa/in/std/13.1b.cc
   vendor/elsa/current/elsa/in/std/13.1c.cc
   vendor/elsa/current/elsa/in/std/13.1d.cc
   vendor/elsa/current/elsa/in/std/13.1e.cc
   vendor/elsa/current/elsa/in/std/13.1f.cc
   vendor/elsa/current/elsa/in/std/13.1g.cc
   vendor/elsa/current/elsa/in/std/13.2a.cc
   vendor/elsa/current/elsa/in/std/13.3.1.1.2.cc
   vendor/elsa/current/elsa/in/std/13.3.3.1.4.cc
   vendor/elsa/current/elsa/in/std/13.3.3.2a.cc
   vendor/elsa/current/elsa/in/std/13.3.3.2b.cc
   vendor/elsa/current/elsa/in/std/13.3.3.2d.cc
   vendor/elsa/current/elsa/in/std/13.3.3b.cc
   vendor/elsa/current/elsa/in/std/13.cc
   vendor/elsa/current/elsa/in/std/3.4.3a.cc
   vendor/elsa/current/elsa/in/std/3.4.5.cc
   vendor/elsa/current/elsa/in/std/7.1.3b.cc
   vendor/elsa/current/elsa/in/std/7.3.1.2b.cc
   vendor/elsa/current/elsa/in/std/7.3.1.cc
   vendor/elsa/current/elsa/in/std/7.3.2.cc
   vendor/elsa/current/elsa/in/std/7.3.3a.cc
   vendor/elsa/current/elsa/in/std/7.3.3b.cc
   vendor/elsa/current/elsa/in/std/7.3.3c.cc
   vendor/elsa/current/elsa/in/std/7.3.3d.cc
   vendor/elsa/current/elsa/in/std/7.3.3e.cc
   vendor/elsa/current/elsa/in/std/7.3.3f.cc
   vendor/elsa/current/elsa/in/std/7.3.3g.cc
   vendor/elsa/current/elsa/in/std/7.3.3h.cc
   vendor/elsa/current/elsa/in/std/7.3.3i.cc
   vendor/elsa/current/elsa/in/std/7.3.3j.cc
   vendor/elsa/current/elsa/in/std/7.3.3k.cc
   vendor/elsa/current/elsa/in/std/7.3.4a.cc
   vendor/elsa/current/elsa/in/std/7.3.4b.cc
   vendor/elsa/current/elsa/in/std/7.3.4c.cc
   vendor/elsa/current/elsa/in/std/7.3.4d.cc
   vendor/elsa/current/elsa/in/std/7.3.4e.cc
   vendor/elsa/current/elsa/in/std/8.2.1.cc
   vendor/elsa/current/elsa/in/std/8.2.7a.cc
   vendor/elsa/current/elsa/in/std/8.2.7b.cc
   vendor/elsa/current/elsa/in/std/8.3.3.2.cc
   vendor/elsa/current/elsa/in/t0001.cc
   vendor/elsa/current/elsa/in/t0002.cc
   vendor/elsa/current/elsa/in/t0003.cc
   vendor/elsa/current/elsa/in/t0004.cc
   vendor/elsa/current/elsa/in/t0005.cc
   vendor/elsa/current/elsa/in/t0006.cc
   vendor/elsa/current/elsa/in/t0007.cc
   vendor/elsa/current/elsa/in/t0008.cc
   vendor/elsa/current/elsa/in/t0009.cc
   vendor/elsa/current/elsa/in/t0010.cc
   vendor/elsa/current/elsa/in/t0011.cc
   vendor/elsa/current/elsa/in/t0012.cc
   vendor/elsa/current/elsa/in/t0013.cc
   vendor/elsa/current/elsa/in/t0014.cc
   vendor/elsa/current/elsa/in/t0014a.cc
   vendor/elsa/current/elsa/in/t0015.cc
   vendor/elsa/current/elsa/in/t0016.cc
   vendor/elsa/current/elsa/in/t0017.cc
   vendor/elsa/current/elsa/in/t0018.cc
   vendor/elsa/current/elsa/in/t0019.cc
   vendor/elsa/current/elsa/in/t0020.cc
   vendor/elsa/current/elsa/in/t0021.cc
   vendor/elsa/current/elsa/in/t0022.cc
   vendor/elsa/current/elsa/in/t0023.cc
   vendor/elsa/current/elsa/in/t0024.cc
   vendor/elsa/current/elsa/in/t0025.cc
   vendor/elsa/current/elsa/in/t0026.cc
   vendor/elsa/current/elsa/in/t0027.cc
   vendor/elsa/current/elsa/in/t0028.cc
   vendor/elsa/current/elsa/in/t0029.cc
   vendor/elsa/current/elsa/in/t0030.cc
   vendor/elsa/current/elsa/in/t0030a.cc
   vendor/elsa/current/elsa/in/t0030b.cc
   vendor/elsa/current/elsa/in/t0031.cc
   vendor/elsa/current/elsa/in/t0032.cc
   vendor/elsa/current/elsa/in/t0033.cc
   vendor/elsa/current/elsa/in/t0034.cc
   vendor/elsa/current/elsa/in/t0035.cc
   vendor/elsa/current/elsa/in/t0036.cc
   vendor/elsa/current/elsa/in/t0037.cc
   vendor/elsa/current/elsa/in/t0038.cc
   vendor/elsa/current/elsa/in/t0039.cc
   vendor/elsa/current/elsa/in/t0040.cc
   vendor/elsa/current/elsa/in/t0041.cc
   vendor/elsa/current/elsa/in/t0042.cc
   vendor/elsa/current/elsa/in/t0043.cc
   vendor/elsa/current/elsa/in/t0044.cc
   vendor/elsa/current/elsa/in/t0045.cc
   vendor/elsa/current/elsa/in/t0046.cc
   vendor/elsa/current/elsa/in/t0047.cc
   vendor/elsa/current/elsa/in/t0048.cc
   vendor/elsa/current/elsa/in/t0049.cc
   vendor/elsa/current/elsa/in/t0050.cc
   vendor/elsa/current/elsa/in/t0051.cc
   vendor/elsa/current/elsa/in/t0052.cc
   vendor/elsa/current/elsa/in/t0053.cc
   vendor/elsa/current/elsa/in/t0054.cc
   vendor/elsa/current/elsa/in/t0055.cc
   vendor/elsa/current/elsa/in/t0056.cc
   vendor/elsa/current/elsa/in/t0057.cc
   vendor/elsa/current/elsa/in/t0058.cc
   vendor/elsa/current/elsa/in/t0059.cc
   vendor/elsa/current/elsa/in/t0060.cc
   vendor/elsa/current/elsa/in/t0061.cc
   vendor/elsa/current/elsa/in/t0062.cc
   vendor/elsa/current/elsa/in/t0063.cc
   vendor/elsa/current/elsa/in/t0064.cc
   vendor/elsa/current/elsa/in/t0065.cc
   vendor/elsa/current/elsa/in/t0066.cc
   vendor/elsa/current/elsa/in/t0067.cc
   vendor/elsa/current/elsa/in/t0068.cc
   vendor/elsa/current/elsa/in/t0069.cc
   vendor/elsa/current/elsa/in/t0070.cc
   vendor/elsa/current/elsa/in/t0071.cc
   vendor/elsa/current/elsa/in/t0072.cc
   vendor/elsa/current/elsa/in/t0073.cc
   vendor/elsa/current/elsa/in/t0074.cc
   vendor/elsa/current/elsa/in/t0075.cc
   vendor/elsa/current/elsa/in/t0076.cc
   vendor/elsa/current/elsa/in/t0077.cc
   vendor/elsa/current/elsa/in/t0078.cc
   vendor/elsa/current/elsa/in/t0079.cc
   vendor/elsa/current/elsa/in/t0080.cc
   vendor/elsa/current/elsa/in/t0081.cc
   vendor/elsa/current/elsa/in/t0082.cc
   vendor/elsa/current/elsa/in/t0083.cc
   vendor/elsa/current/elsa/in/t0084.cc
   vendor/elsa/current/elsa/in/t0085.cc
   vendor/elsa/current/elsa/in/t0086.cc
   vendor/elsa/current/elsa/in/t0087.cc
   vendor/elsa/current/elsa/in/t0088.cc
   vendor/elsa/current/elsa/in/t0089.cc
   vendor/elsa/current/elsa/in/t0090.cc
   vendor/elsa/current/elsa/in/t0091.cc
   vendor/elsa/current/elsa/in/t0092.cc
   vendor/elsa/current/elsa/in/t0093.cc
   vendor/elsa/current/elsa/in/t0094.cc
   vendor/elsa/current/elsa/in/t0095.cc
   vendor/elsa/current/elsa/in/t0096.cc
   vendor/elsa/current/elsa/in/t0097.cc
   vendor/elsa/current/elsa/in/t0098.cc
   vendor/elsa/current/elsa/in/t0099.cc
   vendor/elsa/current/elsa/in/t0100.cc
   vendor/elsa/current/elsa/in/t0101.cc
   vendor/elsa/current/elsa/in/t0102.cc
   vendor/elsa/current/elsa/in/t0103.cc
   vendor/elsa/current/elsa/in/t0104.cc
   vendor/elsa/current/elsa/in/t0105.cc
   vendor/elsa/current/elsa/in/t0106.cc
   vendor/elsa/current/elsa/in/t0107.cc
   vendor/elsa/current/elsa/in/t0108.cc
   vendor/elsa/current/elsa/in/t0108b.cc
   vendor/elsa/current/elsa/in/t0109.cc
   vendor/elsa/current/elsa/in/t0110.cc
   vendor/elsa/current/elsa/in/t0111.cc
   vendor/elsa/current/elsa/in/t0112.cc
   vendor/elsa/current/elsa/in/t0113.cc
   vendor/elsa/current/elsa/in/t0114.cc
   vendor/elsa/current/elsa/in/t0115.cc
   vendor/elsa/current/elsa/in/t0116.cc
   vendor/elsa/current/elsa/in/t0117.cc
   vendor/elsa/current/elsa/in/t0118.cc
   vendor/elsa/current/elsa/in/t0119.cc
   vendor/elsa/current/elsa/in/t0120.cc
   vendor/elsa/current/elsa/in/t0121.cc
   vendor/elsa/current/elsa/in/t0122.cc
   vendor/elsa/current/elsa/in/t0123.cc
   vendor/elsa/current/elsa/in/t0124.cc
   vendor/elsa/current/elsa/in/t0125.cc
   vendor/elsa/current/elsa/in/t0126.cc
   vendor/elsa/current/elsa/in/t0127.cc
   vendor/elsa/current/elsa/in/t0128.cc
   vendor/elsa/current/elsa/in/t0129.cc
   vendor/elsa/current/elsa/in/t0130.cc
   vendor/elsa/current/elsa/in/t0131.cc
   vendor/elsa/current/elsa/in/t0132.cc
   vendor/elsa/current/elsa/in/t0133.cc
   vendor/elsa/current/elsa/in/t0134.cc
   vendor/elsa/current/elsa/in/t0135.cc
   vendor/elsa/current/elsa/in/t0136.cc
   vendor/elsa/current/elsa/in/t0137.cc
   vendor/elsa/current/elsa/in/t0138.cc
   vendor/elsa/current/elsa/in/t0139.cc
   vendor/elsa/current/elsa/in/t0140.cc
   vendor/elsa/current/elsa/in/t0141.cc
   vendor/elsa/current/elsa/in/t0142.cc
   vendor/elsa/current/elsa/in/t0143.cc
   vendor/elsa/current/elsa/in/t0144.cc
   vendor/elsa/current/elsa/in/t0145.cc
   vendor/elsa/current/elsa/in/t0146.cc
   vendor/elsa/current/elsa/in/t0147.cc
   vendor/elsa/current/elsa/in/t0148.cc
   vendor/elsa/current/elsa/in/t0149.cc
   vendor/elsa/current/elsa/in/t0150.cc
   vendor/elsa/current/elsa/in/t0151.cc
   vendor/elsa/current/elsa/in/t0152.cc
   vendor/elsa/current/elsa/in/t0153.cc
   vendor/elsa/current/elsa/in/t0154.cc
   vendor/elsa/current/elsa/in/t0155.cc
   vendor/elsa/current/elsa/in/t0156.cc
   vendor/elsa/current/elsa/in/t0157.cc
   vendor/elsa/current/elsa/in/t0158.cc
   vendor/elsa/current/elsa/in/t0159.cc
   vendor/elsa/current/elsa/in/t0160.cc
   vendor/elsa/current/elsa/in/t0161.cc
   vendor/elsa/current/elsa/in/t0162.cc
   vendor/elsa/current/elsa/in/t0163.cc
   vendor/elsa/current/elsa/in/t0164.cc
   vendor/elsa/current/elsa/in/t0165.cc
   vendor/elsa/current/elsa/in/t0166.cc
   vendor/elsa/current/elsa/in/t0167.cc
   vendor/elsa/current/elsa/in/t0168.cc
   vendor/elsa/current/elsa/in/t0169.cc
   vendor/elsa/current/elsa/in/t0170.cc
   vendor/elsa/current/elsa/in/t0171.cc
   vendor/elsa/current/elsa/in/t0172.cc
   vendor/elsa/current/elsa/in/t0173.cc
   vendor/elsa/current/elsa/in/t0174.cc
   vendor/elsa/current/elsa/in/t0175.cc
   vendor/elsa/current/elsa/in/t0176.cc
   vendor/elsa/current/elsa/in/t0177.cc
   vendor/elsa/current/elsa/in/t0178.cc
   vendor/elsa/current/elsa/in/t0179.cc
   vendor/elsa/current/elsa/in/t0180.cc
   vendor/elsa/current/elsa/in/t0181.cc
   vendor/elsa/current/elsa/in/t0182.cc
   vendor/elsa/current/elsa/in/t0183.cc
   vendor/elsa/current/elsa/in/t0184.cc
   vendor/elsa/current/elsa/in/t0185.cc
   vendor/elsa/current/elsa/in/t0186.cc
   vendor/elsa/current/elsa/in/t0187.cc
   vendor/elsa/current/elsa/in/t0188.cc
   vendor/elsa/current/elsa/in/t0189.cc
   vendor/elsa/current/elsa/in/t0190.cc
   vendor/elsa/current/elsa/in/t0191.cc
   vendor/elsa/current/elsa/in/t0192.cc
   vendor/elsa/current/elsa/in/t0193.cc
   vendor/elsa/current/elsa/in/t0194.cc
   vendor/elsa/current/elsa/in/t0195.cc
   vendor/elsa/current/elsa/in/t0196.cc
   vendor/elsa/current/elsa/in/t0197.cc
   vendor/elsa/current/elsa/in/t0198.cc
   vendor/elsa/current/elsa/in/t0199.cc
   vendor/elsa/current/elsa/in/t0200.cc
   vendor/elsa/current/elsa/in/t0201.cc
   vendor/elsa/current/elsa/in/t0202.cc
   vendor/elsa/current/elsa/in/t0203.cc
   vendor/elsa/current/elsa/in/t0204.cc
   vendor/elsa/current/elsa/in/t0205.cc
   vendor/elsa/current/elsa/in/t0206.cc
   vendor/elsa/current/elsa/in/t0207.cc
   vendor/elsa/current/elsa/in/t0208.cc
   vendor/elsa/current/elsa/in/t0209.cc
   vendor/elsa/current/elsa/in/t0210.cc
   vendor/elsa/current/elsa/in/t0211.cc
   vendor/elsa/current/elsa/in/t0212.cc
   vendor/elsa/current/elsa/in/t0213.cc
   vendor/elsa/current/elsa/in/t0214.cc
   vendor/elsa/current/elsa/in/t0215.cc
   vendor/elsa/current/elsa/in/t0216.cc
   vendor/elsa/current/elsa/in/t0217.cc
   vendor/elsa/current/elsa/in/t0218.cc
   vendor/elsa/current/elsa/in/t0219.cc
   vendor/elsa/current/elsa/in/t0220.cc
   vendor/elsa/current/elsa/in/t0221.cc
   vendor/elsa/current/elsa/in/t0222.cc
   vendor/elsa/current/elsa/in/t0223.cc
   vendor/elsa/current/elsa/in/t0224.cc
   vendor/elsa/current/elsa/in/t0225.cc
   vendor/elsa/current/elsa/in/t0226.cc
   vendor/elsa/current/elsa/in/t0227.cc
   vendor/elsa/current/elsa/in/t0228.cc
   vendor/elsa/current/elsa/in/t0228b.cc
   vendor/elsa/current/elsa/in/t0229.cc
   vendor/elsa/current/elsa/in/t0230.cc
   vendor/elsa/current/elsa/in/t0231.cc
   vendor/elsa/current/elsa/in/t0232.cc
   vendor/elsa/current/elsa/in/t0233.cc
   vendor/elsa/current/elsa/in/t0234.cc
   vendor/elsa/current/elsa/in/t0235.cc
   vendor/elsa/current/elsa/in/t0236.cc
   vendor/elsa/current/elsa/in/t0237.cc
   vendor/elsa/current/elsa/in/t0238.cc
   vendor/elsa/current/elsa/in/t0239.cc
   vendor/elsa/current/elsa/in/t0240.cc
   vendor/elsa/current/elsa/in/t0241.cc
   vendor/elsa/current/elsa/in/t0242.cc
   vendor/elsa/current/elsa/in/t0243.cc
   vendor/elsa/current/elsa/in/t0244.cc
   vendor/elsa/current/elsa/in/t0245.cc
   vendor/elsa/current/elsa/in/t0246.cc
   vendor/elsa/current/elsa/in/t0247.cc
   vendor/elsa/current/elsa/in/t0248.cc
   vendor/elsa/current/elsa/in/t0249.cc
   vendor/elsa/current/elsa/in/t0250.cc
   vendor/elsa/current/elsa/in/t0251.cc
   vendor/elsa/current/elsa/in/t0252.cc
   vendor/elsa/current/elsa/in/t0253.cc
   vendor/elsa/current/elsa/in/t0254.cc
   vendor/elsa/current/elsa/in/t0255.cc
   vendor/elsa/current/elsa/in/t0256.cc
   vendor/elsa/current/elsa/in/t0257.cc
   vendor/elsa/current/elsa/in/t0258.cc
   vendor/elsa/current/elsa/in/t0259.cc
   vendor/elsa/current/elsa/in/t0260.cc
   vendor/elsa/current/elsa/in/t0261.cc
   vendor/elsa/current/elsa/in/t0262.cc
   vendor/elsa/current/elsa/in/t0263.cc
   vendor/elsa/current/elsa/in/t0264.cc
   vendor/elsa/current/elsa/in/t0265.cc
   vendor/elsa/current/elsa/in/t0266.cc
   vendor/elsa/current/elsa/in/t0267.cc
   vendor/elsa/current/elsa/in/t0268.cc
   vendor/elsa/current/elsa/in/t0268a.cc
   vendor/elsa/current/elsa/in/t0269.cc
   vendor/elsa/current/elsa/in/t0270.cc
   vendor/elsa/current/elsa/in/t0271.cc
   vendor/elsa/current/elsa/in/t0272.cc
   vendor/elsa/current/elsa/in/t0273.cc
   vendor/elsa/current/elsa/in/t0274.cc
   vendor/elsa/current/elsa/in/t0275.cc
   vendor/elsa/current/elsa/in/t0276.cc
   vendor/elsa/current/elsa/in/t0277.cc
   vendor/elsa/current/elsa/in/t0278.cc
   vendor/elsa/current/elsa/in/t0279.cc
   vendor/elsa/current/elsa/in/t0280.cc
   vendor/elsa/current/elsa/in/t0281.cc
   vendor/elsa/current/elsa/in/t0282.cc
   vendor/elsa/current/elsa/in/t0283.cc
   vendor/elsa/current/elsa/in/t0284.cc
   vendor/elsa/current/elsa/in/t0285.cc
   vendor/elsa/current/elsa/in/t0286.cc
   vendor/elsa/current/elsa/in/t0287.cc
   vendor/elsa/current/elsa/in/t0288.cc
   vendor/elsa/current/elsa/in/t0289.cc
   vendor/elsa/current/elsa/in/t0290.cc
   vendor/elsa/current/elsa/in/t0290a.cc
   vendor/elsa/current/elsa/in/t0291.cc
   vendor/elsa/current/elsa/in/t0292.cc
   vendor/elsa/current/elsa/in/t0293.cc
   vendor/elsa/current/elsa/in/t0294.cc
   vendor/elsa/current/elsa/in/t0295.cc
   vendor/elsa/current/elsa/in/t0296.cc
   vendor/elsa/current/elsa/in/t0297.cc
   vendor/elsa/current/elsa/in/t0298.cc
   vendor/elsa/current/elsa/in/t0299.cc
   vendor/elsa/current/elsa/in/t0300.cc
   vendor/elsa/current/elsa/in/t0301.cc
   vendor/elsa/current/elsa/in/t0302.cc
   vendor/elsa/current/elsa/in/t0303.cc
   vendor/elsa/current/elsa/in/t0304.cc
   vendor/elsa/current/elsa/in/t0305.cc
   vendor/elsa/current/elsa/in/t0306.cc
   vendor/elsa/current/elsa/in/t0307.cc
   vendor/elsa/current/elsa/in/t0308.cc
   vendor/elsa/current/elsa/in/t0309.cc
   vendor/elsa/current/elsa/in/t0310.cc
   vendor/elsa/current/elsa/in/t0311.cc
   vendor/elsa/current/elsa/in/t0312.cc
   vendor/elsa/current/elsa/in/t0313.cc
   vendor/elsa/current/elsa/in/t0314.cc
   vendor/elsa/current/elsa/in/t0315.cc
   vendor/elsa/current/elsa/in/t0316.cc
   vendor/elsa/current/elsa/in/t0317.cc
   vendor/elsa/current/elsa/in/t0318.cc
   vendor/elsa/current/elsa/in/t0319.cc
   vendor/elsa/current/elsa/in/t0320.cc
   vendor/elsa/current/elsa/in/t0321.cc
   vendor/elsa/current/elsa/in/t0322.cc
   vendor/elsa/current/elsa/in/t0323.cc
   vendor/elsa/current/elsa/in/t0324.cc
   vendor/elsa/current/elsa/in/t0325.cc
   vendor/elsa/current/elsa/in/t0326.cc
   vendor/elsa/current/elsa/in/t0327.cc
   vendor/elsa/current/elsa/in/t0328.cc
   vendor/elsa/current/elsa/in/t0329.cc
   vendor/elsa/current/elsa/in/t0330.cc
   vendor/elsa/current/elsa/in/t0331.cc
   vendor/elsa/current/elsa/in/t0332.cc
   vendor/elsa/current/elsa/in/t0333.cc
   vendor/elsa/current/elsa/in/t0334.cc
   vendor/elsa/current/elsa/in/t0335.cc
   vendor/elsa/current/elsa/in/t0336.cc
   vendor/elsa/current/elsa/in/t0337.cc
   vendor/elsa/current/elsa/in/t0338.cc
   vendor/elsa/current/elsa/in/t0339.cc
   vendor/elsa/current/elsa/in/t0340.cc
   vendor/elsa/current/elsa/in/t0341.cc
   vendor/elsa/current/elsa/in/t0342.cc
   vendor/elsa/current/elsa/in/t0343.cc
   vendor/elsa/current/elsa/in/t0344.cc
   vendor/elsa/current/elsa/in/t0345.cc
   vendor/elsa/current/elsa/in/t0346.cc
   vendor/elsa/current/elsa/in/t0347.cc
   vendor/elsa/current/elsa/in/t0348.cc
   vendor/elsa/current/elsa/in/t0349.cc
   vendor/elsa/current/elsa/in/t0350.cc
   vendor/elsa/current/elsa/in/t0351.cc
   vendor/elsa/current/elsa/in/t0352.cc
   vendor/elsa/current/elsa/in/t0353.cc
   vendor/elsa/current/elsa/in/t0354.cc
   vendor/elsa/current/elsa/in/t0355.cc
   vendor/elsa/current/elsa/in/t0356.cc
   vendor/elsa/current/elsa/in/t0357.cc
   vendor/elsa/current/elsa/in/t0358.cc
   vendor/elsa/current/elsa/in/t0359.cc
   vendor/elsa/current/elsa/in/t0360.cc
   vendor/elsa/current/elsa/in/t0361.cc
   vendor/elsa/current/elsa/in/t0362.cc
   vendor/elsa/current/elsa/in/t0363.cc
   vendor/elsa/current/elsa/in/t0364.cc
   vendor/elsa/current/elsa/in/t0365.cc
   vendor/elsa/current/elsa/in/t0366.cc
   vendor/elsa/current/elsa/in/t0367.cc
   vendor/elsa/current/elsa/in/t0368.cc
   vendor/elsa/current/elsa/in/t0369.cc
   vendor/elsa/current/elsa/in/t0370.cc
   vendor/elsa/current/elsa/in/t0371.cc
   vendor/elsa/current/elsa/in/t0372.cc
   vendor/elsa/current/elsa/in/t0373.cc
   vendor/elsa/current/elsa/in/t0374.cc
   vendor/elsa/current/elsa/in/t0375.cc
   vendor/elsa/current/elsa/in/t0376.cc
   vendor/elsa/current/elsa/in/t0377.cc
   vendor/elsa/current/elsa/in/t0378.cc
   vendor/elsa/current/elsa/in/t0379.cc
   vendor/elsa/current/elsa/in/t0380.cc
   vendor/elsa/current/elsa/in/t0381.cc
   vendor/elsa/current/elsa/in/t0382.cc
   vendor/elsa/current/elsa/in/t0383.cc
   vendor/elsa/current/elsa/in/t0384.cc
   vendor/elsa/current/elsa/in/t0385.cc
   vendor/elsa/current/elsa/in/t0386.cc
   vendor/elsa/current/elsa/in/t0387.cc
   vendor/elsa/current/elsa/in/t0388.cc
   vendor/elsa/current/elsa/in/t0389.cc
   vendor/elsa/current/elsa/in/t0390.cc
   vendor/elsa/current/elsa/in/t0391.cc
   vendor/elsa/current/elsa/in/t0392.cc
   vendor/elsa/current/elsa/in/t0393.cc
   vendor/elsa/current/elsa/in/t0394.cc
   vendor/elsa/current/elsa/in/t0395.cc
   vendor/elsa/current/elsa/in/t0396.cc
   vendor/elsa/current/elsa/in/t0397.cc
   vendor/elsa/current/elsa/in/t0398.cc
   vendor/elsa/current/elsa/in/t0399.cc
   vendor/elsa/current/elsa/in/t0400.cc
   vendor/elsa/current/elsa/in/t0401.cc
   vendor/elsa/current/elsa/in/t0402.cc
   vendor/elsa/current/elsa/in/t0403.cc
   vendor/elsa/current/elsa/in/t0404.cc
   vendor/elsa/current/elsa/in/t0405.cc
   vendor/elsa/current/elsa/in/t0406.cc
   vendor/elsa/current/elsa/in/t0407.cc
   vendor/elsa/current/elsa/in/t0408.cc
   vendor/elsa/current/elsa/in/t0409.cc
   vendor/elsa/current/elsa/in/t0410.cc
   vendor/elsa/current/elsa/in/t0411.cc
   vendor/elsa/current/elsa/in/t0412.cc
   vendor/elsa/current/elsa/in/t0413.cc
   vendor/elsa/current/elsa/in/t0414.cc
   vendor/elsa/current/elsa/in/t0415.cc
   vendor/elsa/current/elsa/in/t0416.cc
   vendor/elsa/current/elsa/in/t0417.cc
   vendor/elsa/current/elsa/in/t0418.cc
   vendor/elsa/current/elsa/in/t0419.cc
   vendor/elsa/current/elsa/in/t0420.cc
   vendor/elsa/current/elsa/in/t0421.cc
   vendor/elsa/current/elsa/in/t0422.cc
   vendor/elsa/current/elsa/in/t0422a.cc
   vendor/elsa/current/elsa/in/t0423.cc
   vendor/elsa/current/elsa/in/t0424.cc
   vendor/elsa/current/elsa/in/t0425.cc
   vendor/elsa/current/elsa/in/t0426.cc
   vendor/elsa/current/elsa/in/t0427.cc
   vendor/elsa/current/elsa/in/t0428.cc
   vendor/elsa/current/elsa/in/t0429.cc
   vendor/elsa/current/elsa/in/t0430.cc
   vendor/elsa/current/elsa/in/t0431.cc
   vendor/elsa/current/elsa/in/t0432.cc
   vendor/elsa/current/elsa/in/t0433.cc
   vendor/elsa/current/elsa/in/t0434.cc
   vendor/elsa/current/elsa/in/t0435.cc
   vendor/elsa/current/elsa/in/t0436.cc
   vendor/elsa/current/elsa/in/t0437.cc
   vendor/elsa/current/elsa/in/t0438.cc
   vendor/elsa/current/elsa/in/t0438a.cc
   vendor/elsa/current/elsa/in/t0439.cc
   vendor/elsa/current/elsa/in/t0440.cc
   vendor/elsa/current/elsa/in/t0441.cc
   vendor/elsa/current/elsa/in/t0441a.cc
   vendor/elsa/current/elsa/in/t0442.cc
   vendor/elsa/current/elsa/in/t0443.cc
   vendor/elsa/current/elsa/in/t0444.cc
   vendor/elsa/current/elsa/in/t0445.cc
   vendor/elsa/current/elsa/in/t0446.cc
   vendor/elsa/current/elsa/in/t0447.cc
   vendor/elsa/current/elsa/in/t0448.cc
   vendor/elsa/current/elsa/in/t0449.cc
   vendor/elsa/current/elsa/in/t0450.cc
   vendor/elsa/current/elsa/in/t0451.cc
   vendor/elsa/current/elsa/in/t0452.cc
   vendor/elsa/current/elsa/in/t0453.cc
   vendor/elsa/current/elsa/in/t0454.cc
   vendor/elsa/current/elsa/in/t0455.cc
   vendor/elsa/current/elsa/in/t0456.cc
   vendor/elsa/current/elsa/in/t0457.cc
   vendor/elsa/current/elsa/in/t0458.cc
   vendor/elsa/current/elsa/in/t0459.cc
   vendor/elsa/current/elsa/in/t0460.cc
   vendor/elsa/current/elsa/in/t0461.cc
   vendor/elsa/current/elsa/in/t0462.cc
   vendor/elsa/current/elsa/in/t0463.cc
   vendor/elsa/current/elsa/in/t0464.cc
   vendor/elsa/current/elsa/in/t0465.cc
   vendor/elsa/current/elsa/in/t0466.cc
   vendor/elsa/current/elsa/in/t0467.cc
   vendor/elsa/current/elsa/in/t0468.cc
   vendor/elsa/current/elsa/in/t0469.cc
   vendor/elsa/current/elsa/in/t0470.cc
   vendor/elsa/current/elsa/in/t0471.cc
   vendor/elsa/current/elsa/in/t0472.cc
   vendor/elsa/current/elsa/in/t0473.cc
   vendor/elsa/current/elsa/in/t0474.cc
   vendor/elsa/current/elsa/in/t0475.cc
   vendor/elsa/current/elsa/in/t0476.cc
   vendor/elsa/current/elsa/in/t0477.cc
   vendor/elsa/current/elsa/in/t0478.cc
   vendor/elsa/current/elsa/in/t0479.cc
   vendor/elsa/current/elsa/in/t0480.cc
   vendor/elsa/current/elsa/in/t0481.cc
   vendor/elsa/current/elsa/in/t0482.cc
   vendor/elsa/current/elsa/in/t0483.cc
   vendor/elsa/current/elsa/in/t0484.cc
   vendor/elsa/current/elsa/in/t0485.cc
   vendor/elsa/current/elsa/in/t0486.cc
   vendor/elsa/current/elsa/in/t0487.cc
   vendor/elsa/current/elsa/in/t0487b.cc
   vendor/elsa/current/elsa/in/t0488.cc
   vendor/elsa/current/elsa/in/t0489.cc
   vendor/elsa/current/elsa/in/t0490.cc
   vendor/elsa/current/elsa/in/t0491.cc
   vendor/elsa/current/elsa/in/t0492.cc
   vendor/elsa/current/elsa/in/t0493.cc
   vendor/elsa/current/elsa/in/t0494.cc
   vendor/elsa/current/elsa/in/t0495.cc
   vendor/elsa/current/elsa/in/t0496.cc
   vendor/elsa/current/elsa/in/t0497.cc
   vendor/elsa/current/elsa/in/t0498.cc
   vendor/elsa/current/elsa/in/t0499.cc
   vendor/elsa/current/elsa/in/t0500.cc
   vendor/elsa/current/elsa/in/t0501.cc
   vendor/elsa/current/elsa/in/t0502.cc
   vendor/elsa/current/elsa/in/t0503.cc
   vendor/elsa/current/elsa/in/t0504.cc
   vendor/elsa/current/elsa/in/t0505.cc
   vendor/elsa/current/elsa/in/t0506.cc
   vendor/elsa/current/elsa/in/t0507.cc
   vendor/elsa/current/elsa/in/t0508.cc
   vendor/elsa/current/elsa/in/t0509.cc
   vendor/elsa/current/elsa/in/t0510.cc
   vendor/elsa/current/elsa/in/t0511.cc
   vendor/elsa/current/elsa/in/t0512.cc
   vendor/elsa/current/elsa/in/t0513.cc
   vendor/elsa/current/elsa/in/t0514.cc
   vendor/elsa/current/elsa/in/t0515.cc
   vendor/elsa/current/elsa/in/t0516.cc
   vendor/elsa/current/elsa/in/t0517.cc
   vendor/elsa/current/elsa/in/t0518.cc
   vendor/elsa/current/elsa/in/t0519.cc
   vendor/elsa/current/elsa/in/t0520.cc
   vendor/elsa/current/elsa/in/t0521.cc
   vendor/elsa/current/elsa/in/t0522.cc
   vendor/elsa/current/elsa/in/t0523.cc
   vendor/elsa/current/elsa/in/t0524.cc
   vendor/elsa/current/elsa/in/t0525.cc
   vendor/elsa/current/elsa/in/t0526.cc
   vendor/elsa/current/elsa/in/t0527.cc
   vendor/elsa/current/elsa/in/t0528.cc
   vendor/elsa/current/elsa/in/t0529.cc
   vendor/elsa/current/elsa/in/t0530.cc
   vendor/elsa/current/elsa/in/t0531.cc
   vendor/elsa/current/elsa/in/t0532.cc
   vendor/elsa/current/elsa/in/t0533.cc
   vendor/elsa/current/elsa/in/t0534.cc
   vendor/elsa/current/elsa/in/t0535.cc
   vendor/elsa/current/elsa/in/t0536.cc
   vendor/elsa/current/elsa/in/t0537.cc
   vendor/elsa/current/elsa/in/t0538.cc
   vendor/elsa/current/elsa/in/t0539.cc
   vendor/elsa/current/elsa/in/t0540.cc
   vendor/elsa/current/elsa/in/t0541.cc
   vendor/elsa/current/elsa/in/t0542.cc
   vendor/elsa/current/elsa/in/t0543.cc
   vendor/elsa/current/elsa/in/t0544.cc
   vendor/elsa/current/elsa/in/t0545.cc
   vendor/elsa/current/elsa/in/t0546.cc
   vendor/elsa/current/elsa/in/t0547.cc
   vendor/elsa/current/elsa/in/t0548.cc
   vendor/elsa/current/elsa/in/t0549.cc
   vendor/elsa/current/elsa/in/t0550.cc
   vendor/elsa/current/elsa/in/t0551.cc
   vendor/elsa/current/elsa/in/t0552.cc
   vendor/elsa/current/elsa/in/t0553.cc
   vendor/elsa/current/elsa/in/t0554.cc
   vendor/elsa/current/elsa/in/t0555.cc
   vendor/elsa/current/elsa/in/t0556.cc
   vendor/elsa/current/elsa/in/t0557.cc
   vendor/elsa/current/elsa/in/t0558.cc
   vendor/elsa/current/elsa/in/t0559.cc
   vendor/elsa/current/elsa/in/t0560.cc
   vendor/elsa/current/elsa/in/t0561.cc
   vendor/elsa/current/elsa/in/t0562.cc
   vendor/elsa/current/elsa/in/t0563.cc
   vendor/elsa/current/elsa/in/t0564.cc
   vendor/elsa/current/elsa/in/t0565.cc
   vendor/elsa/current/elsa/in/t0566.cc
   vendor/elsa/current/elsa/in/t0567.cc
   vendor/elsa/current/elsa/in/t0568.cc
   vendor/elsa/current/elsa/in/t0569.cc
   vendor/elsa/current/elsa/in/t0570.cc
   vendor/elsa/current/elsa/in/t0571.cc
   vendor/elsa/current/elsa/in/t0572.cc
   vendor/elsa/current/elsa/in/t0573.cc
   vendor/elsa/current/elsa/in/t0574.cc
   vendor/elsa/current/elsa/in/t0575.cc
   vendor/elsa/current/elsa/in/t0576.cc
   vendor/elsa/current/elsa/in/t0577.cc
   vendor/elsa/current/elsa/in/t0578.cc
   vendor/elsa/current/elsa/in/t0579.cc
   vendor/elsa/current/elsa/in/t0580.cc
   vendor/elsa/current/elsa/in/t0581.cc
   vendor/elsa/current/elsa/in/t0582.cc
   vendor/elsa/current/elsa/in/t0583.cc
   vendor/elsa/current/elsa/in/t0584.cc
   vendor/elsa/current/elsa/in/t0585.cc
   vendor/elsa/current/elsa/in/t0586.cc
   vendor/elsa/current/elsa/in/t0587.cc
   vendor/elsa/current/elsa/in/t0588.cc
   vendor/elsa/current/elsa/in/t0589.cc
   vendor/elsa/current/elsa/in/t0590.cc
   vendor/elsa/current/elsa/in/t0591.cc
   vendor/elsa/current/elsa/in/u0001.cc
   vendor/elsa/current/elsa/include/
   vendor/elsa/current/elsa/include/README
   vendor/elsa/current/elsa/include/exception.h
   vendor/elsa/current/elsa/include/new.h
   vendor/elsa/current/elsa/include/stdarg.h
   vendor/elsa/current/elsa/include/stddef.h
   vendor/elsa/current/elsa/index.html
   vendor/elsa/current/elsa/integrity.cc
   vendor/elsa/current/elsa/integrity.h
   vendor/elsa/current/elsa/interptest
   vendor/elsa/current/elsa/iptparse.cc
   vendor/elsa/current/elsa/iptparse.h
   vendor/elsa/current/elsa/iptparse.lex
   vendor/elsa/current/elsa/iptree.cc
   vendor/elsa/current/elsa/iptree.h
   vendor/elsa/current/elsa/kandr.ast
   vendor/elsa/current/elsa/kandr.cc
   vendor/elsa/current/elsa/kandr.gr
   vendor/elsa/current/elsa/kandr.h
   vendor/elsa/current/elsa/lexer.cc
   vendor/elsa/current/elsa/lexer.h
   vendor/elsa/current/elsa/license.txt
   vendor/elsa/current/elsa/lookupset.cc
   vendor/elsa/current/elsa/lookupset.h
   vendor/elsa/current/elsa/main.cc
   vendor/elsa/current/elsa/make-token-files
   vendor/elsa/current/elsa/mangle.cc
   vendor/elsa/current/elsa/mangle.h
   vendor/elsa/current/elsa/merge-lexer-exts.pl
   vendor/elsa/current/elsa/mflags.h
   vendor/elsa/current/elsa/mkdist
   vendor/elsa/current/elsa/mtype.cc
   vendor/elsa/current/elsa/mtype.h
   vendor/elsa/current/elsa/multitest.pl
   vendor/elsa/current/elsa/notopt.cc
   vendor/elsa/current/elsa/outdir/
   vendor/elsa/current/elsa/overload.cc
   vendor/elsa/current/elsa/overload.h
   vendor/elsa/current/elsa/packedword.h
   vendor/elsa/current/elsa/packedword_test.cc
   vendor/elsa/current/elsa/parssppt.cc
   vendor/elsa/current/elsa/parssppt.h
   vendor/elsa/current/elsa/regrtest
   vendor/elsa/current/elsa/run-all3
   vendor/elsa/current/elsa/run-all3-multi
   vendor/elsa/current/elsa/run-delta-loop
   vendor/elsa/current/elsa/run-g++
   vendor/elsa/current/elsa/run-icc
   vendor/elsa/current/elsa/semgrep.cc
   vendor/elsa/current/elsa/serialno.cc
   vendor/elsa/current/elsa/serialno.h
   vendor/elsa/current/elsa/smin.cc
   vendor/elsa/current/elsa/smin.h
   vendor/elsa/current/elsa/sprint.cc
   vendor/elsa/current/elsa/sprint.h
   vendor/elsa/current/elsa/stdconv.cc
   vendor/elsa/current/elsa/stdconv.h
   vendor/elsa/current/elsa/strmap.h
   vendor/elsa/current/elsa/template.cc
   vendor/elsa/current/elsa/template.h
   vendor/elsa/current/elsa/test-cipart
   vendor/elsa/current/elsa/test-for-error
   vendor/elsa/current/elsa/test-parse
   vendor/elsa/current/elsa/test-parse-big
   vendor/elsa/current/elsa/test-parse-buildlog
   vendor/elsa/current/elsa/test-parse-manyfiles
   vendor/elsa/current/elsa/test-parse-mozilla
   vendor/elsa/current/elsa/test-parse-mozilla-gcc
   vendor/elsa/current/elsa/test-parse-openssh
   vendor/elsa/current/elsa/test-parse-openssl
   vendor/elsa/current/elsa/test-parse-std
   vendor/elsa/current/elsa/test-perl-crlf.pl
   vendor/elsa/current/elsa/tlexer.cc
   vendor/elsa/current/elsa/todo.txt
   vendor/elsa/current/elsa/token.pl
   vendor/elsa/current/elsa/toplevel/
   vendor/elsa/current/elsa/toplevel/license.txt
   vendor/elsa/current/elsa/toplevel/readme.txt
   vendor/elsa/current/elsa/typelistiter.cc
   vendor/elsa/current/elsa/typelistiter.h
   vendor/elsa/current/elsa/variable.cc
   vendor/elsa/current/elsa/variable.h
   vendor/elsa/current/elsa/xml_ast_reader.cc
   vendor/elsa/current/elsa/xml_ast_reader.h
   vendor/elsa/current/elsa/xml_basic.tokens
   vendor/elsa/current/elsa/xml_do_read.cc
   vendor/elsa/current/elsa/xml_do_read.h
   vendor/elsa/current/elsa/xml_enum.h
   vendor/elsa/current/elsa/xml_file.tokens
   vendor/elsa/current/elsa/xml_file_reader.cc
   vendor/elsa/current/elsa/xml_file_reader.h
   vendor/elsa/current/elsa/xml_file_writer.cc
   vendor/elsa/current/elsa/xml_file_writer.h
   vendor/elsa/current/elsa/xml_lex_0top.lex
   vendor/elsa/current/elsa/xml_lex_2bot.lex
   vendor/elsa/current/elsa/xml_lex_extra.h
   vendor/elsa/current/elsa/xml_lexer.cc
   vendor/elsa/current/elsa/xml_lexer.h
   vendor/elsa/current/elsa/xml_reader.cc
   vendor/elsa/current/elsa/xml_reader.h
   vendor/elsa/current/elsa/xml_test.mk
   vendor/elsa/current/elsa/xml_type.tokens
   vendor/elsa/current/elsa/xml_type_id.h
   vendor/elsa/current/elsa/xml_type_reader.cc
   vendor/elsa/current/elsa/xml_type_reader.h
   vendor/elsa/current/elsa/xml_type_writer.cc
   vendor/elsa/current/elsa/xml_type_writer.h
   vendor/elsa/current/elsa/xml_writer.cc
   vendor/elsa/current/elsa/xml_writer.h
   vendor/elsa/current/license.txt
   vendor/elsa/current/readme.txt
   vendor/elsa/current/smbase/
   vendor/elsa/current/smbase/.gdbinit
   vendor/elsa/current/smbase/SMBASE.IDE
   vendor/elsa/current/smbase/array.h
   vendor/elsa/current/smbase/arraymap.h
   vendor/elsa/current/smbase/arrayqueue.h
   vendor/elsa/current/smbase/astlist.h
   vendor/elsa/current/smbase/autofile.cc
   vendor/elsa/current/smbase/autofile.h
   vendor/elsa/current/smbase/bflatten.cc
   vendor/elsa/current/smbase/bflatten.h
   vendor/elsa/current/smbase/bit2d.cc
   vendor/elsa/current/smbase/bit2d.h
   vendor/elsa/current/smbase/bitarray.cc
   vendor/elsa/current/smbase/bitarray.h
   vendor/elsa/current/smbase/bitwise_array.h
   vendor/elsa/current/smbase/boxprint.cc
   vendor/elsa/current/smbase/boxprint.h
   vendor/elsa/current/smbase/breaker.cpp
   vendor/elsa/current/smbase/breaker.h
   vendor/elsa/current/smbase/check-malloc-trace.pl
   vendor/elsa/current/smbase/ckheap.h
   vendor/elsa/current/smbase/codepatch.pl
   vendor/elsa/current/smbase/configure.pl
   vendor/elsa/current/smbase/crc.cpp
   vendor/elsa/current/smbase/crc.h
   vendor/elsa/current/smbase/cycles.c
   vendor/elsa/current/smbase/cycles.h
   vendor/elsa/current/smbase/d2vector.c
   vendor/elsa/current/smbase/d2vector.h
   vendor/elsa/current/smbase/datablok.cpp
   vendor/elsa/current/smbase/datablok.h
   vendor/elsa/current/smbase/depend.pl
   vendor/elsa/current/smbase/depend.sh
   vendor/elsa/current/smbase/do_strhash_test
   vendor/elsa/current/smbase/exc.cpp
   vendor/elsa/current/smbase/exc.h
   vendor/elsa/current/smbase/flatten.cc
   vendor/elsa/current/smbase/flatten.h
   vendor/elsa/current/smbase/flatutil.h
   vendor/elsa/current/smbase/gprintf.c
   vendor/elsa/current/smbase/gprintf.h
   vendor/elsa/current/smbase/growbuf.cc
   vendor/elsa/current/smbase/growbuf.h
   vendor/elsa/current/smbase/hashline.cc
   vendor/elsa/current/smbase/hashline.h
   vendor/elsa/current/smbase/hashtbl.cc
   vendor/elsa/current/smbase/hashtbl.h
   vendor/elsa/current/smbase/index.html
   vendor/elsa/current/smbase/license.txt
   vendor/elsa/current/smbase/macros.h
   vendor/elsa/current/smbase/make-preproc
   vendor/elsa/current/smbase/malloc.c
   vendor/elsa/current/smbase/malloc_stub.c
   vendor/elsa/current/smbase/missing.cpp
   vendor/elsa/current/smbase/missing.h
   vendor/elsa/current/smbase/mypopen.c
   vendor/elsa/current/smbase/mypopen.h
   vendor/elsa/current/smbase/mysig.cc
   vendor/elsa/current/smbase/mysig.h
   vendor/elsa/current/smbase/nonport.cpp
   vendor/elsa/current/smbase/nonport.h
   vendor/elsa/current/smbase/objlist.h
   vendor/elsa/current/smbase/objmap.h
   vendor/elsa/current/smbase/objpool.h
   vendor/elsa/current/smbase/objstack.h
   vendor/elsa/current/smbase/ofstreamts.cc
   vendor/elsa/current/smbase/ofstreamts.h
   vendor/elsa/current/smbase/ohashtbl.h
   vendor/elsa/current/smbase/okhasharr.h
   vendor/elsa/current/smbase/okhashtbl.h
   vendor/elsa/current/smbase/oobjmap.h
   vendor/elsa/current/smbase/owner.h
   vendor/elsa/current/smbase/pair.h
   vendor/elsa/current/smbase/point.cc
   vendor/elsa/current/smbase/point.h
   vendor/elsa/current/smbase/pprint.cc
   vendor/elsa/current/smbase/pprint.h
   vendor/elsa/current/smbase/ptrintmap.h
   vendor/elsa/current/smbase/ptrmap.h
   vendor/elsa/current/smbase/run-flex.pl
   vendor/elsa/current/smbase/scan-depends.pl
   vendor/elsa/current/smbase/sm_config.pm
   vendor/elsa/current/smbase/sm_flexlexer.h
   vendor/elsa/current/smbase/sm_strstream.h
   vendor/elsa/current/smbase/smbase.dsp
   vendor/elsa/current/smbase/smbase.gif
   vendor/elsa/current/smbase/smregexp.cc
   vendor/elsa/current/smbase/smregexp.h
   vendor/elsa/current/smbase/sobjlist.h
   vendor/elsa/current/smbase/sobjset.h
   vendor/elsa/current/smbase/sobjstack.h
   vendor/elsa/current/smbase/srcloc.cc
   vendor/elsa/current/smbase/srcloc.h
   vendor/elsa/current/smbase/srcloc.test.cc
   vendor/elsa/current/smbase/srcloc.test2.cc
   vendor/elsa/current/smbase/str.cpp
   vendor/elsa/current/smbase/str.h
   vendor/elsa/current/smbase/strdict.cc
   vendor/elsa/current/smbase/strdict.h
   vendor/elsa/current/smbase/strhash.cc
   vendor/elsa/current/smbase/strhash.h
   vendor/elsa/current/smbase/string.txt
   vendor/elsa/current/smbase/stringset.cc
   vendor/elsa/current/smbase/stringset.h
   vendor/elsa/current/smbase/strintdict.h
   vendor/elsa/current/smbase/strobjdict.h
   vendor/elsa/current/smbase/strsobjdict.h
   vendor/elsa/current/smbase/strtable.cc
   vendor/elsa/current/smbase/strtable.h
   vendor/elsa/current/smbase/strtokp.cpp
   vendor/elsa/current/smbase/strtokp.h
   vendor/elsa/current/smbase/strtokpc.h
   vendor/elsa/current/smbase/strutil.cc
   vendor/elsa/current/smbase/strutil.h
   vendor/elsa/current/smbase/svdict.cc
   vendor/elsa/current/smbase/svdict.h
   vendor/elsa/current/smbase/syserr.cpp
   vendor/elsa/current/smbase/syserr.h
   vendor/elsa/current/smbase/taillist.h
   vendor/elsa/current/smbase/taillist_test.cc
   vendor/elsa/current/smbase/tarrayqueue.cc
   vendor/elsa/current/smbase/test.h
   vendor/elsa/current/smbase/test.input
   vendor/elsa/current/smbase/testarray.cc
   vendor/elsa/current/smbase/testcout.cc
   vendor/elsa/current/smbase/testmalloc.cc
   vendor/elsa/current/smbase/thashtbl.h
   vendor/elsa/current/smbase/tmalloc.c
   vendor/elsa/current/smbase/tobjlist.cc
   vendor/elsa/current/smbase/tobjpool.cc
   vendor/elsa/current/smbase/trace.cc
   vendor/elsa/current/smbase/trace.h
   vendor/elsa/current/smbase/trace.html
   vendor/elsa/current/smbase/trdelete.cc
   vendor/elsa/current/smbase/trdelete.h
   vendor/elsa/current/smbase/tsobjlist.cc
   vendor/elsa/current/smbase/typ.h
   vendor/elsa/current/smbase/unixutil.c
   vendor/elsa/current/smbase/unixutil.h
   vendor/elsa/current/smbase/vdtllist.cc
   vendor/elsa/current/smbase/vdtllist.h
   vendor/elsa/current/smbase/voidlist.cc
   vendor/elsa/current/smbase/voidlist.h
   vendor/elsa/current/smbase/vptrmap.cc
   vendor/elsa/current/smbase/vptrmap.h
   vendor/elsa/current/smbase/warn.cpp
   vendor/elsa/current/smbase/warn.h
   vendor/elsa/current/smbase/xassert.h
   vendor/elsa/current/smbase/xobjlist.h
   vendor/elsa/current/smbase/xstrobjdict.h
   vendor/elsa/current/www/
   vendor/elsa/current/www/index.html
Log:
Imported elsa.  (The Oink repository at http://www.cubewano.org -- in
fact, all of cubewano.org -- has been offline for a couple of days
now... svn:externals is no longer going to cut it.)


Added: vendor/elsa/current/ast/.gdbinit
===================================================================
--- vendor/elsa/current/ast/.gdbinit	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/.gdbinit	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+# .gdbinit
+
+#file ccsstr
+#file agrampar
+file astgen
+break main
+break breaker
+set args example.ast
+set print static-members off
+#set args ast.ast
+#set args ../parsgen/gramast.ast
+run

Added: vendor/elsa/current/ast/agramlex.lex
===================================================================
--- vendor/elsa/current/ast/agramlex.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/agramlex.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,334 @@
+/* agrammar.lex            see license.txt for copyright and terms of use
+ * lexical analyzer for my AST input format
+ */
+
+/* ----------------- C definitions -------------------- */
+%{
+
+// pull in my declaration of the lexer class -- this defines
+// the additional lexer state, some of which is used in the
+// action rules below
+#include "gramlex.h"
+
+// pull in the bison-generated token codes
+#include "agrampar.codes.h"
+
+#include <string.h>         // strchr, strrchr
+
+// for maintaining column count
+#define TOKEN_START  tokenStartLoc = fileState.loc /* user ; */
+#define UPD_COL      advCol(yyleng) /* user ; */
+#define TOK_UPD_COL  TOKEN_START; UPD_COL  /* user ; */
+
+%}
+
+
+/* -------------------- flex options ------------------ */
+/* no wrapping is needed; setting this means we don't have to link with libfl.a */
+%option noyywrap
+
+/* don't use the default-echo rules */
+%option nodefault
+
+/* generate a c++ lexer */
+%option c++
+
+/* and I will define the class */
+%option yyclass="GrammarLexer"
+
+
+/* ------------------- definitions -------------------- */
+/* any character, including newline */
+ANY       (.|"\n")
+
+/* any character except newline */
+ANYBUTNL  .
+
+/* starting character in a name */
+LETTER    [a-zA-Z_]
+
+/* starting character in a numeric literal */
+DIGIT     [0-9]
+
+/* double-quote */
+DQUOTE    "\""
+
+/* character that can appear in a quoted string */
+/* (I currently don't have any backslash codes, but I want to
+ * leave open that possibility, for now backslashes are illegal) */
+STRCHR    [^\n\\\"]
+
+/* whitespace that doesn't cross line a boundary */
+SLWHITE   [ \t]
+
+
+/* --------------- start conditions ------------------- */
+%x C_COMMENT
+%x EMBED
+%x INITVAL
+
+
+/* ---------------------- rules ----------------------- */
+%%
+
+  /* -------- whitespace ------ */
+"\n" {
+  newLine();
+}
+
+[ \t\f\v]+ {
+  UPD_COL;
+}
+
+  /* -------- comments -------- */
+"/""*" {
+  /* C-style comments */
+  TOKEN_START;
+  UPD_COL;
+  BEGIN(C_COMMENT);
+}
+
+<C_COMMENT>{
+  "*/" {
+    /* end of comment */
+    UPD_COL;
+    BEGIN(INITIAL);
+  }
+
+  . {
+    /* anything but slash-star or newline -- eat it */
+    UPD_COL;
+  }
+
+  "\n" {
+    newLine();
+  }
+
+  <<EOF>> {
+    UPD_COL;      // <<EOF>> yyleng is 1!
+    errorUnterminatedComment();
+    return TOK_EOF;
+  }
+}
+
+
+"//".*"\n" {
+  /* C++-style comment -- eat it */
+  TOKEN_START;
+  advCol(yyleng-1);   // don't count the newline
+  newLine();          // get it here
+}
+
+
+  /* -------- punctuators, operators, keywords --------- */
+"}"                TOK_UPD_COL;  return TOK_RBRACE;
+";"                TOK_UPD_COL;  return TOK_SEMICOLON;
+"->"               TOK_UPD_COL;  return TOK_ARROW;
+"("                TOK_UPD_COL;  return TOK_LPAREN;
+","                TOK_UPD_COL;  return TOK_COMMA;
+
+"<"                TOK_UPD_COL;  return TOK_LANGLE;
+">"                TOK_UPD_COL;  return TOK_RANGLE;
+"*"                TOK_UPD_COL;  return TOK_STAR;
+"&"                TOK_UPD_COL;  return TOK_AMPERSAND;
+"="                TOK_UPD_COL;  return TOK_EQUALS;
+":"                TOK_UPD_COL;  return TOK_COLON;
+
+"class"            TOK_UPD_COL;  return TOK_CLASS;
+"option"           TOK_UPD_COL;  return TOK_OPTION;
+"new"              TOK_UPD_COL;  return TOK_NEW;
+"enum"             TOK_UPD_COL;  return TOK_ENUM;
+
+  /* --------- embedded text --------- */
+("public"|"protected"|"private"|"ctor"|"dtor"|"pure_virtual")("(")? {
+  TOK_UPD_COL;
+
+  if (prevToken==TOK_COLON || prevToken==TOK_COMMA) {
+    // FREAKING UGLY HACK: Normally, access control keywords introduce
+    // a verbatim section.  But I want to also use them in the syntax
+    // for base classes, to be similar to C++.  But that means that I
+    // have to somehow distinguish those contexts.  As it happens, the
+    // previous token can be used to make the distinction.  So, here
+    // we are in that context, so don't do verbatim stuff.
+    //
+    // Of course, this is an awfully fragile approach.  I'd like to
+    // redesign the verbatim-field syntax at some point to eliminate
+    // this problem, but since I don't know what a good syntax might
+    // be, I'll leave things alone for now.
+    
+    // better not have used a paren..
+    if (yytext[yyleng-1] == '(') {
+      // I'm tempted to make a smart-ass error message... resisting...... *phew*!
+      err("don't put a paren after a base class access control keyword");
+      
+      // now I'm tempted to change the error reporting so that all
+      // error messages are prefixed with "(SNL donatella versaci
+      // voice) you crazy bitch!"  hmm.. maybe too much sugar today?
+    }
+  }
+  else {
+    // the keyword introduces a verbatim section
+
+    // is a paren included?
+    if (yytext[yyleng-1] == '(') {
+      // don't drop into embedded just yet; wait for the ')'
+      embedStart = ')';
+      yyless(yyleng-1);
+      advCol(-1);
+    }
+    else {
+      BEGIN(EMBED);
+    }
+
+    embedded->reset();
+    embedFinish = ';';
+    allowInit = yytext[0]=='p';
+    embedMode = TOK_EMBEDDED_CODE;
+  }
+
+  return yytext[0]=='c'?   TOK_CTOR :
+         yytext[0]=='d'?   TOK_DTOR :
+         yytext[2] == 'b'? TOK_PUBLIC :
+         yytext[2] == 'o'? TOK_PROTECTED :
+         yytext[2] == 'i'? TOK_PRIVATE :
+             /*[2] == 'r'*/TOK_PURE_VIRTUAL ;
+}
+
+("verbatim"|"impl_verbatim"|"xml_verbatim") {
+  TOK_UPD_COL;
+
+  // need to see one more token before we begin embedded processing
+  embedStart = '{';
+  embedFinish = '}';
+  allowInit = false;
+
+  embedded->reset();
+  embedMode = TOK_EMBEDDED_CODE;
+  switch (yytext[0]) {
+  default: xfailure("can't happen");
+  case 'v': return TOK_VERBATIM;
+  case 'i': return TOK_IMPL_VERBATIM;
+  case 'x': return TOK_XML_VERBATIM;
+  }
+}
+
+"custom" {
+  TOK_UPD_COL;
+
+  embedStart = '{';
+  embedFinish = '}';
+  allowInit = false;
+  embedded->reset();
+  embedMode = TOK_EMBEDDED_CODE;
+
+  return TOK_CUSTOM;
+}
+
+  /* punctuation that can start embedded code */
+("{"|")") {
+  TOK_UPD_COL;
+  if (yytext[0] == embedStart) {
+    BEGIN(EMBED);
+  }
+  return yytext[0]=='{'? TOK_LBRACE : TOK_RPAREN;
+}
+
+
+  /* no TOKEN_START here; we'll use the tokenStartLoc that
+   * was computed in the opening punctuation */
+<EMBED>{
+  /* no special significance to lexer */
+  [^;}=\n]+ {
+    UPD_COL;
+    embedded->handle(yytext, yyleng, embedFinish);
+  }
+
+  "\n" {
+    newLine();
+    embedded->handle(yytext, yyleng, embedFinish);
+  }
+
+  /* possibly closing delimiter */
+  ("}"|";"|"=") {
+    UPD_COL;
+
+    // we're done if we're at a zero nesting level and the
+    // delimiter matches ...
+    if (embedded->zeroNesting() && embedFinishMatches(yytext[0])) {
+      // done
+      BEGIN(INITIAL);
+
+      if (yytext[0] == '=') {
+        // switch to a special mode that will handle the '=' and
+        // jump right back into embedded mode
+        BEGIN(INITVAL);
+      }
+      else {
+        // turn off embedded detection
+        embedStart = 0;
+      }
+
+      // put back delimeter so parser will see it
+      yyless(yyleng-1);
+      advCol(-1);
+
+      // in the abstract grammar we don't have embedded expressions
+      embedded->exprOnly = false;
+
+      // and similarly for the other flag
+      embedded->isDeclaration = (embedFinish == ';');
+
+      // caller can get text from embedded->text
+      return embedMode;
+    }
+    else {
+      // embedded delimeter, mostly ignore it
+      embedded->handle(yytext, yyleng, embedFinish);
+    }
+  }
+}
+
+
+<INITVAL>{
+  "=" {
+    // yield the '=', switch back into embedded
+    TOK_UPD_COL;
+    BEGIN(EMBED);
+    embedded->reset();
+    allowInit = false;
+    return TOK_EQUALS;
+  }
+
+  {ANY} {
+    xfailure("somehow got a char other than '=' in INITVAL state");
+  }
+}
+
+
+  /* -------- name literal --------- */
+{LETTER}({LETTER}|{DIGIT})* {
+  // get text from yytext and yyleng
+  TOK_UPD_COL;
+  return TOK_NAME;
+}
+
+  /* --------- integer literal --------- */
+{DIGIT}+ {
+  TOK_UPD_COL;
+  return TOK_INTLIT;
+}
+
+  /* --------- illegal ------------- */
+{ANY} {
+  TOK_UPD_COL;
+  errorIllegalCharacter(yytext[0]);
+}
+
+
+%%
+/* -------------------- additional C code -------------------- */
+
+bool isAGramlexEmbed(int code)
+{
+  return code == TOK_EMBEDDED_CODE;
+}

Added: vendor/elsa/current/ast/agrampar.cc
===================================================================
--- vendor/elsa/current/ast/agrampar.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/agrampar.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,199 @@
+// agrampar.cc            see license.txt for copyright and terms of use
+// code for agrampar.h
+
+#include "agrampar.h"        // this module
+#include "agrampar.tab.h"    // YYSTYPE union
+#include "gramlex.h"         // GrammarLexer
+#include "exc.h"             // xformat
+#include "trace.h"           // tracing debugging functions
+#include "owner.h"           // Owner
+#include "strutil.h"         // trimWhitespace
+#include "strtable.h"        // StringTable
+
+#include <string.h>          // strncmp
+#include <ctype.h>           // isalnum
+#include <fstream.h>         // ifstream
+
+
+string unbox(string *s)
+{
+  string ret = *s;      // later optimization: transfer s.p directly
+  delete s;
+  return ret;
+}
+
+string *box(char const *s)
+{
+  return new string(s);
+}
+
+string *appendStr(string *left, string *right)
+{
+  string *ret = new string(*left & *right);
+  delete left;
+  delete right;
+  return ret;
+}
+
+
+CtorArg *parseCtorArg(rostring origStr)
+{
+  CtorArg *ret = new CtorArg(false, "", "", "");
+
+  // strip leading and trailing whitespace
+  string str = trimWhitespace(origStr);
+
+  // check for owner flag
+  if (prefixEquals(str, "owner")) {
+    ret->isOwner = true;
+    str = str.substring(6, str.length() - 6);    // skip "owner "
+  }
+
+  // check for an initial value
+  char const *equals = strchr(str.c_str(), '=');
+  if (equals) {
+    ret->defaultValue = equals+1;
+    str = trimWhitespace(str.substring(0, equals-str.c_str()));
+    trace("defaultValue") << "split into `" << str
+                          << "' and `" << ret->defaultValue << "'\n";
+  }
+
+  // work from the right adge, collecting alphanumerics into the name;
+  // this restricts the kinds of C type syntaxes we allow, but you can use
+  // typedefs to express any type within these restrictions
+  char const *start = str.c_str();
+  char const *p = start + str.length() - 1;
+  while ((isalnum(*p) || *p == '_') && p > start) {
+    p--;
+  }
+  if (p == start) {
+    xformat(stringc << "missing type specifier in \"" << origStr << "\"");
+  }
+  p++;
+
+  ret->type = trimWhitespace(substring(start, p-start));
+  ret->name = trimWhitespace(string(p));
+
+  return ret;
+}
+
+
+// Bison parser calls this to get a token
+int agrampar_yylex(YYSTYPE *lvalp, void *parseParam)
+{
+  ASTParseParams *par = (ASTParseParams*)parseParam;
+  GrammarLexer &lexer = par->lexer;
+
+  int code = lexer.yylexInc();
+
+  // yield semantic values for some things
+  switch (code) {
+    case TOK_NAME:
+    case TOK_INTLIT:
+      lvalp->str = box(lexer.curToken());
+      break;
+
+    case TOK_EMBEDDED_CODE:
+      lvalp->str = box(lexer.curFuncBody());
+      break;
+
+    default:
+      lvalp->str = NULL;
+  }
+
+  static bool traceIt = tracingSys("tokens");
+  if (traceIt) {
+    ostream &os = trace("tokens");
+    os << lexer.curLocStr() << ": " << code;
+    if (lvalp->str) {
+      os << ", \"" << *(lvalp->str) << "\"";
+    }
+    os << "\n";
+  }
+
+  return code;
+}
+
+
+void agrampar_yyerror(char const *msg, void *parseParam)
+{
+  ((ASTParseParams*)parseParam)->lexer.err(msg);
+}
+
+
+// ---------------- external interface -------------------
+StringTable stringTable;
+
+ASTSpecFile *readAbstractGrammar(char const *fname)
+{
+  if (tracingSys("yydebug")) {
+    #ifndef NDEBUG
+      yydebug = true;
+    #else
+      cout << "debugging disabled by -DNDEBUG\n";
+    #endif
+  }
+
+  Owner<GrammarLexer> lexer;
+  Owner<ifstream> in;
+  if (fname == NULL) {
+    // stdin
+    lexer = new GrammarLexer(isAGramlexEmbed, stringTable);
+  }
+  else {
+    // file
+    in = new ifstream(fname);
+    if (!*in) {
+      throw_XOpen(fname);
+    }
+    trace("tmp") << "in is " << in.get() << endl;
+    lexer = new GrammarLexer(isAGramlexEmbed, stringTable, fname, in.xfr());
+  }
+
+  ASTParseParams params(*lexer);
+
+  traceProgress() << "parsing grammar source..\n";
+  int retval;
+  try {
+    retval = agrampar_yyparse(&params);
+  }
+  catch (xFormat &x) {
+    lexer->err(x.cond());     // print with line number info
+    throw;
+  }
+
+  if (retval == 0) {
+    return params.treeTop;
+  }
+  else {
+    xformat("parsing finished with an error");
+  }
+}
+
+
+
+// ----------------------- test code -----------------------
+#ifdef TEST_AGRAMPAR
+
+#include "test.h"    // ARGS_MAIN
+
+void entry(int argc, char **argv)
+{
+  TRACE_ARGS();
+
+  if (argc != 2) {
+    cout << "usage: " << argv[0] << " ast-spec-file\n";
+    return;
+  }
+
+  // parse the grammar spec
+  Owner<ASTSpecFile> ast;
+  ast = readAbstractGrammar(argv[1]);
+
+  // print it out
+  ast->debugPrint(cout, 0);
+}
+
+ARGS_MAIN
+
+#endif // TEST_AGRAMPAR

Added: vendor/elsa/current/ast/agrampar.codes.h
===================================================================
--- vendor/elsa/current/ast/agrampar.codes.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/agrampar.codes.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+# define YYTOKENTYPE
+#define TOK_NAME 258
+#define TOK_INTLIT 259
+#define TOK_EMBEDDED_CODE 260
+#define TOK_LBRACE 261
+#define TOK_RBRACE 262
+#define TOK_SEMICOLON 263
+#define TOK_ARROW 264
+#define TOK_LPAREN 265
+#define TOK_RPAREN 266
+#define TOK_LANGLE 267
+#define TOK_RANGLE 268
+#define TOK_STAR 269
+#define TOK_AMPERSAND 270
+#define TOK_COMMA 271
+#define TOK_EQUALS 272
+#define TOK_COLON 273
+#define TOK_CLASS 274
+#define TOK_PUBLIC 275
+#define TOK_PRIVATE 276
+#define TOK_PROTECTED 277
+#define TOK_VERBATIM 278
+#define TOK_IMPL_VERBATIM 279
+#define TOK_XML_VERBATIM 280
+#define TOK_CTOR 281
+#define TOK_DTOR 282
+#define TOK_PURE_VIRTUAL 283
+#define TOK_CUSTOM 284
+#define TOK_OPTION 285
+#define TOK_NEW 286
+#define TOK_ENUM 287
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1

Added: vendor/elsa/current/ast/agrampar.h
===================================================================
--- vendor/elsa/current/ast/agrampar.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/agrampar.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+// agrampar.h            see license.txt for copyright and terms of use
+// declarations for things that the bison-generated parser uses
+
+#ifndef AGRAMPAR_H
+#define AGRAMPAR_H
+
+#include "ast.hand.h"       // AST node class declarations
+#include "str.h"            // string
+
+class GrammarLexer;
+
+// ---------------- agrampar's view of the parser --------------------
+// name of extra parameter to yyparse (i.e. the context in
+// which the parser operates, instead of that being stored
+// in some collection of globals)
+#define YYPARSE_PARAM parseParam
+
+// type of thing extra param points at
+struct ASTParseParams {
+  ASTSpecFile *treeTop;       // set when parsing finishes; AST tree top
+  GrammarLexer &lexer;        // lexer we're using
+
+public:
+  ASTParseParams(GrammarLexer &L) :
+    treeTop(NULL),
+    lexer(L)
+  {}
+};
+
+// caller interface to Bison-generated parser; starts parsing
+// (whatever stream lexer is reading) and returns 0 for success and
+// 1 for error; the extra parameter is available to actions to use
+#define YYPARSE_PARAM parseParam
+int agrampar_yyparse(void *YYPARSE_PARAM);
+
+// when this is set to true, bison parser emits info about
+// actions as it's taking them
+extern int yydebug;
+
+
+// ---------- parser's view of the rest of the program -----------
+// return contents of 's', which is then deallocated
+string unbox(string *s);
+
+// box 's' as a string object
+string *box(char const *s);
+
+// return concatenation of two strings; source strings are deallocated
+string *appendStr(string *left, string *right);
+
+// parse a string into components
+CtorArg *parseCtorArg(rostring str);
+
+// error routine
+void agrampar_yyerror(char const *msg, void *parseParam);
+#define yyerror(m) agrampar_yyerror(m, YYPARSE_PARAM)
+
+// parser's view of the lexer
+int agrampar_yylex(union YYSTYPE *lvalp, void *parseParam);
+#define yylex agrampar_yylex
+#define YYLEX_PARAM parseParam
+
+// classify token codes
+bool isAGramlexEmbed(int code);
+
+
+// --------------- external interface to agrampar ---------------
+ASTSpecFile *readAbstractGrammar(char const *fname);
+
+
+#endif // AGRAMPAR_H

Added: vendor/elsa/current/ast/agrampar.tab.cc
===================================================================
--- vendor/elsa/current/ast/agrampar.tab.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/agrampar.tab.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1939 @@
+/* A Bison parser, made by GNU Bison 2.1.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+   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, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Written by Richard Stallman by simplifying the original so called
+   ``semantic'' parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.1"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     TOK_NAME = 258,
+     TOK_INTLIT = 259,
+     TOK_EMBEDDED_CODE = 260,
+     TOK_LBRACE = 261,
+     TOK_RBRACE = 262,
+     TOK_SEMICOLON = 263,
+     TOK_ARROW = 264,
+     TOK_LPAREN = 265,
+     TOK_RPAREN = 266,
+     TOK_LANGLE = 267,
+     TOK_RANGLE = 268,
+     TOK_STAR = 269,
+     TOK_AMPERSAND = 270,
+     TOK_COMMA = 271,
+     TOK_EQUALS = 272,
+     TOK_COLON = 273,
+     TOK_CLASS = 274,
+     TOK_PUBLIC = 275,
+     TOK_PRIVATE = 276,
+     TOK_PROTECTED = 277,
+     TOK_VERBATIM = 278,
+     TOK_IMPL_VERBATIM = 279,
+     TOK_XML_VERBATIM = 280,
+     TOK_CTOR = 281,
+     TOK_DTOR = 282,
+     TOK_PURE_VIRTUAL = 283,
+     TOK_CUSTOM = 284,
+     TOK_OPTION = 285,
+     TOK_NEW = 286,
+     TOK_ENUM = 287
+   };
+#endif
+/* Tokens.  */
+#define TOK_NAME 258
+#define TOK_INTLIT 259
+#define TOK_EMBEDDED_CODE 260
+#define TOK_LBRACE 261
+#define TOK_RBRACE 262
+#define TOK_SEMICOLON 263
+#define TOK_ARROW 264
+#define TOK_LPAREN 265
+#define TOK_RPAREN 266
+#define TOK_LANGLE 267
+#define TOK_RANGLE 268
+#define TOK_STAR 269
+#define TOK_AMPERSAND 270
+#define TOK_COMMA 271
+#define TOK_EQUALS 272
+#define TOK_COLON 273
+#define TOK_CLASS 274
+#define TOK_PUBLIC 275
+#define TOK_PRIVATE 276
+#define TOK_PROTECTED 277
+#define TOK_VERBATIM 278
+#define TOK_IMPL_VERBATIM 279
+#define TOK_XML_VERBATIM 280
+#define TOK_CTOR 281
+#define TOK_DTOR 282
+#define TOK_PURE_VIRTUAL 283
+#define TOK_CUSTOM 284
+#define TOK_OPTION 285
+#define TOK_NEW 286
+#define TOK_ENUM 287
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 6 "agrampar.y"
+
+
+#include "agrampar.h"       // agrampar_yylex, etc.
+
+#include <stdlib.h>         // malloc, free
+#include <iostream.h>       // cout
+
+// enable debugging the parser
+#ifndef NDEBUG
+  #define YYDEBUG 1
+#endif
+
+// permit having other parser's codes in the same program
+#define yyparse agrampar_yyparse
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 69 "agrampar.y"
+typedef union YYSTYPE {
+  ASTSpecFile *file;
+  ASTList<ToplevelForm> *formList;
+  TF_class *tfClass;
+  ASTList<CtorArg> *ctorArgList;
+  ASTList<Annotation> *userDeclList;
+  string *str;
+  enum AccessCtl accessCtl;
+  AccessMod *accessMod;
+  ToplevelForm *verbatim;
+  Annotation *annotation;
+  TF_option *tfOption;
+  ASTList<string> *stringList;
+  TF_enum *tfEnum;
+  ASTList<string> *enumeratorList;
+  string *enumerator;
+  ASTList<BaseClass> *baseClassList;
+  BaseClass *baseClass;
+  CustomCode *customCode;
+} YYSTYPE;
+/* Line 196 of yacc.c.  */
+#line 187 "agrampar.tab.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 219 of yacc.c.  */
+#line 199 "agrampar.tab.c"
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus))
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if defined (__STDC__) || defined (__cplusplus)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     define YYINCLUDED_STDLIB_H
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning. */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1)
+#  endif
+#  ifdef __cplusplus
+extern "C" {
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \
+	&& (defined (__STDC__) || defined (__cplusplus)))
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \
+	&& (defined (__STDC__) || defined (__cplusplus)))
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifdef __cplusplus
+}
+#  endif
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+	 || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short int yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short int) + sizeof (YYSTYPE))			\
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined (__GNUC__) && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+   typedef signed char yysigned_char;
+#else
+   typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL  3
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   114
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS  33
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS  30
+/* YYNRULES -- Number of rules. */
+#define YYNRULES  73
+/* YYNRULES -- Number of states. */
+#define YYNSTATES  116
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   287
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const unsigned char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const unsigned char yyprhs[] =
+{
+       0,     0,     3,     5,     6,     9,    12,    15,    18,    21,
+      24,    31,    39,    40,    42,    46,    48,    49,    56,    65,
+      68,    69,    71,    74,    78,    80,    84,    86,    89,    91,
+      93,    97,    99,   101,   103,   105,   107,   111,   112,   115,
+     118,   124,   126,   130,   133,   137,   139,   141,   143,   145,
+     147,   149,   151,   156,   158,   162,   165,   168,   171,   176,
+     177,   180,   186,   193,   195,   199,   201,   202,   205,   207,
+     211,   213,   215,   217
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+      34,     0,    -1,    35,    -1,    -1,    35,    36,    -1,    35,
+      53,    -1,    35,    54,    -1,    35,    56,    -1,    35,    48,
+      -1,    35,     8,    -1,    37,    19,     3,    40,    59,    38,
+      -1,    37,    19,     3,    41,    41,    59,    38,    -1,    -1,
+      31,    -1,     6,    39,     7,    -1,     8,    -1,    -1,    39,
+       9,     3,    40,    59,     8,    -1,    39,     9,     3,    40,
+      59,     6,    46,     7,    -1,    39,    47,    -1,    -1,    41,
+      -1,    10,    11,    -1,    10,    42,    11,    -1,    43,    -1,
+      42,    16,    43,    -1,    44,    -1,    43,    44,    -1,     3,
+      -1,     4,    -1,    12,    45,    13,    -1,    14,    -1,    15,
+      -1,    17,    -1,    19,    -1,    43,    -1,    43,    16,    45,
+      -1,    -1,    46,    47,    -1,    51,    49,    -1,    51,     5,
+      17,     5,     8,    -1,    48,    -1,    29,     3,    49,    -1,
+       5,     8,    -1,     6,     5,     7,    -1,    20,    -1,    21,
+      -1,    22,    -1,    26,    -1,    27,    -1,    28,    -1,    50,
+      -1,    50,    10,    52,    11,    -1,     3,    -1,    52,    16,
+       3,    -1,    23,    49,    -1,    24,    49,    -1,    25,    49,
+      -1,    30,     3,    55,     8,    -1,    -1,    55,     3,    -1,
+      32,     3,     6,    57,     7,    -1,    32,     3,     6,    57,
+      16,     7,    -1,    58,    -1,    57,    16,    58,    -1,     3,
+      -1,    -1,    18,    60,    -1,    62,    -1,    60,    16,    62,
+      -1,    20,    -1,    21,    -1,    22,    -1,    61,     3,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const unsigned short int yyrline[] =
+{
+       0,   116,   116,   122,   123,   124,   125,   126,   127,   128,
+     133,   137,   145,   146,   158,   160,   168,   169,   171,   173,
+     181,   182,   188,   190,   195,   202,   207,   209,   215,   216,
+     217,   218,   219,   220,   221,   225,   227,   234,   235,   241,
+     243,   245,   251,   257,   259,   265,   266,   267,   268,   269,
+     270,   274,   276,   281,   283,   288,   290,   292,   297,   303,
+     304,   309,   311,   316,   318,   323,   329,   330,   335,   337,
+     343,   344,   345,   349
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "TOK_NAME", "TOK_INTLIT",
+  "TOK_EMBEDDED_CODE", "\"{\"", "\"}\"", "\";\"", "\"->\"", "\"(\"",
+  "\")\"", "\"<\"", "\">\"", "\"*\"", "\"&\"", "\",\"", "\"=\"", "\":\"",
+  "\"class\"", "\"public\"", "\"private\"", "\"protected\"",
+  "\"verbatim\"", "\"impl_verbatim\"", "\"xml_verbatim\"", "\"ctor\"",
+  "\"dtor\"", "\"pure_virtual\"", "\"custom\"", "\"option\"", "\"new\"",
+  "\"enum\"", "$accept", "StartSymbol", "Input", "Class", "NewOpt",
+  "ClassBody", "ClassMembersOpt", "CtorArgsOpt", "CtorArgs", "CtorArgList",
+  "Arg", "ArgWord", "ArgList", "CtorMembersOpt", "Annotation",
+  "CustomCode", "Embedded", "Public", "AccessMod", "StringList",
+  "Verbatim", "Option", "OptionArgs", "Enum", "EnumeratorSeq",
+  "Enumerator", "BaseClassesOpt", "BaseClassSeq", "BaseAccess",
+  "BaseClass", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const unsigned short int yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const unsigned char yyr1[] =
+{
+       0,    33,    34,    35,    35,    35,    35,    35,    35,    35,
+      36,    36,    37,    37,    38,    38,    39,    39,    39,    39,
+      40,    40,    41,    41,    42,    42,    43,    43,    44,    44,
+      44,    44,    44,    44,    44,    45,    45,    46,    46,    47,
+      47,    47,    48,    49,    49,    50,    50,    50,    50,    50,
+      50,    51,    51,    52,    52,    53,    53,    53,    54,    55,
+      55,    56,    56,    57,    57,    58,    59,    59,    60,    60,
+      61,    61,    61,    62
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const unsigned char yyr2[] =
+{
+       0,     2,     1,     0,     2,     2,     2,     2,     2,     2,
+       6,     7,     0,     1,     3,     1,     0,     6,     8,     2,
+       0,     1,     2,     3,     1,     3,     1,     2,     1,     1,
+       3,     1,     1,     1,     1,     1,     3,     0,     2,     2,
+       5,     1,     3,     2,     3,     1,     1,     1,     1,     1,
+       1,     1,     4,     1,     3,     2,     2,     2,     4,     0,
+       2,     5,     6,     1,     3,     1,     0,     2,     1,     3,
+       1,     1,     1,     2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const unsigned char yydefact[] =
+{
+       3,     0,     2,     1,     9,     0,     0,     0,     0,     0,
+      13,     0,     4,     0,     8,     5,     6,     7,     0,     0,
+      55,    56,    57,     0,    59,     0,     0,    43,     0,    42,
+       0,     0,    20,    44,    60,    58,    65,     0,    63,     0,
+      66,    21,    61,     0,    28,    29,    22,     0,    31,    32,
+      33,    34,     0,    24,    26,     0,     0,    66,    62,    64,
+      35,     0,    23,     0,    27,    70,    71,    72,    67,     0,
+      68,    16,    15,    10,     0,     0,    30,    25,     0,    73,
+       0,    11,    36,    69,    14,     0,    45,    46,    47,    48,
+      49,    50,    19,    41,    51,     0,    20,     0,     0,    39,
+      66,    21,    53,     0,     0,     0,    52,     0,     0,    37,
+      17,    54,    40,     0,    18,    38
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+      -1,     1,     2,    12,    13,    73,    80,    40,    41,    52,
+      60,    54,    61,   113,    92,    93,    20,    94,    95,   103,
+      15,    16,    30,    17,    37,    38,    56,    68,    69,    70
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -55
+static const yysigned_char yypact[] =
+{
+     -55,    11,    -4,   -55,   -55,    26,    26,    26,    20,    36,
+     -55,    70,   -55,    33,   -55,   -55,   -55,   -55,    52,    72,
+     -55,   -55,   -55,    26,   -55,    69,    79,   -55,    83,   -55,
+       5,    88,    76,   -55,   -55,   -55,   -55,     0,   -55,    47,
+      74,    76,   -55,     7,   -55,   -55,   -55,    81,   -55,   -55,
+     -55,   -55,    22,    81,   -55,    49,    57,    74,   -55,   -55,
+      64,    84,   -55,    81,   -55,   -55,   -55,   -55,    78,    96,
+     -55,   -55,   -55,   -55,    57,    81,   -55,    81,    49,   -55,
+      15,   -55,   -55,   -55,   -55,    98,   -55,   -55,   -55,   -55,
+     -55,   -55,   -55,   -55,    92,    82,    76,   100,     1,   -55,
+      74,   -55,   -55,    29,    99,    66,   -55,   102,   101,   -55,
+     -55,   -55,   -55,    27,   -55,   -55
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yysigned_char yypgoto[] =
+{
+     -55,   -55,   -55,   -55,   -55,    32,   -55,    12,   -39,   -55,
+     -33,   -48,    35,   -55,    -2,   105,    -6,   -55,   -55,   -55,
+     -55,   -55,   -55,   -55,   -55,    71,   -54,   -55,   -55,    34
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -13
+static const yysigned_char yytable[] =
+{
+      21,    22,    57,    74,     4,    64,    53,    42,    34,    27,
+      36,     3,    64,    35,    58,   -12,    43,    29,   104,     5,
+       6,     7,    84,    23,    85,     8,     9,    10,    11,    64,
+      77,    18,    19,    62,   114,    86,    87,    88,    63,    24,
+     106,    89,    90,    91,     8,   107,   105,    86,    87,    88,
+      44,    45,    26,    89,    90,    91,     8,   101,    46,    47,
+      27,    48,    49,    71,    50,    72,    51,    44,    45,    65,
+      66,    67,   109,    25,   110,    31,    47,    28,    48,    49,
+      75,    50,    32,    51,    44,    45,    39,    98,    19,    99,
+      33,    36,    55,    47,    78,    48,    49,    76,    50,    79,
+      51,    96,    97,   102,   108,   111,    81,    14,   100,   112,
+      82,   115,    83,     0,    59
+};
+
+static const yysigned_char yycheck[] =
+{
+       6,     7,    41,    57,     8,    53,    39,     7,     3,     8,
+       3,     0,    60,     8,     7,    19,    16,    23,    17,    23,
+      24,    25,     7,     3,     9,    29,    30,    31,    32,    77,
+      63,     5,     6,    11,     7,    20,    21,    22,    16,     3,
+      11,    26,    27,    28,    29,    16,   100,    20,    21,    22,
+       3,     4,    19,    26,    27,    28,    29,    96,    11,    12,
+       8,    14,    15,     6,    17,     8,    19,     3,     4,    20,
+      21,    22,     6,     3,     8,     6,    12,     5,    14,    15,
+      16,    17,     3,    19,     3,     4,    10,     5,     6,    95,
+       7,     3,    18,    12,    16,    14,    15,    13,    17,     3,
+      19,     3,    10,     3,     5,     3,    74,     2,    96,     8,
+      75,   113,    78,    -1,    43
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const unsigned char yystos[] =
+{
+       0,    34,    35,     0,     8,    23,    24,    25,    29,    30,
+      31,    32,    36,    37,    48,    53,    54,    56,     5,     6,
+      49,    49,    49,     3,     3,     3,    19,     8,     5,    49,
+      55,     6,     3,     7,     3,     8,     3,    57,    58,    10,
+      40,    41,     7,    16,     3,     4,    11,    12,    14,    15,
+      17,    19,    42,    43,    44,    18,    59,    41,     7,    58,
+      43,    45,    11,    16,    44,    20,    21,    22,    60,    61,
+      62,     6,     8,    38,    59,    16,    13,    43,    16,     3,
+      39,    38,    45,    62,     7,     9,    20,    21,    22,    26,
+      27,    28,    47,    48,    50,    51,     3,    10,     5,    49,
+      40,    41,     3,    52,    17,    59,    11,    16,     5,     6,
+       8,     3,     8,    46,     7,    47
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (0)
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (N)								\
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+              (Loc).first_line, (Loc).first_column,	\
+              (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (0)
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)		\
+do {								\
+  if (yydebug)							\
+    {								\
+      YYFPRINTF (stderr, "%s ", Title);				\
+      yysymprint (stderr,					\
+                  Type, Value);	\
+      YYFPRINTF (stderr, "\n");					\
+    }								\
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    short int *bottom;
+    short int *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (/* Nothing. */; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+    int yyrule;
+#endif
+{
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ",
+             yyrule - 1, yylno);
+  /* Print the symbols being reduced, and their result.  */
+  for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+    YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+  YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (Rule);		\
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      size_t yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+#endif /* YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+  YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+        break;
+    }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+  void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+    ;
+#endif
+#endif
+{
+  /* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  short int yyssa[YYINITDEPTH];
+  short int *yyss = yyssa;
+  short int *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule.  */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack. Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	short int *yyss1 = yyss;
+
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	short int *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a look-ahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 117 "agrampar.y"
+    { (yyval.file) = *((ASTSpecFile**)parseParam) = new ASTSpecFile((yyvsp[0].formList)); ;}
+    break;
+
+  case 3:
+#line 122 "agrampar.y"
+    { (yyval.formList) = new ASTList<ToplevelForm>; ;}
+    break;
+
+  case 4:
+#line 123 "agrampar.y"
+    { ((yyval.formList)=(yyvsp[-1].formList))->append((yyvsp[0].tfClass)); ;}
+    break;
+
+  case 5:
+#line 124 "agrampar.y"
+    { ((yyval.formList)=(yyvsp[-1].formList))->append((yyvsp[0].verbatim)); ;}
+    break;
+
+  case 6:
+#line 125 "agrampar.y"
+    { ((yyval.formList)=(yyvsp[-1].formList))->append((yyvsp[0].tfOption)); ;}
+    break;
+
+  case 7:
+#line 126 "agrampar.y"
+    { ((yyval.formList)=(yyvsp[-1].formList))->append((yyvsp[0].tfEnum)); ;}
+    break;
+
+  case 8:
+#line 127 "agrampar.y"
+    { ((yyval.formList)=(yyvsp[-1].formList))->append(new TF_custom((yyvsp[0].customCode))); ;}
+    break;
+
+  case 9:
+#line 128 "agrampar.y"
+    { (yyval.formList)=(yyvsp[-1].formList); ;}
+    break;
+
+  case 10:
+#line 134 "agrampar.y"
+    { ((yyval.tfClass)=(yyvsp[0].tfClass))->super->name = unbox((yyvsp[-3].str)); 
+           (yyval.tfClass)->super->args.steal((yyvsp[-2].ctorArgList)); 
+           (yyval.tfClass)->super->bases.steal((yyvsp[-1].baseClassList)); ;}
+    break;
+
+  case 11:
+#line 138 "agrampar.y"
+    { ((yyval.tfClass)=(yyvsp[0].tfClass))->super->name = unbox((yyvsp[-4].str));
+           (yyval.tfClass)->super->args.steal((yyvsp[-3].ctorArgList));
+           (yyval.tfClass)->super->lastArgs.steal((yyvsp[-2].ctorArgList));
+           (yyval.tfClass)->super->bases.steal((yyvsp[-1].baseClassList)); ;}
+    break;
+
+  case 12:
+#line 145 "agrampar.y"
+    {;}
+    break;
+
+  case 13:
+#line 146 "agrampar.y"
+    {;}
+    break;
+
+  case 14:
+#line 159 "agrampar.y"
+    { (yyval.tfClass)=(yyvsp[-1].tfClass); ;}
+    break;
+
+  case 15:
+#line 161 "agrampar.y"
+    { (yyval.tfClass) = new TF_class(new ASTClass("(placeholder)", NULL, NULL, NULL, NULL), NULL); ;}
+    break;
+
+  case 16:
+#line 168 "agrampar.y"
+    { (yyval.tfClass) = new TF_class(new ASTClass("(placeholder)", NULL, NULL, NULL, NULL), NULL); ;}
+    break;
+
+  case 17:
+#line 170 "agrampar.y"
+    { ((yyval.tfClass)=(yyvsp[-5].tfClass))->ctors.append(new ASTClass(unbox((yyvsp[-3].str)), (yyvsp[-2].ctorArgList), NULL, (yyvsp[-1].baseClassList), NULL)); ;}
+    break;
+
+  case 18:
+#line 172 "agrampar.y"
+    { ((yyval.tfClass)=(yyvsp[-7].tfClass))->ctors.append(new ASTClass(unbox((yyvsp[-5].str)), (yyvsp[-4].ctorArgList), NULL, (yyvsp[-3].baseClassList), (yyvsp[-1].userDeclList))); ;}
+    break;
+
+  case 19:
+#line 174 "agrampar.y"
+    { ((yyval.tfClass)=(yyvsp[-1].tfClass))->super->decls.append((yyvsp[0].annotation)); ;}
+    break;
+
+  case 20:
+#line 181 "agrampar.y"
+    { (yyval.ctorArgList) = new ASTList<CtorArg>; ;}
+    break;
+
+  case 21:
+#line 183 "agrampar.y"
+    { (yyval.ctorArgList) = (yyvsp[0].ctorArgList); ;}
+    break;
+
+  case 22:
+#line 189 "agrampar.y"
+    { (yyval.ctorArgList) = new ASTList<CtorArg>; ;}
+    break;
+
+  case 23:
+#line 191 "agrampar.y"
+    { (yyval.ctorArgList) = (yyvsp[-1].ctorArgList); ;}
+    break;
+
+  case 24:
+#line 196 "agrampar.y"
+    { (yyval.ctorArgList) = new ASTList<CtorArg>;
+                 {
+                   string tmp = unbox((yyvsp[0].str));
+                   (yyval.ctorArgList)->append(parseCtorArg(tmp));
+                 }
+               ;}
+    break;
+
+  case 25:
+#line 203 "agrampar.y"
+    { ((yyval.ctorArgList)=(yyvsp[-2].ctorArgList))->append(parseCtorArg(unbox((yyvsp[0].str)))); ;}
+    break;
+
+  case 26:
+#line 208 "agrampar.y"
+    { (yyval.str) = (yyvsp[0].str); ;}
+    break;
+
+  case 27:
+#line 210 "agrampar.y"
+    { (yyval.str) = appendStr((yyvsp[-1].str), (yyvsp[0].str)); ;}
+    break;
+
+  case 28:
+#line 215 "agrampar.y"
+    { (yyval.str) = appendStr((yyvsp[0].str), box(" ")); ;}
+    break;
+
+  case 29:
+#line 216 "agrampar.y"
+    { (yyval.str) = appendStr((yyvsp[0].str), box(" ")); ;}
+    break;
+
+  case 30:
+#line 217 "agrampar.y"
+    { (yyval.str) = appendStr(box("<"), appendStr((yyvsp[-1].str), box(">"))); ;}
+    break;
+
+  case 31:
+#line 218 "agrampar.y"
+    { (yyval.str) = box("*"); ;}
+    break;
+
+  case 32:
+#line 219 "agrampar.y"
+    { (yyval.str) = box("&"); ;}
+    break;
+
+  case 33:
+#line 220 "agrampar.y"
+    { (yyval.str) = box("="); ;}
+    break;
+
+  case 34:
+#line 221 "agrampar.y"
+    { (yyval.str) = box("class "); ;}
+    break;
+
+  case 35:
+#line 226 "agrampar.y"
+    { (yyval.str) = (yyvsp[0].str); ;}
+    break;
+
+  case 36:
+#line 228 "agrampar.y"
+    { (yyval.str) = appendStr((yyvsp[-2].str), appendStr(box(","), (yyvsp[0].str))); ;}
+    break;
+
+  case 37:
+#line 234 "agrampar.y"
+    { (yyval.userDeclList) = new ASTList<Annotation>; ;}
+    break;
+
+  case 38:
+#line 236 "agrampar.y"
+    { ((yyval.userDeclList)=(yyvsp[-1].userDeclList))->append((yyvsp[0].annotation)); ;}
+    break;
+
+  case 39:
+#line 242 "agrampar.y"
+    { (yyval.annotation) = new UserDecl((yyvsp[-1].accessMod), unbox((yyvsp[0].str)), ""); ;}
+    break;
+
+  case 40:
+#line 244 "agrampar.y"
+    { (yyval.annotation) = new UserDecl((yyvsp[-4].accessMod), unbox((yyvsp[-3].str)), unbox((yyvsp[-1].str))); ;}
+    break;
+
+  case 41:
+#line 246 "agrampar.y"
+    { (yyval.annotation) = (yyvsp[0].customCode); ;}
+    break;
+
+  case 42:
+#line 252 "agrampar.y"
+    { (yyval.customCode) = new CustomCode(unbox((yyvsp[-1].str)), unbox((yyvsp[0].str))); ;}
+    break;
+
+  case 43:
+#line 258 "agrampar.y"
+    { (yyval.str) = (yyvsp[-1].str); ;}
+    break;
+
+  case 44:
+#line 260 "agrampar.y"
+    { (yyval.str) = (yyvsp[-1].str); ;}
+    break;
+
+  case 45:
+#line 265 "agrampar.y"
+    { (yyval.accessCtl) = AC_PUBLIC; ;}
+    break;
+
+  case 46:
+#line 266 "agrampar.y"
+    { (yyval.accessCtl) = AC_PRIVATE; ;}
+    break;
+
+  case 47:
+#line 267 "agrampar.y"
+    { (yyval.accessCtl) = AC_PROTECTED; ;}
+    break;
+
+  case 48:
+#line 268 "agrampar.y"
+    { (yyval.accessCtl) = AC_CTOR; ;}
+    break;
+
+  case 49:
+#line 269 "agrampar.y"
+    { (yyval.accessCtl) = AC_DTOR; ;}
+    break;
+
+  case 50:
+#line 270 "agrampar.y"
+    { (yyval.accessCtl) = AC_PUREVIRT; ;}
+    break;
+
+  case 51:
+#line 275 "agrampar.y"
+    { (yyval.accessMod) = new AccessMod((yyvsp[0].accessCtl), NULL); ;}
+    break;
+
+  case 52:
+#line 277 "agrampar.y"
+    { (yyval.accessMod) = new AccessMod((yyvsp[-3].accessCtl), (yyvsp[-1].stringList)); ;}
+    break;
+
+  case 53:
+#line 282 "agrampar.y"
+    { (yyval.stringList) = new ASTList<string>((yyvsp[0].str)); ;}
+    break;
+
+  case 54:
+#line 284 "agrampar.y"
+    { ((yyval.stringList)=(yyvsp[-2].stringList))->append((yyvsp[0].str)); ;}
+    break;
+
+  case 55:
+#line 289 "agrampar.y"
+    { (yyval.verbatim) = new TF_verbatim(unbox((yyvsp[0].str))); ;}
+    break;
+
+  case 56:
+#line 291 "agrampar.y"
+    { (yyval.verbatim) = new TF_impl_verbatim(unbox((yyvsp[0].str))); ;}
+    break;
+
+  case 57:
+#line 293 "agrampar.y"
+    { (yyval.verbatim) = new TF_xml_verbatim(unbox((yyvsp[0].str))); ;}
+    break;
+
+  case 58:
+#line 298 "agrampar.y"
+    { (yyval.tfOption) = new TF_option(unbox((yyvsp[-2].str)), (yyvsp[-1].stringList)); ;}
+    break;
+
+  case 59:
+#line 303 "agrampar.y"
+    { (yyval.stringList) = new ASTList<string>; ;}
+    break;
+
+  case 60:
+#line 305 "agrampar.y"
+    { ((yyval.stringList)=(yyvsp[-1].stringList))->append((yyvsp[0].str)); ;}
+    break;
+
+  case 61:
+#line 310 "agrampar.y"
+    { (yyval.tfEnum) = new TF_enum(unbox((yyvsp[-3].str)), (yyvsp[-1].enumeratorList)); ;}
+    break;
+
+  case 62:
+#line 312 "agrampar.y"
+    { (yyval.tfEnum) = new TF_enum(unbox((yyvsp[-4].str)), (yyvsp[-2].enumeratorList)); ;}
+    break;
+
+  case 63:
+#line 317 "agrampar.y"
+    { (yyval.enumeratorList) = new ASTList<string>((yyvsp[0].enumerator)); ;}
+    break;
+
+  case 64:
+#line 319 "agrampar.y"
+    { ((yyval.enumeratorList)=(yyvsp[-2].enumeratorList))->append((yyvsp[0].enumerator)); ;}
+    break;
+
+  case 65:
+#line 324 "agrampar.y"
+    { (yyval.enumerator) = (yyvsp[0].str); ;}
+    break;
+
+  case 66:
+#line 329 "agrampar.y"
+    { (yyval.baseClassList) = new ASTList<BaseClass>; ;}
+    break;
+
+  case 67:
+#line 331 "agrampar.y"
+    { (yyval.baseClassList) = (yyvsp[0].baseClassList); ;}
+    break;
+
+  case 68:
+#line 336 "agrampar.y"
+    { (yyval.baseClassList) = new ASTList<BaseClass>((yyvsp[0].baseClass)); ;}
+    break;
+
+  case 69:
+#line 338 "agrampar.y"
+    { ((yyval.baseClassList)=(yyvsp[-2].baseClassList))->append((yyvsp[0].baseClass)); ;}
+    break;
+
+  case 70:
+#line 343 "agrampar.y"
+    { (yyval.accessCtl) = AC_PUBLIC; ;}
+    break;
+
+  case 71:
+#line 344 "agrampar.y"
+    { (yyval.accessCtl) = AC_PRIVATE; ;}
+    break;
+
+  case 72:
+#line 345 "agrampar.y"
+    { (yyval.accessCtl) = AC_PROTECTED; ;}
+    break;
+
+  case 73:
+#line 350 "agrampar.y"
+    { (yyval.baseClass) = new BaseClass((yyvsp[-1].accessCtl), unbox((yyvsp[0].str))); ;}
+    break;
+
+
+      default: break;
+    }
+
+/* Line 1126 of yacc.c.  */
+#line 1667 "agrampar.tab.c"
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+
+
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (YYPACT_NINF < yyn && yyn < YYLAST)
+	{
+	  int yytype = YYTRANSLATE (yychar);
+	  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+	  YYSIZE_T yysize = yysize0;
+	  YYSIZE_T yysize1;
+	  int yysize_overflow = 0;
+	  char *yymsg = 0;
+#	  define YYERROR_VERBOSE_ARGS_MAXIMUM 5
+	  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+	  int yyx;
+
+#if 0
+	  /* This is so xgettext sees the translatable formats that are
+	     constructed on the fly.  */
+	  YY_("syntax error, unexpected %s");
+	  YY_("syntax error, unexpected %s, expecting %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+#endif
+	  char *yyfmt;
+	  char const *yyf;
+	  static char const yyunexpected[] = "syntax error, unexpected %s";
+	  static char const yyexpecting[] = ", expecting %s";
+	  static char const yyor[] = " or %s";
+	  char yyformat[sizeof yyunexpected
+			+ sizeof yyexpecting - 1
+			+ ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+			   * (sizeof yyor - 1))];
+	  char const *yyprefix = yyexpecting;
+
+	  /* Start YYX at -YYN if negative to avoid negative indexes in
+	     YYCHECK.  */
+	  int yyxbegin = yyn < 0 ? -yyn : 0;
+
+	  /* Stay within bounds of both yycheck and yytname.  */
+	  int yychecklim = YYLAST - yyn;
+	  int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+	  int yycount = 1;
+
+	  yyarg[0] = yytname[yytype];
+	  yyfmt = yystpcpy (yyformat, yyunexpected);
+
+	  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	      {
+		if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+		  {
+		    yycount = 1;
+		    yysize = yysize0;
+		    yyformat[sizeof yyunexpected - 1] = '\0';
+		    break;
+		  }
+		yyarg[yycount++] = yytname[yyx];
+		yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+		yysize_overflow |= yysize1 < yysize;
+		yysize = yysize1;
+		yyfmt = yystpcpy (yyfmt, yyprefix);
+		yyprefix = yyor;
+	      }
+
+	  yyf = YY_(yyformat);
+	  yysize1 = yysize + yystrlen (yyf);
+	  yysize_overflow |= yysize1 < yysize;
+	  yysize = yysize1;
+
+	  if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM)
+	    yymsg = (char *) YYSTACK_ALLOC (yysize);
+	  if (yymsg)
+	    {
+	      /* Avoid sprintf, as that infringes on the user's name space.
+		 Don't have undefined behavior even if the translation
+		 produced a string with the wrong number of "%s"s.  */
+	      char *yyp = yymsg;
+	      int yyi = 0;
+	      while ((*yyp = *yyf))
+		{
+		  if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		    {
+		      yyp += yytnamerr (yyp, yyarg[yyi++]);
+		      yyf += 2;
+		    }
+		  else
+		    {
+		      yyp++;
+		      yyf++;
+		    }
+		}
+	      yyerror (yymsg);
+	      YYSTACK_FREE (yymsg);
+	    }
+	  else
+	    {
+	      yyerror (YY_("syntax error"));
+	      goto yyexhaustedlab;
+	    }
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror (YY_("syntax error"));
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+        }
+      else
+	{
+	  yydestruct ("Error: discarding", yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (0)
+     goto yyerrorlab;
+
+yyvsp -= yylen;
+  yyssp -= yylen;
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping", yystos[yystate], yyvsp);
+      YYPOPSTACK;
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token. */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK;
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+
+
+#line 353 "agrampar.y"
+
+
+/* ----------------- extra C code ------------------- */
+
+

Added: vendor/elsa/current/ast/agrampar.tab.h
===================================================================
--- vendor/elsa/current/ast/agrampar.tab.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/agrampar.tab.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,131 @@
+/* A Bison parser, made by GNU Bison 2.1.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+   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, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     TOK_NAME = 258,
+     TOK_INTLIT = 259,
+     TOK_EMBEDDED_CODE = 260,
+     TOK_LBRACE = 261,
+     TOK_RBRACE = 262,
+     TOK_SEMICOLON = 263,
+     TOK_ARROW = 264,
+     TOK_LPAREN = 265,
+     TOK_RPAREN = 266,
+     TOK_LANGLE = 267,
+     TOK_RANGLE = 268,
+     TOK_STAR = 269,
+     TOK_AMPERSAND = 270,
+     TOK_COMMA = 271,
+     TOK_EQUALS = 272,
+     TOK_COLON = 273,
+     TOK_CLASS = 274,
+     TOK_PUBLIC = 275,
+     TOK_PRIVATE = 276,
+     TOK_PROTECTED = 277,
+     TOK_VERBATIM = 278,
+     TOK_IMPL_VERBATIM = 279,
+     TOK_XML_VERBATIM = 280,
+     TOK_CTOR = 281,
+     TOK_DTOR = 282,
+     TOK_PURE_VIRTUAL = 283,
+     TOK_CUSTOM = 284,
+     TOK_OPTION = 285,
+     TOK_NEW = 286,
+     TOK_ENUM = 287
+   };
+#endif
+/* Tokens.  */
+#define TOK_NAME 258
+#define TOK_INTLIT 259
+#define TOK_EMBEDDED_CODE 260
+#define TOK_LBRACE 261
+#define TOK_RBRACE 262
+#define TOK_SEMICOLON 263
+#define TOK_ARROW 264
+#define TOK_LPAREN 265
+#define TOK_RPAREN 266
+#define TOK_LANGLE 267
+#define TOK_RANGLE 268
+#define TOK_STAR 269
+#define TOK_AMPERSAND 270
+#define TOK_COMMA 271
+#define TOK_EQUALS 272
+#define TOK_COLON 273
+#define TOK_CLASS 274
+#define TOK_PUBLIC 275
+#define TOK_PRIVATE 276
+#define TOK_PROTECTED 277
+#define TOK_VERBATIM 278
+#define TOK_IMPL_VERBATIM 279
+#define TOK_XML_VERBATIM 280
+#define TOK_CTOR 281
+#define TOK_DTOR 282
+#define TOK_PURE_VIRTUAL 283
+#define TOK_CUSTOM 284
+#define TOK_OPTION 285
+#define TOK_NEW 286
+#define TOK_ENUM 287
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 69 "agrampar.y"
+typedef union YYSTYPE {
+  ASTSpecFile *file;
+  ASTList<ToplevelForm> *formList;
+  TF_class *tfClass;
+  ASTList<CtorArg> *ctorArgList;
+  ASTList<Annotation> *userDeclList;
+  string *str;
+  enum AccessCtl accessCtl;
+  AccessMod *accessMod;
+  ToplevelForm *verbatim;
+  Annotation *annotation;
+  TF_option *tfOption;
+  ASTList<string> *stringList;
+  TF_enum *tfEnum;
+  ASTList<string> *enumeratorList;
+  string *enumerator;
+  ASTList<BaseClass> *baseClassList;
+  BaseClass *baseClass;
+  CustomCode *customCode;
+} YYSTYPE;
+/* Line 1447 of yacc.c.  */
+#line 123 "agrampar.tab.h"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+
+

Added: vendor/elsa/current/ast/agrampar.y
===================================================================
--- vendor/elsa/current/ast/agrampar.y	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/agrampar.y	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,356 @@
+/* agrampar.y            see license.txt for copyright and terms of use
+ * parser for abstract grammar definitions (.ast files) */
+
+
+/* C declarations */
+%{
+
+#include "agrampar.h"       // agrampar_yylex, etc.
+
+#include <stdlib.h>         // malloc, free
+#include <iostream.h>       // cout
+
+// enable debugging the parser
+#ifndef NDEBUG
+  #define YYDEBUG 1
+#endif
+
+// permit having other parser's codes in the same program
+#define yyparse agrampar_yyparse
+
+%}
+
+
+/* ================== bison declarations =================== */
+// don't use globals
+%pure_parser
+
+
+/* ===================== tokens ============================ */
+/* tokens that have many lexical spellings */
+%token <str> TOK_NAME
+%token <str> TOK_INTLIT
+%token <str> TOK_EMBEDDED_CODE
+
+/* punctuators */
+%token TOK_LBRACE "{"
+%token TOK_RBRACE "}"
+%token TOK_SEMICOLON ";"
+%token TOK_ARROW "->"
+%token TOK_LPAREN "("
+%token TOK_RPAREN ")"
+%token TOK_LANGLE "<"
+%token TOK_RANGLE ">"
+%token TOK_STAR "*"
+%token TOK_AMPERSAND "&"
+%token TOK_COMMA ","
+%token TOK_EQUALS "="
+%token TOK_COLON ":"
+
+/* keywords */
+%token TOK_CLASS "class"
+%token TOK_PUBLIC "public"
+%token TOK_PRIVATE "private"
+%token TOK_PROTECTED "protected"
+%token TOK_VERBATIM "verbatim"
+%token TOK_IMPL_VERBATIM "impl_verbatim"
+%token TOK_XML_VERBATIM "xml_verbatim"
+%token TOK_CTOR "ctor"
+%token TOK_DTOR "dtor"
+%token TOK_PURE_VIRTUAL "pure_virtual"
+%token TOK_CUSTOM "custom"
+%token TOK_OPTION "option"
+%token TOK_NEW "new"
+%token TOK_ENUM "enum"
+
+
+/* ======================== types ========================== */
+/* all pointers are interpreted as owner pointers */
+%union {
+  ASTSpecFile *file;
+  ASTList<ToplevelForm> *formList;
+  TF_class *tfClass;
+  ASTList<CtorArg> *ctorArgList;
+  ASTList<Annotation> *userDeclList;
+  string *str;
+  enum AccessCtl accessCtl;
+  AccessMod *accessMod;
+  ToplevelForm *verbatim;
+  Annotation *annotation;
+  TF_option *tfOption;
+  ASTList<string> *stringList;
+  TF_enum *tfEnum;
+  ASTList<string> *enumeratorList;
+  string *enumerator;
+  ASTList<BaseClass> *baseClassList;
+  BaseClass *baseClass;
+  CustomCode *customCode;
+}
+
+%type <file> StartSymbol
+%type <formList> Input
+%type <tfClass> Class ClassBody ClassMembersOpt
+%type <ctorArgList> CtorArgsOpt CtorArgs CtorArgList
+%type <userDeclList> CtorMembersOpt
+%type <str> Arg ArgWord Embedded ArgList
+%type <accessCtl> Public
+%type <accessMod> AccessMod
+%type <verbatim> Verbatim
+%type <annotation> Annotation
+%type <tfOption> Option
+%type <stringList> StringList OptionArgs
+%type <tfEnum> Enum
+%type <enumeratorList> EnumeratorSeq
+%type <enumerator> Enumerator
+%type <baseClassList> BaseClassesOpt BaseClassSeq
+%type <accessCtl> BaseAccess
+%type <baseClass> BaseClass
+%type <customCode> CustomCode;
+
+
+/* ===================== productions ======================= */
+%%
+
+/* start symbol */
+/* yields ASTSpecFile, though really $$ isn't used.. */
+StartSymbol: Input
+               { $$ = *((ASTSpecFile**)parseParam) = new ASTSpecFile($1); }
+           ;
+
+/* sequence of toplevel forms */
+/* yields ASTList<ToplevelForm> */
+Input: /* empty */           { $$ = new ASTList<ToplevelForm>; }
+     | Input Class           { ($$=$1)->append($2); }
+     | Input Verbatim        { ($$=$1)->append($2); }
+     | Input Option          { ($$=$1)->append($2); }
+     | Input Enum            { ($$=$1)->append($2); }
+     | Input CustomCode      { ($$=$1)->append(new TF_custom($2)); }
+     | Input ";"             { $$=$1; }     /* ignore extraneous semis */
+     ;
+
+/* a class is a nonterminal in the abstract grammar */
+/* yields TF_class */
+Class: NewOpt "class" TOK_NAME CtorArgsOpt BaseClassesOpt ClassBody
+         { ($$=$6)->super->name = unbox($3); 
+           $$->super->args.steal($4); 
+           $$->super->bases.steal($5); }
+     | NewOpt "class" TOK_NAME CtorArgs CtorArgs BaseClassesOpt ClassBody
+         { ($$=$7)->super->name = unbox($3);
+           $$->super->args.steal($4);
+           $$->super->lastArgs.steal($5);
+           $$->super->bases.steal($6); }
+     ;
+
+/* for now, just allow "new" but don't interpret it */
+NewOpt: /* empty */          {}
+      | "new"                {}
+      ;
+
+/*
+ * I contemplated making both kinds of forms end in semicolon, but then
+ * realized that for consistency I should also put semis after the
+ * inner ctor bodies, which I didn't want to do.  So, I'll stick with the
+ * general schema that entities are followed either by brace-delimited
+ * bodies or a single ";".  I can always put extensions inside the braces,
+ * so the lack of syntax after "}" won't be a problem later.
+ */
+/* yields TF_class */
+ClassBody: "{" ClassMembersOpt "}" /* no ";", see above */
+             { $$=$2; }
+         | ";"
+             { $$ = new TF_class(new ASTClass("(placeholder)", NULL, NULL, NULL, NULL), NULL); }
+         ;
+
+/* yields TF_class */
+/* does this by making an empty one initially, and then adding to it */
+ClassMembersOpt
+  : /* empty */
+      { $$ = new TF_class(new ASTClass("(placeholder)", NULL, NULL, NULL, NULL), NULL); }
+  | ClassMembersOpt "->" TOK_NAME CtorArgsOpt BaseClassesOpt ";"
+      { ($$=$1)->ctors.append(new ASTClass(unbox($3), $4, NULL, $5, NULL)); }
+  | ClassMembersOpt "->" TOK_NAME CtorArgsOpt BaseClassesOpt "{" CtorMembersOpt "}"
+      { ($$=$1)->ctors.append(new ASTClass(unbox($3), $4, NULL, $5, $7)); }
+  | ClassMembersOpt Annotation
+      { ($$=$1)->super->decls.append($2); }
+  ;
+
+/* empty ctor args can have parens or not, at user's discretion */  
+/* yields ASTList<CtorArg> */
+CtorArgsOpt
+  : /* empty */
+      { $$ = new ASTList<CtorArg>; }
+  | CtorArgs
+      { $$ = $1; }
+  ;
+
+/* yields ASTList<CtorArg> */
+CtorArgs
+  : "(" ")"
+      { $$ = new ASTList<CtorArg>; }
+  | "(" CtorArgList ")"
+      { $$ = $2; }
+  ;
+
+/* yields ASTList<CtorArg> */
+CtorArgList: Arg
+               { $$ = new ASTList<CtorArg>;
+                 {
+                   string tmp = unbox($1);
+                   $$->append(parseCtorArg(tmp));
+                 }
+               }
+           | CtorArgList "," Arg
+               { ($$=$1)->append(parseCtorArg(unbox($3))); }
+           ;
+
+/* yields string */
+Arg: ArgWord
+       { $$ = $1; }
+   | Arg ArgWord
+       { $$ = appendStr($1, $2); }   // dealloc's $1, $2
+   ;
+
+/* yields string */
+ArgWord
+  : TOK_NAME         { $$ = appendStr($1, box(" ")); }
+  | TOK_INTLIT       { $$ = appendStr($1, box(" ")); }
+  | "<" ArgList ">"  { $$ = appendStr(box("<"), appendStr($2, box(">"))); }
+  | "*"              { $$ = box("*"); }
+  | "&"              { $$ = box("&"); }
+  | "="              { $$ = box("="); }
+  | TOK_CLASS        { $$ = box("class "); }    /* special b/c is ast spec keyword */
+  ;
+
+/* yields string, and may have commas inside */
+ArgList: Arg
+           { $$ = $1; }
+       | Arg "," ArgList
+           { $$ = appendStr($1, appendStr(box(","), $3)); }
+       ;
+
+/* yields ASTList<Annotation> */
+CtorMembersOpt
+  : /* empty */
+      { $$ = new ASTList<Annotation>; }
+  | CtorMembersOpt Annotation
+      { ($$=$1)->append($2); }
+  ;
+
+/* yields Annotation */
+Annotation
+  : AccessMod Embedded
+      { $$ = new UserDecl($1, unbox($2), ""); }
+  | AccessMod TOK_EMBEDDED_CODE "=" TOK_EMBEDDED_CODE ";"
+      { $$ = new UserDecl($1, unbox($2), unbox($4)); }
+  | CustomCode
+      { $$ = $1; }
+  ;
+
+/* yields CustomCode */
+CustomCode
+  : "custom" TOK_NAME Embedded
+      { $$ = new CustomCode(unbox($2), unbox($3)); }
+  ;
+
+/* yields string */
+Embedded
+  : TOK_EMBEDDED_CODE ";"
+      { $$ = $1; }
+  | "{" TOK_EMBEDDED_CODE "}"
+      { $$ = $2; }
+  ;
+
+/* yields AccessCtl */
+Public
+  : "public"        { $$ = AC_PUBLIC; }
+  | "private"       { $$ = AC_PRIVATE; }
+  | "protected"     { $$ = AC_PROTECTED; }
+  | "ctor"          { $$ = AC_CTOR; }
+  | "dtor"          { $$ = AC_DTOR; }
+  | "pure_virtual"  { $$ = AC_PUREVIRT; }
+  ;
+
+/* yield AccessMod */
+AccessMod: Public
+             { $$ = new AccessMod($1, NULL); }
+         | Public "(" StringList ")"
+             { $$ = new AccessMod($1, $3); }
+         ;
+
+/* yield ASTList<string> */
+StringList: TOK_NAME
+              { $$ = new ASTList<string>($1); }
+          | StringList "," TOK_NAME
+              { ($$=$1)->append($3); }
+          ;
+
+/* yields TF_verbatim */
+Verbatim: "verbatim" Embedded
+            { $$ = new TF_verbatim(unbox($2)); }
+        | "impl_verbatim" Embedded
+            { $$ = new TF_impl_verbatim(unbox($2)); }
+        | "xml_verbatim" Embedded
+            { $$ = new TF_xml_verbatim(unbox($2)); }
+        ;
+
+/* yields TF_option */
+Option: "option" TOK_NAME OptionArgs ";"
+	  { $$ = new TF_option(unbox($2), $3); }
+      ;
+      
+/* yields ASTList<string> */
+OptionArgs: /*empty*/
+              { $$ = new ASTList<string>; }
+          | OptionArgs TOK_NAME
+              { ($$=$1)->append($2); }
+          ;
+
+/* yields TF_enum */
+Enum: "enum" TOK_NAME "{" EnumeratorSeq "}"
+        { $$ = new TF_enum(unbox($2), $4); }
+    | "enum" TOK_NAME "{" EnumeratorSeq "," "}"
+        { $$ = new TF_enum(unbox($2), $4); }
+    ;
+
+/* yields ASTList<string> */
+EnumeratorSeq: Enumerator
+                 { $$ = new ASTList<string>($1); }
+             | EnumeratorSeq "," Enumerator
+                 { ($$=$1)->append($3); }
+             ;
+
+/* yields string */
+Enumerator: TOK_NAME
+              { $$ = $1; }
+          ;
+
+/* yields ASTList<BaseClass> */
+BaseClassesOpt: /* empty */
+                  { $$ = new ASTList<BaseClass>; }
+              | ":" BaseClassSeq
+                  { $$ = $2; }
+              ;
+
+/* yields ASTList<BaseClass> */
+BaseClassSeq: BaseClass
+                { $$ = new ASTList<BaseClass>($1); }
+            | BaseClassSeq "," BaseClass
+                { ($$=$1)->append($3); }
+            ;
+
+/* yields AccessCtl */
+BaseAccess
+  : "public"        { $$ = AC_PUBLIC; }
+  | "private"       { $$ = AC_PRIVATE; }
+  | "protected"     { $$ = AC_PROTECTED; }
+  ;
+
+/* yields BaseClass */
+BaseClass: BaseAccess TOK_NAME
+             { $$ = new BaseClass($1, unbox($2)); }
+         ;
+
+%%
+
+/* ----------------- extra C code ------------------- */
+

Added: vendor/elsa/current/ast/ast.ast
===================================================================
--- vendor/elsa/current/ast/ast.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/ast.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,186 @@
+// ast.ast            see license.txt for copyright and terms of use
+// ast definition for an ast definition
+
+verbatim {
+  #include "str.h"         // string
+
+  // this signals to ast.hand.cc that ast.ast.cc is nonempty,
+  // so none of the bootstrap code in ast.hand.cc should be used
+  #define GENERATED_AST_PRESENT
+}
+
+// the entire specification
+class ASTSpecFile (ASTList<ToplevelForm> forms);
+
+class ToplevelForm {
+  // code to be copied verbatim into the generated .h file
+  -> TF_verbatim(string code);
+
+  // code to be copied verbatim into the generated .cc file
+  -> TF_impl_verbatim(string code);
+
+  // code to be copied verbatim into the generated optional xmlVisitor class
+  -> TF_xml_verbatim(string code);
+
+  // a superclass, and a list of subclasses ("constructors")
+  -> TF_class(ASTClass super,
+              ASTList<ASTClass> ctors) {
+       public bool hasChildren() const { return ctors.isNotEmpty(); };
+     }
+   
+  // a generic option: first word specifies the kind of option, and
+  // additional words (if any) are arguments
+  -> TF_option(string name, ASTList<string> args);
+  
+  // generic custom/verbatim code
+  -> TF_custom(CustomCode cust);
+
+  // enumeration (at one point I had support for explicit enumerator
+  // values, but decided that if the user wants that, they should put
+  // the enum in a 'verbatim' section instead)
+  -> TF_enum(string name, ASTList<string> enumerators);
+}
+
+// a definition of a grammar terminal or nonterminal
+class ASTClass (string name,
+                ASTList<CtorArg> args,
+                ASTList<CtorArg> lastArgs,    // only for nonterminal
+                ASTList<BaseClass> bases,
+                ASTList<Annotation> decls) {
+  // the name of the enum constant denoting this ctor, as distinguished
+  // from its sibling ctors
+  public string classKindName() const;
+}
+
+verbatim {
+  // specifies what kind of userdecl this is; pub/priv/prot are uninterpreted
+  // class members with the associated access control; ctor and dtor are
+  // code to be inserted into the ctor or dtor, respectively
+  enum AccessCtl {
+    AC_PUBLIC,      // access
+    AC_PRIVATE,     //   control
+    AC_PROTECTED,   //     keywords
+    AC_CTOR,        // insert into ctor
+    AC_DTOR,        // insert into dtor
+    AC_PUREVIRT,    // declare pure virtual in superclass, and impl in subclass
+    NUM_ACCESSCTLS
+  };
+
+  // map the enum value to a string like "public"
+  string toString(AccessCtl acc);      // defined in ast.cc
+}
+
+// an access control keyword with optional modifier list
+class AccessMod(AccessCtl acc, ASTList<string> mods) {
+  // true if the given modifier is present
+  public bool hasMod(char const *mod) const;
+  // true if the given modifier prefix is present as a prefix of a modifier
+  public bool hasModPrefix(char const *mod) const;
+  // get the suffix after the given prefix of the (first) modifier it matches
+  public string getModSuffixFromPrefix(char const *mod) const;
+}
+
+// additional user annotations
+class Annotation {
+  // verbatim declarations, plus an access qualifier, to be
+  // copied into the a class declaration; also has an optional
+  // initializer (might be "")
+  -> UserDecl (AccessMod amod, string code, string init) {
+       public AccessCtl access() const { return amod->acc; };
+     }
+
+  // verbatim code to be inserted somewhere; exactly where depends
+  // on the qualifier string
+  -> CustomCode (string qualifier, string code) {
+       // keep track of whether it gets used
+       public bool used;  ctor used=false;
+     }
+}
+
+// something that has to be passed to create a constructor
+class CtorArg (bool isOwner, string type, string name, string defaultValue);
+
+// designate a class that one of the ASTClasses should inherit; for
+// AST subclasses, this inheritance is in addition to inheriting the
+// corresponding AST superclass
+class BaseClass (AccessCtl access, string name);
+
+
+// ------------------- extra implementation helpers ------------------
+impl_verbatim {
+
+#include "strutil.h"      // stringToupper
+
+string toString(AccessCtl acc)
+{
+  char const *arr[] = {
+    "public",
+    "private",
+    "protected",
+    "ctor",
+    "dtor",
+    "pure_virtual"
+  };
+  STATIC_ASSERT(TABLESIZE(arr) == NUM_ACCESSCTLS);
+  xassert((unsigned)acc < NUM_ACCESSCTLS);
+  return string(arr[acc]);
+}
+
+string ASTClass::classKindName() const
+{
+  string ret = stringToupper(name);
+  if (ret == name) {
+    // this simplemindedly avoids collisions with itself, and I think
+    // it even avoids collisions with other classes, since if they would
+    // collide with this, they'd collide with themselves too, and hence
+    // get an extra "KIND_" prepended..
+    ret &= "KIND_";
+  }
+  return ret;
+}
+
+bool AccessMod::hasMod(char const *mod) const
+{
+  FOREACH_ASTLIST(string, mods, iter) {
+    if (iter.data()->equals(mod)) {
+      return true;
+    }
+  }
+  return false;      // not found
+}
+
+bool AccessMod::hasModPrefix(char const *mod) const
+{
+  string mod0(mod);
+  FOREACH_ASTLIST(string, mods, iter) {
+    rostring i = *iter.data();
+    if (prefixEquals(i, mod0)) {
+      return true;
+    }
+  }
+  return false;      // not found
+}
+
+string AccessMod::getModSuffixFromPrefix(char const *mod) const
+{
+  string mod0(mod);
+  string ret;
+  bool found = false;
+  FOREACH_ASTLIST(string, mods, iter) {
+    rostring s = *iter.data();
+    if (prefixEquals(s, mod0)) {
+      if (found) {
+        xfailure(stringc << "two modifiers with this prefix found " << mod);
+      }
+      int len = strlen(mod);
+      ret = s.substring(len, s.length()-len);
+      found = true;
+    }
+  }
+  if (!found) {
+    xfailure(stringc << "no such prefix found " << mod);
+  }
+  return ret;
+}
+
+} // end impl_verbatim

Added: vendor/elsa/current/ast/ast.ast.cc
===================================================================
--- vendor/elsa/current/ast/ast.ast.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/ast.ast.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,488 @@
+// ast.ast.cc
+// *** DO NOT EDIT ***
+// generated automatically by astgen, from ast.ast
+
+#include "ast.ast.h"      // this module
+
+
+// ------------------ ASTSpecFile -------------------
+// *** DO NOT EDIT ***
+ASTSpecFile::~ASTSpecFile()
+{
+  forms.deleteAll();
+}
+
+void ASTSpecFile::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, ASTSpecFile);
+
+  PRINT_LIST(ToplevelForm, forms);
+}
+
+ASTSpecFile *ASTSpecFile::clone() const
+{
+  ASTSpecFile *ret = new ASTSpecFile(
+    cloneASTList(forms)
+  );
+  return ret;
+}
+
+
+// ------------------ ToplevelForm -------------------
+// *** DO NOT EDIT ***
+ToplevelForm::~ToplevelForm()
+{
+}
+
+char const * const ToplevelForm::kindNames[ToplevelForm::NUM_KINDS] = {
+  "TF_verbatim",
+  "TF_impl_verbatim",
+  "TF_xml_verbatim",
+  "TF_class",
+  "TF_option",
+  "TF_custom",
+  "TF_enum",
+};
+
+void ToplevelForm::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+}
+
+DEFN_AST_DOWNCASTS(ToplevelForm, TF_verbatim, TF_VERBATIM)
+
+TF_verbatim::~TF_verbatim()
+{
+}
+
+void TF_verbatim::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, TF_verbatim);
+
+  ToplevelForm::debugPrint(os, indent, subtreeName);
+
+  PRINT_STRING(code);
+}
+
+TF_verbatim *TF_verbatim::clone() const
+{
+  TF_verbatim *ret = new TF_verbatim(
+    code
+  );
+  return ret;
+}
+
+DEFN_AST_DOWNCASTS(ToplevelForm, TF_impl_verbatim, TF_IMPL_VERBATIM)
+
+TF_impl_verbatim::~TF_impl_verbatim()
+{
+}
+
+void TF_impl_verbatim::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, TF_impl_verbatim);
+
+  ToplevelForm::debugPrint(os, indent, subtreeName);
+
+  PRINT_STRING(code);
+}
+
+TF_impl_verbatim *TF_impl_verbatim::clone() const
+{
+  TF_impl_verbatim *ret = new TF_impl_verbatim(
+    code
+  );
+  return ret;
+}
+
+DEFN_AST_DOWNCASTS(ToplevelForm, TF_xml_verbatim, TF_XML_VERBATIM)
+
+TF_xml_verbatim::~TF_xml_verbatim()
+{
+}
+
+void TF_xml_verbatim::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, TF_xml_verbatim);
+
+  ToplevelForm::debugPrint(os, indent, subtreeName);
+
+  PRINT_STRING(code);
+}
+
+TF_xml_verbatim *TF_xml_verbatim::clone() const
+{
+  TF_xml_verbatim *ret = new TF_xml_verbatim(
+    code
+  );
+  return ret;
+}
+
+DEFN_AST_DOWNCASTS(ToplevelForm, TF_class, TF_CLASS)
+
+TF_class::~TF_class()
+{
+  delete super;
+  ctors.deleteAll();
+}
+
+void TF_class::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, TF_class);
+
+  ToplevelForm::debugPrint(os, indent, subtreeName);
+
+  PRINT_SUBTREE(super);
+  PRINT_LIST(ASTClass, ctors);
+}
+
+TF_class *TF_class::clone() const
+{
+  TF_class *ret = new TF_class(
+    super? super->clone() : NULL,
+    cloneASTList(ctors)
+  );
+  return ret;
+}
+
+DEFN_AST_DOWNCASTS(ToplevelForm, TF_option, TF_OPTION)
+
+TF_option::~TF_option()
+{
+  while (args.isNotEmpty()) {
+    args.removeFirst();
+  }
+}
+
+void TF_option::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, TF_option);
+
+  ToplevelForm::debugPrint(os, indent, subtreeName);
+
+  PRINT_STRING(name);
+  PRINT_LIST(string, args);
+}
+
+TF_option *TF_option::clone() const
+{
+  TF_option *ret = new TF_option(
+    name,
+    shallowCloneASTList(args)
+  );
+  return ret;
+}
+
+DEFN_AST_DOWNCASTS(ToplevelForm, TF_custom, TF_CUSTOM)
+
+TF_custom::~TF_custom()
+{
+  delete cust;
+}
+
+void TF_custom::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, TF_custom);
+
+  ToplevelForm::debugPrint(os, indent, subtreeName);
+
+  PRINT_SUBTREE(cust);
+}
+
+TF_custom *TF_custom::clone() const
+{
+  TF_custom *ret = new TF_custom(
+    cust? cust->clone() : NULL
+  );
+  return ret;
+}
+
+DEFN_AST_DOWNCASTS(ToplevelForm, TF_enum, TF_ENUM)
+
+TF_enum::~TF_enum()
+{
+  while (enumerators.isNotEmpty()) {
+    enumerators.removeFirst();
+  }
+}
+
+void TF_enum::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, TF_enum);
+
+  ToplevelForm::debugPrint(os, indent, subtreeName);
+
+  PRINT_STRING(name);
+  PRINT_LIST(string, enumerators);
+}
+
+TF_enum *TF_enum::clone() const
+{
+  TF_enum *ret = new TF_enum(
+    name,
+    shallowCloneASTList(enumerators)
+  );
+  return ret;
+}
+
+
+// ------------------ ASTClass -------------------
+// *** DO NOT EDIT ***
+ASTClass::~ASTClass()
+{
+  args.deleteAll();
+  lastArgs.deleteAll();
+  bases.deleteAll();
+  decls.deleteAll();
+}
+
+void ASTClass::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, ASTClass);
+
+  PRINT_STRING(name);
+  PRINT_LIST(CtorArg, args);
+  PRINT_LIST(CtorArg, lastArgs);
+  PRINT_LIST(BaseClass, bases);
+  PRINT_LIST(Annotation, decls);
+}
+
+ASTClass *ASTClass::clone() const
+{
+  ASTClass *ret = new ASTClass(
+    name,
+    cloneASTList(args),
+    cloneASTList(lastArgs),
+    cloneASTList(bases),
+    cloneASTList(decls)
+  );
+  return ret;
+}
+
+
+// ------------------ AccessMod -------------------
+// *** DO NOT EDIT ***
+AccessMod::~AccessMod()
+{
+  while (mods.isNotEmpty()) {
+    mods.removeFirst();
+  }
+}
+
+void AccessMod::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, AccessMod);
+
+  PRINT_GENERIC(acc);
+  PRINT_LIST(string, mods);
+}
+
+AccessMod *AccessMod::clone() const
+{
+  AccessMod *ret = new AccessMod(
+    acc,
+    shallowCloneASTList(mods)
+  );
+  return ret;
+}
+
+
+// ------------------ Annotation -------------------
+// *** DO NOT EDIT ***
+Annotation::~Annotation()
+{
+}
+
+char const * const Annotation::kindNames[Annotation::NUM_KINDS] = {
+  "UserDecl",
+  "CustomCode",
+};
+
+void Annotation::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+}
+
+DEFN_AST_DOWNCASTS(Annotation, UserDecl, USERDECL)
+
+UserDecl::~UserDecl()
+{
+  delete amod;
+}
+
+void UserDecl::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, UserDecl);
+
+  Annotation::debugPrint(os, indent, subtreeName);
+
+  PRINT_SUBTREE(amod);
+  PRINT_STRING(code);
+  PRINT_STRING(init);
+}
+
+UserDecl *UserDecl::clone() const
+{
+  UserDecl *ret = new UserDecl(
+    amod? amod->clone() : NULL,
+    code,
+    init
+  );
+  return ret;
+}
+
+DEFN_AST_DOWNCASTS(Annotation, CustomCode, CUSTOMCODE)
+
+CustomCode::~CustomCode()
+{
+}
+
+void CustomCode::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, CustomCode);
+
+  Annotation::debugPrint(os, indent, subtreeName);
+
+  PRINT_STRING(qualifier);
+  PRINT_STRING(code);
+}
+
+CustomCode *CustomCode::clone() const
+{
+  CustomCode *ret = new CustomCode(
+    qualifier,
+    code
+  );
+  return ret;
+}
+
+
+// ------------------ CtorArg -------------------
+// *** DO NOT EDIT ***
+CtorArg::~CtorArg()
+{
+}
+
+void CtorArg::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, CtorArg);
+
+  PRINT_BOOL(isOwner);
+  PRINT_STRING(type);
+  PRINT_STRING(name);
+  PRINT_STRING(defaultValue);
+}
+
+CtorArg *CtorArg::clone() const
+{
+  CtorArg *ret = new CtorArg(
+    isOwner,
+    type,
+    name,
+    defaultValue
+  );
+  return ret;
+}
+
+
+// ------------------ BaseClass -------------------
+// *** DO NOT EDIT ***
+BaseClass::~BaseClass()
+{
+}
+
+void BaseClass::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  PRINT_HEADER(subtreeName, BaseClass);
+
+  PRINT_GENERIC(access);
+  PRINT_STRING(name);
+}
+
+BaseClass *BaseClass::clone() const
+{
+  BaseClass *ret = new BaseClass(
+    access,
+    name
+  );
+  return ret;
+}
+
+
+// *** DO NOT EDIT ***
+
+
+#include "strutil.h"      // stringToupper
+
+string toString(AccessCtl acc)
+{
+  char const *arr[] = {
+    "public",
+    "private",
+    "protected",
+    "ctor",
+    "dtor",
+    "pure_virtual"
+  };
+  STATIC_ASSERT(TABLESIZE(arr) == NUM_ACCESSCTLS);
+  xassert((unsigned)acc < NUM_ACCESSCTLS);
+  return string(arr[acc]);
+}
+
+string ASTClass::classKindName() const
+{
+  string ret = stringToupper(name);
+  if (ret == name) {
+    // this simplemindedly avoids collisions with itself, and I think
+    // it even avoids collisions with other classes, since if they would
+    // collide with this, they'd collide with themselves too, and hence
+    // get an extra "KIND_" prepended..
+    ret &= "KIND_";
+  }
+  return ret;
+}
+
+bool AccessMod::hasMod(char const *mod) const
+{
+  FOREACH_ASTLIST(string, mods, iter) {
+    if (iter.data()->equals(mod)) {
+      return true;
+    }
+  }
+  return false;      // not found
+}
+
+bool AccessMod::hasModPrefix(char const *mod) const
+{
+  string mod0(mod);
+  FOREACH_ASTLIST(string, mods, iter) {
+    rostring i = *iter.data();
+    if (prefixEquals(i, mod0)) {
+      return true;
+    }
+  }
+  return false;      // not found
+}
+
+string AccessMod::getModSuffixFromPrefix(char const *mod) const
+{
+  string mod0(mod);
+  string ret;
+  bool found = false;
+  FOREACH_ASTLIST(string, mods, iter) {
+    rostring s = *iter.data();
+    if (prefixEquals(s, mod0)) {
+      if (found) {
+        xfailure(stringc << "two modifiers with this prefix found " << mod);
+      }
+      int len = strlen(mod);
+      ret = s.substring(len, s.length()-len);
+      found = true;
+    }
+  }
+  if (!found) {
+    xfailure(stringc << "no such prefix found " << mod);
+  }
+  return ret;
+}
+
+
+

Added: vendor/elsa/current/ast/ast.ast.h
===================================================================
--- vendor/elsa/current/ast/ast.ast.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/ast.ast.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,398 @@
+// ast.ast.h
+// *** DO NOT EDIT ***
+// generated automatically by astgen, from ast.ast
+
+#ifndef AST_AST_H
+#define AST_AST_H
+
+#include "asthelp.h"        // helpers for generated code
+
+// fwd decls
+class ASTSpecFile;
+class ToplevelForm;
+class TF_verbatim;
+class TF_impl_verbatim;
+class TF_xml_verbatim;
+class TF_class;
+class TF_option;
+class TF_custom;
+class TF_enum;
+class ASTClass;
+class AccessMod;
+class Annotation;
+class UserDecl;
+class CustomCode;
+class CtorArg;
+class BaseClass;
+
+
+// *** DO NOT EDIT ***
+
+  #include "str.h"         // string
+
+  // this signals to ast.hand.cc that ast.ast.cc is nonempty,
+  // so none of the bootstrap code in ast.hand.cc should be used
+  #define GENERATED_AST_PRESENT
+
+// *** DO NOT EDIT ***
+class ASTSpecFile {
+public:      // data
+  ASTList <ToplevelForm > forms;
+
+public:      // funcs
+  ASTSpecFile(ASTList <ToplevelForm > *_forms) : forms(_forms) {
+  }
+  ~ASTSpecFile();
+
+  char const *kindName() const { return "ASTSpecFile"; }
+
+  ASTSpecFile *clone() const;
+
+  void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+};
+
+
+
+// *** DO NOT EDIT ***
+class ToplevelForm {
+public:      // data
+
+public:      // funcs
+  ToplevelForm() {
+  }
+  virtual ~ToplevelForm();
+
+  enum Kind { TF_VERBATIM, TF_IMPL_VERBATIM, TF_XML_VERBATIM, TF_CLASS, TF_OPTION, TF_CUSTOM, TF_ENUM, NUM_KINDS };
+  virtual Kind kind() const = 0;
+
+  static char const * const kindNames[NUM_KINDS];
+  char const *kindName() const { return kindNames[kind()]; }
+
+  DECL_AST_DOWNCASTS(TF_verbatim, TF_VERBATIM)
+  DECL_AST_DOWNCASTS(TF_impl_verbatim, TF_IMPL_VERBATIM)
+  DECL_AST_DOWNCASTS(TF_xml_verbatim, TF_XML_VERBATIM)
+  DECL_AST_DOWNCASTS(TF_class, TF_CLASS)
+  DECL_AST_DOWNCASTS(TF_option, TF_OPTION)
+  DECL_AST_DOWNCASTS(TF_custom, TF_CUSTOM)
+  DECL_AST_DOWNCASTS(TF_enum, TF_ENUM)
+
+  virtual ToplevelForm* clone() const=0;
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+};
+
+class TF_verbatim : public ToplevelForm {
+public:      // data
+  string code;
+
+public:      // funcs
+  TF_verbatim(string _code) : ToplevelForm(), code(_code) {
+  }
+  virtual ~TF_verbatim();
+
+  virtual Kind kind() const { return TF_VERBATIM; }
+  enum { TYPE_TAG = TF_VERBATIM };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual TF_verbatim *clone() const;
+
+};
+
+class TF_impl_verbatim : public ToplevelForm {
+public:      // data
+  string code;
+
+public:      // funcs
+  TF_impl_verbatim(string _code) : ToplevelForm(), code(_code) {
+  }
+  virtual ~TF_impl_verbatim();
+
+  virtual Kind kind() const { return TF_IMPL_VERBATIM; }
+  enum { TYPE_TAG = TF_IMPL_VERBATIM };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual TF_impl_verbatim *clone() const;
+
+};
+
+class TF_xml_verbatim : public ToplevelForm {
+public:      // data
+  string code;
+
+public:      // funcs
+  TF_xml_verbatim(string _code) : ToplevelForm(), code(_code) {
+  }
+  virtual ~TF_xml_verbatim();
+
+  virtual Kind kind() const { return TF_XML_VERBATIM; }
+  enum { TYPE_TAG = TF_XML_VERBATIM };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual TF_xml_verbatim *clone() const;
+
+};
+
+class TF_class : public ToplevelForm {
+public:      // data
+  ASTClass *super;
+  ASTList <ASTClass > ctors;
+
+public:      // funcs
+  TF_class(ASTClass *_super, ASTList <ASTClass > *_ctors) : ToplevelForm(), super(_super), ctors(_ctors) {
+  }
+  virtual ~TF_class();
+
+  virtual Kind kind() const { return TF_CLASS; }
+  enum { TYPE_TAG = TF_CLASS };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual TF_class *clone() const;
+
+  public:  bool hasChildren() const { return ctors.isNotEmpty(); };
+};
+
+class TF_option : public ToplevelForm {
+public:      // data
+  string name;
+  ASTList <string > args;
+
+public:      // funcs
+  TF_option(string _name, ASTList <string > *_args) : ToplevelForm(), name(_name), args(_args) {
+  }
+  virtual ~TF_option();
+
+  virtual Kind kind() const { return TF_OPTION; }
+  enum { TYPE_TAG = TF_OPTION };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual TF_option *clone() const;
+
+};
+
+class TF_custom : public ToplevelForm {
+public:      // data
+  CustomCode *cust;
+
+public:      // funcs
+  TF_custom(CustomCode *_cust) : ToplevelForm(), cust(_cust) {
+  }
+  virtual ~TF_custom();
+
+  virtual Kind kind() const { return TF_CUSTOM; }
+  enum { TYPE_TAG = TF_CUSTOM };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual TF_custom *clone() const;
+
+};
+
+class TF_enum : public ToplevelForm {
+public:      // data
+  string name;
+  ASTList <string > enumerators;
+
+public:      // funcs
+  TF_enum(string _name, ASTList <string > *_enumerators) : ToplevelForm(), name(_name), enumerators(_enumerators) {
+  }
+  virtual ~TF_enum();
+
+  virtual Kind kind() const { return TF_ENUM; }
+  enum { TYPE_TAG = TF_ENUM };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual TF_enum *clone() const;
+
+};
+
+
+
+// *** DO NOT EDIT ***
+class ASTClass {
+public:      // data
+  string name;
+  ASTList <CtorArg > args;
+  ASTList <CtorArg > lastArgs;
+  ASTList <BaseClass > bases;
+  ASTList <Annotation > decls;
+
+public:      // funcs
+  ASTClass(string _name, ASTList <CtorArg > *_args, ASTList <CtorArg > *_lastArgs, ASTList <BaseClass > *_bases, ASTList <Annotation > *_decls) : name(_name), args(_args), lastArgs(_lastArgs), bases(_bases), decls(_decls) {
+  }
+  ~ASTClass();
+
+  char const *kindName() const { return "ASTClass"; }
+
+  ASTClass *clone() const;
+
+  void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  public:  string classKindName() const;
+};
+
+
+
+// *** DO NOT EDIT ***
+
+  // specifies what kind of userdecl this is; pub/priv/prot are uninterpreted
+  // class members with the associated access control; ctor and dtor are
+  // code to be inserted into the ctor or dtor, respectively
+  enum AccessCtl {
+    AC_PUBLIC,      // access
+    AC_PRIVATE,     //   control
+    AC_PROTECTED,   //     keywords
+    AC_CTOR,        // insert into ctor
+    AC_DTOR,        // insert into dtor
+    AC_PUREVIRT,    // declare pure virtual in superclass, and impl in subclass
+    NUM_ACCESSCTLS
+  };
+
+  // map the enum value to a string like "public"
+  string toString(AccessCtl acc);      // defined in ast.cc
+
+// *** DO NOT EDIT ***
+class AccessMod {
+public:      // data
+  AccessCtl acc;
+  ASTList <string > mods;
+
+public:      // funcs
+  AccessMod(AccessCtl _acc, ASTList <string > *_mods) : acc(_acc), mods(_mods) {
+  }
+  ~AccessMod();
+
+  char const *kindName() const { return "AccessMod"; }
+
+  AccessMod *clone() const;
+
+  void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  public:  bool hasMod(char const *mod) const;
+  public:  bool hasModPrefix(char const *mod) const;
+  public:  string getModSuffixFromPrefix(char const *mod) const;
+};
+
+
+
+// *** DO NOT EDIT ***
+class Annotation {
+public:      // data
+
+public:      // funcs
+  Annotation() {
+  }
+  virtual ~Annotation();
+
+  enum Kind { USERDECL, CUSTOMCODE, NUM_KINDS };
+  virtual Kind kind() const = 0;
+
+  static char const * const kindNames[NUM_KINDS];
+  char const *kindName() const { return kindNames[kind()]; }
+
+  DECL_AST_DOWNCASTS(UserDecl, USERDECL)
+  DECL_AST_DOWNCASTS(CustomCode, CUSTOMCODE)
+
+  virtual Annotation* clone() const=0;
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+};
+
+class UserDecl : public Annotation {
+public:      // data
+  AccessMod *amod;
+  string code;
+  string init;
+
+public:      // funcs
+  UserDecl(AccessMod *_amod, string _code, string _init) : Annotation(), amod(_amod), code(_code), init(_init) {
+  }
+  virtual ~UserDecl();
+
+  virtual Kind kind() const { return USERDECL; }
+  enum { TYPE_TAG = USERDECL };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual UserDecl *clone() const;
+
+  public:  AccessCtl access() const { return amod->acc; };
+};
+
+class CustomCode : public Annotation {
+public:      // data
+  string qualifier;
+  string code;
+
+public:      // funcs
+  CustomCode(string _qualifier, string _code) : Annotation(), qualifier(_qualifier), code(_code) {
+     used=false;
+  }
+  virtual ~CustomCode();
+
+  virtual Kind kind() const { return CUSTOMCODE; }
+  enum { TYPE_TAG = CUSTOMCODE };
+
+  virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+  virtual CustomCode *clone() const;
+
+  public:  bool used;
+};
+
+
+
+// *** DO NOT EDIT ***
+class CtorArg {
+public:      // data
+  bool isOwner;
+  string type;
+  string name;
+  string defaultValue;
+
+public:      // funcs
+  CtorArg(bool _isOwner, string _type, string _name, string _defaultValue) : isOwner(_isOwner), type(_type), name(_name), defaultValue(_defaultValue) {
+  }
+  ~CtorArg();
+
+  char const *kindName() const { return "CtorArg"; }
+
+  CtorArg *clone() const;
+
+  void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+};
+
+
+
+// *** DO NOT EDIT ***
+class BaseClass {
+public:      // data
+  AccessCtl access;
+  string name;
+
+public:      // funcs
+  BaseClass(AccessCtl _access, string _name) : access(_access), name(_name) {
+  }
+  ~BaseClass();
+
+  char const *kindName() const { return "BaseClass"; }
+
+  BaseClass *clone() const;
+
+  void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+
+};
+
+
+
+
+#endif // AST_AST_H

Added: vendor/elsa/current/ast/ast.hand.cc
===================================================================
--- vendor/elsa/current/ast/ast.hand.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/ast.hand.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,87 @@
+// ast.hand.cc            see license.txt for copyright and terms of use
+// hand-generated form of what I want to be autogenerated later
+
+#ifndef BOOTSTRAP
+  // in non-bootstrap, use autogen'd code
+  #include "ast.ast.cc"
+#endif
+
+#ifndef GENERATED_AST_PRESENT
+// if either we're in bootstrap mode, or else ast.gen.cc was empty, use this
+
+#include "ast.hand.h"      // this module
+
+
+// ------------------- ASTSpecFile ----------------------
+void ASTSpecFile::debugPrint(ostream &os, int indent) const
+{
+  PRINT_HEADER(ASTSpecFile);
+
+  PRINT_LIST(ToplevelForm, forms);
+}
+
+
+// ----------------- ToplevelForm -------------------
+void ToplevelForm::debugPrint(ostream &os, int indent) const
+{}
+
+
+DEFN_AST_DOWNCASTS(ToplevelForm, TF_verbatim, TF_VERBATIM)
+DEFN_AST_DOWNCASTS(ToplevelForm, ASTClass, ASTCLASS)
+
+
+void TF_verbatim::debugPrint(ostream &os, int indent) const
+{
+  PRINT_HEADER(TF_verbatim);
+
+  ToplevelForm::debugPrint(os, indent);
+
+  PRINT_STRING(code);
+}
+
+void ASTClass::debugPrint(ostream &os, int indent) const
+{
+  PRINT_HEADER(ASTClass);
+
+  ToplevelForm::debugPrint(os, indent);
+
+  PRINT_STRING(name);
+  PRINT_LIST(CtorArg, superCtor);
+  PRINT_LIST(UserDecl, decls);
+  PRINT_LIST(ASTCtor, ctors);
+}
+
+
+// ------------------ UserDecl --------------------
+void UserDecl::debugPrint(ostream &os, int indent) const
+{
+  PRINT_HEADER(UserDecl);
+
+  PRINT_GENERIC(access);
+  PRINT_STRING(code);
+}
+
+
+// -------------------- ASTCtor -----------------
+void ASTCtor::debugPrint(ostream &os, int indent) const
+{
+  PRINT_HEADER(ASTCtor);
+
+  PRINT_STRING(name);
+  PRINT_LIST(CtorArg, args);
+  PRINT_LIST(UserDecl, decls);
+}
+
+
+// ------------------ CtorArg -------------------
+void CtorArg::debugPrint(ostream &os, int indent) const
+{
+  PRINT_HEADER(CtorArg);
+
+  PRINT_BOOL(owner);
+  PRINT_STRING(type);
+  PRINT_STRING(name);
+}
+
+
+#endif // !GENERATED_AST_PRESENT

Added: vendor/elsa/current/ast/ast.hand.h
===================================================================
--- vendor/elsa/current/ast/ast.hand.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/ast.hand.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,152 @@
+// ast.hand.h            see license.txt for copyright and terms of use
+// generated (by hand) from ast.ast
+
+#ifndef BOOTSTRAP
+  // in non-bootstrap mode, use the generated file
+  #include "ast.ast.h"
+#endif
+
+#ifndef GENERATED_AST_PRESENT
+// use the code below if either:
+//   - BOOTSTRAP was defined
+//   - ast.gen.h was empty
+
+#ifndef AST_HAND_H
+#define AST_HAND_H
+
+#include "asthelp.h"     // helpers for generated code
+
+// fwd decls
+class ASTSpecFile;
+class ToplevelForm;
+class TF_verbatim;
+class ASTClass;
+class UserDecl;
+class ASTCtor;
+class CtorArg;
+
+
+  #include "str.h"         // string
+
+class ASTSpecFile {
+public:
+  ASTList<ToplevelForm> forms;
+
+public:
+  ASTSpecFile(ASTList<ToplevelForm> *_forms) : forms(_forms) {}
+  ~ASTSpecFile() {}
+
+  void debugPrint(ostream &os, int indent) const;
+};
+
+
+class ToplevelForm {
+public:
+  ToplevelForm() {}
+  virtual ~ToplevelForm() {}
+
+  enum Kind { TF_VERBATIM, ASTCLASS, NUM_KINDS };
+  virtual Kind kind() const = 0;
+
+  DECL_AST_DOWNCASTS(TF_verbatim, TF_VERBATIM)
+  DECL_AST_DOWNCASTS(ASTClass, ASTCLASS)
+
+  virtual void debugPrint(ostream &os, int indent) const;
+};
+
+class TF_verbatim : public ToplevelForm {
+public:
+  string code;
+
+public:
+  TF_verbatim(string _code)
+    : code(_code) 
+  {}
+  virtual ~TF_verbatim() {}
+
+  virtual Kind kind() const { return TF_VERBATIM; }
+  enum { TYPE_TAG = TF_VERBATIM };
+
+  virtual void debugPrint(ostream &os, int indent) const;
+};
+
+class ASTClass : public ToplevelForm {
+public:
+  string name;
+  ASTList<CtorArg> superCtor;
+  ASTList<UserDecl> decls;
+  ASTList<ASTCtor> ctors;
+
+public:
+  ASTClass(string _name, ASTList<CtorArg> *_superCtor,
+           ASTList<UserDecl> *_decls, ASTList<ASTCtor> *_ctors) :
+    name(_name), superCtor(_superCtor), decls(_decls), ctors(_ctors)
+  {}
+  ~ASTClass() {}
+
+  virtual Kind kind() const { return ASTCLASS; }
+  enum { TYPE_TAG = ASTCLASS };
+
+  virtual void debugPrint(ostream &os, int indent) const;
+  
+  public: bool hasChildren() const { return ctors.isNotEmpty(); }
+};
+
+
+  enum AccessCtl { AC_PUBLIC, AC_PRIVATE, AC_PROTECTED };
+  string toString(AccessCtl acc);      // defined in ast.cc
+
+
+class UserDecl {
+public:
+  AccessCtl access;
+  string code;
+
+public:
+  UserDecl(AccessCtl _access, string _code)
+    : access(_access), code(_code)
+  {}
+  ~UserDecl() {}
+
+  void debugPrint(ostream &os, int indent) const;
+};
+
+
+class ASTCtor {
+public:
+  string name;
+  ASTList<CtorArg> args;
+  ASTList<UserDecl> decls;
+
+public:
+  ASTCtor(string _name, ASTList<CtorArg> *_args, ASTList<UserDecl> *_decls)
+    : name(_name), args(_args), decls(_decls)
+  {}
+  ~ASTCtor() {}
+
+  void debugPrint(ostream &os, int indent) const;
+  
+  public: string kindName() const;
+};
+
+
+class CtorArg {
+public:
+  bool owner;
+  string type;
+  string name;
+
+public:
+  CtorArg(bool _owner, string _type, string _name)
+    : owner(_owner),
+      type(_type),
+      name(_name)
+  {}
+  ~CtorArg() {}
+
+  void debugPrint(ostream &os, int indent) const;
+};
+
+#endif // AST_HAND_H
+
+#endif // !GENERATED_AST_PRESENT

Added: vendor/elsa/current/ast/astgen.cc
===================================================================
--- vendor/elsa/current/ast/astgen.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/astgen.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3390 @@
+// astgen.cc            see license.txt for copyright and terms of use
+// program to generate C++ code from an AST specification
+
+#include "agrampar.h"      // readAbstractGrammar
+#include "test.h"          // ARGS_MAIN
+#include "trace.h"         // TRACE_ARGS
+#include "owner.h"         // Owner
+#include "ckheap.h"        // checkHeap
+#include "strutil.h"       // replace, translate, localTimeString
+#include "sobjlist.h"      // SObjList
+#include "stringset.h"     // StringSet
+#include "srcloc.h"        // SourceLocManager
+#include "strtokp.h"       // StrtokParse
+#include "exc.h"           // xfatal
+#include "strdict.h"       // StringDict
+#include "ofstreamts.h"    // ofstreamTS
+
+#include <string.h>        // strncmp
+#include <fstream.h>       // ofstream
+#include <ctype.h>         // isalnum
+
+// propertly a member of ListClass below, but I don't like nested
+// things
+enum ListKind {
+  LK_NONE,
+  LK_ASTList,
+  LK_FakeList,
+};
+
+// a product type of the information relevant to a list member of a
+// class; used to construct the traverse calls and visitors to the
+// fictional list classes
+struct ListClass {
+  ListKind lkind;
+  string classAndMemberName;
+  string elementClassName;
+  explicit ListClass(ListKind lkind0, rostring classAndMemberName0, rostring elementClassName0)
+    : lkind(lkind0)
+    , classAndMemberName(classAndMemberName0)
+    , elementClassName(elementClassName0)
+  {}
+  char const * kindName() const;
+};
+
+char const * ListClass::kindName() const {
+  if (lkind == LK_ASTList) return "ASTList";
+  else if (lkind == LK_FakeList) return "FakeList";
+  else xfailure("illegal ListKind");
+}
+
+// this is the name of the visitor interface class, or ""
+// if the user does not want a visitor
+string visitorName;
+inline bool wantVisitor() { return !visitorName.empty(); }
+
+// this is the name of the delegator-visitor if desired
+string dvisitorName;
+inline bool wantDVisitor() { return !dvisitorName.empty(); }
+
+// this is the name of the xml-visitor if desired
+string xmlVisitorName;
+inline bool wantXmlVisitor() { return !xmlVisitorName.empty(); }
+
+// this is the prefix of the filenames rendered for xml lexing and
+// parsing
+string xmlParserName;
+inline bool wantXmlParser() { return !xmlParserName.empty(); }
+
+// similar for the modification visitor ("mvisitor")
+string mvisitorName;
+inline bool wantMVisitor() { return !mvisitorName.empty(); }
+
+string identityManagerName;
+inline bool wantIdentityManager() { return !identityManagerName.empty(); }
+
+// entire input
+ASTSpecFile *wholeAST = NULL;
+
+// list of all TF_classes in the input, useful for certain
+// applications which don't care about other forms
+SObjList<TF_class> allClasses;
+
+// list of all ASTList "list classes"
+StringSet listClassesSet;
+ASTList<ListClass> listClasses;
+
+// true if the user wants the gdb() functions
+bool wantGDB = false;
+
+// true if we should use a hack to work around the absence of
+// support for covariant return types in MSVC; see
+//   http://support.microsoft.com/kb/240862/EN-US/
+// The approach is to use
+//   virtual Super *nocvr_clone() const;
+//   Sub *clone() const { return static_cast<Sub*>(nocvr_clone()); }
+// in place of
+//   virtual Sub *clone() const;
+bool nocvr = false;
+
+
+// ------------------ shared gen functions ----------------------
+enum TreeNodeKind { TKN_NONE, TKN_SUPERCLASS, TKN_SUBCLASS };
+
+class Gen {
+protected:        // data
+  string srcFname;                  // name of source file
+  ObjList<string> const &modules;   // extension modules
+  string destFname;                 // name of output file
+  ofstreamTS out;                   // output stream
+  ASTSpecFile const &file;          // AST specification
+
+public:           // funcs
+  Gen(rostring srcFname, ObjList<string> const &modules,
+      rostring destFname, ASTSpecFile const &file);
+  ~Gen();
+
+  // shared output sequences
+  void headerComments();
+  void doNotEdit();
+  void emitFiltered(ASTList<Annotation> const &decls, AccessCtl mode,
+                    rostring indent);
+};
+
+
+Gen::Gen(rostring srcfn, ObjList<string> const &mods,
+         rostring destfn, ASTSpecFile const &f)
+  : srcFname(srcfn),
+    modules(mods),
+    destFname(destfn),
+    out(toCStr(destfn)),
+    file(f)
+{
+  if (!out) {
+    throw_XOpen(destfn);
+  }
+}
+
+Gen::~Gen()
+{}
+
+
+// type queries
+TreeNodeKind getTreeNodeKind(rostring type);
+TreeNodeKind getTreeNodePtrKind(rostring type);
+
+bool isTreeNode(rostring type)
+{ return getTreeNodeKind(type) != TKN_NONE; }
+bool isTreeNodePtr(rostring type)
+{ return getTreeNodePtrKind(type) != TKN_NONE; }
+bool isSuperclassTreeNode(rostring type)
+{ return getTreeNodeKind(type) == TKN_SUPERCLASS; }
+bool isSuperclassTreeNodePtr(rostring type)
+{ return getTreeNodePtrKind(type) == TKN_SUPERCLASS; }
+bool isSubclassTreeNode(rostring type)
+{ return getTreeNodeKind(type) == TKN_SUBCLASS; }
+bool isSubclassTreeNodePtr(rostring type)
+{ return getTreeNodePtrKind(type) == TKN_SUBCLASS; }
+
+string extractNodeType(rostring type);
+string getSuperTypeOf(rostring sub);
+
+bool isListType(rostring type);
+bool isFakeListType(rostring type);
+bool isTreeListType(rostring type);
+string extractListType(rostring type);
+
+
+// dsw: I just need to know if the thing is an object or not
+bool isPtrKind(rostring type)
+{
+  return type[strlen(type)-1] == '*';
+}
+
+
+TreeNodeKind getTreeNodePtrKind(rostring type)
+{
+  if (isPtrKind(type)) {
+    // is pointer type; get base type; dsw: FIX: I think this is
+    // wrong; you might want to consider the same replacement in other
+    // places where trimWhitespace() is used.
+//      string base = trimWhitespace(substring(type, strlen(type)-1));
+    string base = firstAlphanumToken(substring(type, strlen(type)-1));
+
+    return getTreeNodeKind(base);
+  }
+
+  // not a pointer type
+  return TKN_NONE;
+}
+
+
+TreeNodeKind getTreeNodeKind(rostring base)
+{
+  // search among defined classes for this name
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    if (c->super->name.equals(base)) {
+      // found it in a superclass
+      return TKN_SUPERCLASS;
+    }
+
+    // check the subclasses
+    FOREACH_ASTLIST(ASTClass, c->ctors, ctor) {
+      if (ctor.data()->name.equals(base)) {
+        // found it in a subclass
+        return TKN_SUBCLASS;
+      }
+    }
+  }
+
+  return TKN_NONE;
+}
+
+
+string getSuperTypeOf(rostring sub)
+{
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    // look among the subclasses
+    FOREACH_ASTLIST(ASTClass, c->ctors, ctor) {
+      if (ctor.data()->name.equals(sub)) {
+        // found it
+        return c->super->name;
+      }
+    }
+  }
+
+  xfailure("getSuperTypeOf: invalid subclass name");
+  return "";    // silence warning
+}
+
+
+// get just the first alphanumeric word
+string extractNodeType(rostring type)
+{
+  char const *end = toCStr(type);
+  while (isalnum(*end) || *end=='_') {
+    end++;
+  }
+  return substring(type, end-toCStr(type));
+}
+
+
+// is this type a use of my ASTList template?
+bool isListType(rostring type)
+{
+  // do a fairly coarse analysis.. (the space before "<" is
+  // there because the type string is actually parsed by the
+  // grammar, and as it assembles it back into a string it
+  // inserts a space after every name-like token)
+  return prefixEquals(type, "ASTList <");
+}
+
+// similar for FakeList
+bool isFakeListType(rostring type)
+{
+  return prefixEquals(type, "FakeList <");
+}
+
+// is it a list type, with the elements being tree nodes?
+bool isTreeListType(rostring type)
+{
+  return isListType(type) && isTreeNode(extractListType(type));
+}
+
+// given a type for which 'is[Fake]ListType' returns true, extract
+// the type in the template argument angle brackets; this is used
+// to get the name of the type so we can pass it to the macros
+// which print list contents
+string extractListType(rostring type)
+{
+  xassert(isListType(type) || isFakeListType(type));
+  char const *langle = strchr(toCStr(type), '<');
+  char const *rangle = strchr(toCStr(type), '>');
+  xassert(langle && rangle);
+  return trimWhitespace(substring(langle+1, rangle-langle-1));
+}
+
+
+// given a string that comes from a user's declaration of a field
+// of a class, extract the type and the name; this assumes that,
+// syntactically, they separate cleanly (without the name in the
+// middle of the type syntax)
+void parseFieldDecl(string &type, string &name, const char *decl)
+{
+  // it's not trivial to extract the name of the field from
+  // its declaration.. so let's use a simple heuristic: it's
+  // probably the last sequence of non-whitespace alphanum chars
+  StrtokParse tok(decl, " \t*()[]<>,");
+
+  // now, find the offset of the start of the last token
+  int ofs = tok.offset(tok.tokc()-1);
+
+  // extract the parts
+  type = trimWhitespace(substring(decl, ofs));
+  name = trimWhitespace(decl+ofs);
+}
+
+string extractFieldType(rostring decl)
+{
+  string t, n;
+  parseFieldDecl(t, n, decl.c_str());
+  return t;
+}
+
+string extractFieldName(rostring decl)
+{
+  string t, n;
+  parseFieldDecl(t, n, decl.c_str());
+  return n;
+}
+
+
+// I scatter this throughout the generated code as pervasive
+// reminders that these files shouldn't be edited -- I often
+// accidentally edit them and then have to backtrack and reapply
+// the changes to where they were supposed to go ..
+void Gen::doNotEdit()
+{
+  out << "// *** DO NOT EDIT ***\n";
+}
+
+
+void Gen::headerComments()
+{
+  out << "// " << sm_basename(destFname) << "\n";
+  doNotEdit();
+  out << "// generated automatically by astgen, from " << sm_basename(srcFname) << "\n";
+
+  if (modules.count()) {
+    out << "// active extension modules:";
+    FOREACH_OBJLIST(string, modules, iter) {
+      out << " " << *(iter.data());
+    }
+    out << "\n";
+  }
+
+  // the inclusion of the date introduces gratuitous changes when the
+  // tool is re-run for whatever reason
+  //out << "//   on " << localTimeString() << "\n";
+
+  out << "\n";
+}
+
+
+void Gen::emitFiltered(ASTList<Annotation> const &decls, AccessCtl mode,
+                       rostring indent)
+{
+  FOREACH_ASTLIST(Annotation, decls, iter) {
+    if (iter.data()->kind() == Annotation::USERDECL) {
+      UserDecl const &decl = *( iter.data()->asUserDeclC() );
+      if (decl.access() == mode) {
+        out << indent << decl.code << ";\n";
+      }
+    }
+  }
+}
+
+
+// ------------------ generation of the header -----------------------
+// translation-wide state
+class HGen : public Gen {
+private:        // funcs
+  void emitVerbatim(TF_verbatim const &v);
+  void emitTFClass(TF_class const &cls);
+  void emitBaseClassDecls(ASTClass const &cls, int ct);
+  static char const *virtualIfChildren(TF_class const &cls);
+  void emitCtorFields(ASTList<CtorArg> const &args,
+                      ASTList<CtorArg> const &lastArgs);
+  void innerEmitCtorFields(ASTList<CtorArg> const &args);
+  void emitCtorFormal(int &ct, CtorArg const *arg);
+  void emitCtorFormals(int &ct, ASTList<CtorArg> const &args);
+  void emitCtorDefn(ASTClass const &cls, ASTClass const *parent);
+  void passParentCtorArgs(int &ct, ASTList<CtorArg> const &args);
+  void initializeMyCtorArgs(int &ct, ASTList<CtorArg> const &args);
+  void emitCommonFuncs(rostring virt);
+  void emitUserDecls(ASTList<Annotation> const &decls);
+  void emitCtor(ASTClass const &ctor, ASTClass const &parent);
+
+  void emitVisitorInterfacePrelude(rostring visitorName);
+  void emitVisitorInterface();
+  void emitDVisitorInterface();
+  void emitXmlVisitorInterface();
+  void emitMVisitorInterface();
+
+public:         // funcs
+  HGen(rostring srcFname, ObjList<string> const &modules,
+       rostring destFname, ASTSpecFile const &file)
+    : Gen(srcFname, modules, destFname, file)
+  {}
+  void emitFile();
+};
+
+
+// emit header code for an entire AST spec file
+void HGen::emitFile()
+{
+  string includeLatch = translate(sm_basename(destFname), "a-z.", "A-Z_");
+
+  headerComments();
+
+  out << "#ifndef " << includeLatch << "\n";
+  out << "#define " << includeLatch << "\n";
+  out << "\n";
+  out << "#include \"asthelp.h\"        // helpers for generated code\n";
+  if (wantDVisitor()) {
+    out << "#include \"sobjset.h\"        // SObjSet\n";
+  }
+  out << "\n";
+
+  // forward-declare all the classes
+  out << "// fwd decls\n";
+  FOREACH_ASTLIST(ToplevelForm, file.forms, form) {
+    TF_class const *c = form.data()->ifTF_classC();
+    if (c) {
+      out << "class " << c->super->name << ";\n";
+
+      FOREACH_ASTLIST(ASTClass, c->ctors, ctor) {
+        out << "class " << ctor.data()->name << ";\n";
+      }
+    }
+  }
+  out << "\n\n";
+
+  if (wantVisitor()) {
+    out << "// visitor interface class\n"
+        << "class " << visitorName << ";\n\n";
+  }
+  if (wantDVisitor()) {
+    // dsw: this seems necessary and here seems as good a place as any
+    // to do it
+    if (!wantVisitor()) {
+      xfatal("If you specify the 'dvisitor' option, you must also specify the 'visitor' option");
+    }
+    out << "// delegator-visitor interface class\n"
+        << "class " << dvisitorName << ";\n\n";
+  }
+  if (wantXmlVisitor()) {
+    // dsw: this seems necessary and here seems as good a place as any
+    // to do it
+    if (!wantVisitor()) {
+      xfatal("If you specify the 'xmlVisitor' option, you must also specify the 'visitor' option");
+    }
+    out << "// xml-visitor interface class\n"
+        << "class " << xmlVisitorName << ";\n\n";
+  }
+  if (wantMVisitor()) {
+    out << "class " << mvisitorName << ";\n\n";
+  }
+  if (wantIdentityManager()) {
+    out << "class " << identityManagerName << ";\n\n";
+  }
+
+  // do all the enums first; this became necessary when I had an
+  // enum in an extension, since the use of the enum ended up
+  // before the enum itself, due to the use being in a class that
+  // was defined in the base module
+  {
+    FOREACH_ASTLIST(ToplevelForm, file.forms, form) {
+      if (form.data()->isTF_enum()) {
+        TF_enum const *e = form.data()->asTF_enumC();
+        out << "enum " << e->name << " {\n";
+        FOREACH_ASTLIST(string, e->enumerators, iter) {
+          out << "  " << *(iter.data()) << ",\n";
+        }
+        out << "};\n"
+            << "\n"
+            << "char const *toString(" << e->name << ");\n"
+            ;
+
+        if (wantXmlParser()) {
+          out << "inline char const *toXml(" << e->name << " id)\n"
+              << "  { return toString(id); }\n"
+              << "void fromXml(" << e->name << " &out, rostring str);\n"
+              ;
+        }
+
+        out << "\n"
+            << "\n"
+            ;
+      }
+    }
+  }
+
+  // process each (non-enum) directive
+  FOREACH_ASTLIST(ToplevelForm, file.forms, form) {
+    switch (form.data()->kind()) {
+      case ToplevelForm::TF_VERBATIM:
+        emitVerbatim(*( form.data()->asTF_verbatimC() ));
+        break;
+
+      case ToplevelForm::TF_IMPL_VERBATIM:
+        // nop
+        break;
+
+      case ToplevelForm::TF_CLASS:
+        emitTFClass(*( form.data()->asTF_classC() ));
+        break;
+
+      default:
+        // ignore other toplevel forms (e.g. TF_option)
+        break;
+    }
+
+    out << "\n";
+  }
+
+  if (wantVisitor()) {
+    emitVisitorInterface();
+  }
+  if (wantDVisitor()) {
+    emitDVisitorInterface();
+  }
+  if (wantXmlVisitor()) {
+    emitXmlVisitorInterface();
+  }
+  if (wantMVisitor()) {
+    emitMVisitorInterface();
+  }
+
+  out << "#endif // " << includeLatch << "\n";
+}
+
+
+// emit a verbatim section
+void HGen::emitVerbatim(TF_verbatim const &v)
+{
+  doNotEdit();
+  out << v.code;
+}
+
+
+STATICDEF char const *HGen::virtualIfChildren(TF_class const &cls)
+{
+  if (cls.hasChildren()) {
+    // since this class has children, make certain functions virtual
+    return "virtual ";
+  }
+  else {
+    // no children, no need to introduce a vtable
+    return "";
+  }
+}
+
+
+// emit declaration for a class ("phylum")
+void HGen::emitTFClass(TF_class const &cls)
+{
+  doNotEdit();
+  out << "class " << cls.super->name;
+  emitBaseClassDecls(*(cls.super), 0 /*ct*/);
+  out << " {\n";
+
+  // the xml visitor needs to be able to see the internals of the
+  // classes
+  if (wantXmlVisitor()) {
+    out << "  friend class " << xmlVisitorName << ";\n";
+    out << "  friend class XmlAstReader;\n";
+  }
+
+  emitCtorFields(cls.super->args, cls.super->lastArgs);
+  emitCtorDefn(*(cls.super), NULL /*parent*/);
+
+  // destructor
+  char const *virt = virtualIfChildren(cls);
+  out << "  " << virt << "~" << cls.super->name << "();\n";
+  out << "\n";
+
+  // declare the child kind selector
+  if (cls.hasChildren()) {
+    out << "  enum Kind { ";
+    FOREACH_ASTLIST(ASTClass, cls.ctors, ctor) {
+      out << ctor.data()->classKindName() << ", ";
+    }
+    out << "NUM_KINDS };\n";
+
+    out << "  virtual Kind kind() const = 0;\n";
+    out << "\n";
+    out << "  static char const * const kindNames[NUM_KINDS];\n";
+    out << "  char const *kindName() const { return kindNames[kind()]; }\n";
+    out << "\n";
+  }
+  else {
+    // even if the phylum doesn't have children, it's nice to be able
+    // to ask an AST node for its name (e.g. in templatized code that
+    // deals with arbitrary AST node types), so define the
+    // 'kindName()' method anyway
+    out << "  char const *kindName() const { return \"" << cls.super->name << "\"; }\n";
+  }
+
+  // declare checked downcast functions
+  {
+    FOREACH_ASTLIST(ASTClass, cls.ctors, ctor) {
+      // declare the const downcast
+      ASTClass const &c = *(ctor.data());
+      out << "  DECL_AST_DOWNCASTS(" << c.name << ", " << c.classKindName() << ")\n";
+    }
+    out << "\n";
+  }
+
+  // declare clone function
+  if (cls.hasChildren()) {
+    if (!nocvr) {
+      // normal case
+      out << "  virtual " << cls.super->name << "* clone() const=0;\n";
+    }
+    else {
+      // msvc hack case
+      out << "  virtual " << cls.super->name << "* nocvr_clone() const=0;\n";
+      out << "  " << cls.super->name << "* clone() const { return nocvr_clone(); }\n";
+    }
+  }
+  else {
+    // not pure or virtual
+    out << "  " << cls.super->name << " *clone() const;\n";
+  }
+  out << "\n";
+
+  emitCommonFuncs(virt);
+
+  if (wantGDB) {
+    out << "  void gdb() const;\n\n";
+  }
+
+  emitUserDecls(cls.super->decls);
+
+  // close the declaration of the parent class
+  out << "};\n";
+  out << "\n";
+
+  // print declarations for all child classes
+  {
+    FOREACH_ASTLIST(ASTClass, cls.ctors, ctor) {
+      emitCtor(*(ctor.data()), *(cls.super));
+    }
+  }
+
+  out << "\n";
+}
+
+
+void HGen::emitBaseClassDecls(ASTClass const &cls, int ct)
+{
+  FOREACH_ASTLIST(BaseClass, cls.bases, iter) {
+    out << ((ct++ > 0)? ", " : " : ")
+        << toString(iter.data()->access) << " "
+        << iter.data()->name
+        ;
+  }
+}
+
+
+// emit data fields implied by the constructor
+void HGen::emitCtorFields(ASTList<CtorArg> const &args,
+                          ASTList<CtorArg> const &lastArgs)
+{
+  out << "public:      // data\n";
+  innerEmitCtorFields(args);
+  innerEmitCtorFields(lastArgs);
+  out << "\n";
+}
+
+void HGen::innerEmitCtorFields(ASTList<CtorArg> const &args)
+{
+  // go over the arguments in the ctor and declare fields for them
+  {
+    FOREACH_ASTLIST(CtorArg, args, arg) {
+      char const *star = "";
+      if (isTreeNode(arg.data()->type)) {
+        // make it a pointer in the concrete representation
+        star = "*";
+      }
+
+      out << "  " << arg.data()->type << " " << star << arg.data()->name << ";\n";
+    }
+  }
+}
+
+
+// emit the declaration of a formal argument to a constructor
+void HGen::emitCtorFormal(int &ct, CtorArg const *arg)
+{
+  // put commas between formals
+  if (ct++ > 0) {
+    out << ", ";
+  }
+
+  string const &type = arg->type;
+  out << type << " ";
+  if (isListType(type) ||
+      isTreeNode(type) ||
+      type.equals("LocString")) {
+    // lists and subtrees and LocStrings are constructed by passing pointers
+    trace("putStar") << "putting star for " << type << endl;
+    out << "*";
+  }
+  else {
+    trace("putStar") << "NOT putting star for " << type << endl;
+  }
+
+  out << "_" << arg->name;      // prepend underscore to param's name
+
+  // emit default value, if any
+  if (! arg->defaultValue.empty()) {
+    out << " = " << arg->defaultValue;
+  }
+}
+
+void HGen::emitCtorFormals(int &ct, ASTList<CtorArg> const &args)
+{
+  FOREACH_ASTLIST(CtorArg, args, arg) {
+    emitCtorFormal(ct, arg.data());
+  }
+}
+
+
+// true if 'ud' seems to declare a function, as opposed to data
+bool isFuncDecl(UserDecl const *ud)
+{
+  return ud->amod->hasMod("virtual") ||
+         ud->amod->hasMod("func");
+}
+
+// emit the definition of the constructor itself
+void HGen::emitCtorDefn(ASTClass const &cls, ASTClass const *parent)
+{
+  // declare the constructor
+  {
+    out << "public:      // funcs\n";
+    out << "  " << cls.name << "(";
+
+    // list of formal parameters to the constructor
+    {
+      int ct = 0;
+      if (parent) {
+        emitCtorFormals(ct, parent->args);
+      }
+      emitCtorFormals(ct, cls.args);
+      emitCtorFormals(ct, cls.lastArgs);
+      if (parent) {
+        emitCtorFormals(ct, parent->lastArgs);
+      }
+    }
+    out << ")";
+
+    // pass args to superclass, and initialize fields
+    {
+      int ct = 0;
+
+      if (parent) {
+        out << " : " << parent->name << "(";
+        passParentCtorArgs(ct, parent->args);
+        passParentCtorArgs(ct, parent->lastArgs);
+        ct++;     // make sure we print a comma, below
+        out << ")";
+      }
+
+      initializeMyCtorArgs(ct, cls.args);
+      initializeMyCtorArgs(ct, cls.lastArgs);
+
+      // initialize fields that have initializers
+      FOREACH_ASTLIST(Annotation, cls.decls, ann) {
+        if (!ann.data()->isUserDecl()) continue;
+        UserDecl const *ud = ann.data()->asUserDeclC();
+        if (ud->init.empty()) continue;
+        if (isFuncDecl(ud)) continue;       // don't do this for functions!
+
+        if (ct++ > 0) {
+          out << ", ";
+        }
+        else {
+          out << " : ";
+        }
+
+        out << extractFieldName(ud->code) << "(" << ud->init << ")";
+      }
+    }
+
+    // insert user's ctor code
+    out << " {\n";
+    emitFiltered(cls.decls, AC_CTOR, "    ");
+    out << "  }\n";
+  }
+}
+
+void HGen::passParentCtorArgs(int &ct, ASTList<CtorArg> const &args)
+{
+  FOREACH_ASTLIST(CtorArg, args, parg) {
+    if (ct++ > 0) {
+      out << ", ";
+    }
+    // pass the formal arg to the parent ctor
+    out << "_" << parg.data()->name;
+  }
+}
+
+void HGen::initializeMyCtorArgs(int &ct, ASTList<CtorArg> const &args)
+{
+  FOREACH_ASTLIST(CtorArg, args, arg) {
+    if (ct++ > 0) {
+      out << ", ";
+    }
+    else {
+      out << " : ";    // only used when 'parent' is NULL
+    }
+
+    // initialize the field with the formal argument
+    out << arg.data()->name << "(_" << arg.data()->name << ")";
+  }
+}
+
+// emit functions that are declared in every tree node
+void HGen::emitCommonFuncs(rostring virt)
+{
+  // declare the functions they all have
+  out << "  " << virt
+      << "void debugPrint(ostream &os, int indent, char const *subtreeName = \"tree\") const;\n";
+
+  if (wantVisitor()) {
+    // visitor traversal entry point
+    out << "  " << virt << "void traverse(" << visitorName << " &vis);\n";
+  }
+
+  out << "\n";
+}
+
+// emit user-supplied declarations
+void HGen::emitUserDecls(ASTList<Annotation> const &decls)
+{
+  FOREACH_ASTLIST(Annotation, decls, iter) {
+    // in the header, we only look at userdecl annotations
+    if (iter.data()->kind() == Annotation::USERDECL) {
+      UserDecl const &decl = *( iter.data()->asUserDeclC() );
+      if (decl.access() == AC_PUBLIC ||
+          decl.access() == AC_PRIVATE ||
+          decl.access() == AC_PROTECTED) {
+        out << "  " << toString(decl.access()) << ": ";
+
+        if (decl.amod->hasMod("virtual")) {
+          out << "virtual ";
+        }
+        out << decl.code;
+
+        if (isFuncDecl(&decl) && !decl.init.empty()) {
+          out << " = " << decl.init;     // the "=0" of a pure virtual function
+        }
+        out << ";";
+
+        // emit field flags as comments, to help debug astgen
+        if (decl.amod->mods.count()) {
+          out << "   //";
+          FOREACH_ASTLIST(string, decl.amod->mods, mod) {
+            out << " " << *(mod.data());
+          }
+        }
+        out << "\n";
+      }
+      if (decl.access() == AC_PUREVIRT) {
+        // this is the parent class: declare it pure virtual
+        out << "  public: virtual " << decl.code << "=0;\n";
+      }
+    }
+  }
+}
+
+// emit declaration for a specific class instance constructor
+void HGen::emitCtor(ASTClass const &ctor, ASTClass const &parent)
+{
+  out << "class " << ctor.name << " : public " << parent.name;
+  emitBaseClassDecls(ctor, 1 /*ct*/);
+  out << " {\n";
+
+  emitCtorFields(ctor.args, ctor.lastArgs);
+  emitCtorDefn(ctor, &parent);
+
+  // destructor
+  out << "  virtual ~" << ctor.name << "();\n";
+  out << "\n";
+
+  // type tag
+  out << "  virtual Kind kind() const { return " << ctor.classKindName() << "; }\n";
+  out << "  enum { TYPE_TAG = " << ctor.classKindName() << " };\n";
+  out << "\n";
+
+  // common functions
+  emitCommonFuncs("virtual ");
+
+  // clone function (take advantage of covariant return types)
+  if (!nocvr) {
+    // normal case
+    out << "  virtual " << ctor.name << " *clone() const;\n";
+  }
+  else {
+    // msvc hack case
+    out << "  virtual " << parent.name << "* nocvr_clone() const;\n";
+    out << "  " << ctor.name << "* clone() const\n"
+        << "    { return static_cast<" << ctor.name << "*>(nocvr_clone()); }\n";
+  }
+
+  out << "\n";
+  emitUserDecls(ctor.decls);
+
+  // emit implementation declarations for parent's pure virtuals
+  FOREACH_ASTLIST(Annotation, parent.decls, iter) {
+    UserDecl const *decl = iter.data()->ifUserDeclC();
+    if (!decl) continue;
+
+    if (decl->access() == AC_PUREVIRT) {
+      out << "  public: virtual " << decl->code << ";\n";
+    }
+    else if (decl->amod->hasMod("virtual")) {
+      out << "  " << toString(decl->access())
+          << ": virtual " << decl->code << ";\n";
+    }
+  }
+
+  // close the decl
+  out << "};\n";
+  out << "\n";
+}
+
+
+// --------------------- generation of C++ code file --------------------------
+class CGen : public Gen {
+public:
+  string hdrFname;      // name of associated .h file
+
+public:
+  CGen(rostring srcFname, ObjList<string> const &modules,
+       rostring destFname, ASTSpecFile const &file,
+       rostring hdr)
+    : Gen(srcFname, modules, destFname, file),
+      hdrFname(hdr)
+  {}
+
+  void emitFile();
+  void emitTFClass(TF_class const &cls);
+  void emitDestructor(ASTClass const &cls);
+  void emitDestroyField(bool isOwner, rostring type, rostring name);
+  void emitPrintCtorArgs(ASTList<CtorArg> const &args);
+  void emitPrintFields(ASTList<Annotation> const &decls);
+  void emitPrintField(rostring print,
+                      bool isOwner, rostring type, rostring name);
+
+  bool emitCustomCode(ASTList<Annotation> const &list, rostring tag);
+
+  void emitCloneCtorArg(CtorArg const *arg, int &ct);
+  void emitCloneCtorArgs(int &ct, ASTList<CtorArg> const &args);
+  void emitCloneCode(ASTClass const *super, ASTClass const *sub);
+
+  void emitVisitorImplementation();
+
+  private:
+  void emitDVisitorImplVisitedCheck(char const *name);
+  public:
+  void emitDVisitorImplementation();
+
+  private:
+  void emitXmlCtorArgs(ASTList<CtorArg> const &args, char const *baseName, string const &className);
+  void emitXmlFields(ASTList<Annotation> const &decls, char const *baseName, string const &className);
+  void emitXmlField(rostring type, rostring name, char const *baseName,
+                    string const &className, AccessMod *amod);
+  void emitXmlVisitorImplVisitedCheck(char const *name);
+  public:
+  void emitXmlVisitorImplementation();
+
+  void emitTraverse(ASTClass const *c, ASTClass const * /*nullable*/ super,
+                    bool hasChildren);
+  private:
+  void emitOneTraverseCall(rostring className, string name, string type);
+
+  public:
+  void emitMVisitorImplementation();
+  void emitMTraverse(ASTClass const *c, rostring obj, rostring ident);
+  void emitMTraverseCall(rostring i, rostring eltType, rostring argVar);
+};
+
+
+// generation of xml parser
+class XmlParserGen {
+  StringSet attributeNames;     // names of attributes of AST nodes
+
+  ofstreamTS tokensOut;
+  ofstreamTS parser0_decls;
+  ofstreamTS parser1_defs;
+  ofstreamTS parser2_ctorCalls;
+  ofstreamTS parser3_registerCalls;
+
+  public:
+  XmlParserGen(string &xmlParserName)
+    : tokensOut(stringc << xmlParserName << "_ast.gen.tokens")
+    , parser0_decls(stringc << xmlParserName << "_ast_reader_0decl.gen.h")
+    , parser1_defs (stringc << xmlParserName << "_ast_reader_1defn.gen.cc")
+    , parser2_ctorCalls    (stringc << xmlParserName << "_ast_reader_2ctrc.gen.cc")
+    , parser3_registerCalls(stringc << xmlParserName << "_ast_reader_3regc.gen.cc")
+  {}
+
+  private:
+  void collectXmlParserCtorArgs(ASTList<CtorArg> const &args, char const *baseName);
+  void collectXmlParserFields(ASTList<Annotation> const &decls, char const *baseName);
+  void collectXmlParserField
+    (rostring type, rostring name, char const *baseName, AccessMod *amod);
+
+  void emitXmlCtorArgs_AttributeParseRule(ASTList<CtorArg> const &args, string &baseName);
+  void emitXmlFields_AttributeParseRule(ASTList<Annotation> const &decls, string &baseName);
+  void emitXmlField_AttributeParseRule
+    (rostring type, rostring name, string &baseName, AccessMod *amod);
+
+  void emitXmlParser_objCtorArgs
+    (ASTList<CtorArg> const &args, bool &firstTime);
+
+  void emitXmlParser_Node
+    (ASTClass const *clazz,
+     ASTList<CtorArg> const *args,
+     ASTList<Annotation> const *decls,
+     ASTList<CtorArg> const *lastArgs,
+     ASTList<CtorArg> const *childArgs = NULL,
+     ASTList<Annotation> const *childDecls = NULL);
+  void emitXmlParser_Node_registerAttr
+    (ASTClass const *clazz,
+     ASTList<CtorArg> const *args,
+     ASTList<Annotation> const *decls,
+     ASTList<CtorArg> const *lastArgs,
+     ASTList<CtorArg> const *childArgs = NULL,
+     ASTList<Annotation> const *childDecls = NULL);
+  void emitXmlParser_ASTList(ListClass const *type);
+  void emitXmlParser_FakeList(ListClass const *type);
+
+  public:
+  void emitXmlParserImplementation();
+};
+
+
+void CGen::emitFile()
+{
+  headerComments();
+
+  out << "#include \"" << hdrFname << "\"      // this module\n";
+  if (wantXmlVisitor()) {
+    out << "#include \"xmlhelp.h\"      // to/fromXml_bool/int\n";
+  }
+  if (wantXmlParser()) {
+    out << "#include <string.h>       // strcmp\n";
+    out << "#include \"exc.h\"          // xformat\n";
+  }
+  out << "\n";
+  out << "\n";
+
+  FOREACH_ASTLIST(ToplevelForm, file.forms, form) {
+    ASTSWITCHC(ToplevelForm, form.data()) {
+      //ASTCASEC(TF_verbatim, v) {
+      //  // nop
+      //}
+      ASTCASEC(TF_impl_verbatim, v) {
+        doNotEdit();
+        out << v->code;
+      }
+      ASTNEXTC(TF_class, c) {
+        emitTFClass(*c);
+      }
+      ASTNEXTC(TF_enum, e) {
+        int numEnumeratorValues = 0;
+        out << "char const *toString(" << e->name << " x)\n"
+            << "{\n"
+            << "  static char const * const map[] = {\n";
+        FOREACH_ASTLIST(string, e->enumerators, iter) {
+          out << "    \"" << *(iter.data()) << "\",\n";
+          numEnumeratorValues++;
+        }
+        out << "  };\n"
+            << "  xassert((unsigned)x < TABLESIZE(map));\n"
+            << "  return map[x];\n"
+            << "};\n"
+            << "\n"
+            ;
+
+        // sm: I'm emitting this into the normal .gen.cc file, rather
+        // than the specialized XML generation files, because I do not
+        // understand how the latter are structured (and, the code I
+        // am replacing had this effect anyway)
+        if (wantXmlParser()) {
+          // toXml is inline, no need to generate anything
+
+          // fromXml
+          out << "void fromXml(" << e->name << " &out, rostring str)\n"
+              << "{\n"
+              << "  for (int i=0; i<" << numEnumeratorValues << "; i++) {\n"
+              << "    " << e->name << " e = (" << e->name << ")i;\n"
+              << "    if (0==strcmp(str, toString(e))) {\n"
+              << "      out = e;\n"
+              << "      return;\n"
+              << "    }\n"
+              << "  }\n"
+              << "  xformat(stringc << \"bad " << e->name << " value: \" << str);\n"
+              << "}\n"
+              << "\n"
+              ;
+        }
+
+        out << "\n";
+        break;
+      }
+      ASTENDCASECD
+    }
+  }
+  out << "\n\n";
+
+  if (wantVisitor()) {
+    emitVisitorImplementation();
+  }
+  if (wantDVisitor()) {
+    emitDVisitorImplementation();
+  }
+  if (wantXmlVisitor()) {
+    emitXmlVisitorImplementation();
+  }
+  if (wantMVisitor()) {
+    emitMVisitorImplementation();
+  }
+}
+
+
+void CGen::emitTFClass(TF_class const &cls)
+{
+  out << "// ------------------ " << cls.super->name << " -------------------\n";
+  doNotEdit();
+
+  // class destructor
+  emitDestructor(*(cls.super));
+
+  // kind name map
+  if (cls.hasChildren()) {
+    out << "char const * const " << cls.super->name << "::kindNames["
+        <<   cls.super->name << "::NUM_KINDS] = {\n";
+    FOREACH_ASTLIST(ASTClass, cls.ctors, ctor) {
+      out << "  \"" << ctor.data()->name << "\",\n";
+    }
+    out << "};\n";
+    out << "\n";
+  }
+
+
+  // debugPrint
+  out << "void " << cls.super->name << "::debugPrint(ostream &os, int indent, char const *subtreeName) const\n";
+  out << "{\n";
+  if (!cls.hasChildren()) {
+    // childless superclasses get the preempt in the superclass;
+    // otherwise it goes into the child classes
+    emitCustomCode(cls.super->decls, "preemptDebugPrint");
+
+    // childless superclasses print headers; otherwise the subclass
+    // prints the header
+    out << "  PRINT_HEADER(subtreeName, " << cls.super->name << ");\n";
+    out << "\n";
+  }
+
+  // 10/31/01: decided I wanted custom debug print first, since it's
+  // often much shorter (and more important) than the subtrees
+  emitCustomCode(cls.super->decls, "debugPrint");
+  emitPrintCtorArgs(cls.super->args);
+  if (cls.super->lastArgs.isNotEmpty()) {
+    out << "  // (lastArgs are printed by subclasses)\n";
+  }
+  emitPrintFields(cls.super->decls);
+
+  out << "}\n";
+  out << "\n";
+
+  // gdb()
+  if (wantGDB) {
+    out << "void " << cls.super->name << "::gdb() const\n"
+        << "  { debugPrint(cout, 0); }\n"
+        << "\n"
+        ;
+  }
+
+  // clone for childless superclasses
+  if (!cls.hasChildren()) {
+    emitCloneCode(cls.super, NULL /*sub*/);
+  }
+
+
+  // constructors (class hierarchy children)
+  FOREACH_ASTLIST(ASTClass, cls.ctors, ctoriter) {
+    ASTClass const &ctor = *(ctoriter.data());
+
+    // downcast function
+    out << "DEFN_AST_DOWNCASTS(" << cls.super->name << ", "
+                                 << ctor.name << ", "
+                                 << ctor.classKindName() << ")\n";
+    out << "\n";
+
+    // subclass destructor
+    emitDestructor(ctor);
+
+    // subclass debugPrint
+    out << "void " << ctor.name << "::debugPrint(ostream &os, int indent, char const *subtreeName) const\n";
+    out << "{\n";
+
+    // the debug print preempter is declared in the outer "class",
+    // but inserted into the print methods of the inner "constructors"
+    emitCustomCode(cls.super->decls, "preemptDebugPrint");
+
+    // do same if it's declared only in the subclass
+    emitCustomCode(ctor.decls, "preemptDebugPrint");
+
+    out << "  PRINT_HEADER(subtreeName, " << ctor.name << ");\n";
+    out << "\n";
+
+    // call the superclass's fn to get its data members
+    out << "  " << cls.super->name << "::debugPrint(os, indent, subtreeName);\n";
+    out << "\n";
+
+    emitCustomCode(ctor.decls, "debugPrint");
+    emitPrintCtorArgs(ctor.args);
+    emitPrintFields(ctor.decls);
+
+    // superclass 'last' args come after all subclass things
+    emitPrintCtorArgs(cls.super->lastArgs);
+
+    out << "}\n";
+    out << "\n";
+
+    // clone for subclasses
+    emitCloneCode(cls.super, &ctor);
+  }
+
+  out << "\n";
+}
+
+
+bool CGen::emitCustomCode(ASTList<Annotation> const &list, rostring tag)
+{
+  bool emitted = false;
+
+  FOREACH_ASTLIST(Annotation, list, iter) {
+    CustomCode const *cc = iter.data()->ifCustomCodeC();
+    if (cc && cc->qualifier.equals(tag)) {
+      out << "  " << cc->code << ";\n";
+      emitted = true;
+
+      // conceptually mutable..
+      const_cast<bool&>(cc->used) = true;
+    }
+  }
+
+  return emitted;
+}
+
+
+void CGen::emitDestructor(ASTClass const &cls)
+{
+  out << cls.name << "::~" << cls.name << "()\n";
+  out << "{\n";
+
+  // user's code first
+  emitFiltered(cls.decls, AC_DTOR, "  ");
+
+  // constructor arguments
+  FOREACH_ASTLIST(CtorArg, cls.args, argiter) {
+    CtorArg const &arg = *(argiter.data());
+    emitDestroyField(arg.isOwner, arg.type, arg.name);
+  }
+
+  // owner fields
+  FOREACH_ASTLIST(Annotation, cls.decls, iter) {
+    if (!iter.data()->isUserDecl()) continue;
+    UserDecl const *ud = iter.data()->asUserDeclC();
+    if (!ud->amod->hasMod("owner")) continue;
+
+    emitDestroyField(true /*isOwner*/,
+                     extractFieldType(ud->code),
+                     extractFieldName(ud->code));
+  }
+
+  out << "}\n";
+  out << "\n";
+}
+
+void CGen::emitDestroyField(bool isOwner, rostring type, rostring name)
+{
+  if (isTreeListType(type)) {
+    // explicitly destroy list elements, because it's easy to do, and
+    // because if there is a problem, it's much easier to see its
+    // role in a debugger backtrace
+    out << "  " << name << ".deleteAll();\n";
+  }
+  else if (isListType(type)) {
+    if (streq(extractListType(type), "LocString")) {
+      // these are owned even though they aren't actually tree nodes
+      out << "  " << name << ".deleteAll();\n";
+
+      // TODO: this analysis is duplicated below, during cloning;
+      // the astgen tool should do a better job of encapsulating
+      // the relationships (particularly owning/non-owning) between
+      // its parts, instead of doing ad-hoc type inspection in random
+      // places during emission
+    }
+    else {
+      // we don't own the list elements; it's *essential* to
+      // explicitly remove the elements; this is a hack, since the
+      // ideal solution is to make a variant of ASTList which is
+      // explicitly serf pointers.. the real ASTList doesn't have
+      // a removeAll method (since it's an owner list), and rather
+      // than corrupting that interface I'll emit the code each time..
+      out << "  while (" << name << ".isNotEmpty()) {\n"
+          << "    " << name << ".removeFirst();\n"
+          << "  }\n";
+      //out << "  " << name << ".removeAll();\n";
+    }
+  }
+  else if (isOwner || isTreeNode(type)) {
+    out << "  delete " << name << ";\n";
+  }
+}
+
+
+void CGen::emitPrintCtorArgs(ASTList<CtorArg> const &args)
+{
+  FOREACH_ASTLIST(CtorArg, args, argiter) {
+    CtorArg const &arg = *(argiter.data());
+
+    emitPrintField("PRINT", arg.isOwner, arg.type, arg.name);
+  }
+}
+
+void CGen::emitPrintFields(ASTList<Annotation> const &decls)
+{
+  FOREACH_ASTLIST(Annotation, decls, iter) {
+    if (!iter.data()->isUserDecl()) continue;
+    UserDecl const *ud = iter.data()->asUserDeclC();
+    if (!ud->amod->hasMod("field")) continue;
+
+    emitPrintField("PRINT",
+                   ud->amod->hasMod("owner"),
+                   extractFieldType(ud->code),
+                   extractFieldName(ud->code));
+  }
+}
+
+void CGen::emitPrintField(rostring print,
+                          bool isOwner, rostring type, rostring name)
+{
+  if (streq(type, "string")) {
+    out << "  " << print << "_STRING(" << name << ");\n";
+  }
+  else if (streq(type, "StringRef")) {
+    out << "  " << print << "_CSTRING(" << name << ");\n";
+  }
+  else if (streq(type, "bool")) {
+    out << "  " << print << "_BOOL(" << name << ");\n";
+  }
+  else if (isListType(type)) {
+    // for now, I'll continue to assume that any class that appears
+    // in ASTList<> is compatible with the printing regime here
+    out << "  " << print << "_LIST(" << extractListType(type) << ", "
+        << name << ");\n";
+  }
+  else if (isFakeListType(type)) {
+    // similar printing approach for FakeLists
+    out << "  " << print << "_FAKE_LIST(" << extractListType(type) << ", "
+        << name << ");\n";
+  }
+  else if (isTreeNode(type) ||
+           (isTreeNodePtr(type) && isOwner)) {
+    // don't print subtrees that are possibly shared or circular
+    out << "  " << print << "_SUBTREE(" << name << ");\n";
+  }
+  else {
+    // catch-all ..
+    out << "  " << print << "_GENERIC(" << name << ");\n";
+  }
+}
+
+
+void CGen::emitCloneCtorArg(CtorArg const *arg, int &ct)
+{
+  if (ct++ > 0) {
+    out << ",";
+  }
+  out << "\n    ";
+
+  string argName = arg->name;
+  if (argName == "ret") {
+    // avoid clash with local variable name
+    argName = "this->ret";
+
+    // NOTE: I do not simply want to make the local variable name
+    // something ugly like __astgen_ret because in the user-defined
+    // clone() augmentation functions, the user is supposed to be
+    // able to use 'ret' to refer to the tree constructed so far.
+  }
+
+  if (isTreeListType(arg->type)) {
+    // clone an ASTList of tree nodes
+    out << "cloneASTList(" << argName << ")";
+  }
+  else if (isListType(arg->type)) {
+    if (streq(extractListType(arg->type), "LocString")) {
+      // these are owned, so clone deeply
+      out << "cloneASTList(" << argName << ")";
+    }
+    else {
+      // clone an ASTList of non-tree nodes
+      out << "shallowCloneASTList(" << argName << ")";
+    }
+  }
+  else if (isFakeListType(arg->type)) {
+    // clone a FakeList (of tree nodes, we assume..)
+    out << "cloneFakeList(" << argName << ")";
+  }
+  else if (isTreeNode(arg->type)) {
+    // clone a tree node
+    out << argName << "? " << argName << "->clone() : NULL";
+  }
+  else if (streq(arg->type, "LocString")) {
+    // clone a LocString; we store objects, but pass pointers
+    out << argName << ".clone()";
+  }
+  else {
+    // pass the non-tree node's value directly
+    out << argName;
+  }
+}
+
+void CGen::emitCloneCtorArgs(int &ct, ASTList<CtorArg> const &args)
+{
+  FOREACH_ASTLIST(CtorArg, args, iter) {
+    emitCloneCtorArg(iter.data(), ct);
+  }
+}
+
+
+void CGen::emitCloneCode(ASTClass const *super, ASTClass const *sub)
+{
+  ASTClass const *myClass = sub? sub : super;
+  string const &name = myClass->name;
+
+  if (!nocvr || !sub) {
+    // normal case, or childless superclass case
+    out << name << " *" << name << "::clone() const\n";
+  }
+  else {
+    // msvc hack case
+    out << super->name << " *" << name << "::nocvr_clone() const\n";
+  }
+  out << "{\n";
+
+  if (!emitCustomCode(myClass->decls, "substituteClone")) {
+    out << "  " << name << " *ret = new " << name << "(";
+
+    // clone each of the superclass ctor arguments
+    int ct=0;
+    emitCloneCtorArgs(ct, super->args);
+
+    // and likewise for the subclass ctor arguments
+    if (sub) {
+      emitCloneCtorArgs(ct, sub->args);
+      emitCloneCtorArgs(ct, sub->lastArgs);
+    }
+
+    emitCloneCtorArgs(ct, super->lastArgs);
+
+    out << "\n"
+        << "  );\n";
+
+    // custom clone code
+    emitCustomCode(super->decls, "clone");
+    if (sub) {
+      emitCustomCode(sub->decls, "clone");
+    }
+
+    out << "  return ret;\n";
+  }
+
+  out << "}\n"
+      << "\n";
+}
+
+
+// -------------------------- visitor ---------------------------
+void emitTF_custom(ofstream &out, rostring qualifierName, bool addNewline)
+{
+  FOREACH_ASTLIST_NC(ToplevelForm, wholeAST->forms, iter) {
+    if (iter.data()->isTF_custom()) {
+      CustomCode *cc = iter.data()->asTF_customC()->cust;
+      if (cc->qualifier == qualifierName) {
+        out << cc->code;
+        if (addNewline) {
+          out << "\n";
+        }
+        cc->used = true;
+      }
+    }
+  }
+}
+
+
+void HGen::emitVisitorInterfacePrelude(rostring visitorName)
+{
+  // custom additions to this visitor
+  emitTF_custom(out, visitorName, true /*addNewline*/);
+
+  out << "private:     // disallowed, not implemented\n"
+      << "  " << visitorName << "(" << visitorName << "&);\n"
+      << "  void operator= (" << visitorName << "&);\n"
+      << "\n"
+      << "public:      // funcs\n"
+      << "  " << visitorName << "() {"
+      ;
+
+  // custom additions to the visitor's constructor
+  emitTF_custom(out, stringc << visitorName << "_ctor", false /*addNewline*/);
+
+  out << "}\n"
+      << "  virtual ~" << visitorName << "();   // silence gcc warning...\n"
+      << "\n"
+      ;
+}
+
+void HGen::emitVisitorInterface()
+{
+  out << "// the visitor interface class\n"
+      << "class " << visitorName << " {\n";
+  emitVisitorInterfacePrelude(visitorName);
+
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    out << "  virtual bool visit" << c->super->name << "("
+        <<   c->super->name << " *obj);\n"
+        << "  virtual void postvisit" << c->super->name << "("
+        <<   c->super->name << " *obj);\n"
+        ;
+  }
+
+  out << "\n  // List 'classes'\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    out << "  virtual bool visitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">*);\n";
+    out << "  virtual void postvisitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">*);\n";
+  }
+
+  StringSet listItemClassesSet; // set of list item classes printed so far
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    xassert(!listItemClassesSet.contains(cls->classAndMemberName)); // should not repeat
+    listItemClassesSet.add(cls->classAndMemberName);
+    out << "  virtual bool visitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << "*);\n";
+    out << "  virtual void postvisitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << "*);\n";
+  }
+
+  out << "};\n\n";
+}
+
+
+void CGen::emitVisitorImplementation()
+{
+  out << "// ---------------------- " << visitorName << " ---------------------\n";
+  out << "// default no-op visitor\n";
+  out << visitorName << "::~" << visitorName << "() {}\n";
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    out << "bool " << visitorName << "::visit" << c->super->name << "("
+        <<   c->super->name << " *obj) { return true; }\n"
+        << "void " << visitorName << "::postvisit" << c->super->name << "("
+        <<   c->super->name << " *obj) {}\n";
+  }
+
+  out << "\n// List 'classes'\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    out << "bool " << visitorName << "::visitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">*) { return true; }\n";
+    out << "void " << visitorName << "::postvisitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">*) {}\n";
+  }
+
+  StringSet listItemClassesSet; // set of list item classes printed so far
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    xassert(!listItemClassesSet.contains(cls->classAndMemberName)); // should not repeat
+    listItemClassesSet.add(cls->classAndMemberName);
+    out << "bool " << visitorName << "::visitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << "*) { return true; }\n";
+    out << "void " << visitorName << "::postvisitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << "*) {}\n";
+  }
+
+  out << "\n\n";
+
+  // implementations of traversal functions
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    // superclass traversal
+    emitTraverse(c->super, NULL /*super*/, c->hasChildren());
+
+    // subclass traversal
+    FOREACH_ASTLIST(ASTClass, c->ctors, iter) {
+      ASTClass const *sub = iter.data();
+
+      emitTraverse(sub, c->super, false /*hasChildren*/);
+    }
+  }
+  out << "\n";
+}
+
+
+void CGen::emitOneTraverseCall(rostring className, string name, string type)
+{
+  if (isTreeNode(type) || isTreeNodePtr(type)) {
+    // traverse it directly
+//      cout << "emitOneTraverseCall, name:" << name << ", type: " << type << endl;
+    out << "  if (" << name << ") { " << name << "->traverse(vis); }\n";
+  }
+
+  else if ((isListType(type) || isFakeListType(type)) &&
+           isTreeNode(extractListType(type))) {
+    // list of tree nodes: iterate and traverse
+    string eltType = extractListType(type);
+
+    // could add an assertion here that the elt type is one of the
+    // list types extracted earlier during getListClasses()
+
+    // compute list accessor names
+    char const *iterMacroName = "FOREACH_ASTLIST_NC";
+    char const *iterElt = ".data()";
+    char const *argNamePrefix = "&";
+    if (isFakeListType(type)) {
+      iterMacroName = "FAKELIST_FOREACH_NC";
+      iterElt = "";
+      argNamePrefix = "";
+    }
+
+    // emit the pre-visit call to the fantasy "list class"
+    out << "  if (vis.visitList_" << className << "_" << name
+        << "(" << argNamePrefix << name << ")) {\n";
+    out << "    " << iterMacroName << "(" << eltType << ", " << name << ", iter) {\n";
+
+    out << "      if (vis.visitListItem_" << className << "_" << name
+        << "(iter" << iterElt << ")) {\n";
+    out << "        iter" << iterElt << "->traverse(vis);\n";
+    out << "        vis.postvisitListItem_" << className << "_" << name
+        << "(iter" << iterElt << ");\n";
+    out << "      }\n";         // end of if
+
+    out << "    }\n";           // end of iter
+    out << "    vis.postvisitList_" << className << "_" << name
+        << "(" << argNamePrefix << name << ");\n";
+    out << "  }\n";             // end of if
+  }
+}
+
+void CGen::emitTraverse(ASTClass const *c, ASTClass const * /*nullable*/ super,
+                        bool hasChildren)
+{
+  out << "void " << c->name << "::traverse("
+      <<   visitorName << " &vis)\n"
+      << "{\n";
+
+  // do any initial traversal action specified by the user
+  emitCustomCode(c->decls, "preemptTraverse");
+
+  // name of the 'visit' method that applies to this class;
+  // these methods are always named according to the least-derived
+  // class in the hierarchy
+  string visitName = stringc << "visit" << (super? super : c)->name;
+
+  // we only call 'visit' in the most-derived classes; this of course
+  // assumes that classes with children are never themselves instantiated
+  if (!hasChildren) {
+    // visit this node; if the visitor doesn't want to traverse
+    // the children, then bail
+    out << "  if (!vis." << visitName << "(this)) { return; }\n\n";
+  }
+  else {
+    out << "  // no 'visit' because it's handled by subclasses\n\n";
+  }
+
+  if (super) {
+    // traverse superclass ctor args, if this class has one
+    out << "  " << super->name << "::traverse(vis);\n"
+        << "\n";
+  }
+
+  // traverse into the ctor arguments
+  FOREACH_ASTLIST(CtorArg, c->args, iter) {
+    CtorArg const *arg = iter.data();
+    emitOneTraverseCall(c->name, arg->name, arg->type);
+  }
+
+  // dsw: I need a way to make fields traversable
+  FOREACH_ASTLIST(Annotation, c->decls, iter) {
+    if (!iter.data()->isUserDecl()) continue;
+    UserDecl const *ud = iter.data()->asUserDeclC();
+    if (!ud->amod->hasMod("traverse")) continue;
+    emitOneTraverseCall(c->name, extractFieldName(ud->code), extractFieldType(ud->code));
+  }
+
+  // do any final traversal action specified by the user
+  emitCustomCode(c->decls, "traverse");
+
+  // traverse into the ctor last arguments
+  FOREACH_ASTLIST(CtorArg, c->lastArgs, iter) {
+    CtorArg const *arg = iter.data();
+    emitOneTraverseCall(c->name, arg->name, arg->type);
+  }
+
+  if (!hasChildren) {
+    // if we did the preorder visit on the way in, do the
+    // postorder visit now
+    out << "  vis.post" << visitName << "(this);\n";
+  }
+  else {
+    out << "  // no 'postvisit' either\n";
+  }
+
+  out << "}\n\n";
+}
+
+
+// ------------------- delegation visitor --------------------
+void HGen::emitDVisitorInterface()
+{
+  out << "// the delegator-visitor interface class\n"
+      << "class " << dvisitorName << " : public " << visitorName << " {\n";
+
+  out << "protected:   // data\n";
+  out << "  " << visitorName << " *client;      // visitor to delegate to\n";
+  out << "  bool ensureOneVisit;                // check for visiting at most once?\n";
+  out << "  SObjSet<void*> wasVisitedASTNodes;  // set of visited nodes\n";
+  out << "  SObjSet<void*> wasVisitedList_ASTListNodes; // set of visited ASTLists\n";
+  out << "  SObjSet<void*> wasVisitedList_FakeListNodes; // set of visited FakeLists\n";
+  out << "\n";
+
+  out << "protected:   // funcs\n";
+  out << "  bool wasVisitedAST(void *ast);\n";
+  out << "  bool wasVisitedList_ASTList(void *ast);\n";
+  out << "  bool wasVisitedList_FakeList(void *ast);\n";
+  out << "\n";
+
+  // ctor
+  out << "public:      // funcs\n";
+  out << "  explicit " << dvisitorName << "("
+      << visitorName << " *client0 = NULL, "
+    // NOTE: it is too expensive to make this true by default; let
+    // code turn it on manually if they really want this
+      << "bool ensureOneVisit0 = false"
+      << ")\n";
+  out << "    : client(client0)\n";
+  out << "    , ensureOneVisit(ensureOneVisit0)\n";
+  out << "  {}\n";
+  out << "\n";
+
+  // visitor methods
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+    out << "  virtual bool visit" << c->super->name << "("
+        <<   c->super->name << " *obj);\n"
+        << "  virtual void postvisit" << c->super->name << "("
+        <<   c->super->name << " *obj);\n";
+  }
+
+  out << "\n  // List 'classes'\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    out << "  virtual bool visitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">*);\n";
+    out << "  virtual void postvisitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">*);\n";
+  }
+
+  StringSet listItemClassesSet; // set of list item classes printed so far
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    xassert(!listItemClassesSet.contains(cls->classAndMemberName)); // should not repeat
+    listItemClassesSet.add(cls->classAndMemberName);
+    out << "  virtual bool visitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << "*);\n";
+    out << "  virtual void postvisitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << "*);\n";
+  }
+
+  // we are done
+  out << "};\n\n";
+}
+
+
+void CGen::emitDVisitorImplVisitedCheck(char const *name) {
+  out << "bool " << dvisitorName << "::" << name << "(void *ast)\n";
+  out << "{\n";
+  // NOTE: this was moved outside to the call site to avoid the
+  // function call
+//   out << "  // do not bother to check if the user does not want us to\n";
+//   out << "  if (!ensureOneVisit) {\n";
+//   out << "    return false;\n";
+//   out << "  }\n\n";
+  out << "  if (!ast) {return false;} // avoid NULL; actually happens for FakeLists\n";
+  out << "  if (" << name << "Nodes.contains(ast)) {\n";
+  out << "    return true;\n";
+  out << "  } else {\n";
+  out << "    " << name << "Nodes.add(ast);\n";
+  out << "    return false;\n";
+  out << "  }\n";
+  out << "}\n\n";
+}
+
+
+void CGen::emitDVisitorImplementation()
+{
+  out << "// ---------------------- " << dvisitorName << " ---------------------\n";
+
+  emitDVisitorImplVisitedCheck("wasVisitedAST");
+  emitDVisitorImplVisitedCheck("wasVisitedList_ASTList");
+  emitDVisitorImplVisitedCheck("wasVisitedList_FakeList");
+
+  out << "// default no-op delegator-visitor\n";
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    out << "bool " << dvisitorName << "::visit" << c->super->name
+        << "(" << c->super->name << " *obj) {\n"
+      // dsw: I changed this back to xassert() from xassertdb()
+      // because NDEBUG just gets turned on more often than I like.
+      // quarl 2006-05-13: changed back to xassertdb(); it's worth removing
+      // this as it accounts for 15% of qualcc runtime
+      // dsw & quarl: ok, we need this on, but in the code we protect
+      // it with a flag
+        << "  if (ensureOneVisit) xassert(!wasVisitedAST(obj));\n"
+        << "  return client ? client->visit" << c->super->name << "(obj) : true;\n"
+        << "}\n";
+
+    out << "void " << dvisitorName << "::postvisit" << c->super->name
+        << "(" << c->super->name << " *obj) {\n"
+        << "  if (client) {\n"
+        << "    client->postvisit" << c->super->name << "(obj);\n"
+        << "  }\n"
+        << "}\n";
+  }
+
+  out << "\n// List 'classes'\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    // visit
+    out << "bool " << dvisitorName << "::visitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">* obj) {\n";
+    out << "  if (ensureOneVisit) xassert(!wasVisitedList_" << cls->kindName() << "(obj));\n";
+    out << "  return client ? client->visitList_" << cls->classAndMemberName << "(obj) : true;\n";
+    out << "}\n";
+
+    // post visit
+    out << "void " << dvisitorName << "::postvisitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">* obj) {\n";
+    out << "  if (client) {\n";
+    out << "    client->postvisitList_" << cls->classAndMemberName << "(obj);\n";
+    out << "  }\n";
+    out << "}\n";
+  }
+
+  StringSet listItemClassesSet; // set of list item classes printed so far
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    xassert(!listItemClassesSet.contains(cls->classAndMemberName)); // should not repeat
+    listItemClassesSet.add(cls->classAndMemberName);
+
+    // visit item
+    out << "bool " << dvisitorName << "::visitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << " *obj) {\n";
+    // NOTE: we do NOT check that it has been visited before; this is
+    // the point of list items: that they are visited multiple times
+    // even if the contained item itself is not
+    out << "  return client ? client->visitListItem_" << cls->classAndMemberName << "(obj) : true;\n";
+    out << "}\n";
+
+    // post visit item
+    out << "void " << dvisitorName << "::postvisitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << " *obj) {\n";
+    out << "  if (client) {\n";
+    out << "    client->postvisitListItem_" << cls->classAndMemberName << "(obj);\n";
+    out << "  }\n";
+    out << "}\n";
+  }
+
+  out << "\n\n";
+}
+
+// ------------------- xml visitor --------------------
+
+void CGen::emitXmlCtorArgs(ASTList<CtorArg> const &args, char const *baseName,
+                           string const &className) {
+  FOREACH_ASTLIST(CtorArg, args, argiter) {
+    CtorArg const &arg = *(argiter.data());
+    emitXmlField(arg.type, arg.name, baseName, className, NULL);
+  }
+}
+
+void CGen::emitXmlFields(ASTList<Annotation> const &decls, char const *baseName,
+                         string const &className) {
+  FOREACH_ASTLIST(Annotation, decls, iter) {
+    if (!iter.data()->isUserDecl()) continue;
+    UserDecl const *ud = iter.data()->asUserDeclC();
+    if (!ud->amod->hasModPrefix("xml")) continue;
+    emitXmlField(extractFieldType(ud->code),
+                 extractFieldName(ud->code),
+                 baseName,
+                 className,
+                 ud->amod);
+  }
+}
+
+void CGen::emitXmlField(rostring type, rostring name, char const *baseName,
+                        string const &className, AccessMod *amod) {
+  // FIX: there is a problem with coming up with a way to serialize a
+  // NULL string: 1) the value must be quoted, 2) any string you use
+  // to represent NULL is also a valid string value, 3) quoting twice
+  // is expensive; For now, I simply omit mention of it: it will
+  // default to NULL.
+  if (streq(type, "string") || streq(type, "StringRef")) {
+    out << "  if (" << baseName << "->" << name << ") {\n";
+    out << "    out << '\\n';\n";
+    out << "    if (indent) printIndentation();\n";
+    out << "    out << \"" << name << "=\";\n";
+    out << "    outputXmlAttrQuoted(out, " << baseName << "->" << name << ");\n";
+    out << "  } else {\n";
+    // print nothing; the default value is NULL
+//      out << "    out << \"\\\"0\\\"\";\n";
+    out << "  }\n";
+  }
+  else if (streq(type, "bool")) {
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"" << name << "=\";\n";
+    out << "  outputXmlAttrQuotedNoEscape(out, toXml_bool(" << baseName << "->" << name << "));\n";
+  }
+  else if (streq(type, "int")) {
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"" << name << "=\";\n";
+    out << "  outputXmlAttrQuotedNoEscape(out, toXml_int(" << baseName << "->" << name << "));\n";
+  }
+  else if (streq(type, "unsigned int")) {
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"" << name << "=\";\n";
+    out << "  outputXmlAttrQuotedNoEscape(out, toXml_unsigned_int(" << baseName << "->" << name << "));\n";
+  }
+  else if (streq(type, "long")) {
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"" << name << "=\";\n";
+    out << "  outputXmlAttrQuotedNoEscape(out, toXml_long(" << baseName << "->" << name << "));\n";
+  }
+  else if (streq(type, "unsigned long")) {
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"" << name << "=\";\n";
+    out << "  outputXmlAttrQuotedNoEscape(out, toXml_unsigned_long(" << baseName << "->" << name << "));\n";
+  }
+  else if (streq(type, "double")) {
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"" << name << "=\";\n";
+    out << "  outputXmlAttrQuotedNoEscape(out, toXml_double(" << baseName << "->" << name << "));\n";
+  }
+  else if (streq(type, "SourceLoc")) {
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"" << name << "=\";\n";
+    out << "  outputXmlAttrQuoted(out, toXml_SourceLoc(" << baseName << "->" << name << "));\n";
+  }
+  else if (isListType(type)) {
+    out << "  if (" << baseName << " && " << baseName << "->" << name << ".isNotEmpty()) {\n";
+    out << "    out << '\\n';\n";
+    out << "    if (indent) printIndentation();\n";
+    out << "    out << \"" << name << "=\";\n";
+    out << "    outputXmlPointerQuoted(out, \"AL\", uniqueIdAST(&(" << baseName << "->" << name << ")));\n";
+    out << "  }\n";
+  }
+  else if (isFakeListType(type)) {
+    out << "  if (" << baseName << " && " << baseName << "->" << name << ") {\n";
+    out << "    out << '\\n';\n";
+    out << "    if (indent) printIndentation();\n";
+    out << "    out << \"" << name << "=\";\n";
+    out << "    outputXmlPointerQuoted(out, \"FL\", uniqueIdAST(" << baseName << "->" << name << "));\n";
+    out << "  }\n";
+  }
+  else if (isTreeNode(type) || (isTreeNodePtr(type))) {
+    out << "  if (" << baseName << " && " << baseName << "->" << name << ") {\n";
+    out << "    out << '\\n';\n";
+    out << "    if (indent) printIndentation();\n";
+    out << "    out << \"" << name << "=\";\n";
+    out << "    outputXmlPointerQuoted(out, \"AST\", uniqueIdAST(" << baseName << "->" << name << "));\n";
+    out << "  }\n";
+  } else if (amod && amod->hasModPrefix("xmlEmbed") && amod->hasModPrefix("xml_")) {
+    rostring idPrefix = amod->getModSuffixFromPrefix("xml_");
+    out << "  if (" << baseName << ") {\n";
+    out << "    out << '\\n';\n";
+    out << "    if (indent) printIndentation();\n";
+    out << "    out << \"" << name << "=\";\n";
+    out << "    outputXmlPointerQuoted(out, \"" << idPrefix << "\", uniqueIdAST(&" << baseName << "->" << name << "));\n";
+    out << "  }\n";
+  }
+
+    // FIX: relace the below with this; see note at "crap" below.
+//    else if (isPtrKind(type) && amod && amod->hasModPrefix("xml_")) {
+  else if (
+           (!amod && isPtrKind(type))
+           || (amod && amod->hasModPrefix("xml_"))
+           ) {
+    // catch-all for xml objects
+    string idPrefix;
+    bool shouldSerialize0 = false;
+    if (amod) {
+      idPrefix = amod->getModSuffixFromPrefix("xml_");
+      shouldSerialize0 = amod->hasModPrefix("xmlShouldSerialize");
+    } else {
+      // FIX: get rid of this piece of crap when we get a way to put
+      // an access specifier onto a ctor argument in the ast language
+      idPrefix = stringc << "TY";
+    }
+    out << "  if (" << baseName
+        << " && " << baseName << "->" << name;
+    if (shouldSerialize0) {
+      out << " && shouldSerialize(" << baseName << "->" << name << ")";
+    }
+    out << ") {\n";
+    out << "    out << '\\n';\n";
+    out << "    if (indent) printIndentation();\n";
+    out << "    out << \"" << name << "=\";\n";
+    out << "    /*catch-all*/outputXmlPointerQuoted(out, \"" << idPrefix << "\", ";
+    if (wantIdentityManager()) out << "idmgr.";
+    out << "uniqueId(" << baseName << "->" << name << "));\n";
+    out << "  }\n";
+
+  } else {
+    // catch-all for non-objects
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"" << name << "=\";\n";
+    out << "  outputXmlAttrQuoted(out, toXml(" << baseName << "->" << name << "));\n";
+  }
+}
+
+void HGen::emitXmlVisitorInterface()
+{
+  out << "// the xml-visitor interface class\n"
+      << "class " << xmlVisitorName << " : public " << visitorName << " {\n";
+
+  out << "protected:   // data\n";
+  out << "  ostream &out;                       // output stream to print to\n";
+
+  if (wantIdentityManager()) {
+    out << "  " << identityManagerName << " &idmgr; // Identity Manager to use\n";
+  }
+
+  out << "  int &depth;                         // current depth\n";
+  out << "  bool indent;                        // should the xml be indented\n";
+  out << "  SObjSet<void*> wasVisitedASTNodes;  // set of visited nodes\n";
+  out << "  SObjSet<void*> wasVisitedList_ASTListNodes; // set of visited ASTLists\n";
+  out << "  SObjSet<void*> wasVisitedList_FakeListNodes; // set of visited FakeLists\n";
+
+  out << "\n";
+
+  out << "protected:   // funcs\n";
+  out << "  bool wasVisitedAST(void *ast);\n";
+  out << "  bool wasVisitedList_ASTList(void *ast);\n";
+  out << "  bool wasVisitedList_FakeList(void *ast);\n";
+  out << "  void printIndentation();\n";
+  out << "\n";
+
+  // emit the xml_verbatim section if it exists
+  FOREACH_ASTLIST(ToplevelForm, file.forms, form) {
+    TF_xml_verbatim const *xmlVb = form.data()->ifTF_xml_verbatimC();
+    if (xmlVb) {
+      out << xmlVb->code;
+    }
+  }
+
+  // ctor
+  out << "public:      // funcs\n";
+  out << "  explicit " << xmlVisitorName << "("
+      << "ostream &out0, ";
+  if (wantIdentityManager()) out << identityManagerName << " &idmgr0, ";
+  out << "int &depth0, "
+      << "bool indent0 = false"
+      << ")\n";
+  out << "    : out(out0)\n";
+  if (wantIdentityManager()) out << "    , idmgr(idmgr0)\n";
+  out << "    , depth(depth0)\n";
+  out << "    , indent(indent0)\n";
+  out << "  {}\n";
+  out << "\n";
+
+  // visitor methods
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+    out << "  virtual bool visit" << c->super->name << "("
+        <<   c->super->name << " *obj);\n"
+        << "  virtual void postvisit" << c->super->name << "("
+        <<   c->super->name << " *obj);\n";
+  }
+
+  out << "\n  // List 'classes'\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    out << "  virtual bool visitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">*);\n";
+    out << "  virtual void postvisitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">*);\n";
+  }
+
+  StringSet listItemClassesSet; // set of list item classes printed so far
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    xassert(!listItemClassesSet.contains(cls->classAndMemberName)); // should not repeat
+    listItemClassesSet.add(cls->classAndMemberName);
+    out << "  virtual bool visitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << "*);\n";
+    out << "  virtual void postvisitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << "*);\n";
+  }
+
+  // we are done
+  out << "};\n\n";
+}
+
+
+void CGen::emitXmlVisitorImplVisitedCheck(char const *name) {
+  out << "bool " << xmlVisitorName << "::" << name << "(void *ast)\n";
+  out << "{\n";
+  out << "  if (!ast) {return false;} // avoid NULL; actually happens for FakeLists\n";
+  out << "  if (" << name << "Nodes.contains(ast)) {\n";
+  out << "    return true;\n";
+  out << "  } else {\n";
+  out << "    " << name << "Nodes.add(ast);\n";
+  out << "    return false;\n";
+  out << "  }\n";
+  out << "}\n\n";
+}
+
+
+void CGen::emitXmlVisitorImplementation()
+{
+  out << "// ---------------------- " << xmlVisitorName << " ---------------------\n";
+
+  emitXmlVisitorImplVisitedCheck("wasVisitedAST");
+  emitXmlVisitorImplVisitedCheck("wasVisitedList_ASTList");
+  emitXmlVisitorImplVisitedCheck("wasVisitedList_FakeList");
+
+  out << "void " << xmlVisitorName << "::printIndentation()\n";
+  out << "{\n";
+  out << "  writeSpaces(out, depth);\n";
+  out << "}\n\n";
+
+  out << "// default xml-visitor\n";
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    out << "bool " << xmlVisitorName << "::visit" << c->super->name;
+    out << "(" << c->super->name << " *obj) {\n";
+    out << "  if (wasVisitedAST(obj)) return false;\n";
+    // for now everything is a container tag
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << '<' << obj->kindName();\n";
+
+    // print the attributes of the superclass
+    out << "  ++depth;\n";      // indent them one level
+
+    // emit the id property
+    // put it on the same line as the tag
+//      out << "  out << '\\n';\n";
+//      out << "  if (indent) printIndentation();\n";
+    out << "  out << \" _id=\";\n";
+    out << "  outputXmlPointerQuoted(out, \"AST\", uniqueIdAST(obj));\n";
+
+    // emit other properties
+    emitXmlCtorArgs(c->super->args, "obj", c->super->name);
+    emitXmlFields(c->super->decls, "obj", c->super->name);
+
+    // print the attributes of the subclasses
+    if (c->hasChildren()) {
+      out << "  switch(obj->kind()) {\n";
+      out << "  default: xfailure(\"bad tag\"); break;\n";
+      FOREACH_ASTLIST(ASTClass, c->ctors, iter) {
+        ASTClass const *clazz = iter.data();
+        out << "  case " << c->super->name << "::" << clazz->classKindName() << ": {\n";
+        // prevent unused variable warning when compiling client code;
+        // FIX: turn on when take away the '= NULL' code below.
+//          if (clazz->args.isNotEmpty() || clazz->decls.isNotEmpty()) {
+        out << "    " << clazz->name << " *obj0 = obj->as" << clazz->name << "();\n";
+//          }
+        emitXmlCtorArgs(clazz->args, "obj0", clazz->name);
+        emitXmlFields(clazz->decls, "obj0", clazz->name);
+
+        // prevent unused variable warning when compiling client code;
+        // FIX: remove when all kinds of fields are printed
+        out << "    obj0 = NULL;\n";
+
+        out << "    break;\n";
+        out << "    }\n";
+      }
+      out << "  }\n";
+    }
+
+    // print the 'last' attributes of the superclass, which come after
+    // all subclass things
+    emitXmlCtorArgs(c->super->lastArgs, "obj", c->super->name);
+
+    out << "  --depth;\n";      // outdent temporarily so close bracket lines up with open
+    // commenting out these two lines puts the closing angle bracket
+    // on the same line as the last attribute, or if none, on the same
+    // line as the tag
+//      out << "  out << '\\n';\n";
+//      out << "  if (indent) printIndentation();\n";
+    out << "  out << '>';\n";
+    out << "  ++depth;\n";      // indent for nested children
+    out << "  return true;\n";
+    out << "}\n\n";;
+
+    out << "void " << xmlVisitorName << "::postvisit" << c->super->name;
+    out << "(" << c->super->name << " *obj) {\n";
+    out << "  --depth;\n";
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << '<' << '/' << obj->kindName() << '>';\n";
+    out << "}\n\n";
+  }
+
+  out << "\n// List 'classes'\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    // visit
+    out << "bool " << xmlVisitorName << "::visitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">* obj) {\n";
+    out << "  if (obj->isNotEmpty()) {\n";
+    out << "    if(wasVisitedList_" << cls->kindName() << "(obj)) return false;\n";
+    out << "    out << '\\n';\n";
+    out << "    if (indent) printIndentation();\n";
+    out << "    out << \"<List_" << cls->classAndMemberName << " _id=\";\n";
+    out << "    outputXmlPointerQuoted(out, \"";
+    if (cls->lkind == LK_ASTList) {
+      out << "AL";
+    } else if (cls->lkind == LK_FakeList) {
+      out << "FL";
+    } else xfailure("illegal list kind");
+    out << "\", uniqueIdAST(obj));\n";
+    out << "    out << '>';\n";
+    out << "    ++depth;\n";
+    out << "  };\n";
+    out << "  return true;\n";
+    out << "}\n\n";
+
+    // post visit
+    out << "void " << xmlVisitorName << "::postvisitList_" << cls->classAndMemberName
+        << "(" << cls->kindName() << "<" << cls->elementClassName << ">* obj) {\n";
+    out << "  if (obj->isNotEmpty()) {\n";
+    out << "    --depth;\n";
+    out << "    out << '\\n';\n";
+    out << "    if (indent) printIndentation();\n";
+    out << "    out << \"</List_" << cls->classAndMemberName << ">\";\n";
+    out << "  }\n";
+    out << "}\n\n";
+
+    // visit item
+    out << "bool " << xmlVisitorName << "::visitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << " *obj) {\n";
+    out << "  xassert(obj);\n";
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"<_List_Item\" << \" item=\";\n";
+    out << "  outputXmlPointerQuoted(out, \"AST\", uniqueIdAST(obj));\n";
+    out << "  out << '>';\n";
+    out << "  ++depth;\n";
+    out << "  return true;\n";
+    out << "}\n\n";
+
+    // post visit item
+    out << "void " << xmlVisitorName << "::postvisitListItem_" << cls->classAndMemberName
+        << "(" << cls->elementClassName << " *obj) {\n";
+    out << "  xassert(obj);\n";
+    out << "  --depth;\n";
+    out << "  out << '\\n';\n";
+    out << "  if (indent) printIndentation();\n";
+    out << "  out << \"</_List_Item>\";\n";
+    out << "}\n\n";
+  }
+
+  out << "\n\n";
+}
+
+
+// ------------------- modification visitor --------------------
+void HGen::emitMVisitorInterface()
+{
+  out << "// the modification visitor interface class\n"
+      << "class " << mvisitorName << " {\n";
+  emitVisitorInterfacePrelude(mvisitorName);
+
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    out << "  virtual bool visit" << c->super->name << "("
+        <<   c->super->name << " *&obj);\n"
+        << "  void mtraverse(" << c->super->name << " *&obj);\n"
+        ;
+  }
+  out << "};\n\n";
+}
+
+
+// The generated code does:
+//   - any actions specified for the superclass in the .ast file
+//   - invoke the visitor method, returning if it returns false
+//   - recursively traverse superclass fields
+//   - switch on subclass type, if there are any
+//   - do actions specified for the subclass in the .ast file
+//   - recursively visit the subclass fields
+// There is a slightly nonideal aspect to the above, in that the
+// subclass 'mtraverse' action is done *after* the superclass fields
+// are traversed, so the former can't skip the latter, but I'll leave
+// it for now (would require emitting two switch blocks to fix).
+void CGen::emitMVisitorImplementation()
+{
+  out << "// ---------------------- " << mvisitorName << " ---------------------\n";
+
+  out << mvisitorName << "::~" << mvisitorName << "() {}\n\n";
+
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    out << "bool " << mvisitorName << "::visit" << c->super->name << "("
+        <<   c->super->name << " *&obj) { return true; }\n"
+        << "\n"
+        ;
+
+    out << "void " << mvisitorName << "::mtraverse(" << c->super->name << " *&obj)\n"
+        << "{\n"
+        ;
+
+    // invoke visitor function
+    out << "  if (!visit" << c->super->name << "(obj)) { return; }\n"
+        << "\n"
+        ;
+
+    // superclass action specified in .ast file
+    emitCustomCode(c->super->decls, "mtraverse");
+
+    // superclass field traversal
+    emitMTraverse(c->super, "obj", "  ");
+
+    if (c->hasChildren()) {
+      out << "  switch (obj->kind()) {\n";
+
+      // subclass traversal
+      FOREACH_ASTLIST(ASTClass, c->ctors, iter) {
+        ASTClass const *sub = iter.data();
+
+        out << "    case " << c->super->name << "::" << sub->classKindName() << ": {\n"
+            << "      " << sub->name << " *sub = (" << sub->name << "*)obj;\n"
+            << "      (void)sub;\n"      // silence warning if unused
+            ;
+
+        // subclass action specified in .ast file
+        emitCustomCode(sub->decls, "mtraverse");
+
+        // subclass field traversal
+        emitMTraverse(sub, "sub", "      ");
+
+        out << "      break;\n"
+            << "    }\n"
+            ;
+      }
+
+      out << "    default:;\n"       // silence warning
+          << "  }\n";
+    }
+
+    out << "}\n"
+        << "\n"
+        << "\n"
+        ;
+  }
+  out << "\n";
+}
+
+
+// emit mtraverse calls for the fields
+void CGen::emitMTraverse(ASTClass const *c, rostring obj, rostring i)
+{
+  // traverse into the ctor arguments
+  FOREACH_ASTLIST(CtorArg, c->args, iter) {
+    CtorArg const *arg = iter.data();
+    string argVar = stringc << obj << "->" << arg->name;
+
+    if (isTreeNode(arg->type) || isTreeNodePtr(arg->type)) {
+      string eltType = extractNodeType(arg->type);
+
+      out << i << "if (" << argVar << ") {\n";
+      emitMTraverseCall(stringc << i << "  ", eltType, argVar);
+      out << i << "}\n";
+    }
+
+    else if (isListType(arg->type) &&
+             isTreeNode(extractListType(arg->type))) {
+      string eltType = extractListType(arg->type);
+
+      // list of tree nodes: iterate and traverse
+      out << i << "FOREACH_ASTLIST_NC(" << eltType << ", " << argVar << ", iter) {\n";
+      emitMTraverseCall(stringc << i << "  ", eltType, "iter.dataRef()");
+      out << i << "}\n";
+    }
+
+    else if (isFakeListType(arg->type) &&
+             isTreeNode(extractListType(arg->type))) {
+      string eltType = extractListType(arg->type);
+
+      // fakelist mtraversal is a little complicated because I
+      // need to break apart the 'FakeList' abstraction so I can
+      // modify elements, iterate into the substituted part, etc.
+      out << i << "// fakelist mtraversal: " << argVar << "\n"
+          << i << "{\n"
+          << i << "  " << eltType << " **iter = "
+               <<   "(" << eltType << "**)&(" << argVar << ");\n"
+          << i << "  while (*iter) {\n"
+          ;
+
+      emitMTraverseCall(stringc << i << "    ", eltType, "*iter");
+
+      out << i << "    iter = &( (*iter)->next );\n"
+          << i << "  }\n"
+          << i << "}\n"
+          ;
+    }
+  }
+}
+
+
+void CGen::emitMTraverseCall(rostring i, rostring eltType, rostring argVar)
+{
+  if (isSuperclassTreeNode(eltType)) {
+    // easy case
+    out << i << "mtraverse(" << argVar << ");\n";
+    return;
+  }
+
+  // because the field is declared to be a specific subclass type, we
+  // invoke mtraverse but then check that the result has that type
+
+  xassert(isSubclassTreeNode(eltType));
+  string superType = getSuperTypeOf(eltType);
+  out << i << superType << "* tmp = " << argVar << ";\n"
+      << i << "mtraverse(tmp);\n"
+      << i << "if (tmp != " << argVar << ") {\n"
+      << i << "  " << argVar << " = tmp->as" << eltType << "();\n"
+      << i << "}\n"
+      ;
+}
+
+
+// ------------------- xml parser --------------------
+
+// FIX: an iterator desing pattern over the fields/ctor_args of an AST
+// node would be better than this repeated copies of the DFS
+
+void XmlParserGen::collectXmlParserCtorArgs(ASTList<CtorArg> const &args, char const *baseName)
+{
+  FOREACH_ASTLIST(CtorArg, args, argiter) {
+    CtorArg const &arg = *(argiter.data());
+    collectXmlParserField(arg.type, arg.name, baseName, NULL);
+  }
+}
+
+void XmlParserGen::collectXmlParserFields(ASTList<Annotation> const &decls, char const *baseName)
+{
+  FOREACH_ASTLIST(Annotation, decls, iter) {
+    if (!iter.data()->isUserDecl()) continue;
+    UserDecl const *ud = iter.data()->asUserDeclC();
+    if (!ud->amod->hasModPrefix("xml")) continue;
+    collectXmlParserField(extractFieldType(ud->code),
+                          extractFieldName(ud->code),
+                          baseName,
+                          ud->amod);
+  }
+}
+
+// FIX: this is now very redundant, but we can still change it to
+// exclude some fields of some types, so lets keep it for now.
+void XmlParserGen::collectXmlParserField
+  (rostring type, rostring name, char const *baseName, AccessMod*)
+{
+  if (streq(type, "string")) {
+    attributeNames.add(name);
+  }
+  else if (streq(type, "StringRef")) {
+    attributeNames.add(name);
+  }
+  else if (streq(type, "bool")) {
+    attributeNames.add(name);
+  }
+
+  else if (isListType(type)) {
+    attributeNames.add(name);
+  }
+  else if (isFakeListType(type)) {
+    attributeNames.add(name);
+  }
+  else if (isTreeNode(type) || (isTreeNodePtr(type))) {
+    attributeNames.add(name);
+  }
+
+  // If you start being more selective, be sure to include the names
+  // for things marked "xml"
+
+  else {
+    // catch-all ..
+//      out << "  " << print << "_GENERIC(" << name << ");\n";
+    attributeNames.add(name);
+  }
+}
+
+
+void XmlParserGen::emitXmlCtorArgs_AttributeParseRule
+  (ASTList<CtorArg> const &args, string &baseName)
+{
+  FOREACH_ASTLIST(CtorArg, args, argiter) {
+    CtorArg const &arg = *(argiter.data());
+    emitXmlField_AttributeParseRule(arg.type, arg.name, baseName, NULL);
+  }
+}
+
+void XmlParserGen::emitXmlFields_AttributeParseRule
+  (ASTList<Annotation> const &decls, string &baseName)
+{
+  FOREACH_ASTLIST(Annotation, decls, iter) {
+    if (!iter.data()->isUserDecl()) continue;
+    UserDecl const *ud = iter.data()->asUserDeclC();
+    if (!ud->amod->hasModPrefix("xml")) continue;
+    emitXmlField_AttributeParseRule(extractFieldType(ud->code),
+                                    extractFieldName(ud->code),
+                                    baseName,
+                                    ud->amod);
+  }
+}
+
+void XmlParserGen::emitXmlField_AttributeParseRule
+  (rostring type0, rostring name, string &baseName, AccessMod *amod)
+{
+  string type = trimWhitespace(type0);
+  //  cout << "emitXmlField_AttributeParseRule() name:" << name << ", type:" << type << endl;
+  if (streq(type, "string")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    obj->" << name << " = strdup(strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (streq(type, "StringRef")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    obj->" << name << " = manager->strTable(strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (streq(type, "bool")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    fromXml_bool(obj->" << name << ", strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (streq(type, "int")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    fromXml_int(obj->" << name << ", strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (streq(type, "unsigned int")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    fromXml_unsigned_int(obj->" << name
+                 << ", strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (streq(type, "long")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    fromXml_long(obj->" << name << ", strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (streq(type, "unsigned long")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    fromXml_unsigned_long(obj->" << name
+                 << ", strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (streq(type, "double")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    fromXml_double(obj->" << name << ", strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (streq(type, "SourceLoc")) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    fromXml_SourceLoc(obj->" << name << ", strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (isListType(type)) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    manager->addUnsatLink(new UnsatLink("
+                 << "(void*) &(obj->" << name << "), strValue, "
+                 << "XTOK_List_" << baseName << "_" << name << ", true));\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (isFakeListType(type)) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    manager->addUnsatLink(new UnsatLink("
+                 << "(void*) &(obj->" << name << "), strValue, "
+                 << "XTOK_List_" << baseName << "_" << name << ", true));\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (isTreeNode(type) || (isTreeNodePtr(type))) {
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    manager->addUnsatLink(new UnsatLink("
+                 << "(void*) &(obj->" << name << "), strValue,"
+                 << "XTOK_" << extractNodeType(type) << ", false));\n";
+    parser1_defs << "    break;\n";
+  }
+  else if (isPtrKind(type)) {
+    // catch-all for objects
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    manager->addUnsatLink(new UnsatLink("
+                 << "(void*) &(obj->" << name << "), strValue,"
+                 << "XTOK_" << extractNodeType(type) << ", false));\n";
+    parser1_defs << "    break;\n";
+  } else if (amod && amod->hasModPrefix("xmlEmbed")) {
+    // embedded thing
+    rostring kind = amod->getModSuffixFromPrefix("xmlEmbed");
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    manager->addUnsatLink(new UnsatLink("
+                 << "(void*) &(obj->" << name << "), strValue,"
+                 << "XTOK" << kind << "_" << baseName << "_" << name << ", true));\n";
+    parser1_defs << "    break;\n";
+  } else {
+    // catch-all for non-objects
+    parser1_defs << "  case XTOK_" << name << ":\n";
+    parser1_defs << "    fromXml(obj->" << name << ", strValue);\n";
+    parser1_defs << "    break;\n";
+  }
+}
+
+void XmlParserGen::emitXmlParser_objCtorArgs
+  (ASTList<CtorArg> const &args, bool &firstTime)
+{
+  FOREACH_ASTLIST(CtorArg, args, argiter) {
+    CtorArg const &arg = *(argiter.data());
+    if (firstTime) { firstTime = false; }
+    else { parser2_ctorCalls << ", "; }
+    if (strlen(arg.defaultValue.c_str())>0) {
+      parser2_ctorCalls << arg.defaultValue;
+    } else {
+      // dsw: this is Scott's idea of how to initialize a type that we
+      // know nothing about with no information
+      string type = arg.type;
+      if (isListType(arg.type)) {
+        // need to put a pointer onto the end of ASTList types
+        type = stringc << type << "*";
+      } else if (isTreeNode(arg.type)) {
+        // dsw: FIX: I should probably have something like this here
+        // (isTreeNodePtr(type) && isOwner)
+        //
+        // also for AST node types
+        type = stringc << type << "*";
+      }
+      parser2_ctorCalls << "(" << type << ")0";
+    }
+  }
+}
+
+void XmlParserGen::emitXmlParser_Node
+  (ASTClass const *clazz,
+
+   ASTList<CtorArg> const *args,
+   ASTList<Annotation> const *decls,
+   ASTList<CtorArg> const *lastArgs,
+
+   // these two default to NULL, which is used in the case of a top
+   // level class with no subclasses
+   ASTList<CtorArg> const *childArgs,
+   ASTList<Annotation> const *childDecls)
+{
+  string name = clazz->name;
+
+  parser0_decls
+    << "void registerAttr_" << name
+    << "(" << name << " *obj, int attr, char const *strValue);\n";
+
+  parser3_registerCalls
+    << "      case XTOK_" << name << ":\n"
+    << "        registerAttr_" << name
+    << "((" << name << "*)target, attr, yytext0);\n"
+    << "      break;\n";
+
+  // we need to supply however many NULL args here as there are ctor args.
+  parser2_ctorCalls << "    case XTOK_" << name << ":\n"
+                    << "      return new " << name << "(";
+  bool firstTime = true;
+  if (args)      {emitXmlParser_objCtorArgs(*args, firstTime);}
+  if (childArgs) {emitXmlParser_objCtorArgs(*childArgs, firstTime);}
+  if (lastArgs)  {emitXmlParser_objCtorArgs(*lastArgs, firstTime);}
+  parser2_ctorCalls << ");\n"
+                    << "      break;\n";
+}
+
+void XmlParserGen::emitXmlParser_Node_registerAttr
+  (ASTClass const *clazz,
+
+   ASTList<CtorArg> const *args,
+   ASTList<Annotation> const *decls,
+   ASTList<CtorArg> const *lastArgs,
+
+   // these two default to NULL, which is used in the case of a top
+   // level class with no subclasses
+   ASTList<CtorArg> const *childArgs,
+   ASTList<Annotation> const *childDecls)
+{
+  string name = clazz->name;
+
+  parser1_defs
+    << "\nvoid XmlAstReader::registerAttr_" << name
+    << "(" << name << " *obj, int attr, char const *strValue) {\n";
+  parser1_defs << "  switch(attr) {\n";
+  parser1_defs << "  default:\n";
+  parser1_defs << "    xmlUserFatalError(\"illegal attribute for a " << name << "\");\n";
+  parser1_defs << "    break;\n";
+
+  // for each attribute, emit a rule to parse it as an attribute of this tag
+  emitXmlCtorArgs_AttributeParseRule(*args, name);
+  emitXmlFields_AttributeParseRule(*decls, name);
+  emitXmlCtorArgs_AttributeParseRule(*lastArgs, name);
+  if (childArgs) {
+    xassert(childDecls);
+    emitXmlCtorArgs_AttributeParseRule(*childArgs, name);
+    emitXmlFields_AttributeParseRule(*childDecls, name);
+  }
+
+  parser1_defs << "  }\n";
+  parser1_defs << "}\n";
+}
+
+void XmlParserGen::emitXmlParser_ASTList(ListClass const *cls)
+{
+  string name = stringc << "List_" << cls->classAndMemberName;
+  // only one rule as lists are homogeneous
+  xassert(isTreeNode(cls->elementClassName));
+  parser2_ctorCalls << "    case XTOK_" << name << ":\n"
+                    << "      return new ASTList<" << cls->elementClassName << ">();\n"
+                    << "      break;\n";
+}
+
+void XmlParserGen::emitXmlParser_FakeList(ListClass const *cls)
+{
+  // quarl 2006-06-01
+  //    We deserialize directly into FakeLists, so return an empty FakeList
+  //    (i.e. NULL).  (We used to first deserialize into an ASTList and then
+  //    convert, but we no longer do that.)
+
+  // TODO: this doesn't need to be a 'string'
+  string name = stringc << "List_" << cls->classAndMemberName;
+  // only one rule as lists are homogeneous
+  xassert(isTreeNode(cls->elementClassName));
+  parser2_ctorCalls << "    case XTOK_" << name << ":\n"
+                    << "      return new FakeList<" << cls->elementClassName << "> *;\n"
+                    << "      break;\n";
+}
+
+void XmlParserGen::emitXmlParserImplementation()
+{
+  tokensOut  << "  # Xml tokens for serializing Ast nodes\n";
+
+  parser1_defs << "bool XmlAstReader::kind2kindCat(int kind, KindCategory *kindCat) {\n";
+  parser1_defs << "  switch(kind) {\n";
+  parser1_defs << "  default: return false; // don't know this kind\n";
+
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+
+    tokensOut << c->super->name << "\n";
+    parser1_defs << "  case XTOK_" << c->super->name << ": *kindCat = KC_Node; break;\n";
+
+    collectXmlParserCtorArgs(c->super->args, "obj");
+    collectXmlParserFields(c->super->decls, "obj");
+    collectXmlParserCtorArgs(c->super->lastArgs, "obj");
+
+    if (c->hasChildren()) {
+      FOREACH_ASTLIST(ASTClass, c->ctors, iter) {
+        ASTClass const *clazz = iter.data();
+
+        tokensOut << "  " << clazz->name << "\n";
+        parser1_defs << "  case XTOK_" << clazz->name << ": *kindCat = KC_Node; break;\n";
+
+        collectXmlParserCtorArgs(clazz->args, "obj0");
+        collectXmlParserFields(clazz->decls, "obj0");
+        emitXmlParser_Node(clazz,
+                           &c->super->args, &c->super->decls, &c->super->lastArgs,
+                           &clazz->args, &clazz->decls);
+      }
+    } else {
+      emitXmlParser_Node(c->super,
+                         &c->super->args, &c->super->decls, &c->super->lastArgs);
+    }
+  }
+
+  tokensOut << "\n  # List 'classes'\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    tokensOut << "  List_" << cls->classAndMemberName << "\n";
+    parser1_defs << "  case XTOK_List_" << cls->classAndMemberName << ": *kindCat = ";
+    if (cls->lkind == LK_FakeList) {
+      emitXmlParser_FakeList(cls);
+      parser1_defs << "KC_FakeList";
+    } else if (cls->lkind == LK_ASTList) {
+      emitXmlParser_ASTList(cls);
+      parser1_defs << "KC_ASTList";
+    } else xfailure("illegal list kind");
+    parser1_defs << "; break;\n";
+  }
+
+  parser1_defs << "  }\n";
+  parser1_defs << "  return true;\n";
+  parser1_defs << "}\n";
+
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+    if (c->hasChildren()) {
+      FOREACH_ASTLIST(ASTClass, c->ctors, iter) {
+        ASTClass const *clazz = iter.data();
+        emitXmlParser_Node_registerAttr
+          (clazz,
+           &c->super->args, &c->super->decls, &c->super->lastArgs,
+           &clazz->args, &clazz->decls);
+      }
+    } else {
+      emitXmlParser_Node_registerAttr
+        (c->super,
+         &c->super->args, &c->super->decls, &c->super->lastArgs);
+    }
+  }
+
+  // generate the method that says we should not record the kind of
+  // any tag that is parsed as there is no multiple inheritance going
+  // on in the AST
+  parser1_defs << "\nbool XmlAstReader::recordKind(int kind, bool& answer) {\n";
+  parser1_defs << "  switch(kind) {\n";
+  parser1_defs << "  default: return false; break;\n";
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+    if (c->hasChildren()) {
+      FOREACH_ASTLIST(ASTClass, c->ctors, iter) {
+        string name = iter.data()->name;
+        parser1_defs << "  case XTOK_" << name << ": answer = false; return true; break;\n";
+      }
+    } else {
+      string name = c->super->name;
+      parser1_defs << "  case XTOK_" << name << ": answer = false; return true; break;\n";
+    }
+  }
+
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    parser1_defs << "  case XTOK_List_" << cls->classAndMemberName << ": answer = false; return true; break;\n";
+  }
+  parser1_defs << "  }\n";
+  parser1_defs << "}\n";
+
+  // generate the method that says we should not record the kind of
+  // any tag that is parsed as there is no multiple inheritance going
+  // on in the AST
+  parser1_defs << "\nbool XmlAstReader::upcastToWantedType";
+  parser1_defs << "(void *obj, int kind, void **target, int targetKind) {\n";
+  parser1_defs << "  switch(kind) {\n";
+  parser1_defs << "  default: return false; break;\n";
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+    if (c->hasChildren()) {
+      FOREACH_ASTLIST(ASTClass, c->ctors, iter) {
+        parser1_defs << "  case XTOK_" << iter.data()->name << ":\n";
+      }
+    } else {
+      parser1_defs << "  case XTOK_" << c->super->name << ":\n";
+    }
+  }
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    parser1_defs << "  case XTOK_List_" << iter.data()->classAndMemberName << ":\n";
+  }
+  parser1_defs << "    xfailure(\"should never be called\"); return true; break;\n";
+  parser1_defs << "  }\n";
+  parser1_defs << "}\n";
+
+  // generate the method that says we should not have to call
+  // operator=() on any objects because no AST nodes embed into one
+  // another
+  parser1_defs << "\nbool XmlAstReader::callOpAssignToEmbeddedObj";
+  parser1_defs << "(void *obj, int kind, void *target) {\n";
+  parser1_defs << "  switch(kind) {\n";
+  parser1_defs << "  default: return false; break;\n";
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *c = iter.data();
+    if (c->hasChildren()) {
+      FOREACH_ASTLIST(ASTClass, c->ctors, iter) {
+        parser1_defs << "  case XTOK_" << iter.data()->name << ":\n";
+      }
+    } else {
+      parser1_defs << "  case XTOK_" << c->super->name << ":\n";
+    }
+  }
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    parser1_defs << "  case XTOK_List_" << iter.data()->classAndMemberName << ":\n";
+  }
+  parser1_defs << "    xfailure(\"should never be called\"); return true; break;\n";
+  parser1_defs << "  }\n";
+  parser1_defs << "}\n";
+
+  // generate generic FakeList
+  parser1_defs << "bool XmlAstReader::prependToFakeList(void *&list, void *obj, int listKind) {\n";
+  parser1_defs << "  switch(listKind) {\n";
+  parser1_defs << "  default: return false; // we did not find a matching tag\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    if (cls->lkind != LK_FakeList) continue;
+    parser1_defs << "  case XTOK_List_" << cls->classAndMemberName << ": {\n";
+    parser1_defs << "    prependToFakeList0<" << cls->elementClassName << ">(list, obj);\n";
+    parser1_defs << "    break;\n";
+    parser1_defs << "  }\n";
+  }
+  parser1_defs << "  }\n";
+  parser1_defs << "  return true;\n";
+  parser1_defs << "}\n";
+
+  parser1_defs << "bool XmlAstReader::reverseFakeList(void *&list, int listKind) {\n";
+  parser1_defs << "  switch(listKind) {\n";
+  parser1_defs << "  default: return false; // we did not find a matching tag\n";
+  FOREACH_ASTLIST(ListClass, listClasses, iter) {
+    ListClass const *cls = iter.data();
+    if (cls->lkind != LK_FakeList) continue;
+    parser1_defs << "  case XTOK_List_" << cls->classAndMemberName << ": {\n";
+    parser1_defs << "    reverseFakeList0<" << cls->elementClassName << ">(list);\n";
+    parser1_defs << "    break;\n";
+    parser1_defs << "  }\n";
+  }
+  parser1_defs << "  }\n";
+  parser1_defs << "  return true;\n";
+  parser1_defs << "}\n";
+
+  tokensOut << "\n  # child attribute names\n";
+  FOREACH_STRINGSET(attributeNames, attrIter) {
+    string const &attr = attrIter.data();
+    tokensOut << "  " << attr << "\n";
+  }
+}
+
+
+// -------------------- extension merging ------------------
+// the 'allClasses' list is filled in after merging, so I
+// can't use it in this section
+#define allClasses NO!
+
+void mergeClass(ASTClass *base, ASTClass *ext)
+{
+  xassert(base->name.equals(ext->name));
+  trace("merge") << "merging class: " << ext->name << endl;
+
+  // move all ctor args to the base
+  while (ext->args.isNotEmpty()) {
+    base->args.append(ext->args.removeFirst());
+  }
+
+  // and same for annotations
+  while (ext->decls.isNotEmpty()) {
+    base->decls.append(ext->decls.removeFirst());
+  }
+}
+
+
+void mergeEnum(TF_enum *base, TF_enum *ext)
+{
+  xassert(base->name.equals(ext->name));
+  trace("merge") << "merging enum: " << ext->name << endl;
+
+  while (ext->enumerators.isNotEmpty()) {
+    base->enumerators.append(ext->enumerators.removeFirst());
+  }
+}
+
+
+ASTClass *findClass(TF_class *base, rostring name)
+{
+  FOREACH_ASTLIST_NC(ASTClass, base->ctors, iter) {
+    if (iter.data()->name.equals(name)) {
+      return iter.data();
+    }
+  }
+  return NULL;   // not found
+}
+
+void mergeSuperclass(TF_class *base, TF_class *ext)
+{
+  // should only get here for same-named classes
+  xassert(base->super->name.equals(ext->super->name));
+  trace("merge") << "merging superclass: " << ext->super->name << endl;
+
+  // merge the superclass ctor args and annotations
+  mergeClass(base->super, ext->super);
+
+  // for each subclass, either add it or merge it
+  while (ext->ctors.isNotEmpty()) {
+    ASTClass * /*owner*/ c = ext->ctors.removeFirst();
+
+    ASTClass *prev = findClass(base, c->name);
+    if (prev) {
+      mergeClass(prev, c);
+      delete c;
+    }
+    else {
+      // add it wholesale
+      trace("merge") << "adding subclass: " << c->name << endl;
+      base->ctors.append(c);
+    }
+  }
+}
+
+
+TF_class *findSuperclass(ASTSpecFile *base, rostring name)
+{
+  // I can *not* simply iterate over 'allClasses', because that
+  // list is created *after* merging!
+  FOREACH_ASTLIST_NC(ToplevelForm, base->forms, iter) {
+    ToplevelForm *tf = iter.data();
+    if (tf->isTF_class() &&
+        tf->asTF_class()->super->name.equals(name)) {
+      return tf->asTF_class();
+    }
+  }
+  return NULL;    // not found
+}
+
+TF_enum *findEnum(ASTSpecFile *base, rostring name)
+{
+  FOREACH_ASTLIST_NC(ToplevelForm, base->forms, iter) {
+    ToplevelForm *tf = iter.data();
+    if (tf->isTF_enum() &&
+        tf->asTF_enum()->name.equals(name)) {
+      return tf->asTF_enum();
+    }
+  }
+  return NULL;    // not found
+}
+
+void mergeExtension(ASTSpecFile *base, ASTSpecFile *ext)
+{
+  // for each toplevel form, either add it or merge it
+  int ct = 0;
+  while (ext->forms.isNotEmpty()) {
+    ToplevelForm * /*owner*/ tf = ext->forms.removeFirst();
+
+    if (tf->isTF_class()) {
+      TF_class *c = tf->asTF_class();
+
+      // is the superclass name something present in the
+      // base specification?
+      TF_class *prev = findSuperclass(base, c->super->name);
+      if (prev) {
+        mergeSuperclass(prev, c);
+        delete c;
+      }
+      else {
+        // add the whole class
+        trace("merge") << "adding new superclass: " << c->super->name << endl;
+        base->forms.append(c);
+      }
+    }
+
+    else if (tf->isTF_enum()) {
+      TF_enum *e = tf->asTF_enum();
+
+      // is the enum present in the base?
+      TF_enum *prev = findEnum(base, e->name);
+      if (prev) {
+        mergeEnum(prev, e);
+        delete e;
+      }
+      else {
+        // add the whole enum
+        trace("merge") << "adding new enum: " << e->name << endl;
+        base->forms.append(e);
+      }
+    }
+
+    else {
+      // verbatim or option: just add it directly
+
+      if (ct == 0) {
+        // *first* verbatim: goes into a special place in the
+        // base, before any classes but after any base verbatims
+        int i;
+        for (i=0; i < base->forms.count(); i++) {
+          ToplevelForm *baseForm = base->forms.nth(i);
+
+          if (baseForm->isTF_class()) {
+            // ok, this is the first class, so stop here
+            // and we'll insert at 'i', thus inserting
+            // just before this class
+            break;
+          }
+        }
+
+        // insert the base so it becomes position 'i'
+        trace("merge") << "inserting extension verbatim near top\n";
+        base->forms.insertAt(tf, i);
+      }
+
+      else {
+        // normal processing: append everything
+        trace("merge") << "appending extension verbatim/option section\n";
+        base->forms.append(tf);
+      }
+    }
+
+    ct++;
+  }
+}
+
+// re-enable allClasses
+#undef allClasses
+
+void recordListClass(ListKind lkind, rostring className, CtorArg const *arg) {
+  rostring argName = arg->name;
+  ListClass *cls = new ListClass
+    (lkind, stringc << className << "_" << argName, extractListType(arg->type));
+  if (!listClassesSet.contains(cls->classAndMemberName)) {
+    listClassesSet.add(cls->classAndMemberName);
+    listClasses.append(cls);
+  } else {
+    delete cls;
+  }
+}
+
+void getListClasses(rostring className, CtorArg const *arg) {
+  // I would rather visit all the lists, but we don't seem to generate
+  // visit() traversals for non-tree nodes, so there is nothing to put
+  // inside the nesting
+  if (isListType(arg->type) && isTreeNode(extractListType(arg->type))) {
+    recordListClass(LK_ASTList, className, arg);
+  }
+  if (isFakeListType(arg->type) && isTreeNode(extractListType(arg->type))) {
+    recordListClass(LK_FakeList, className, arg);
+  }
+}
+
+void getListClasses(ASTClass const *c) {
+  rostring className = c->name;
+  FOREACH_ASTLIST(CtorArg, c->args, ctorIter) {
+    getListClasses(className, ctorIter.data());
+  }
+  FOREACH_ASTLIST(CtorArg, c->lastArgs, ctorIter) {
+    getListClasses(className, ctorIter.data());
+  }
+}
+
+void getListClasses() {
+  SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+    TF_class const *cls = iter.data();
+    getListClasses(cls->super);
+    FOREACH_ASTLIST(ASTClass, cls->ctors, ctorIter) {
+      getListClasses(ctorIter.data());
+    }
+  }
+}
+
+
+// --------------------- toplevel control ----------------------
+void checkUnusedCustoms(ASTClass const *c)
+{
+  FOREACH_ASTLIST(Annotation, c->decls, iter) {
+    Annotation const *a = iter.data();
+
+    if (a->isCustomCode()) {
+      CustomCode const *cc = a->asCustomCodeC();
+      if (cc->used == false) {
+        cout << "warning: unused custom code `" << cc->qualifier << "'\n";
+      }
+    }
+  }
+}
+
+
+void grabOptionName(rostring opname, string &oparg, TF_option const *op)
+{
+  if (op->args.count() != 1) {
+    xfatal("'" << opname << "' option requires one argument");
+  }
+
+  if (!oparg.empty()) {
+    // It would be conceivable to allow multiple visitors, but
+    // I don't see any advantage to doing so.  If the extension
+    // simply changes the name, then the resulting error messages
+    // (compilation errors from parts of the system using the
+    // old name) are not obvious to diagnose.
+    xfatal("there is already " << a_or_an(opname) <<
+           " class, called " << oparg << ";\n" <<
+           "you should use (subclass) that one");
+  }
+
+  // name of the visitor interface class
+  oparg = *( op->args.firstC() );
+}
+
+
+void entry(int argc, char **argv)
+{
+  TRACE_ARGS();
+  checkHeap();
+  SourceLocManager mgr;
+
+  if (argc < 2) {
+    cout << "usage: " << argv[0] << " [options] file.ast [extension.ast [...]]\n"
+         << "  options:\n"
+         << "    -o<name>   output filenames are name.{h,cc}\n"
+         << "               (default is \"file\" for \"file.ast\")\n"
+         << "    -v         verbose operation, particularly for merging\n"
+         << "    -nocvr     do not use covariant return types in clone()\n"
+         ;
+
+    return;
+  }
+
+  char const *basename = NULL;      // nothing set
+
+  argv++;
+  while (argv[0][0] == '-') {
+    if (argv[0][1] == 'b' ||        // 'b' is for compatibility
+        argv[0][1] == 'o') {
+      if (argv[0][2]) {
+        // name specified directly after the -o
+        basename = argv[0]+2;
+      }
+      else if (argv[1]) {
+        // name follows the -o option
+        basename = argv[1];
+        argv++;
+      }
+    }
+    else if (argv[0][1] == 'v') {
+      traceAddSys("merge");
+    }
+    else if (streq(argv[0], "-nocvr")) {
+      nocvr = true;
+    }
+    else {
+      xfatal("unknown option: " << argv[0]);
+    }
+    argv++;
+  }
+  if (!argv[0]) {
+    xfatal("missing ast spec file name");
+  }
+
+  char const *srcFname = argv[0];
+  argv++;
+
+  // parse the grammar spec
+  Owner<ASTSpecFile> ast;
+  ast = readAbstractGrammar(srcFname);
+  wholeAST = ast;
+
+  // parse and merge extension modules
+  ObjList<string> modules;
+  while (*argv) {
+    char const *fname = *argv;
+    argv++;
+
+    modules.append(new string(fname));
+
+    Owner<ASTSpecFile> extension;
+    extension = readAbstractGrammar(fname);
+
+    mergeExtension(ast, extension);
+  }
+
+  // scan options, and fill 'allClasses'
+  {
+    FOREACH_ASTLIST_NC(ToplevelForm, ast->forms, iter) {
+      if (iter.data()->isTF_option()) {
+        TF_option const *op = iter.data()->asTF_optionC();
+
+        if (op->name.equals("visitor")) {
+          grabOptionName("visitor", visitorName, op);
+        }
+        else if (op->name.equals("dvisitor")) {
+          grabOptionName("dvisitor", dvisitorName, op);
+        }
+        else if (op->name.equals("xmlVisitor")) {
+          grabOptionName("xmlVisitor", xmlVisitorName, op);
+        }
+        else if (op->name.equals("xmlParser")) {
+          grabOptionName("xmlParser", xmlParserName, op);
+        }
+        else if (op->name.equals("mvisitor")) {
+          grabOptionName("mvisitor", mvisitorName, op);
+        }
+        else if (op->name.equals("identityManager")) {
+          grabOptionName("identityManager", identityManagerName, op);
+        }
+        else if (op->name.equals("gdb")) {
+          wantGDB = true;
+        }
+        else {
+          xfatal("unknown option: " << op->name);
+        }
+      }
+
+      else if (iter.data()->isTF_class()) {
+        allClasses.prepend(iter.data()->asTF_class());
+      }
+    }
+  }
+
+  // I built it in reverse for O(n) performance
+  allClasses.reverse();
+
+  // generate the header
+  string base = replace(srcFname, ".ast", "");
+  if (basename) {
+    base = basename;
+  }
+
+  // get all of the list classes
+  getListClasses();
+
+  // dsw: I want a way to generate just the parser and nothing else;
+  // this separation into two blocks suggests that parsing the ast
+  // file and generating something from it should perhaps be separated
+  // into two parts
+  if (!tracingSys("no_ast.gen")) {
+    string hdrFname = base & ".h";
+    HGen hg(srcFname, modules, hdrFname, *ast);
+    cout << "writing " << hdrFname << "...\n";
+    hg.emitFile();
+
+    // generated the c++ code
+    string codeFname = base & ".cc";
+    CGen cg(srcFname, modules, codeFname, *ast, hdrFname);
+    cout << "writing " << codeFname << "...\n";
+    cg.emitFile();
+
+    // dsw: the xml parser stuff won't use the custom sections, so
+    // this generates a lot of spurious warnings if I put it outside
+    // of this block
+    //
+    // check for any unused 'custom' sections; a given section is only
+    // used if one of the generation routines asks for it by name, so
+    // a mistyped custom section name would not yet have been noticed
+    {
+      SFOREACH_OBJLIST(TF_class, allClasses, iter) {
+        TF_class const *c = iter.data();
+        checkUnusedCustoms(c->super);
+
+        FOREACH_ASTLIST(ASTClass, c->ctors, subIter) {
+          checkUnusedCustoms(subIter.data());
+        }
+      }
+
+      FOREACH_ASTLIST(ToplevelForm, ast->forms, iter2) {
+        if (iter2.data()->isTF_custom()) {
+          CustomCode const *cc = iter2.data()->asTF_customC()->cust;
+          if (cc->used == false) {
+            cout << "warning: unused custom code `" << cc->qualifier << "'\n";
+          }
+        }
+      }
+    }
+  }
+
+  // dsw: this is really completely independent of the other generated
+  // files
+  if (tracingSys("xmlParser") && wantXmlParser()) {
+    XmlParserGen xgen(xmlParserName);
+    xgen.emitXmlParserImplementation();
+  }
+}
+
+ARGS_MAIN

Added: vendor/elsa/current/ast/asthelp.cc
===================================================================
--- vendor/elsa/current/ast/asthelp.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/asthelp.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,78 @@
+// asthelp.cc            see license.txt for copyright and terms of use
+// code for what's declared in asthelp.h
+
+#include "asthelp.h"       // this module
+#include "strutil.h"       // quoted
+#include "exc.h"           // xformat
+
+
+// ----------- debugPrint helpers -----------------------
+ostream &ind(ostream &os, int indent)
+{
+  while (indent--) {
+    os << " ";
+  }
+  return os;
+}
+
+
+void debugPrintStr(string const &s, char const *name,
+                   ostream &os, int indent)
+{
+  debugPrintStr(s.c_str(), name, os, indent);
+}
+
+void debugPrintStr(char const *s, char const *name,
+                   ostream &os, int indent)
+{
+  string s1((s) ? string(s) : string("NULL"));
+  ind(os, indent) << name << " = " << quoted(s1) << "\n";
+}
+
+
+void debugPrintCStr(char const *s, char const *name,
+                    ostream &os, int indent)
+{
+  ind(os, indent) << name << " = ";
+  if (s) {
+    os << quoted(s);
+  }
+  else {
+    os << "(null)";
+  }
+  os << "\n";
+}
+
+
+template <class STR>
+void debugPrintStringList(ASTList<STR> const &list, char const *name,
+                          ostream &os, int indent)
+{
+  ind(os, indent) << name << ": ";
+  {
+    int ct=0;
+    FOREACH_ASTLIST(STR, list, iter) {
+      if (ct++ > 0) {
+        os << ", ";
+      }
+      os << quoted(string(*( iter.data() )));
+    }
+  }
+  os << "\n";
+}
+
+
+void debugPrintList(ASTList<string> const &list, char const *name,
+                    ostream &os, int indent)
+{
+  debugPrintStringList(list, name, os, indent);
+}
+
+void debugPrintList(ASTList<LocString> const &list, char const *name,
+                    ostream &os, int indent)
+{
+  debugPrintStringList(list, name, os, indent);
+}
+
+
+// EOF

Added: vendor/elsa/current/ast/asthelp.h
===================================================================
--- vendor/elsa/current/ast/asthelp.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/asthelp.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,322 @@
+// asthelp.h            see license.txt for copyright and terms of use
+// included by generated ast code
+
+#ifndef ASTHELP_H
+#define ASTHELP_H
+
+#include "astlist.h"     // ASTList
+#include "fakelist.h"    // FakeList
+#include "str.h"         // string
+#include "locstr.h"      // LocString
+
+#include <iostream.h>    // ostream
+
+// ----------------- downcasts --------------------
+// the 'if' variants return NULL if the type isn't what's expected;
+// the 'as' variants throw an exception in that case
+#define DECL_AST_DOWNCASTS(type, tag)            \
+  type const *if##type##C() const;               \
+  type *if##type()                               \
+    { return const_cast<type*>(if##type##C()); } \
+  type const *as##type##C() const;               \
+  type *as##type()                               \
+    { return const_cast<type*>(as##type##C()); } \
+  bool is##type() const                          \
+    { return kind() == tag; }
+
+
+#define DEFN_AST_DOWNCASTS(superclass, type, tag)\
+  type const *superclass::if##type##C() const    \
+  {                                              \
+    if (kind() == tag) {                         \
+      return (type const*)this;                  \
+    }                                            \
+    else {                                       \
+      return NULL;                               \
+    }                                            \
+  }                                              \
+                                                 \
+  type const *superclass::as##type##C() const    \
+  {                                              \
+    xassert(kind() == tag);                      \
+    return (type const*)this;                    \
+  }
+
+
+// ------------------- const typecase --------------------
+#define ASTSWITCHC(supertype, nodeptr)           \
+{                                                \
+  supertype const *switch_nodeptr = (nodeptr);   \
+  switch (switch_nodeptr->kind())
+
+#define ASTCASEC(type, var)                           \
+  case type::TYPE_TAG: {                              \
+    type const *var = switch_nodeptr->as##type##C();
+
+// the "1" versions mean "one argument", i.e. they
+// do not bind a variable of the specified type
+#define ASTCASEC1(type)                               \
+  case type::TYPE_TAG: {
+
+#define ASTNEXTC(type, var)                           \
+    break;                                            \
+  } /* end previous case */                           \
+  case type::TYPE_TAG: {                              \
+    type const *var = switch_nodeptr->as##type##C();
+
+#define ASTNEXTC1(type)                               \
+    break;                                            \
+  } /* end previous case */                           \
+  case type::TYPE_TAG: {
+
+// end a case, and add an empty 'default' construct
+#define ASTENDCASECD                                  \
+    break;                                            \
+  } /* end final case */                              \
+  default: ;    /* silence warning */                 \
+} /* end scope started before switch */
+
+#define ASTDEFAULTC                                   \
+    break;                                            \
+  } /* end final case */                              \
+  default: {
+
+// end a case where an explicit default was present, or
+// there is no need to add one (e.g. because it was exhaustive)
+#define ASTENDCASEC                                   \
+    break;                                            \
+  } /* end final case */                              \
+} /* end scope started before switch */
+
+
+// ------------------- non-const typecase --------------------
+#define ASTSWITCH(supertype, nodeptr)            \
+{                                                \
+  supertype *switch_nodeptr = (nodeptr);         \
+  switch (switch_nodeptr->kind())
+
+#define ASTCASE(type, var)                            \
+  case type::TYPE_TAG: {                              \
+    type *var = switch_nodeptr->as##type();
+
+#define ASTCASE1(type)                                \
+  case type::TYPE_TAG: {
+
+#define ASTNEXT(type, var)                            \
+    break;                                            \
+  } /* end previous case */                           \
+  case type::TYPE_TAG: {                              \
+    type *var = switch_nodeptr->as##type();
+
+#define ASTNEXT1(type)                                \
+    break;                                            \
+  } /* end previous case */                           \
+  case type::TYPE_TAG: {
+
+// end-of-switch behavior is same as in const case
+#define ASTENDCASED ASTENDCASECD
+#define ASTDEFAULT ASTDEFAULTC
+#define ASTENDCASE ASTENDCASEC
+
+
+// ------------------- const parallel typecase --------------------
+// nodeptr1 and nodeptr2 should already be known to have the same kind
+#define ASTSWITCH2C(supertype, nodeptr1, nodeptr2)      \
+{                                                       \
+  supertype const *switch_nodeptr1 = (nodeptr1);        \
+  supertype const *switch_nodeptr2 = (nodeptr2);        \
+  switch (switch_nodeptr1->kind())
+
+#define ASTCASE2C(type, var1, var2)                     \
+  case type::TYPE_TAG: {                                \
+    type const *var1 = switch_nodeptr1->as##type##C();  \
+    type const *var2 = switch_nodeptr2->as##type##C();
+
+#define ASTCASE2C1(type)                                \
+  case type::TYPE_TAG: {
+
+#define ASTNEXT2C(type, var1, var2)                     \
+    break;                                              \
+  } /* end previous case */                             \
+  case type::TYPE_TAG: {                                \
+    type const *var1 = switch_nodeptr1->as##type##C();  \
+    type const *var2 = switch_nodeptr2->as##type##C();
+
+#define ASTNEXT2C1(type)                                \
+    break;                                              \
+  } /* end previous case */                             \
+  case type::TYPE_TAG: {
+
+// same invocation syntax as ASTNEXT2C but without actually
+// declaring the variables because they are unused
+#define ASTNEXT2CU(type, var1, var2)                    \
+    break;                                              \
+  } /* end previous case */                             \
+  case type::TYPE_TAG: {
+
+#define ASTENDCASE2CD                                   \
+    break;                                              \
+  } /* end final case */                                \
+  default: ;    /* silence warning */                   \
+} /* end scope started before switch */
+
+#define ASTDEFAULT2C                                    \
+    break;                                              \
+  } /* end final case */                                \
+  default: {
+
+#define ASTENDCASE2C                                    \
+    break;                                              \
+  } /* end final case */                                \
+} /* end scope started before switch */
+
+
+
+// ------------------- debug print helpers -----------------
+ostream &ind(ostream &os, int indent);
+
+// I occasionally want to see addresses, so I just throw this
+// switch and recompile..
+#if 1
+  // headers w/o addresses
+  #define PRINT_HEADER(subtreeName, clsname)                 \
+    ind(os, indent) << subtreeName << " = " #clsname ":\n";  \
+    indent += 2   /* user ; */
+#else
+  // headers w/ addresses
+  #define PRINT_HEADER(subtreeName, clsname)                                           \
+    ind(os, indent) << subtreeName << " = " #clsname " (" << ((void*)this) << "):\n";  \
+    indent += 2   /* user ; */
+#endif
+
+
+#define PRINT_STRING(var) \
+  debugPrintStr((var), #var, os, indent)    /* user ; */
+
+void debugPrintStr(string const &s, char const *name,
+                   ostream &os, int indent);
+void debugPrintStr(char const *s, char const *name,
+                   ostream &os, int indent);
+
+
+#define PRINT_CSTRING(var) \
+  debugPrintCStr(var, #var, os, indent)    /* user ; */
+
+void debugPrintCStr(char const *s, char const *name,
+                    ostream &os, int indent);
+
+
+#define PRINT_LIST(T, list) \
+  debugPrintList(list, #list, os, indent)     /* user ; */
+
+template <class T>
+void debugPrintList(ASTList<T> const &list, char const *name,
+                    ostream &os, int indent)
+{
+  ind(os, indent) << name << ":\n";
+  int ct=0;
+  {
+    FOREACH_ASTLIST(T, list, iter) {
+      iter.data()->debugPrint(os, indent+2,
+        stringc << name << "[" << ct++ << "]");
+    }
+  }
+}
+
+// provide explicit specialization for strings
+void debugPrintList(ASTList<string> const &list, char const *name,
+                    ostream &os, int indent);
+void debugPrintList(ASTList<LocString> const &list, char const *name,
+                    ostream &os, int indent);
+
+
+#define PRINT_FAKE_LIST(T, list) \
+  debugPrintFakeList(list, #list, os, indent)     /* user ; */
+
+template <class T>
+void debugPrintFakeList(FakeList<T> const *list, char const *name,
+                        ostream &os, int indent)
+{
+  ind(os, indent) << name << ":\n";
+  int ct=0;
+  {
+    FAKELIST_FOREACH(T, list, iter) {
+      iter->debugPrint(os, indent+2,
+        stringc << name << "[" << ct++ << "]");
+    }
+  }
+}
+
+// note that we never make FakeLists of strings, since of course
+// strings do not have a 'next' pointer
+
+
+#define PRINT_SUBTREE(tree)                     \
+  if (tree) {                                   \
+    (tree)->debugPrint(os, indent, #tree);      \
+  }                                             \
+  else {                                        \
+    ind(os, indent) << #tree << " is null\n";   \
+  } /* user ; (optional) */
+
+
+#define PRINT_GENERIC(var) \
+  ind(os, indent) << #var << " = " << ::toString(var) << "\n"   /* user ; */
+
+
+#define PRINT_BOOL(var) \
+  ind(os, indent) << #var << " = " << (var? "true" : "false") << "\n"   /* user ; */
+
+
+// ---------------------- deep-copy ------------------
+// returns a new'd list because the AST node ctors want
+// to accept an owner ptr to a list
+template <class T>
+ASTList<T> * /*owner*/ cloneASTList(ASTList<T> const &src)
+{
+  ASTList<T> *ret = new ASTList<T>;
+
+  FOREACH_ASTLIST(T, src, iter) {
+    ret->append(iter.data()->clone());
+  }
+
+  return ret;
+}
+
+
+// returns owner pointer to list of serfs.. using this isn't ideal
+// because ASTList normally is owning, and probably deletes its
+// elements in its destructor..
+template <class T>
+ASTList<T> * /*owner*/ shallowCloneASTList(ASTList<T> const &src)
+{
+  ASTList<T> *ret = new ASTList<T>;
+
+  FOREACH_ASTLIST(T, src, iter) {
+    // list backbone is const, but nodes' constness leaks away..
+    ret->append(const_cast<T*>(iter.data()));
+  }
+
+  return ret;
+}
+
+
+// deep copy of a FakeList
+template <class T>
+FakeList<T> * /*owner*/ cloneFakeList(FakeList<T> const *src)
+{
+  if (!src) {
+    return FakeList<T>::emptyList();     // base case of recursion
+  }
+
+  // clone first element
+  T *head = src->firstC()->clone();
+  xassert(head->next == NULL);     // it had better not copy the list tail itself!
+
+  // attach to result of cloning the tail
+  FakeList<T> *tail = cloneFakeList(src->butFirstC());
+  return tail->prepend(head);
+}
+
+
+#endif // ASTHELP_H

Added: vendor/elsa/current/ast/ccsstr.cc
===================================================================
--- vendor/elsa/current/ast/ccsstr.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/ccsstr.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,360 @@
+// ccsstr.cc            see license.txt for copyright and terms of use
+// code for ccsstr.h
+
+#include "ccsstr.h"      // this module
+#include "xassert.h"     // xassert
+#include "exc.h"         // xformat
+#include "strutil.h"     // string, replace
+#include "reporterr.h"   // silentReportError
+
+#include <iostream.h>    // cout
+#include <ctype.h>       // isspace
+
+
+CCSubstrate::CCSubstrate(ReportError *err)
+  : EmbeddedLang(err)
+{
+  reset();
+}
+
+void CCSubstrate::reset(int initNest)
+{
+  state = ST_NORMAL;
+  nesting = initNest;
+  backslash = false;
+  star = false;
+  text.setlength(0);
+}
+
+
+CCSubstrate::~CCSubstrate()
+{}
+
+
+void CCSubstrate::handle(char const *str, int len, char finalDelim)
+{
+  text.append(str, len);
+
+  for (; len>0; len--,str++) {
+    switch (state) {
+      case ST_NORMAL:
+        switch (*str) {
+          case '{':
+          case '(':
+          case '[':
+            nesting++;
+            break;
+
+          case '}':
+          case ')':
+          case ']':
+            if (nesting == 0) {
+              err->reportError(stringc
+                << "unexpected closing delimiter `" << *str
+                << "' -- probably due to missing `" << finalDelim << "'");
+            }
+            else {
+              nesting--;
+            }
+            break;
+
+          case '\"':
+            state = ST_STRING;
+            break;
+
+          case '\'':
+            state = ST_CHAR;
+            break;
+
+          case '/':
+            state = ST_SLASH;
+            break;
+        }
+        break;
+
+      case ST_STRING:
+      case ST_CHAR:
+        if (!backslash) {
+          if ((state == ST_STRING && *str == '\"') ||
+              (state == ST_CHAR && *str == '\'')) {
+            state = ST_NORMAL;
+          }
+          else if (*str == '\\') {
+            backslash = true;
+          }
+          else if (*str == '\n') {
+            err->reportError("unterminated string or char literal");
+          }
+        }
+        else {
+          backslash = false;
+        }
+        break;
+
+      case ST_SLASH:
+        if (*str == '*') {
+          state = ST_C_COMMENT;
+        }
+        else if (*str == '/') {
+          state = ST_CC_COMMENT;
+        }
+        else {
+          state = ST_NORMAL;
+        }
+        break;
+
+      case ST_C_COMMENT:
+        if (!star) {
+          if (*str == '*') {
+            star = true;
+          }
+        }
+        else {
+          star = false;
+          if (*str == '/') {
+            state = ST_NORMAL;
+          }
+        }
+        break;
+
+      case ST_CC_COMMENT:
+        // I don't like the possibility of escaped newlines
+        // in C++ comments, so I don't support it (so there!)
+        if (*str == '\n') {
+          state = ST_NORMAL;
+        }
+        break;
+
+      default:
+        xfailure("unknown state");
+    }
+  }
+}
+
+
+bool CCSubstrate::zeroNesting() const
+{
+  return (state == ST_NORMAL || state == ST_SLASH) &&
+         nesting == 0;
+}
+
+
+string CCSubstrate::getFuncBody() const
+{
+  if (isDeclaration) {
+    // I used to be appending ';' here, but now I need the flexibility to
+    // add additional test before it, so I will rely on the caller to add
+    // semicolons where necessary
+    return text;
+  }
+  else if (exprOnly) {
+    return stringc << "return " << text << ";";
+  }
+  else {
+    return text;
+  }
+}
+
+
+string CCSubstrate::getDeclName() const
+{
+  // go with the rather inelegant heuristic that the word
+  // just before the first '(' is the function's name
+  char const *start = text.c_str();
+  char const *p = start;
+  
+  // find first '('
+  while (*p && *p!='(') { p++; }
+  if (!*p) {
+    xformat("missing '('");
+  }             
+  if (p == start) {
+    xformat("missing name");
+  }
+
+  // skip backward past any whitespace before the '('
+  p--;
+  while (p>=start && isspace(*p)) { p--; }
+  if (p<start) {
+    xformat("missing name");
+  }
+  char const *nameEnd = p+1;    // char just past last
+  
+  // move backward through the name
+  while (p>=start && 
+         (isalnum(*p) || *p=='_'))
+    { p--; }
+  p++;    // move back to most recent legal char
+  
+  // done
+  return substring(p, nameEnd-p);
+}
+
+
+// ------------------ test code -------------------
+#ifdef TEST_CCSSTR
+
+#define CC CCSubstrate
+#define Test CCSubstrateTest
+
+// test code is put into a class just so that CCSubstrate
+// can grant it access to private fields
+class Test {
+public:
+  void feed(CC &cc, rostring src);
+  void test(rostring src, CC::State state, int nesting, bool flag);
+  void normal(rostring src, int nesting);
+  void str(rostring src, int nesting, bool bs);
+  void yes(rostring src);
+  void no(rostring src);
+  void name(rostring body, rostring n);
+  void badname(rostring body);
+  int main();
+};
+
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+void Test::feed(CC &cc, rostring origSrc)
+{
+  char const *src = toCStr(origSrc);
+
+  //cout << "trying: " << src << endl;
+  while (*src) {
+    // feed it in 10 char increments, to test split processing too
+    int len = min(strlen(src), 10);
+    cc.handle(src, len, '}');
+    src += len;
+  }
+}
+
+
+void Test::test(rostring src, CC::State state, int nesting, bool flag)
+{
+  CC cc(&silentReportError);
+  feed(cc, src);
+
+  if (!( cc.state == state &&
+         cc.nesting == nesting &&
+         (state==CC::ST_C_COMMENT? cc.star==flag :
+                                   cc.backslash==flag) )) {
+    xfailure(stringc << "failed on src: " << src);
+  }
+}
+
+
+void Test::normal(rostring src, int nesting)
+{
+  test(src, CC::ST_NORMAL, nesting, false);
+}
+
+void Test::str(rostring src, int nesting, bool bs)
+{
+  test(src, CC::ST_STRING, nesting, bs);
+
+  // repeat the test with single-tick
+  string another = replace(src, "\"", "\'");
+  test(another, CC::ST_CHAR, nesting, bs);
+}
+
+
+void Test::yes(rostring src)
+{
+  CC cc(&silentReportError);
+  feed(cc, src);
+
+  xassert(cc.zeroNesting());
+}
+
+void Test::no(rostring src)
+{
+  CC cc(&silentReportError);
+  feed(cc, src);
+
+  xassert(!cc.zeroNesting());
+}
+
+void Test::name(rostring body, rostring n)
+{
+  CC cc(&silentReportError);
+  feed(cc, body);
+  xassert(cc.getDeclName().equals(n));
+}
+
+void Test::badname(rostring body)
+{
+  CC cc(&silentReportError);
+  feed(cc, body);
+  try {
+    cc.getDeclName();
+    xfailure("got a name when it shoudn't have!");
+  }
+  catch (...)
+    {}
+}
+
+
+int Test::main()
+{
+  // quiet!
+  xBase::logExceptions = false;
+
+  normal("int main()", 0);
+  normal("int main() { hi", 1);
+  normal("int main() { hi {", 2);
+  normal("int main() { hi { foo[5", 3);
+  normal("int main() { hi { foo[5] and ", 2);
+  normal("int main() { hi { foo[5] and } bar ", 1);
+  normal("int main() { hi { foo[5] and } bar } baz ", 0);
+
+  normal("main() { printf(\"hello \\ world\"); ret", 1);
+
+  normal("()[]{}([{}])", 0);
+  normal("{ ()[]{}([{}]) } ", 0);
+  normal("( ()[]{}([{}]) )", 0);
+  normal("[ ()[]{}([{}]) ]", 0);
+  normal("\"foo\" ()[]{}([{}])", 0);
+
+  str("main() { printf(\"hello", 2, false);
+  str("main() { printf(\"hello \\", 2, true);
+  str("main() { printf(\"hello \\ world", 2, false);
+  str("main() { printf(\"hello \\ world\", \"hi", 2, false);
+
+  test("\"a\" 'b' (", CC::ST_NORMAL, 1, false);
+
+  yes("main() {}");
+  yes("main() { printf(\"foo\", 3, 4 /*yep{*/); }");
+  yes("some // junk {\n more");
+  yes("'\\''");
+  yes("\"\\\"\"");
+  yes("[][][][][]");
+  yes("\"[[[\"");
+  yes("*");
+  yes("/* [ /* [ */");
+
+  no("\"");
+  no("(");
+  no(" ( /* ) */ ");
+
+  name("int main()", "main");
+  name("int eval(Environment &env)", "eval");
+  name("man()", "man");
+  badname("(");
+  badname("  (");
+  badname("  ");
+  badname("");
+  badname(")");
+  badname("main");
+
+  cout << "\nccsstr: all tests PASSED\n";
+
+  return 0;
+}
+
+int main()
+{
+  Test t;
+  return t.main();
+}
+
+#endif // TEST_CCSSTR

Added: vendor/elsa/current/ast/ccsstr.h
===================================================================
--- vendor/elsa/current/ast/ccsstr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/ccsstr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// ccsstr.h            see license.txt for copyright and terms of use
+// C++ substrate for my parser
+
+#ifndef CCSSTR_H
+#define CCSSTR_H
+
+#include "embedded.h"      // EmbeddedLang
+
+class CCSubstrateTest;
+
+class CCSubstrate : public EmbeddedLang {
+private:
+  enum State {
+    ST_NORMAL,       // normal text
+    ST_STRING,       // inside a string literal
+    ST_CHAR,         // inside a char literal
+    ST_SLASH,        // from ST_NORMAL, just saw a slash
+    ST_C_COMMENT,    // inside a C comment
+    ST_CC_COMMENT,   // inside a C++ comment
+    NUM_STATES
+  } state;
+  int nesting;       // depth of paren/bracket/brace nesting
+  bool backslash;    // in ST_{STRING,CHAR}, just seen backslash?
+  bool star;         // in ST_C_COMMENT, just seen '*'?
+
+  // so test code can interrogate internal state
+  friend class CCSubstrateTest;
+
+public:
+  CCSubstrate(ReportError *err = NULL);
+  virtual ~CCSubstrate();
+
+  // EmbeddedLang entry points (see embedded.h for description
+  // of each function)
+  virtual void reset(int initNest = 0);
+  virtual void handle(char const *str, int len, char finalDelim);
+  virtual bool zeroNesting() const;
+  virtual string getFuncBody() const;
+  virtual string getDeclName() const;
+};
+
+#endif // CCSSTR_H

Added: vendor/elsa/current/ast/configure.pl
===================================================================
--- vendor/elsa/current/ast/configure.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/configure.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,120 @@
+#!/usr/bin/perl -w
+# configure script for ast
+
+use strict 'subs';
+
+# default location of smbase relative to this package
+$SMBASE = "../smbase";
+$req_smcv = 1.03;            # required sm_config version number
+$thisPackage = "ast";
+
+# -------------- BEGIN common block ---------------
+# do an initial argument scan to find if smbase is somewhere else
+for (my $i=0; $i < @ARGV; $i++) {
+  my ($d) = ($ARGV[$i] =~ m/-*smbase=(.*)/);
+  if (defined($d)) {
+    $SMBASE = $d;
+  }
+}
+
+# try to load the sm_config module
+eval {
+  push @INC, ($SMBASE);
+  require sm_config;
+};
+if ($@) {
+  die("$@" .     # ends with newline, usually
+      "\n" .
+      "I looked for smbase in \"$SMBASE\".\n" .
+      "\n" .
+      "You can explicitly specify the location of smbase with the -smbase=<dir>\n" .
+      "command-line argument.\n");
+}
+
+# check version number
+$smcv = get_sm_config_version();
+if ($smcv < $req_smcv) {
+  die("This package requires version $req_smcv of sm_config, but found\n" .
+      "only version $smcv.\n");
+}
+# -------------- END common block ---------------
+
+
+sub usage {
+  standardUsage();
+
+  print(<<"EOF");
+package options:
+  -prof              enable profiling
+  -devel             add options useful while developing
+EOF
+}
+
+
+# -------------- BEGIN common block 2 -------------
+# global variables holding information about the current command-line
+# option being processed
+$option = "";
+$value = "";
+
+# process command-line arguments
+foreach $optionAndValue (@ARGV) {
+  # ignore leading '-' characters, and split at first '=' (if any)
+  ($option, $value) =
+    ($optionAndValue =~ m/^-*([^-][^=]*)=?(.*)$/);
+                      #      option     = value
+
+  my $arg = $option;
+
+  if (handleStandardOption()) {
+    # handled by sm_config.pm
+  }
+  # -------------- END common block 2 -------------
+
+  elsif ($arg eq "prof") {
+    push @CCFLAGS, "-pg";
+  }
+
+  elsif ($arg eq "devel") {
+    push @CCFLAGS, "-Werror";
+  }
+
+  else {
+    die "unknown option: $arg\n";
+  }
+}
+
+finishedOptionProcessing();
+
+
+# ------------------ check for needed components ----------------
+test_smbase_presence();
+
+test_CXX_compiler();
+
+$PERL = get_PERL_variable();
+
+
+# ------------------ config.summary -----------------
+$summary = getStandardConfigSummary();
+writeConfigSummary($summary);
+
+
+# ------------------- config.status ------------------
+writeConfigStatus("PERL" => "$PERL");
+
+
+# ----------------- final actions -----------------
+# run the output file generator
+run("./config.status");
+
+print("\nYou can now run make, usually called 'make' or 'gmake'.\n");
+
+exit(0);
+
+
+# silence warnings
+pretendUsed($thisPackage);
+
+
+# EOF


Property changes on: vendor/elsa/current/ast/configure.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/ast/demo.ast
===================================================================
--- vendor/elsa/current/ast/demo.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/demo.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// demo.ast
+// demonstrates basic ast concepts; for the documentation
+
+class Root(A a, B b);
+
+class A {
+  -> A_one(string name);
+  -> A_two(B b);
+}
+
+class B(string name) {
+  public int x = 0;
+
+  -> B_one(int y);
+  -> B_two(char c);
+}

Added: vendor/elsa/current/ast/embedded.cc
===================================================================
--- vendor/elsa/current/ast/embedded.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/embedded.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// embedded.cc            see license.txt for copyright and terms of use
+// code for embedded.h
+
+#include "embedded.h"     // EmbeddedLang
+
+EmbeddedLang::EmbeddedLang(ReportError *e)
+  : err(e? e : &simpleReportError),
+    text(),
+    exprOnly(false),
+    isDeclaration(false)
+{}
+
+EmbeddedLang::~EmbeddedLang()
+{}

Added: vendor/elsa/current/ast/embedded.h
===================================================================
--- vendor/elsa/current/ast/embedded.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/embedded.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,58 @@
+// embedded.h            see license.txt for copyright and terms of use
+// interface to an embedded language processor
+
+#ifndef EMBEDDED_H
+#define EMBEDDED_H
+
+#include "str.h"        // stringBuilder
+#include "reporterr.h"  // ReportError
+
+class EmbeddedLang {
+public:
+  // for reporting errors
+  ReportError *err;
+
+  // all text processed so far; it collects the
+  // embedded code; clients will call 'handle' a
+  // bunch of times and then expect to retrieve
+  // the text from here
+  stringBuilder text;
+
+  // when true (set by the lexer), the 'text' is to
+  // be interpreted as an expression, rather than a
+  // complete function body; this affects what
+  // getFuncBody() returns
+  bool exprOnly;
+
+  // when true the text is a declaration, so we have to
+  // add a single semicolon
+  bool isDeclaration;
+
+public:
+  EmbeddedLang(ReportError *err = NULL /*print to stdout*/);
+  virtual ~EmbeddedLang();    // silence warning
+
+  // start from scratch
+  virtual void reset(int initNest = 0) = 0;
+
+  // process the given string of characters, as source text in
+  // the embedded language; 'finalDelim' is provided for printing
+  // informative error messages
+  virtual void handle(char const *str, int len, char finalDelim) = 0;
+
+  // return true if we're at a nesting level of zero
+  // and not in a string, etc. -- characters at this
+  // level have "usual" meaning
+  virtual bool zeroNesting() const = 0;
+
+  // return the body of the embedded function; should
+  // always return a complete function body, even when
+  // exprOnly is true (by adding to 'text' if necessary)
+  virtual string getFuncBody() const = 0;
+
+  // return the name of the declared function, assuming
+  // that is the context in which 'text' was collected
+  virtual string getDeclName() const = 0;
+};
+
+#endif // EMBEDDED_H

Added: vendor/elsa/current/ast/example.ast
===================================================================
--- vendor/elsa/current/ast/example.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/example.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,117 @@
+// example.ast            see license.txt for copyright and terms of use
+// demonstrate a few features; I use this a testbed for features
+
+verbatim {
+  // first verbatim in example.ast
+}
+
+// I want a visitor, with the interface called ExampleVisitor
+option visitor ExampleVisitor;
+option mvisitor ExampleMVisitor;
+option dvisitor ExampleDVisitor;
+
+// add a field to the visitor
+custom ExampleVisitor {
+public:
+  int someVisitorField;
+}
+
+// initialize it...
+custom ExampleVisitor_ctor { someVisitorField = 0; }
+
+// dsw: these turn on the xml serialization and de-serialization code
+option xmlVisitor ToXmlASTVisitor;
+// Scott says:
+// for the moment I just want this so I can test to/fromXML
+// code for enums
+option xmlParser example_xml;
+
+// and gdb
+option gdb;
+
+
+
+class Node (
+  int x,
+  int y
+) {
+  public Node *next;
+  ctor next=NULL;
+  
+  public(field) int w = 3;
+  public FakeList<Node> *listptr = NULL;
+
+  custom traverse { next->traverse(vis); }
+  custom mtraverse { mtraverse(obj->next); }
+}
+
+class NodeList (
+  FakeList<Node> *list
+);
+
+
+class AnotherList (
+  ASTList<Node> list2,
+  LocString str
+);
+
+
+class Super (int x) {
+  protected(virtual) int foo();
+
+  public(owner) int *p = NULL;
+
+  public(virtual) int onlyInSubclasses() = 0;
+  public(virtual) int everywhere();
+
+  -> Sub1(int y);
+  -> Sub2(int z);
+  -> SubWithDefault(int q = 5);
+  -> Sub3(Super s1, Sub2 s2);
+}
+
+// 2005-03-25: Changed this from two enumerators to three, because
+// gcc-3.4.0 emits an unusual warning in the toString method if
+// the enumerator only has two elements.  This warning is not
+// emitted by gcc-3.4.3...
+enum AnEnum { AE_ONE, AE_TWO, AE_THREE };
+
+// eliminated explicit enumerator values...
+enum AnotherEnum {
+  anotherone,
+  anothertwo,
+  anotherthree
+};
+
+class UsesEnum {
+  -> UE_a(AnEnum x);
+  -> UE_b(int y);
+}
+
+verbatim {
+  class Base1 {};
+  class Base2 {};
+  class Base3 {};
+}
+
+class InheritsSomething : public Base1 {
+  -> IS_a(int z) : public Base2 ;
+  -> IS_b(int q) : public Base3 {
+       public float f;
+     }
+  -> IS_c(int ret);       // testing ctor arg with name 'ret'
+  -> IS_d(UsesEnum ret);  // another
+}
+
+class HasLastArgs(int x)(int w) {
+  -> Hla1(int y);
+  -> Hla2(int y, int z);
+}
+
+class SomethingElse(int x, int y) {
+  custom substituteClone 
+    { return new SomethingElse(x,y); /*my own clone() code*/ }
+}
+
+
+// EOF

Added: vendor/elsa/current/ast/exampletest.cc
===================================================================
--- vendor/elsa/current/ast/exampletest.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/exampletest.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,43 @@
+// Test printing the example.
+// Daniel S. Wilkerson
+
+#include "example.h"
+#include "../smbase/astlist.h"
+#include "../smbase/objlist.h"
+#include "locstr.h"
+
+int main() {
+  // **** build the thing
+  FakeList<Node> *fl0;          // build in reverse
+  Node *n1 = new Node(1,101);
+  fl0 = FakeList<Node>::makeList(n1);
+  Node *n0 = new Node(0,100);
+  fl0 = fl0->prepend(n0);
+  NodeList *nl0 = new NodeList(fl0);
+
+  Node *n10 = new Node(10,110);
+  Node *n20 = new Node(20,120);
+  ASTList<Node> *astl0 = new ASTList<Node>();
+  astl0->append(n10);
+  astl0->append(n20);
+  LocString *loc0 = new LocString(SourceLocation(FileLocation(200,201), new SourceFile("there0")),
+                                  "somefilename");
+  AnotherList *al0 = new AnotherList(astl0, loc0);
+
+  Super *s3 = new Sub1(3, 103);
+
+  Super *s4 = new Sub2(4, 104);
+
+  // **** render it into xml
+  cout << "**************** first" << endl;
+  nl0->xmlPrint(cout,0);
+  cout << "**************** second" << endl;
+  al0->xmlPrint(cout,0);
+  cout << "**************** third" << endl;
+  s3->xmlPrint(cout,0);
+  cout << "**************** fourth" << endl;
+  s4->xmlPrint(cout,0);
+  cout << "**************** done" << endl;
+
+  return 0;
+}

Added: vendor/elsa/current/ast/ext1.ast
===================================================================
--- vendor/elsa/current/ast/ext1.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/ext1.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// ext1.ast
+// an extension module for example.ast
+
+// this should go before any classes in the generated file
+verbatim {
+  // first verbatim in ext1.ast
+}
+
+// another visitor?  now it's an error
+//option visitor ExtVisitor;
+
+class Node (int z) {
+  public int an_annotation;
+}
+
+class Super {
+  -> Sub3(int q);
+  -> Sub4 {
+       public int r;
+     }
+}
+
+class NodeList {
+  -> ASubclass(int x);
+}
+
+// you can extend a given nonterminal several times
+// in an extension file
+class NodeList {
+  -> AnotherSubclass(int x);
+}
+
+verbatim {
+  // verbatim before ANewClass
+}
+
+new class ANewClass(int foo);
+
+
+// extension of an enum
+enum AnEnum { AE_FOUR };

Added: vendor/elsa/current/ast/fakelist.h
===================================================================
--- vendor/elsa/current/ast/fakelist.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/fakelist.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,181 @@
+// fakelist.h            see license.txt for copyright and terms of use
+// headerless list of nodes where each node has a 'next' field
+
+#ifndef FAKELIST_H
+#define FAKELIST_H
+
+// idea: define a templatized class such that a pointer to
+// this class appears to present access to a list of the
+// underlying T objects; but in fact, the pointer is actually
+// a T pointer, and T contains a field called 'next' which
+// inductively defines the list contents.  then such a pointer
+// could be used to provide documentation of the presence of
+// the list (and not just one node), and a uniform (with other
+// list interfaces) syntactic interface, while hiding an
+// efficient representation
+
+// why not just insist that all objects be derived from some
+// base class, e.g. FakeListNode, that defines 'next'?  because
+// what is the type of 'next'?  it has to be FakeListNode*, but
+// then either it must be physically first, or else 'next' is
+// a pointer to the interior and I have to worry about whether
+// the casts to/from the outer type will be correctly offset; and
+// then getting to the next node requires a cast (the usual
+// problem with subtyping polymorphism)
+
+// for now, the list is non-owning (unless you call 'deallocNodes')
+
+class Some_undefined_class;
+
+template <class T>
+class FakeList {
+private:
+  // you can't create or delete one of these
+  FakeList();
+  ~FakeList();
+
+  // silence a silly egcs-1.1.2 warning (this class isn't defined)
+  friend class Some_undefined_class;
+
+  // this class has *no* data--an object of this type is
+  // never actually created!  instead we play with pointers
+  // to this "type", and cast to T* as necessary
+
+public:
+  // this is as much of a constructor as there is
+  static FakeList<T> *makeList(T *node) { return (FakeList<T>*)node; }
+  static FakeList<T> *emptyList()       { return NULL; }
+
+  // this will deallocate all the nodes in the list; the list itself
+  // is, therefore, also deallocated and should not be used after this
+  void deallocNodes();
+
+  // simple selectors
+  int count() const;
+  bool isEmpty() const                  { return this == NULL; }
+  bool isNotEmpty() const               { return !isEmpty(); }
+
+  // "car" in Lisp terminology
+  T *first()                            { return (T*)this; }
+  T const *firstC() const               { return (T const*)this; }
+
+  // "cdr" in Lisp terminology
+  FakeList<T> *butFirst()               { return makeList(first()->next); }
+  FakeList<T> const *butFirstC() const  { return makeList(firstC()->next); }
+
+  // similar to "cons" in Lisp terminology (but this doesn't allocate)
+  FakeList<T> *prepend(T *newHead)
+  {
+    // I'm going to be surprised if this is ever not true.. it's
+    // a potential problem in cc.gr, since I'm assuming there that
+    // 'newHead' is not already on any other lists...
+    //
+    // update: This does occasionally get triggered, because a node
+    // might get yielded to two contexts.  Failing this assertion is a
+    // symptom that the sharing needs to be more carefully managed.
+    // It's often the case that newHead->next in fact equals first()
+    // already, but if the client code wants to let that slide it's
+    // going to have to check itself; I don't want to silently allow
+    // accidental happens-to-not-change-anything overwriting down in
+    // this code.
+    xassert(newHead->next == NULL);
+
+    newHead->next = first();
+    return makeList(newHead);
+  }
+
+  // random access (linear time of course)
+  T const *nthC(int n) const;
+  T *nth(int n) { return const_cast<T*>(nthC(n)); }
+
+  // don't add an 'append' method; I think if you're trying to append
+  // with FakeLists then you're probably misusing them
+
+  // perhaps breaking the idea a little...
+  FakeList<T> *reverse();
+
+  // this class is deliberately sparse on methods for now, since I'm
+  // not sure what kind of manipulations I'll want, given that this
+  // class's purpose is fairly specialized (AST lists)
+};
+
+
+
+// I'm deliberately contradicting the convention elsewhere, where
+// "FOREACH" comes first; I think it should have come second to begin
+// with, and since this class isn't derived from any of the others
+// with the opposite convention, this is as good a place as any to
+// reverse it
+
+#define FAKELIST_FOREACH(NodeType, listPtr, nodePtrVar)   \
+  for (NodeType const *nodePtrVar = listPtr->firstC();    \
+       nodePtrVar != NULL;                                \
+       nodePtrVar = nodePtrVar->next)
+
+#define FAKELIST_FOREACH_NC(NodeType, listPtr, nodePtrVar)   \
+  for (NodeType *nodePtrVar = listPtr->first();              \
+       nodePtrVar != NULL;                                   \
+       nodePtrVar = nodePtrVar->next)
+
+
+template <class T>
+void FakeList<T>::deallocNodes()
+{
+  T *p = first();
+  while (p) {
+    T *next = p->next;
+
+    // just in case T's destructor thinks it owns 'next',
+    // nullify it since I'm going to dealloc it myself
+    p->next = NULL;
+    delete p;
+
+    p = next;
+  }
+}
+
+
+template <class T>
+int FakeList<T>::count() const
+{
+  int ct = 0;
+  FAKELIST_FOREACH(T, this, p) {
+    ct++;
+  }
+  return ct;
+}
+
+
+template <class T>
+T const *FakeList<T>::nthC(int n) const
+{
+  const FakeList<T> *p = this;
+  while (n > 0) {
+    p = p->butFirstC();  // segfaults if n is too small
+    n--;
+  }
+  return p->firstC();
+}
+
+
+template <class T>
+FakeList<T> *FakeList<T>::reverse()
+{
+  FakeList<T> *src = this;
+  FakeList<T> *dest = emptyList();
+
+  while (src->isNotEmpty()) {
+    // remove first element of 'src'
+    T *first = src->first();
+    src = src->butFirst();
+    first->next = NULL;
+
+    // put it at the head of 'dest'
+    dest = dest->prepend(first);
+  }
+
+  return dest;
+}
+
+
+#endif // FAKELIST_H

Added: vendor/elsa/current/ast/fileloc.cc
===================================================================
--- vendor/elsa/current/ast/fileloc.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/fileloc.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,146 @@
+// fileloc.cc            see license.txt for copyright and terms of use
+// code for fileloc.h
+
+#include "fileloc.h"       // this module
+#include "flatten.h"       // Flatten
+
+#include <string.h>        // streq
+
+
+// -------------------- FileLocation -----------------------------
+void FileLocation::xfer(Flatten &flat)
+{
+  flat.xferInt(line);
+  flat.xferInt(col);
+}
+
+
+string FileLocation::toString() const
+{
+  if (validLoc()) {
+    return stringc << "line " << line << ", col " << col;
+  }
+  else {
+    return string("(unknown loc)");
+  }
+}
+
+
+void FileLocation::advance(char const *text, int length)
+{ 
+  // can't advance an invalid location
+  xassert(validLoc());
+
+  char const *p = text;
+  char const *endp = text + length;
+  for (; p < endp; p++) {
+    if (*p == '\n') {      // new line
+      line++;
+      col = 1;
+    }
+    else {	      	   // ordinary character
+      col++;
+    }
+  }
+}
+
+
+void FileLocation::newLine()
+{
+  // can't advance an invalid location
+  xassert(validLoc());
+
+  line++;
+  col = firstColumn;
+}
+
+
+// ------------------- SourceFile --------------------
+SourceFile::~SourceFile()
+{}
+
+
+// ------------------- SourceLocation --------------------
+void SourceLocation::xfer(Flatten &flat)
+{
+  if (flat.writing()) { 
+    char *str = file? file->filename.pchar() : NULL;
+    flat.xferCharString(str);
+  }
+
+  else { // reading
+    char *str;
+    flat.xferCharString(str);
+
+    if (!str) {
+      file = NULL;
+    }
+    else {
+      // not null; allocate a new (if necessary) object in the global list
+      file = sourceFileList.open(str);
+      delete[] str;
+    }
+  }
+}
+
+
+char const *SourceLocation::fname() const
+{ 
+  if (file) {
+    return file->filename;
+  }
+  else {
+    return NULL;
+  }
+}
+
+string SourceLocation::oldToString() const
+{
+  if (fname()) {
+    return stringc << "file " << fname() << ", "
+                   << FileLocation::toString();
+  }
+  else {
+    return FileLocation::toString();
+  }
+}
+
+string SourceLocation::likeGccToString() const
+{
+  if (validLoc()) {
+    return stringc << fname() << ":" << line << ":" << col;
+  }
+  else {
+    return string("(?loc?)");
+  }
+}
+
+
+// ------------------- SourceFileList -----------------
+SourceFileList::SourceFileList()
+{}
+
+SourceFileList::~SourceFileList()
+{}
+
+
+SourceFile *SourceFileList::open(char const *fname)
+{
+  // check for an existing SourceFile
+  MUTATE_EACH_OBJLIST(SourceFile, files, iter) {
+    if (streq(iter.data()->filename, fname)) {
+      // found match
+      return iter.data();
+    }
+  }
+
+  // make a new one
+  SourceFile *ret = new SourceFile(fname);
+  files.append(ret);
+  return ret;
+}
+
+
+// the global list
+// (not thread-safe)
+SourceFileList sourceFileList;

Added: vendor/elsa/current/ast/fileloc.h
===================================================================
--- vendor/elsa/current/ast/fileloc.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/fileloc.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,150 @@
+// fileloc.h            see license.txt for copyright and terms of use
+// data structures for recording character positions in files
+
+#ifndef __FILELOC_H
+#define __FILELOC_H
+
+// I'm replacing all uses of this module with srcloc.h, but for
+// the time being I'll leave fileloc.h in the repository.
+#error do not use me, use srcloc.h instead
+
+#include "str.h"       // string
+#include "objlist.h"   // ObjList
+
+class Flatten;
+
+// identifies a location in a source file
+class FileLocation {
+public:
+  enum Constants {
+    // I pick 1,1 as my upper left, since it's traditional to number
+    // lines at 1, and 1,1 is nicer than 0,1 as an origin; I modified
+    // emacs' sources to display 1-based columns on my system..
+    firstColumn = 1,               // number of first column
+    firstLine = 1,                 // number of first line
+
+    invalid = -1,                  // no useful value known
+  };
+
+  int line;    // line #, 1-based
+  int col;     // column #, 1-based
+
+public:
+  FileLocation()                          : line(invalid), col(invalid) {}
+  FileLocation(int l, int c)              : line(l), col(c) {}
+  FileLocation(FileLocation const &obj)	  : line(obj.line), col(obj.col) {}
+  ~FileLocation()                         {}
+
+  FileLocation(Flatten&)                  {}
+  void xfer(Flatten &flat);
+
+  FileLocation& operator= (FileLocation const &obj)
+    { line=obj.line; col=obj.col; return *this; }
+
+  bool validLoc() const { return line != invalid; }
+
+  void reset() { line=firstLine; col=firstColumn; }
+
+  // "line %d, col %d"
+  string toString() const;
+
+  // move forward to reflect location after 'text'
+  void advance(char const *text, int length);
+
+  // wrap to the next line
+  void newLine();
+};
+
+
+// names a source file
+// (will get bigger; mostly a placeholder for now)
+class SourceFile {
+public:
+  string filename;
+
+public:
+  SourceFile(char const *fn) : filename(fn) {}
+  ~SourceFile();
+};
+
+
+// position in file, and pointer to which file
+class SourceLocation : public FileLocation {
+public:
+  SourceFile *file;         // (serf)
+
+public:
+  SourceLocation(SourceFile *f = NULL) : file(f) {}
+  SourceLocation(FileLocation const &floc, SourceFile *f)
+    : FileLocation(floc),
+      file(f)
+  {}
+  SourceLocation(SourceLocation const &obj)
+    : FileLocation(obj),
+      file(obj.file)
+  {}
+  ~SourceLocation() {}
+
+  SourceLocation(Flatten&) {}
+  void xfer(Flatten &flat);
+
+  SourceLocation& operator= (SourceLocation const &obj)
+  {
+    FileLocation::operator=(obj);
+    file = obj.file;
+    return *this;
+  }
+
+  // can return NULL
+  char const *fname() const;
+
+  // "file %s, line %d, col %d"
+  string oldToString() const;
+
+  // "<file>:<line>:<col>", or "" if no loc info
+  string likeGccToString() const;
+
+  string toString() const { return likeGccToString(); }
+
+  friend stringBuilder& operator<< (stringBuilder &sb, SourceLocation const &obj)
+    { return sb << obj.toString(); }
+  friend ostream& operator<< (ostream &os, SourceLocation const &obj)
+    { return os << obj.toString(); }
+};
+
+inline string toString(SourceLocation const &loc)
+  { return loc.toString(); }
+
+
+// global list of files processed; expectation is tools toss
+// files in here when opened and use the resulting pointer to
+// refer to the file, even after it's closed
+class SourceFileList {
+private:     // data
+  ObjList<SourceFile> files;
+  
+public:
+  SourceFileList();
+  ~SourceFileList();
+
+  // get permanent name for a file; if you call open twice
+  // with the same name (case sensitive), it will return the
+  // same structure as before
+  SourceFile * /*serf*/ open(char const *fname);
+
+  // clear all files
+  void clear() { files.deleteAll(); }
+};
+
+// the global list
+extern SourceFileList sourceFileList;
+
+
+// macro for obtaining a source location that points at the 
+// point in the source code where this macro is invoked
+#define HERE_SOURCELOCATION                        \
+  SourceLocation(FileLocation(__LINE__, 1),        \
+                 sourceFileList.open(__FILE__))
+
+
+#endif // __FILELOC_H

Added: vendor/elsa/current/ast/gramlex.cc
===================================================================
--- vendor/elsa/current/ast/gramlex.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/gramlex.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,368 @@
+// gramlex.cc            see license.txt for copyright and terms of use
+// code for gramlex.h
+
+#include "gramlex.h"     // this module
+#include "trace.h"       // debugging trace()
+#include "ccsstr.h"      // CCSubstrate
+#include "ckheap.h"      // checkHeap
+
+#include <fstream.h>     // cout, ifstream
+
+
+// workaround for flex-2.5.31
+#ifdef FLEX_STD    // detect later versions of flex
+  // copied from flex's output
+  #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                            ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                            : NULL)
+
+  // the 'yy_current_buffer' field was replaced by the buffer stack
+  // alluded to above
+  #define yy_current_buffer YY_CURRENT_BUFFER
+#endif // FLEX_STD
+
+
+// ----------------- GrammarLexer::AltReportError ---------------
+void GrammarLexer::AltReportError::reportError(rostring msg)
+{
+  lexer.printError(lexer.fileState.loc, msg);
+}
+
+void GrammarLexer::AltReportError::reportWarning(rostring msg)
+{
+  lexer.printWarning(lexer.fileState.loc, msg);
+}
+
+
+// ----------------- GrammarLexer::FileState --------------------
+GrammarLexer::FileState::FileState(rostring filename, istream *src)
+  : loc(sourceLocManager->encodeBegin(toCStr(filename))),
+    source(src),
+    bufstate(NULL)
+{}
+
+
+GrammarLexer::FileState::~FileState()
+{
+  // we let ~GrammarLexer take care of deletions here since we
+  // have to know what ~yyFlexLexer is going to do, and we
+  // don't have enough context here to know that
+}
+
+
+GrammarLexer::FileState::FileState(FileState const &obj)
+{
+  *this = obj;
+}
+
+
+GrammarLexer::FileState &GrammarLexer::FileState::
+  operator= (FileState const &obj)
+{
+  if (this != &obj) {
+    loc = obj.loc;
+    source = obj.source;
+    bufstate = obj.bufstate;
+  }
+  return *this;
+}
+
+
+// ---------------------- GrammarLexer --------------------------
+GrammarLexer::GrammarLexer(isEmbedTok test, StringTable &strtbl,
+                           char const *fname, istream *source,
+                           EmbeddedLang *userEmb)
+  : yyFlexLexer(source),
+    altReporter(*this),
+    fileState(fname, source),
+    fileStack(),
+    tokenStartLoc(SL_UNKNOWN),
+    embedStart(0),
+    embedFinish(0),
+    embedMode(0),
+    embedded(userEmb? userEmb : new CCSubstrate(&altReporter)),
+    embedTokTest(test),
+    allowInit(false),
+    prevState(0),       // same as INITIAL, but this value isn't used
+    prevToken(0),       // hack..
+    integerLiteral(0),
+    stringLiteral(""),
+    includeFileName(""),
+    strtable(strtbl),
+    errors(0)
+{
+  trace("tmp") << "source is " << source << endl;
+
+  // grab initial buffer object so we can restore it after
+  // processing an include file (turns out this doesn't work
+  // because it's NULL now; see recursivelyProcess())
+  fileState.bufstate = yy_current_buffer;
+}
+
+GrammarLexer::~GrammarLexer()
+{
+  // ~yyFlexLexer deletes its current buffer, but not any
+  // of the istream sources it's been passed
+
+  // first let's unpop any unpopped input files
+  while (hasPendingFiles()) {
+    popRecursiveFile();
+  }
+
+  // now delete the original istream source
+  // 
+  // 10/09/04: This used to say "fileState.source != cin", but that
+  // invokes cin.operator void*(), which always returns 0 or -1 in
+  // gcc-2.95.3's library.  I believe I intended to compare addresses,
+  // though at this point I'm not sure since I don't know where the
+  // call sites to the constructor are.  (I found this problem because
+  // at one point Elsa (erroneously) choked on this construction.)
+  if (fileState.source &&
+      fileState.source != &cin) {
+    //checkHeap();
+    //checkHeapNode(fileState.source);   // this is wrong b/c of virtual inheritance..
+    delete fileState.source;
+    //checkHeap();
+  }
+
+  delete embedded;
+}
+
+
+int GrammarLexer::yylexInc()
+{
+  // get raw token
+  int code = yylex();
+  
+  // save this code for next time; part of what makes this hack
+  // problematic is that this assignment is only performed if the
+  // client calls 'yylexInc'..
+  prevToken = code;
+
+  // include processing
+  if (code == TOK_INCLUDE) {
+    string fname = includeFileName;
+
+    // 'in' will be deleted in ~GrammarLexer
+    ifstream *in = new ifstream(fname.c_str());
+    if (!*in) {
+      err(stringc << "unable to open include file `" << fname << "'");
+    }
+    else {
+      recursivelyProcess(fname, in);
+    }
+
+    // go to next token (tail recursive)
+    return yylexInc();
+  }
+
+  if (code == TOK_EOF  &&  hasPendingFiles()) {
+    popRecursiveFile();
+    return yylexInc();
+  }
+
+  #if 1
+  // possible performance problem
+  if (embedTokTest(code)) {
+    trace("lex") << "yielding embedded (" << code << ") at "
+                 << curLocStr() << ": "
+                 << curFuncBody() << endl;
+  }
+  else {
+    trace("lex") << "yielding token (" << code << ") "
+                 << curToken() << " at "
+                 << curLocStr() << endl;
+  }
+  #endif // 0/1
+
+  // nothing special
+  return code;
+}
+
+
+StringRef GrammarLexer::curToken() const
+{
+  return addString(yytext, yyleng);
+}
+
+StringRef GrammarLexer::addString(char *str, int len) const
+{
+  // write a null terminator temporarily
+  char wasThere = str[len];
+  if (wasThere) {
+    str[len] = 0;
+    StringRef ret = strtable.add(str);
+    str[len] = wasThere;
+    return ret;
+  }
+  else {
+    return strtable.add(str);
+  }
+}
+
+
+bool GrammarLexer::embedFinishMatches(char ch) const
+{
+  return ch == embedFinish ||
+         (allowInit && ch=='=');     // to handle initial value syntax
+}
+
+
+StringRef GrammarLexer::curFuncBody() const
+{
+  return strtable.add(embedded->getFuncBody().c_str());
+}
+
+
+StringRef GrammarLexer::curDeclName() const
+{
+  return strtable.add(embedded->getDeclName().c_str());
+}
+
+
+string GrammarLexer::curLocStr() const
+{
+  return toString(curLoc());
+}
+
+
+void GrammarLexer::reportError(rostring msg)
+{
+  printError(curLoc(), msg);
+}
+
+void GrammarLexer::printError(SourceLoc loc, rostring msg)
+{
+  errors++;
+  cerr << toString(loc) << ": error: " << msg << endl;
+}
+
+
+void GrammarLexer::reportWarning(rostring msg)
+{
+  printWarning(curLoc(), msg);
+}
+
+void GrammarLexer::printWarning(SourceLoc loc, rostring msg)
+{
+  cerr << toString(loc) << ": warning: " << msg << endl;
+}
+
+
+void GrammarLexer::errorUnterminatedComment()
+{
+  err(stringc << "unterminated comment, beginning on line " //<< commentStartLine);
+              << sourceLocManager->getLine(tokenStartLoc));
+}
+
+void GrammarLexer::errorMalformedInclude()
+{
+  err(stringc << "malformed include");
+}
+
+void GrammarLexer::errorIllegalCharacter(char ch)
+{
+  err(stringc << "illegal character: `" << ch << "'");
+}
+
+
+void GrammarLexer::recursivelyProcess(rostring fname, istream *source)
+{
+  trace("lex") << "recursively processing " << fname << endl;
+                       
+  // grab current buffer; this is necessary because when we
+  // tried to grab it in the ctor it was NULL
+  fileState.bufstate = yy_current_buffer;
+  xassert(fileState.bufstate);
+
+  // push current state
+  fileStack.prepend(new FileState(fileState));
+
+  // reset current state
+  fileState = FileState(fname, source);
+
+  // storing this in 'bufstate' is redundant because of the
+  // assignment above, but no big deal
+  fileState.bufstate = yy_create_buffer(source, lexBufferSize);
+
+  // switch underlying lexer over to new file
+  yy_switch_to_buffer(fileState.bufstate);
+}
+
+
+void GrammarLexer::popRecursiveFile()
+{
+  trace("lex") << "done processing " <<     
+    sourceLocManager->getFile(fileState.loc) << endl;
+
+  // among other things, this prevents us from accidentally deleting
+  // flex's first buffer (which it presumably takes care of) or
+  // deleting 'cin'
+  xassert(hasPendingFiles());
+
+  // close down stuff associated with current file
+  yy_delete_buffer(fileState.bufstate);
+  delete fileState.source;
+
+  // pop stack
+  FileState *st = fileStack.removeAt(0);
+  fileState = *st;
+  delete st;
+  
+  // point flex at the new (old) buffer
+  yy_switch_to_buffer(fileState.bufstate);
+}
+
+
+bool GrammarLexer::hasPendingFiles() const
+{
+  return fileStack.isNotEmpty();
+}
+
+
+
+#ifdef TEST_GRAMLEX
+
+// defined in gramlex.lex
+bool isGramlexEmbed(int code);
+
+int main(int argc)
+{
+  SourceLocManager mgr;
+  GrammarLexer lexer(isGramlexEmbed);
+  traceAddSys("lex");
+
+  cout << "go!\n";
+
+  while (1) {
+    // any argument disables include processing
+    int code = argc==1? lexer.yylexInc() : lexer.yylex();
+    if (code == 0) {  // eof
+      break;
+    }
+
+    else if (isGramlexEmbed(code)) {
+      cout << "embedded code at " << lexer.curLocStr()
+           << ": " << lexer.curFuncBody()
+           << endl;
+    }
+    
+    else if (code == TOK_INCLUDE) {
+      // if I use yylexInc above, this is never reached
+      cout << "include at " << lexer.curLocStr()
+           << ": filename is `" << lexer.includeFileName.pcharc()
+           << "'\n";
+    }
+    
+    else {
+      cout << "token at " << lexer.curLocStr()
+           << ": code=" << code
+           << ", text: " << lexer.curToken().pcharc()
+           << endl;
+    }
+  }
+
+  return 0;
+}
+
+#endif // TEST_GRAMLEX

Added: vendor/elsa/current/ast/gramlex.h
===================================================================
--- vendor/elsa/current/ast/gramlex.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/gramlex.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,198 @@
+// gramlex.h            see license.txt for copyright and terms of use
+// GrammarLexer: a c++ lexer class for use with Flex's generated c++ scanner
+// this lexer class is used both for parsing both AST and grammar descriptions;
+// they differ in their .lex description, but their lexing state is the same
+
+#ifndef __GRAMLEX_H
+#define __GRAMLEX_H
+
+
+// This included file is part of the Flex distribution.  It is
+// installed in /usr/include on my Linux machine.  By including it, we
+// get the declaration of the yyFlexLexer class.  Note that the file
+// that flex generates, gramlex.yy.cc, also #includes this file.
+// Perhaps also worth mentioning: I'm developing this with flex 2.5.4.
+//
+// update: This approach was too problematic.  I've taken to distributing
+// FlexLexer.h myself.
+#include "sm_flexlexer.h"     // yyFlexLexer
+
+#include <iostream.h>         // istream
+
+// token code definitions
+#define TOK_EOF 0             // better name
+#define TOK_INCLUDE 1         // not seen by parser
+
+
+// other includes
+#include "str.h"              // string
+#include "objlist.h"          // ObjList
+#include "srcloc.h"           // SourceLoc
+#include "embedded.h"         // EmbeddedLang
+#include "strtable.h"         // StringTable, StringRef
+
+
+// this class just holds the lexer state so it is properly encapsulated
+// (and therefore, among other things, re-entrant)
+class GrammarLexer : public yyFlexLexer, public ReportError {
+public:      // types
+  enum Constants {
+    lexBufferSize = 4096,          // size of new lex buffers
+  };
+
+  // return true if the given token code is one of those representing
+  // embedded text
+  typedef bool (*isEmbedTok)(int tokCode);
+
+  // error reporter that uses fileState instead of tokenStartLoc
+  class AltReportError : public ReportError {
+    GrammarLexer &lexer;
+
+  public:
+    AltReportError(GrammarLexer &L) : lexer(L) {}
+
+    virtual void reportError(rostring msg);
+    virtual void reportWarning(rostring msg);
+  };
+  friend class AltReportError;
+  
+public:      // data
+  // exposed so a user-provided 'embedded' can use it
+  AltReportError altReporter;
+
+private:     // data
+  // state of a file we were or are lexing
+  struct FileState {
+    SourceLoc loc;                 // location in the file
+    istream *source;               // (owner?) source stream
+    yy_buffer_state *bufstate;     // (owner?) flex's internal buffer state
+
+  public:
+    FileState(rostring filename, istream *source);
+    ~FileState();
+
+    FileState(FileState const &obj);
+    FileState& operator= (FileState const &obj);
+  };
+
+  FileState fileState;             // state for file we're lexing now
+  ObjList<FileState> fileStack;    // stack of files we will return to
+
+  SourceLoc tokenStartLoc;         // location of start of current token
+
+  // support for embedded code
+  char embedStart;                 // if nonzero, punctuation that triggers
+                                   // embedded processing
+  char embedFinish;                // which character ends the embedded section
+  int embedMode;                   // TOK_FUNDECL_BODY or TOK_FUN_BODY
+  EmbeddedLang *embedded;          // (owner) the processor
+  isEmbedTok embedTokTest;         // for printing diagnostics
+  bool allowInit;                  // true if embedded can have an initializer
+
+  int prevState;                   // so /**/ doesn't change start state
+  
+  int prevToken;                   // last token code yielded (ugly hack)
+
+public:      // data
+  // todo: can eliminate commentStartLine in favor of tokenStartLoc?
+  //int commentStartLine;            // for reporting unterminated C comments
+  int integerLiteral;              // to store number literal value
+  StringRef stringLiteral;         // string in quotes, minus the quotes
+  StringRef includeFileName;       // name in an #include directive
+
+  // defined in the base class, FlexLexer:
+  //   const char *YYText();           // start of matched text
+  //   int YYLeng();                   // number of matched characters
+
+  StringTable &strtable;           // string table
+
+  // count of errors encountered
+  int errors;
+
+private:     // funcs
+  // disallowed
+  GrammarLexer(GrammarLexer const &);
+
+  // called to advance the column count
+  void advCol(int n) 
+    { fileState.loc = sourceLocManager->advCol(fileState.loc, n); }
+
+  // called when a newline is encountered
+  void newLine()
+    { fileState.loc = sourceLocManager->advLine(fileState.loc); }
+  
+  // adds a string with only the specified # of chars; writes (but
+  // then restores) a null terminator if necessary, so 'str' isn't const
+  StringRef addString(char *str, int len) const;
+                                        
+  // nominally true if 'ch' equals 'embedFinish', but with a niggle
+  bool embedFinishMatches(char ch) const;
+
+public:      // funcs
+  // create a new lexer that will read from to named stream,
+  // or stdin if it is NULL
+  GrammarLexer(isEmbedTok embedTokTest,
+               StringTable &strtable,
+               char const *fname = "<stdin>",
+               istream * /*owner*/ source = NULL,
+               EmbeddedLang * /*owner*/ embedded = NULL /*i.e. assume C lexics*/);
+
+  // clean up
+  ~GrammarLexer();
+
+  // get current token as a string
+  StringRef curToken() const;
+  int curLen() const { return const_cast<GrammarLexer*>(this)->YYLeng(); }
+
+  // current token's embedded text
+  StringRef curFuncBody() const;
+  StringRef curDeclBody() const { return curFuncBody(); }    // implementation artifact
+  StringRef curDeclName() const;
+
+  // read the next token and return its code; returns TOK_EOF for end of file;
+  // this function is defined in flex's output source code; this one
+  // *does* return TOK_INCLUDE
+  virtual int yylex();
+
+  // similar to yylex, but process TOK_INCLUDE internally
+  int yylexInc();
+
+  // begin an embedded sequence
+  void beginEmbed(char finish, int mode, int initNest = 0)
+  {
+    embedded->reset(initNest);
+    embedFinish = finish;
+    embedMode = mode;
+  }
+
+  // info about location of current token
+  char const *curFname() const 
+    { return sourceLocManager->getFile(tokenStartLoc); }
+  int curLine() const 
+    { return sourceLocManager->getLine(tokenStartLoc); }
+  int curCol() const 
+    { return sourceLocManager->getCol(tokenStartLoc); }
+  SourceLoc curLoc() const { return tokenStartLoc; }
+  string curLocStr() const;    // string with file/line/col
+
+  // error reporting; called by the lexer code
+  void err(rostring msg) { reportError(msg); }     // msg should not include a newline
+  void errorUnterminatedComment();
+  void errorMalformedInclude();
+  void errorIllegalCharacter(char ch);
+
+  void printError(SourceLoc loc, rostring msg);
+  void printWarning(SourceLoc loc, rostring msg);
+
+  // for processing includes
+  void recursivelyProcess(rostring fname, istream * /*owner*/ source);
+  void popRecursiveFile();
+  bool hasPendingFiles() const;
+  
+  // ReportError funcs
+  virtual void reportError(rostring msg);
+  virtual void reportWarning(rostring msg);
+};
+
+
+#endif // __GRAMLEX_H

Added: vendor/elsa/current/ast/index.html
===================================================================
--- vendor/elsa/current/ast/index.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/index.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>ast</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+</HEAD>
+
+<body>
+
+<center><h2>
+ast: A system for creating Abstract Syntax Trees
+</h2></center>
+
+<p>
+The "ast" system takes as input a description of a heterogenous tree
+structure, and outputs C++ code to define a set of classes that
+implement the described tree.  Abstract Syntax Trees, used in language
+processors (like compilers), are the principal intended application,
+though of course the need for heterogenous trees arises in other
+situations as well.
+
+<p>
+As a short example, the following is a sample input to the "astgen"
+tool.  It's also in the file <a href="demo.ast">demo.ast</a>.
+<pre>
+  class Root(A a, B b);
+
+  class A {
+    -> A_one(string name);
+    -> A_two(B b);
+  }
+
+  class B(string name) {
+    public int x = 0;
+
+    -> B_one(int y);
+    -> B_two(char c);
+  }
+</pre>
+
+<p>
+From this description, astgen produces two files,
+<a href="gendoc/demo.h">demo.h</a> and
+<a href="gendoc/demo.cc">demo.cc</a>.  You can then write C++
+code that uses these tree classes.
+
+<p>
+The basic inspiration for the ast system is ML's disjoint union types,
+but I extended them in several ways:
+<ul>
+<li>You can have fields that are present in all variants; the 'name'
+    field of class B, above, is an example.
+<li>You can have fields that are not initialized by arguments to the 
+    constructor, but instead have a default value, and behave like mutable 
+    annotations.  The 'x' field of class B is an example.
+<li>The fields that <em>are</em> set in the constructor can have default
+    values, using C++'s usual mechanism, so it's possible to add a field
+    without having to rewrite every occurrence of a call to the
+    constructor.
+<li>ast classes are full C++ classes, and as such can have methods, etc.
+</ul>
+
+<p>
+For more information about the features of the ast system,
+consult the <a href="manual.html">AST Manual</a>.
+
+<p>
+The ast system requires the following external software:
+<ul>
+<li><a href="../smbase/index.html">smbase</a>, my utility library.
+<li><a href="http://www.gnu.org/software/flex/flex.html">Flex</a>,
+    a lexical analyzer generator.
+<li><a href="http://www.gnu.org/software/bison/bison.html">Bison</a>,
+    a parser generator.
+</ul>
+
+<p>
+Build instructions:
+<pre>
+  $ ./configure
+  $ make
+  $ make check
+</pre>
+<a href="configure"><tt>./configure</tt></a> understands
+<a href="gendoc/configure.txt">these options</a>.  You can also
+look at the <a href="Makefile.in">Makefile</a>.
+
+<p>
+Module List:
+<ul>
+
+<li><a href="agramlex.lex">agramlex.lex</a>:
+Lexical analyzer for .ast files.
+See also <a href="gramlex.h">gramlex.h</a>.
+
+<li><a href="agrampar.y">agrampar.y</a>,
+    <a href="agrampar.h">agrampar.h</a>,
+    <a href="agrampar.cc">agrampar.cc</a>:
+Parser for .ast files.
+
+<li><a href="ast.ast">ast.ast</a>,
+    <a href="ast.ast.h">ast.ast.h</a>,
+    <a href="ast.ast.cc">ast.ast.cc</a>:
+The AST of an .ast file.  The outputs of astgen are included for
+bootstrapping purposes.
+
+<li><a href="astgen.cc">astgen.cc</a>:
+The main program.  Translates .ast files into .h and .cc files.
+
+<li><a href="asthelp.h">asthelp.h</a>,
+    <a href="asthelp.cc">asthelp.cc</a>:
+This is a support module for astgen-generated code.
+
+<li><a href="ccsstr.h">ccsstr.h</a>:
+    <a href="ccsstr.cc">ccsstr.cc</a>:
+Implements the EmbeddedLang interface (<a href="embedded.h">embedded.h</a>)
+for C++.
+
+<li><a href="embedded.h">embedded.h</a>,
+    <a href="embedded.cc">embedded.cc</a>:
+Interface for skipping comments and balanced delimiters in a
+language embedded into another.
+
+<li><a href="example.ast">example.ast</a>,
+    <a href="exampletest.cc">exampletest.cc</a>:
+Testbed for new astgen features.  Not a particularly good pedagogical
+example.
+
+<li><a href="ext1.ast">ext1.ast</a>:
+Example extension module for <a href="example.ast">example.ast</a>.
+
+<li><a href="fakelist.h">fakelist.h</a>:
+FakeList, a linked-list wrapper module for lists of objects built
+out of internal 'next' pointers.  See <a href="fakelist.h">fakelist.h</a>
+for a more complete description and rationale.
+
+<li><a href="gramlex.h">gramlex.h</a>,
+    <a href="gramlex.cc">gramlex.cc</a>:
+Lexical analyzer support module.  Goes with
+<a href="agramlex.lex">agramlex.lex</a>.  This module is also used by
+<a href="../elkhound/gramlex.lex">elkhound/gramlex.lex</a> in the
+<a href="../elkhound/index.html">Elkhound</a> distribution.
+
+<li><a href="locstr.h">locstr.h</a>,
+    <a href="locstr.cc">locstr.cc</a>:
+Pair of a SourceLoc (<a href="../smbase/srcloc.h">smbase/srcloc.h</a>)
+and a StringRef (<a href="strtable.h">strtable.h</a>).
+
+<li><a href="reporterr.h">reporterr.h</a>,
+    <a href="reporterr.cc">reporterr.cc</a>:
+Interface for reporting errors and warnings.
+
+<li><a href="strtable.h">strtable.h</a>,
+    <a href="strtable.cc">strtable.cc</a>:
+StringTable, a global table of immutable strings.  Duplicate strings 
+are mapped to the same entry, allowing pointer comparisons to suffice
+for string equality tests.
+
+</ul>
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+
+</HTML>

Added: vendor/elsa/current/ast/license.txt
===================================================================
--- vendor/elsa/current/ast/license.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/license.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+The software in this directory is
+Copyright (c) 2002, Regents of the University of California
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above 
+      copyright notice, this list of conditions and the following 
+      disclaimer in the documentation and/or other materials provided 
+      with the distribution.
+
+    * Neither the name of the University of California, Berkeley nor 
+      the names of its contributors may be used to endorse or promote 
+      products derived from this software without specific prior 
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: vendor/elsa/current/ast/locstr.cc
===================================================================
--- vendor/elsa/current/ast/locstr.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/locstr.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,82 @@
+// locstr.cc            see license.txt for copyright and terms of use
+// code for locstr.h
+
+#include "locstr.h"     // this module
+#include "exc.h"        // LocString
+
+LocString::LocString()
+  : loc(SL_UNKNOWN),
+    str(NULL)           // problem with "" is we don't have the string table here..
+{}
+
+LocString::LocString(LocString const &obj)
+  : loc(obj.loc),
+    str(obj.str)
+{}
+
+LocString::LocString(SourceLoc L, StringRef s)
+  : loc(L),
+    str(s)
+{}
+
+
+LocString::LocString(Flatten&)
+  : loc(SL_UNKNOWN), str(NULL)
+{}
+
+void LocString::xfer(Flatten &flat)
+{
+  // doh.. flattening locs is hard.  I wasn't even doing
+  // it before.  issues:
+  //   - don't want to store the file name lots of times
+  //   - what if the file goes away, or we're in a different directory?
+  //   - what if the file is changed, what loc to use then?
+  // so for now I'm punting and not saving the loc at all...
+
+  xassert(flattenStrTable);
+  flattenStrTable->xfer(flat, str);
+}
+
+
+void LocString::copyAndDel(LocString *obj)
+{
+  loc = obj->loc;
+  str = obj->str;
+  delete obj;
+}
+
+LocString *LocString::clone() const
+{
+  return new LocString(*this);
+}
+
+
+bool LocString::equals(char const *other) const
+{
+  if (!str) {
+    return !other;                            // equal if both null
+  }
+  else {
+    return other && streq(str, other); // or same contents
+  }
+}
+
+string toString(LocString const &s)
+{
+  return string(s.str);
+}
+
+
+string toXml(LocString op)
+{
+  xunimp("XML serialization of LocString");
+  return "";
+}
+
+void fromXml(LocString &out, rostring str)
+{
+  xunimp("XML serialization of LocString");
+}
+
+
+// EOF

Added: vendor/elsa/current/ast/locstr.h
===================================================================
--- vendor/elsa/current/ast/locstr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/locstr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+// locstr.h            see license.txt for copyright and terms of use
+// location & string table reference
+
+#ifndef LOCSTR_H
+#define LOCSTR_H
+                                          
+#include <iostream.h>    // ostream
+#include <string.h>      // strlen
+
+#include "strtable.h"    // StringRef
+#include "srcloc.h"      // SourceLoc
+
+class LocString {
+public:    // data
+  SourceLoc loc;
+  StringRef str;
+
+public:    // funcs
+  LocString();
+  LocString(LocString const &obj);
+  LocString(SourceLoc loc, StringRef str);
+
+  LocString(Flatten&);
+  void xfer(Flatten &flat);
+
+  // deallocates its argument; intended for convenient use in bison grammar files
+  EXPLICIT LocString(LocString *obj) { copyAndDel(obj); }
+  void copyAndDel(LocString *obj);
+
+  // sometimes useful for generating arguments to the above ctor
+  LocString *clone() const;
+
+  LocString& operator= (LocString const &obj)
+    { loc = obj.loc; str = obj.str; return *this; }
+
+  // string with location info
+  string locString() const { return toString(loc); }
+
+  // (read-only) string-like behavior
+  friend ostream& operator<< (ostream &os, LocString const &loc)
+    { return os << loc.str; }
+  friend stringBuilder& operator<< (stringBuilder &sb, LocString const &loc)
+    { return sb << loc.str; }
+  StringRef strref() const { return str; }
+  operator StringRef () const { return str; }
+  char operator [] (int index) const { return str[index]; }
+  bool equals(char const *other) const;    // string comparison
+  int length() const { return strlen(str); }
+
+  // experimenting with allowing 'str' to be null, which is convenient
+  // when the string table isn't available
+  bool isNull() const { return str == NULL; }
+  bool isNonNull() const { return !isNull(); }
+  
+  bool validLoc() const { return loc != SL_UNKNOWN; }
+};
+
+// yields simply the string, no location info
+string toString(LocString const &s);
+
+// xml stuff...
+string toXml(LocString op);
+void fromXml(LocString &out, rostring str);
+
+
+// useful for constructing literal strings in source code
+#define LITERAL_LOCSTRING(str)                                   \
+  LocString(HERE_SOURCELOC, str)
+
+
+#endif // LOCSTR_H

Added: vendor/elsa/current/ast/manual.html
===================================================================
--- vendor/elsa/current/ast/manual.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/manual.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,400 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>AST Manual</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+</HEAD>
+
+<body>
+
+<center><h2>
+AST Manual
+</h2></center>
+
+<p>
+astgen is a simple tool for creating C++ data type descriptions of
+heterogenous tree structures.  "ast" comes from the common use of
+heterogeneous trees to make abstract syntax trees for compilers.  This
+page is its documentation.  <a href="index.html">Another page</a>
+describes the module structure of its implementation.
+
+<p>Fair warning: The astgen input language was developed "bottom up",
+adding features and wrinkles as needs arose.  Consequently, it is
+fairly concise in practice, but sort of awkard to describe.  There are
+several instances of incomplete orthogonalization ("irregularities").
+It's probably time for a redesign; but for now it is what it is.
+
+<h2>1. Input description</h2>
+
+<p>
+astgen input files are free-form (all whitespace is treated the same),
+like C++ itself, and the syntax is inspired by C++ in other ways as
+well.  In particular, Emacs' c++-mode works fine for highlighting.
+
+<p>
+For an example ast description, see <a href="ast.ast">ast.ast</a>.
+
+<p>
+The input file is a sequence of three kinds of things:
+<ul>
+<li>verbatim code to be copied to the output
+<li>options
+<li>tree class definitions
+</ul>
+
+<h3>1.1 Verbatim</h3>
+
+<p>
+Verbatim code is exactly what it sounds like: a string that gets
+copied to either the generated header file (for "verbatim") or
+the generated C++ implementation file (for "impl_verbatim").  The
+verbatim code is delimited by braces ("{}").
+
+<h3>1.2 Options</h3>
+
+<p>
+There are currently three options:
+<ul>
+<li><tt>visitor</tt>: Emit code for traversal using a visitor.  See Section 3.
+<li><tt>gdb</tt>: To make it easier to call <tt>debugPrint()</tt>
+    from with a debugger (such as gdb), emit methods called
+    <tt>gdb()</tt> that just call <tt>debugPrint(cout,0)</tt>.
+<li><tt>xmlPrint</tt>: Emit xmlPrint methods, similar to the debugPrint methods.
+    The current xmlPrint is just a prototype and isn't used; improving
+    it is still on the todo list.
+</ul>
+
+<h3>1.3 Tree class definitions</h3>
+
+<p>
+A tree class definition begins with the keyword "class", then the
+class name, then an optional constructor (hereafter: "ctor") argument
+list, then a brace-delimited body:
+
+<pre>
+  class MyClass (int arg1, AnotherClass arg2) {
+    // ... the body ...
+  }
+</pre>
+
+<p>
+If there are no ctor arguments, either use "()" or leave out the
+parentheses entirely.
+
+<p>
+If there is nothing to put in the class body, you can abbreviate
+"{}" as ";".  Note that if you put the braces, there is *not* a
+semicolon following the "}".
+
+<h4>1.3.1 Constructor ("ctor") Arguments</h4>
+
+<p>
+Ctor arguments play two roles.  First, they become parameters to
+the generated class' constructor function.  Thus, (above) any time
+a MyClass is constructed, the caller has to supply two arguments
+of the given types.  Ctor arguments may be given default values
+using the usual C++ syntax, in which case those become default values
+for the associated constructor parameters.
+
+<p>
+Second, ctor arguments become fields in the generated class, and
+those fields are initialized by the constructor call.  So a MyClass
+has (at least) two fields, an int and an AnotherClass.
+
+<p>
+Actually, the above is a bit of a lie, if AnotherClass is another one
+of the tree classes defined in the same astgen input file.  astgen
+recognizes several special forms of ctor argument types, and each has
+slightly different semantics.  In each case below, "A" is the name of
+a class defined elsewhere in the astgen input file (or one of the
+extensions it has been combined with, see Section 2).
+
+<p>
+<b>Tree:</b> If the type is "A", then the constructor argument and class
+field are both of type "A*" (pointer to A).  Further, the class is
+regarded as the owner of this pointer, and thus will deallocate it in
+its destructor.
+
+<p>
+<b>Tree pointer:</b> If the type is "A*", then the argument and field are
+both "A*", and the pointer is non-owning.  However, astgen recognizes
+that it knows how to traverse into such a field, which comes into
+play during visiting.
+
+<p>
+<b>ASTList:</b> If the type is "ASTList&lt;A&gt;" 
+(see <a href="../smbase/astlist.h">smbase/astlist.h</a>), then the
+constructor argument becomes "ASTList&lt;A&gt;*" and the field is
+"ASTList&lt;A&gt;".  ASTList has a constructor which accepts a pointer to
+another ASTList, and <em>deallocates</em> the argument list, taking ownership
+of the argument list's elements.  This makes it possible to create an
+ASTList on the heap, pass it around as a simple pointer, and then
+consume it by passing to a class with an ASTList-typed ctor arg.
+
+<p>
+<b>FakeList:</b> If the type is "FakeList&lt;A&gt;" (see smbase/fakelist.h), then
+the constructor argument and class field are both "FakeList&lt;A&gt;*".
+This is really just a pointer to an A, but the class is considered to
+own the whole list, not just the first element.
+
+<p>
+<b>Anything else:</b> For any other type T, the argument is type T and
+the field is type T.  astgen doesn't do anything special since it
+assumes it doesn't know how to interact with the type.
+
+<h4>1.3.2 Fields</h4>
+
+<p>
+Classes can be given fields (and in fact methods) that astgen doesn't
+interpret.  These don't become part of the constructor parameter list,
+so they should either have or be given default values.  Fields are
+introduced with one of the keywords "public", "private", or "protected",
+and the end with a semicolon.  Semicolons can appear
+in the field text, as long as they're bracketed by braces, parentheses,
+or brackets (the lexer counts nested delimiters when looking for the
+final ";").
+
+<p>
+The keywords "public", "private", and "protected" are all treated the
+same way: the output class will contain the field text, prepended with
+"public:" (or whatever the keyword was).  Syntactically they work
+similarly to Java class fields.
+
+<p>
+Optionally, the introducer keyword can be immediately followed (no
+whitespace) by a comma-separated list of field modifiers, in
+parentheses.  The field modifiers are:
+<ul>
+<li><tt>field</tt>: Signals that the member is a data field, which
+    currently only means that it is printed during debugPrint along
+    with the constructor arguments.
+<li><tt>func</tt>: Indicates that the declaration is a function; this
+    is rarely needed.
+<li><tt>owner</tt>: For pointers, this means that the destructor
+    should delete the object pointed to.
+<li><tt>virtual</tt>: First, adds the "virtual" keyword to the emitted
+    declaration.  Then, it adds declarations for overriding implementations
+    of the function to all subclasses.
+</ul>
+For example:
+<pre>
+  public(field) int w;             // 'w' gets printed by debugPrint
+  protected(virtual) int foo();    // 'foo' declared in subclasses too
+  private(owner) int *p;           // 'p' deleted by destructor
+</pre>
+
+<p>
+Also optionally, before the final semicolon, an initializing expression
+can be provided.  This expression will be used to initialize the data
+member in the constructor.  Also, if the "virtual" modifier is used,
+this will be applied to the declaration of a function, to make it
+a "pure virtual" function.
+<pre>
+  public int x = 3;                // 'x' initialized to 3 in constructor
+  public(virtual) int bar() = 0;   // 'bar' pure in superclass
+</pre>
+
+<p>
+The declaration of <tt>bar</tt> above could also be written
+<pre>
+  pure_virtual int bar();
+</pre>
+as <tt>pure_virtual</tt> is syntactic sugar for a public, virtual
+(automatic declarations in subclasses) field that is pure in the
+superclass.
+
+
+<h4>1.3.3 Custom Code</h4>
+
+<p>
+astgen can insert user-specified code at key points in the code it
+emits.  This is useful for doing some processing with the otherwise
+uninterpreted fields (the fields astgen doesn't know how to process).
+The user specifies such code by saying
+
+<pre>
+  custom &lt;kind&gt; { /* ...code... */ }
+</pre>
+
+<p>
+The &lt;kind&gt;, lexically just an identifier, controls where this code
+gets inserted.  The current kinds recognized are:
+
+<ul>
+<li><tt>debugPrint</tt>: Inserted into the 'debugPrint' method after the
+    header is printed.
+
+<li><tt>preemptDebugPrint</tt>: Inserted into 'debugPrint' before anything
+    else is printed.
+
+<li><tt>clone</tt>: Inserted into the 'clone' method.
+
+<li><tt>traverse</tt>: Inserted into the 'traverse' method.
+</ul>
+
+<p>
+If you specify a &lt;kind&gt; which is not among these, you'll get a
+warning when 'astgen' runs.
+
+<h4>1.3.4 Subclasses</h4>
+
+<p>
+The classes form a two-level hierarchy.  Subclasses are introduced
+with "<tt>-&gt;</tt>" inside the superclass body.  The syntax following "<tt>-&gt;</tt>"
+is identical to what follows "class".
+
+<p>
+If a class has subclasses, then the superclass is abstract (you
+can't instantiate it).  Further, most of the generated methods
+are virtual, so subclass implementations will be used.
+
+<p>
+Superclasses with subclasses get some additional methods, useful
+for interrogating the type at run-time (this is essentially an
+alternative to the C++ language's RTTI mechanism).
+
+<p>
+First, the superclass declares an enum called "Kind", with one value
+for each subclass, where the name is obtained by capitalizing all the
+subclass name's letters.  Then a pure virtual method "kind()" is
+declared, and the subclass implementations return their Kind.
+
+<p>
+Then, for each subclass "Foo" you get:
+<pre>
+  bool isFoo() const;
+  Foo *asFoo();                // checked downcast
+  Foo const asFooC() const;    // checked downcast, const version
+</pre>
+
+<p>
+The generated header file obtains these functions through the
+<tt>DECL_AST_DOWNCASTS</tt> macro, defined in 
+<a href="asthelp.h">asthelp.h</a>.
+
+<h4>1.3.5 "Last" Ctor Parameters</h4>
+
+<p>
+Occasionally, it is convenient for a ctor parameter to be supplied with
+the superclass (so that all subclasses have it) but desirable to pass
+and print the value <em>after</em> the subclass parameters.  For
+example, a superclass Foo might want to have a "Foo *next" to form a
+linked list, but we would want "next" to be at the end of all subclass
+argument lists, printed last (so the list is printed in the "logical"
+order), etc.
+
+<p>
+The syntax for this is a second parameter list in the superclass:
+<pre>
+  class Foo (/*first*/ int x, int y) (/*last*/ Foo next) {
+    -> F_one(int z);
+    ...
+  }
+</pre>
+In this example, "x" and "y" are ordinary ("first") ctor parameters,
+and "next" is a "last" parameter.  For example, to construct an instance
+of "F_one", write
+<pre>
+  new F_one(x, y, z, next)
+</pre>
+
+
+<h3>1.4 Miscellaneous</h3>
+
+<p>
+Comments are either C++-style "//" or C-style "/**/" form.
+
+<p>
+Some things are keywords, used to aid parsing.  Keywords currently
+include:
+<pre>
+  class
+  public
+  private
+  protected
+  verbatim
+  impl_verbatim
+  ctor
+  dtor
+  pure_virtual
+  custom
+  option
+</pre>
+
+<p>
+You cannot use a keyword as the name of a class, or a data member,
+or in any other way besides as that keyword.
+
+
+<h2>2. Extension Modules</h2>
+
+<p>
+Tree structures often consist of a base definition and then one or
+more annotation systems on top of the base.  Rather than clutter the
+base with the annotations (making it hard to re-use the base for other
+projects), annotations should be collected into extension modules.
+
+<p>
+The extension system is very simple.  You supply additional astgen
+input files on the command line, and the extensions are simply
+unioned with the base in the obvious way:
+<ul>
+<li>ctor args are appended
+<li>fields are added
+<li>class names that don't exist in the base define new classes
+</ul>
+
+<p>
+There can be multiple extension modules, and they are added in the
+order specified on the command line.
+
+
+<h2>3. Visitor Interface</h2>
+
+<p>
+If the input file includes an option of the form
+<pre>
+  option visitor &lt;name&gt;;
+</pre>
+
+<p>
+Then a visitor implementation will be generated, and &lt;name&gt; used as
+the name of the interface class.
+
+<h3>3.1 The Interface Class</h3>
+
+<p>
+The visitor interface class declares two virtual functions for
+each superclass "Foo" in the astgen input:
+<pre>
+  bool visitFoo(Foo *obj);
+  void postvisitFoo(Foo *obj);
+</pre>
+visitFoo is called in pre-order (before any children are visited)
+and postvisitFoo is called in post-order.  If visitFoo returns
+false, then its children are not visited and postvisitFoo is not
+called.
+
+<h3>3.2 The Traversal Functions</h3>
+
+<p>
+Each tree class is given a method:
+<pre>
+  void traverse(&lt;name&gt; &amp;vis);
+</pre>
+where &lt;name&gt; is the visitor interface class name.  You can start
+a visiting traversal by saying "<tt>node-&gt;traverse(vis)</tt>" where "vis"
+is an object that implements the visitor interface.  This function
+is virtual if the class in question has children (subclasses).
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+
+</HTML>

Added: vendor/elsa/current/ast/readme.txt
===================================================================
--- vendor/elsa/current/ast/readme.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/readme.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+readme.txt for astgen
+
+The contents of this file have been superceded by
+manual.html and index.html.

Added: vendor/elsa/current/ast/reporterr.cc
===================================================================
--- vendor/elsa/current/ast/reporterr.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/reporterr.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// reporterr.cc            see license.txt for copyright and terms of use
+// code for reporterr.h
+
+#include "reporterr.h"      // this module
+
+#include <iostream.h>       // cout
+
+
+// --------------------- SilentReportError -------------------------
+SilentReportError::SilentReportError()
+  : errors(0),
+    warnings(0)
+{}
+
+void SilentReportError::reportError(rostring str)
+{
+  errors++;
+}
+
+void SilentReportError::reportWarning(rostring str)
+{
+  warnings++;
+}
+
+SilentReportError silentReportError;
+
+
+// --------------------- SimpleReportError -------------------------
+void SimpleReportError::reportError(rostring str)
+{
+  SilentReportError::reportError(str);
+  cout << "error: " << str << endl;
+}
+
+void SimpleReportError::reportWarning(rostring str)
+{
+  SilentReportError::reportWarning(str);
+  cout << "warning: " << str << endl;
+}
+
+SimpleReportError simpleReportError;
+
+
+// EOF

Added: vendor/elsa/current/ast/reporterr.h
===================================================================
--- vendor/elsa/current/ast/reporterr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/reporterr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,47 @@
+// reporterr.h            see license.txt for copyright and terms of use
+// interface for reporting errors and warnings
+
+#ifndef REPORTERR_H
+#define REPORTERR_H
+
+#include "str.h"        // rostring
+
+class ReportError {
+public:
+  virtual ~ReportError() {}
+  // report an error; 'str' should not have a newline
+  virtual void reportError(rostring str)=0;
+
+  // report a warning
+  virtual void reportWarning(rostring str)=0;
+};
+
+
+// throw away messages, but count them
+class SilentReportError : public ReportError {
+public:
+  int errors;
+  int warnings;
+
+public:
+  virtual ~SilentReportError() {}
+  SilentReportError();
+  virtual void reportError(rostring str);
+  virtual void reportWarning(rostring str);
+};
+
+extern SilentReportError silentReportError;
+
+
+// print messages to stdout with "error: " or "warning: " prepended
+class SimpleReportError : public SilentReportError {
+public:
+  virtual ~SimpleReportError() {}
+  virtual void reportError(rostring str);
+  virtual void reportWarning(rostring str);
+};
+
+extern SimpleReportError simpleReportError;
+
+
+#endif // REPORTERR_H

Added: vendor/elsa/current/ast/tiny.ast
===================================================================
--- vendor/elsa/current/ast/tiny.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/tiny.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// tiny.ast            see license.txt for copyright and terms of use
+// minimal ast test file
+
+class C(int x);

Added: vendor/elsa/current/ast/towner.cc
===================================================================
--- vendor/elsa/current/ast/towner.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/towner.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,115 @@
+// towner.cc            see license.txt for copyright and terms of use
+// test owner stuff
+
+#include "owner.h"    // module to test
+#include <stdio.h>    // printf
+
+class Foo;
+void someCrap(Foo *f)
+{
+  //delete f;
+  // good -- egcs-1.1.2 doesn't allow this, so I won't accidentally
+  // get destructors missed because of forward decls (like could
+  // happen with Borland)
+}
+
+
+// a simple class to play with
+class Foo {
+public:
+  static int count;    // # of Foos there are
+  int x;
+
+public:
+  Foo(int a);
+  ~Foo();
+};
+
+int Foo::count = 0;
+
+Foo::Foo(int ax)
+  : x(ax)
+{
+  printf("created Foo at %p\n", this);
+  count++;
+}
+
+Foo::~Foo()
+{
+  printf("destroying Foo at %p\n", this);
+  count--;
+}
+
+
+void printFoo(Foo *f)
+{
+  printf("Foo at %p, x=%d\n", f, f? f->x : 0);
+}
+
+void printFooC(Foo const *f)
+{
+  printf("const Foo at %p, x=%d\n", f, f? f->x : 0);
+}
+
+void printInt(int x)
+{
+  printf("int x is %d\n", x);
+}
+
+
+// make it, forget to free it
+void test1()
+{
+  printf("----------- test1 -----------\n");
+  Owner<Foo> f;
+  f = new Foo(4);
+}
+
+// access all of the operators as non-const
+void test2()
+{
+  printf("----------- test2 -----------\n");
+  Owner<Foo> f(new Foo(6));
+
+  printFoo(f);
+  (*f).x = 9;
+  f->x = 12;
+}
+
+// access all of the operators as const
+void test3()
+{
+  printf("----------- test3 -----------\n");
+  Owner<Foo> f(new Foo(8));
+  Owner<Foo> const &g = f;
+
+  printFooC(g);
+  printInt((*g).x);      // egcs-1.1.2 allows this for non-const operator fn!!!
+  printInt(g->x);
+}
+
+// test exchange of ownership
+void test4()
+{
+  printf("----------- test4 -----------\n");
+  //Owner<Foo> f = new Foo(3);     // egcs-1.1.2 does the wrong thing here
+  Owner<Foo> f(new Foo(3));
+  Owner<Foo> g;
+  g = f;
+  printFoo(f);    // should be null
+  f = g.xfr();
+  printFoo(g);    // should be null
+}
+
+
+int main()
+{
+  test1();
+  test2();
+  test3();
+  test4();
+  
+  printf("%d Foos leaked\n", Foo::count);
+  return Foo::count;
+}
+

Added: vendor/elsa/current/ast/xmlhelp.cc
===================================================================
--- vendor/elsa/current/ast/xmlhelp.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/xmlhelp.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,449 @@
+// xmlhelp.cc
+// support routines for XML reading/writing
+
+#include "xmlhelp.h"            // this module
+#include <stdlib.h>             // atof, atol
+#include <ctype.h>              // isprint, isdigit, isxdigit
+#include <stdio.h>              // sprintf
+// #include "strtokp.h"            // StrtokParse
+#include "exc.h"                // xformat
+#include "ptrintmap.h"          // PtrIntMap
+
+
+// FIX: pull this out into the configuration script
+#define CANONICAL_XML_IDS
+
+#ifdef CANONICAL_XML_IDS
+xmlUniqueId_t nextXmlUniqueId = 1;
+PtrIntMap<void const, xmlUniqueId_t> addr2id;
+#endif
+
+xmlUniqueId_t mapAddrToUniqueId(void const * const addr) {
+#ifdef CANONICAL_XML_IDS
+  // special-case the NULL pointer
+  if (addr == NULL) return 0;
+  // otherwise, maintain a map to a canonical address
+  xmlUniqueId_t id0 = addr2id.get(addr);
+  if (!id0) {
+    id0 = nextXmlUniqueId++;
+    addr2id.add(addr, id0);
+  }
+  return id0;
+#else
+  // avoid using the map
+  return reinterpret_cast<xmlUniqueId_t>(addr);
+#endif
+}
+
+// manage identity of AST nodes
+xmlUniqueId_t uniqueIdAST(void const * const obj) {
+  return mapAddrToUniqueId(obj);
+}
+
+// string xmlPrintPointer(char const *label, xmlUniqueId_t id) {
+//   stringBuilder sb;
+//   sb.reserve(20);
+//   if (!id) {
+//     // sm: previously, the code for this function just inserted 'p'
+//     // as a 'void const *', but that is nonportable, as gcc-3 inserts
+//     // "0" while gcc-2 emits "(nil)"
+//     sb << label << "0";
+//   }
+//   else {
+//     sb << label;
+//     // sm: I question whether this is portable, but it may not matter
+//     // since null pointers are the only ones that are treated
+//     // specially (as far as I can tell)
+// //     sb << stringBuilder::Hex(reinterpret_cast<long unsigned>(p));
+//     // dsw: just using ints now
+//     sb << id;
+//   }
+//   return sb;
+// }
+
+// string toXml_bool(bool b) {
+//   if (b) return "true";
+//   else return "false";
+// }
+
+
+// string toXml_int(int i) {
+//   return stringc << i;
+// }
+
+void fromXml_int(int &i, const char *str) {
+  long i0 = strtol(str, NULL, 10);
+  i = i0;
+}
+
+
+// string toXml_long(long i) {
+//   return stringc << i;
+// }
+
+void fromXml_long(long &i, const char *str) {
+  long i0 = strtol(str, NULL, 10);
+  i = i0;
+}
+
+
+// string toXml_unsigned_int(unsigned int i) {
+//   return stringc << i;
+// }
+
+void fromXml_unsigned_int(unsigned int &i, const char *str) {
+  unsigned long i0 = strtoul(str, NULL, 10);
+  i = i0;
+}
+
+
+// string toXml_unsigned_long(unsigned long i) {
+//   return stringc << i;
+// }
+
+void fromXml_unsigned_long(unsigned long &i, const char *str) {
+  unsigned long i0 = strtoul(str, NULL, 10);
+  i = i0;
+}
+
+
+// string toXml_double(double x) {
+//   return stringc << x;
+// }
+
+void fromXml_double(double &x, const char *str) {
+  x = atof(str);
+}
+
+
+string toXml_SourceLoc(SourceLoc loc) {
+  // use "(noloc)" and "(init)" so we don't have to encode to &lt;init&gt;
+  if (loc == SL_UNKNOWN) {
+    return "(noloc)";
+  } else if (loc == SL_INIT) {
+    return "(init)";
+  } else {
+    // NOTE: the nohashline here is very important; never change it
+    return sourceLocManager->getString_nohashline(loc);
+  }
+}
+
+// Avoid allocating memory to construct a substring, by being sneaky.  This
+// isn't thread safe.  When put on the stack, the optimizer should only end up
+// using one word, for 'save'.
+class SneakySubstring {
+public:
+  SneakySubstring(const char *begin0, const char *end0)
+    : begin(begin0), end(end0), save(*end0)
+  {
+    const_cast<char*>(end) [0] = '\0';
+  }
+
+  ~SneakySubstring() {
+    const_cast<char*>(end) [0] = save;
+  }
+
+  operator const char *() const {
+    return begin;
+  }
+
+  const char *begin;
+  const char *end;
+  char save;
+};
+
+
+// #define string_prefix_match(s, prefix) (0==strncmp(s, prefix, sizeof(prefix)-1))
+
+// Note: this function is performance-critical for deserialization, so don't
+// use StrtokParse.
+void fromXml_SourceLoc(SourceLoc &loc, const char *str) {
+  // the file format is filename:line:column
+
+  if (streq(str, "(noloc)")) {
+    loc = SL_UNKNOWN;
+    return;
+  }
+
+  if (streq(str, "(init)")) {
+    loc = SL_INIT;
+    return;
+  }
+
+  char const *end = str + strlen(str);
+
+  int line;
+  int col;
+
+  while (true) {
+    if (end <= str) {
+      // FIX: this is a parsing error but I don't want to throw an
+      // exception out of this library function
+      loc = SL_UNKNOWN;
+      return;
+    }
+
+    end--;
+    if (*end == ':') {
+      col = atoi(end+1);
+      if (!col) {
+        loc = SL_UNKNOWN;
+        return;
+      }
+      break;
+    }
+
+    if (!isdigit(*end)) {
+      loc = SL_UNKNOWN;
+      return;
+    }
+  }
+
+  while (true) {
+    if (end <= str) {
+      loc = SL_UNKNOWN;
+      return;
+    }
+
+    end--;
+    if (*end == ':') {
+      line = atoi(end+1);
+      if (!line) {
+        loc = SL_UNKNOWN;
+        return;
+      }
+      break;
+    }
+
+    if (!isdigit(*end)) {
+      loc = SL_UNKNOWN;
+      return;
+    }
+  }
+
+  if (end <= str) {
+    loc = SL_UNKNOWN;
+    return;
+  }
+
+  // the substring (str, end] is the filename.
+  SneakySubstring file(str, end);
+
+  loc = sourceLocManager->encodeLineCol(file, line, col);
+}
+
+// named escape codes
+#define lt_CODE "lt;"
+#define gt_CODE "gt;"
+#define amp_CODE "amp;"
+#define quot_CODE "quot;"
+#define apos_CODE "apos;"
+// int const lt_codelen   = strlen(lt_CODE);
+// int const gt_codelen   = strlen(gt_CODE);
+// int const amp_codelen  = strlen(amp_CODE);
+// int const quot_codelen = strlen(quot_CODE);
+
+// Output SRC with escaping and quotes to output stream directly.  This is
+// more efficient than constructing strings and then outputting that.
+ostream &outputXmlAttrQuoted(ostream &o, const char *src)
+{
+  o << '\'';
+
+  for (; *src; ++src) {
+    unsigned char c = *src;
+
+    // escape those special to xml attributes;
+    // http://www.w3.org/TR/2004/REC-xml-20040204/#NT-AttValue
+    switch (c) {
+    default: break;             // try below
+    case '<': o << "&" lt_CODE;   continue;
+    case '>': o << "&" gt_CODE;   continue; // this one not strictly required here
+    case '&': o << "&" amp_CODE;  continue;
+      // Don't need to escape '"' if surrounding quote is "'"
+    // case '"': o << "&" quot_CODE; continue;
+    case '\'': o << "&" apos_CODE; continue;
+    }
+
+    // try itself
+    if (isprint(c)) {
+      o << c;
+      continue;
+    }
+
+    // use the most general notation
+    char tmp[7];
+    // dsw: the sillyness of XML knows no bounds: it is actually more
+    // efficient to use the decimal encoding since sometimes you only
+    // need 4 or 5 characters, whereas with hex you are guaranteed to
+    // need 6, however the uniformity makes it easier to decode hex.
+    // Why not make the shorter encoding also the default so that it
+    // really is shorter in the big picture?
+    sprintf(tmp, "&#x%02X;", c);
+    o << tmp;
+  }
+
+  return o << '\'';
+}
+
+string xmlAttrEncode(char const *p, int len) {
+  stringBuilder sb;
+  sb.reserve(len*3/2);
+
+  for(int i=0; i<len; ++i) {
+    unsigned char c = p[i];
+
+    // escape those special to xml attributes;
+    // http://www.w3.org/TR/2004/REC-xml-20040204/#NT-AttValue
+    switch (c) {
+    default: break;             // try below
+    case '<': sb << "&" lt_CODE;   continue;
+    case '>': sb << "&" gt_CODE;   continue; // this one not strictly required here
+    case '&': sb << "&" amp_CODE;  continue;
+    case '"': sb << "&" quot_CODE; continue;
+    case '\'': sb << "&" apos_CODE; continue;
+    }
+
+    // try itself
+    if (isprint(c)) {
+      sb << c;
+      continue;
+    }
+
+    // use the most general notation
+    char tmp[7];
+    // dsw: the sillyness of XML knows no bounds: it is actually more
+    // efficient to use the decimal encoding since sometimes you only
+    // need 4 or 5 characters, whereas with hex you are guaranteed to
+    // need 6, however the uniformity makes it easier to decode hex.
+    // Why not make the shorter encoding also the default so that it
+    // really is shorter in the big picture?
+    sprintf(tmp, "&#x%02X;", c);
+    sb << tmp;
+  }
+
+  return sb;
+}
+
+string xmlAttrEncode(const char *src) {
+  return xmlAttrEncode(src, strlen(src));
+}
+
+string xmlAttrQuote(const char *src) {
+  return stringc << '\''
+                 << xmlAttrEncode(src)
+                 << '\'';
+}
+
+// XML dequoting and unescaping is now done in the lexer: see
+// xml_lex_extra.cc.
+
+
+// string xmlAttrDeQuote(const char *text) {
+//   int len = strlen(text);
+
+//   if ( text[0] == '\'' && text[len-1] == '\'' ) {
+//     // decode escapes
+//     return xmlAttrDecode(text+1, text+len-1, '\'');
+//   }
+
+//   if ( text[0] == '"' && text[len-1] == '"' ) {
+//     // decode escapes
+//     return xmlAttrDecode(text+1, text+len-1, '"');
+//   }
+
+//   xformat(stringc << "quoted string is missing quotes: " << text);
+// }
+
+// // process characters between 'src' and 'end'.  The 'end' is so we don't have
+// // to create a new string just to strip quotes.
+// string xmlAttrDecode(char const *src, const char *end, char delim)
+// {
+//   stringBuilder result;
+//   result.reserve(end-src);
+//   while (src != end) {
+//     // check for newlines
+//     if (*src == '\n') {
+//       xformat("unescaped newline (unterminated string)");
+//     }
+
+//     // check for the delimiter
+//     if (*src == delim) {
+//       xformat(stringc << "unescaped delimiter (" << delim << ") in "
+//               << substring(src,end-src));
+//     }
+
+//     // check for normal characters
+//     if (*src != '&') {
+//       // normal character
+//       result << char(*src);
+//       src++;
+//       continue;
+//     }
+//     src++;                      // advance past amperstand
+
+//     // checked for named escape codes
+// #define DO_ESCAPE(NAME, CHAR)
+//     if (strncmp(NAME ##_CODE, src, (sizeof(NAME ##_CODE)-1)) == 0) {
+//       result << char(CHAR);
+//       src += (sizeof(NAME ##_CODE)-1);
+//       continue;
+//     }
+
+//     DO_ESCAPE(lt,   '<');
+//     DO_ESCAPE(gt,   '>');
+//     DO_ESCAPE(amp,  '&');
+//     DO_ESCAPE(quot, '"');
+//     DO_ESCAPE(apos, '\'');
+// #undef DO_ESCAPE
+
+//     // check for numerical escapes
+//     if (*src != '#') {
+//       xformat(stringc << "use of an unimplemented or illegal amperstand escape (" << *src << ")");
+//     }
+//     ++src;
+
+//     // process decimal and hex escapes: decimal '&#DDD;' where D is a
+//     // decimal digit or hexadecimal '&#xHH;' where H is a hex digit.
+//     if (!(*src == 'x' || isdigit(*src))) {
+//       xformat(stringc << "illegal charcter after '&#' (" << *src << ")");
+//     }
+
+//     // are we doing hex or decimal processing?
+//     //
+//     // http://www.w3.org/TR/2004/REC-xml-20040204/#NT-CharRef "If the
+//     // character reference begins with "&#x", the digits and letters
+//     // up to the terminating ; provide a hexadecimal representation of
+//     // the character's code point in ISO/IEC 10646. If it begins just
+//     // with "&#", the digits up to the terminating ; provide a decimal
+//     // representation of the character's code point."
+//     bool hex = (*src == 'x');
+//     if (hex) {
+//       src++;
+
+//       // strtoul is willing to skip leading whitespace, so I need
+//       // to catch it myself
+//       if (!isxdigit(*src)) {
+//         // dsw: NOTE: in the non-hex case, the leading digit has
+//         // already been seen
+//         xformat("non-hex digit following '&#x' escape");
+//       }
+//       xassert(isxdigit(*src));
+//     } else {
+//       xassert(isdigit(*src));
+//     }
+
+//     // parse the digit
+//     char const *endptr;
+//     unsigned long val = strtoul(src, (char**)&endptr, hex? 16 : 10);
+//     if (src == endptr) {
+//       // this can't happen with the octal escapes because
+//       // there is always at least one valid digit
+//       xformat("invalid '&#' escape");
+//     }
+
+//     // keep it
+//     result << ((char)(unsigned char)val);    // possible truncation..
+//     src = endptr;
+//   }
+//   return result;
+// }

Added: vendor/elsa/current/ast/xmlhelp.h
===================================================================
--- vendor/elsa/current/ast/xmlhelp.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/ast/xmlhelp.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,150 @@
+// xmlhelp.h            see license.txt for copyright and terms of use
+// included by generated ast code
+
+// Generic serialization and de-serialization support.
+
+#ifndef XMLHELP_H
+#define XMLHELP_H
+
+#include "str.h"         // string
+#include "srcloc.h"      // SourceLoc
+
+typedef unsigned long xmlUniqueId_t;
+
+// manage identity canonicality; we now map addresses one to one to a
+// sequence number; this means that the ids should be canonical now
+// given isomorphic inputs
+xmlUniqueId_t mapAddrToUniqueId(void const * const addr);
+
+// manage identity of AST; FIX: I am not absolutely sure that we are
+// not accidentally using this for user classes instead of just AST
+// classes; to be absolutely sure, make a superclass of all of the AST
+// classes and make the argument here take a pointer to that.
+xmlUniqueId_t uniqueIdAST(void const * const obj);
+
+// Print a unique id with prefix, directly to output stream, for example
+// "FL12345678"; guaranteed to print (e.g.) "FL0" for NULL pointers; the "FL"
+// part is the label
+//
+// quarl 2006-05-22: print directly to stream without 'string' creation
+static inline
+ostream &outputXmlPointer(ostream &out, char const *label, xmlUniqueId_t id) {
+  if (id == 0) {
+    // make it easy to parse this later, as a string without a label
+    return out << "(null)";
+  } else {
+    return out << label << id;
+  }
+}
+
+static inline
+ostream &outputXmlPointerQuoted(ostream &out, char const *label, xmlUniqueId_t id) {
+  if (id == 0) {
+    return out << "'(null)'";
+  } else {
+    // assume label does not contain characters requiring quoting/escaping
+    return out << '\'' << label << id << '\'';
+  }
+}
+
+// string xmlPrintPointer(char const *label, xmlUniqueId_t id);
+
+
+// quarl 2006-05-05 These used to take an rostring, but I changed them to const char
+// *, because these functions are performance-critical and they were not
+// strings until now, so don't allocate a string just to call these functions.
+
+// I have manually mangled the name to include "_bool" or "_int" as
+// otherwise what happens is that if a toXml() for some enum flag is
+// missing then the C++ compiler will just use the toXml(bool)
+// instead, which is a bug.
+
+// string toXml_bool(bool b);
+static inline const char * toXml_bool(bool b) { return b ? "true" : "false"; }
+
+static inline
+bool fromXml_bool(const char *str) { return streq(str, "true"); }
+static inline
+void fromXml_bool(bool &b, const char *str) { b = fromXml_bool(str); }
+
+// string toXml_int(int i);
+static inline int toXml_int(int i) { return i; }
+void fromXml_int(int &i, const char *str);
+
+// string toXml_long(long i);
+static inline long toXml_long(long i) { return i; }
+void fromXml_long(long &i, const char *str);
+
+// string toXml_unsigned_int(unsigned int i);
+static inline unsigned int toXml_unsigned_int(unsigned int i) { return i; }
+void fromXml_unsigned_int(unsigned int &i, const char *str);
+
+// string toXml_unsigned_long(unsigned long i);
+static inline unsigned long toXml_unsigned_long(unsigned long i) { return i; }
+void fromXml_unsigned_long(unsigned long &i, const char *str);
+
+// string toXml_double(double x);
+static inline double toXml_double(double i) { return i; }
+void fromXml_double(double &x, const char *str);
+
+string toXml_SourceLoc(SourceLoc loc);
+void fromXml_SourceLoc(SourceLoc &loc, const char *str);
+
+// output SRC with encoding and quotes around it.
+ostream &outputXmlAttrQuoted(ostream &o, const char *src);
+static inline ostream &outputXmlAttrQuoted(ostream &o, string const &src)
+{ return outputXmlAttrQuoted(o, src.c_str()); }
+
+// Output SRC with quotes, but no encoding.  Only use with objects that do not
+// contain ["'<>&]
+//
+// Works for any type with ostream insertion operators, e.g. const char*,
+// string, int, ...  Avoiding going to a string improves serialization
+// performance a lot.
+template <typename T>
+inline
+ostream &outputXmlAttrQuotedNoEscape(ostream &o, T src)
+{
+  return o << '\'' << src << '\'';
+}
+
+// for quoting and unquoting xml attribute strings
+string xmlAttrQuote(const char *src);
+inline string xmlAttrQuote(rostring src) { return xmlAttrQuote(src.c_str()); }
+// string xmlAttrEncode(char const *src);
+// string xmlAttrEncode(char const *p, int len);
+
+
+// Use of xmlAttrDeQuote() is now almost certainly an error since the lexer
+// returns dequoted/unescaped strings.
+
+// string xmlAttrDeQuote(const char *text);
+// // dsw: This function does not process all XML escapes.  I only
+// // process the ones that I use in the partner encoding function
+// // xmlAttrEncode().
+// string xmlAttrDecode(char const *src, const char *end, char delim);
+
+
+// write N spaces to OUT.
+static inline
+void writeSpaces(ostream &out, size_t n)
+{
+  static char const spaces[] =
+    "                                                  "
+    "                                                  "
+    "                                                  "
+    "                                                  ";
+
+  static size_t const max_spaces = sizeof spaces - 1;
+
+  // If we're printing more than this many spaces it's pretty useless anyway,
+  // since it's only for human viewing pleasure!
+  while (n > max_spaces) {
+    out.write(spaces, max_spaces);
+    n -= max_spaces;
+  }
+  out.write(spaces, n);
+}
+
+
+#endif // XMLHELP_H

Added: vendor/elsa/current/elkhound/algorithm.html
===================================================================
--- vendor/elsa/current/elkhound/algorithm.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/algorithm.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,177 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elkhound Algorithm</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+  </style>
+</HEAD>
+
+<body>
+
+<center><h2>
+Elkhound Algorithm
+</h2></center>
+
+<p>
+This page describes some of the details of the variant of GLR that
+Elkhound uses, placing it in context with some of the other GLR
+variants that have been proposed.
+
+<h1>Goals</h1>
+
+<p>
+First, the primary goals of Elkhound:
+<ol>
+<li>It must have the capability to execute arbitrary user-provided
+    reduction actions.  Building a parse tree isn't good enough, it
+    takes too much time and space.
+<li>Reductions and merges should be performed bottom-up (unless the
+    grammar is cyclic).
+<li>It should be competitive with Bison for LALR (fragements of)
+    grammars, and degrade gracefully from there.  On the scale of
+    grammar nondeterminism, from none (LALR) to some to lots, "some" 
+    is the niche Elkhound is going after.
+</ol>
+
+<p>
+These goals are driven by Elkhound's primary application, the
+Elsa C++ Parser.  In essence, Elkhound came about because I wanted
+to apply automatic parsing technology to parsing C++, but found
+exiting systems inadequate.
+
+<h1>History</h1>
+
+<p>
+The approximate algorithm descendency sequence:
+<ul>
+<li>Bernard Lang is typically credited with the original GLR idea:
+    <blockquote>  
+      Deterministic Techniques for Efficient Non-deterministic Parsers.<br>
+      Bernard Lang.<br>
+      Automata, Languages and Programming, Springer, 1974.
+    </blockquote>
+<li>Later, Tomita published the algorithm with the intent of using it
+    for natural language processing.  He popularized the term
+    "Generalized LR Parsing", or GLR.
+    <blockquote>
+      Efficient Parsing for Natural Language.<br>
+      Masaru Tomita.<br>
+      Int. Series in Engineering and Computer Science, Kluwer, 1985.
+    </blockquote>
+<li>Tomita's algorithm fails for some grammars with epsilon rules.
+    Farshi proposed a fix involving doing a GSS search after some
+    reductions.
+    <blockquote>
+      GLR Parsing for epsilon-grammars.<br>
+      Rahman Nozohoor-Farshi.<br>
+      In Generalized LR Parsing, Kluwer, 1991.
+    </blockquote>
+<li>Rekers adapted Farshi's solution for use in
+    <a href="http://www.cwi.nl/htbin/sen1/twiki/bin/view/SEN1/MetaEnvironment">ASF+SDF</a>.
+    Rekers added
+    parse table construction to what was otherwise a recognizer.
+    His algorithm was what I based the original Elkhound 
+    implementation on.
+    <blockquote>
+      Parser Generation for Interactive Environments.<br>
+      Jan Rekers.<br>
+      PhD thesis, University of Amsterdam, 1992.
+    </blockquote>
+<li>When straightforwardly modified to execute user actions, the Rekers 
+    algorithm does not always do merges and reductions bottom-up, which makes
+    using it in a parser much harder.  Further,
+    it is slower than Bison (by about a factor of 10) even on LALR grammars.
+    George Necula and I remedied these deficiencies while building the Elkhound GLR parser
+    generator.
+    <blockquote>
+      <a href="http://www.cs.berkeley.edu/~smcpeak/papers/elkhound_cc04.ps">
+      Elkhound: A Fast, Practical GLR Parser Generator.</a><br>
+      Scott McPeak and George C. Necula.<br>
+      In Proceedings of Conference on Compiler Constructor (CC04), 2004.
+    </blockquote>
+</ul>
+
+<h1>Right Nulled GLR</h1>
+
+<p>
+At the CC04 conference I became acquainted with <a
+href="http://www.cs.rhul.ac.uk/people/staff/johnstone.html">Adrian
+Johnstone</a> and his work.  He and his coathors have not only more
+thoroughly documented the history of GLR, but also proposed a novel
+alternative solution to the problem Farshi originally addressed,
+which they call "Right Nulled GLR Parsing".
+
+<p>
+The basic idea of Right Nulled GLR is, rather than re-examining work
+already done to check for newly exposed reduction opportunities (as
+Farshi does), do those reductions that would be found by the search
+earlier in the parse, namely as soon as the rule in question only
+has nullable components remaining to recognize.
+
+<p>
+However, while this approach is certainly appealing, I still have
+questions about exactly how to adapt it to use user-defined reduction
+actions.  At some point I want to implement the right-nulled variant
+in Elkhound to experiment more with it, but haven't gotten around to it.
+
+<h1>Algorithm Features</h1>
+
+<p>
+The
+<a href="http://www.cs.berkeley.edu/~smcpeak/papers/elkhound_tr.ps">Technical Report</a>
+has most of the details, so I'll just point out some key distinguishing
+characteristics here.
+
+<ul>
+<li><strong>Hybrid LR/GLR.</strong>
+    The Elkhound Graph-Structured Stack carries
+    sufficient information (in the form of the "deterministic depth") to
+    tell when a given parse action (shift or reduce) can be performed
+    using the ordinary LR algorithm.  Essentially, if there isn't any
+    nondeterminism near the stack top, LR can be used.  LR actions are
+    much faster to execute, so this leads to a big performance win (a
+    factor of 5 to 10) when the input and grammar are mostly deterministic.
+    
+<li><strong>User-defined Actions.</strong>  In addition to the usual
+    reduction actions (such as with Bison), Elkhound exposes actions
+    to create and destroy semantic values (dup and del), and an action
+    to merge ambiguous regions (merge).  The user can then do whatever
+    is desired in these actions, typically building an abstract syntax
+    tree.  In contrast, most other GLR implementations build a parse 
+    tree, which is quite expensive.  (Parse trees tend to be at least
+    10 times larger than abstract syntax trees.)
+
+<li><strong>Reduction Worklist.</strong> As alluded to above, the
+    Rekers algorithm will sometimes mix up the order of reduces and
+    merges.  The problem is with the granularity of the GSS Node
+    worklist; it forces certain actions (all those associated with the
+    node) to happen together, even when something else should happen
+    in between.  Elkhound solves this by maintaining a finer-grained
+    worklist of reduction opportunties, and keeps this worklist sorted
+    in a specific order, such that a bottom-up reduction/merge order
+    will always be used when possible.  (With a cyclic grammar, there
+    may be a cycle in the reduction order, precluding bottom-up
+    execution.  Elkhound reports cyclic grammars to the user, but then
+    goes ahead and parses with them.)
+
+<li><strong>Reference-Counted GSS.</strong>  This is mostly a minor 
+    detail, but using reference counting in the GSS produces much
+    better locality than garbage collection alone (and manual
+    deallocation is impossible due to the nature of the algorithm).
+
+<li><strong>C++ and OCaml Interfaces.</strong> Though not a feature of
+    the parsing algorithm per se, a nice feature is the ability to let
+    the user write actions in either C++ or OCaml.  There are actually
+    two parser core impementations, a C++ implementation and an OCaml
+    implementation, and the user simply links Elkhound's output with
+    the appropriate parser core.
+</ul>
+
+</body>
+</html>

Added: vendor/elsa/current/elkhound/asfsdf/DeclExpr.sdf
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/DeclExpr.sdf	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/DeclExpr.sdf	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+module DeclExpr
+
+exports
+  sorts Body Stmt Decl Declarator Expr
+  context-free syntax
+                       -> Body
+    Body Stmt          -> Body
+    Decl "S"           -> Stmt
+    Expr "S"           -> Stmt
+    Id Declarator      -> Decl
+    "A"                -> Id
+    "B"                -> Id
+    Id                 -> Declarator
+    "L" Declarator "R" -> Declarator
+    Id                 -> Expr
+    Expr "L" Expr "R"  -> Expr

Added: vendor/elsa/current/elkhound/asfsdf/EEb.sdf
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/EEb.sdf	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/EEb.sdf	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+module EEb
+
+exports
+  sorts E
+  context-free syntax
+    "B" -> E
+    E "P" E -> E

Added: vendor/elsa/current/elkhound/asfsdf/EFa.sdf
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/EFa.sdf	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/EFa.sdf	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+module EFa
+
+exports
+  sorts S E F
+  context-free syntax
+    E            -> S
+    E "P" F      -> E
+    F            -> E
+    "A"          -> F
+    "L" E "R"    -> F

Added: vendor/elsa/current/elkhound/asfsdf/SSSx.sdf
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/SSSx.sdf	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/SSSx.sdf	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+module SSSx
+
+exports
+  sorts S
+  context-free syntax
+    "X" -> S
+    S "X" -> S
+    S S S "X" -> S

Added: vendor/elsa/current/elkhound/asfsdf/SSx.sdf
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/SSx.sdf	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/SSx.sdf	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+module SSx
+
+exports
+  sorts S
+  context-free syntax
+    "X" -> S
+    S S "X" -> S

Added: vendor/elsa/current/elkhound/asfsdf/eeb.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/eeb.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/eeb.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+10: cycles: 592250
+20: cycles: 2436987
+50: cycles: 35102835
+100: cycles: 414115950
+200: cycles: 10897627702
+300: cycles: 69762992460
+400: cycles: 228609216127
+500: cycles: 557131498838

Added: vendor/elsa/current/elkhound/asfsdf/eeb.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/eeb.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/eeb.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+ 5: cycles:   5889086
+ 6: cycles:   9165321
+ 7: cycles:  18729383
+ 8: cycles:  48019177
+ 9: cycles: 105785430
+10: cycles: 292349917

Added: vendor/elsa/current/elkhound/asfsdf/efa.notree.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/efa.notree.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/efa.notree.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 3602372
+0000500, 3413044
+0000500, 3409554
+0000500, 3567939
+0000500, 3445549
+0001000, 5893168
+0001000, 7736205
+0001000, 5864206
+0001000, 6072278
+0001000, 5876330
+0001500, 8822207
+0001500, 8467045
+0001500, 8000135
+0001500, 7976734
+0001500, 8180892
+0002000, 10382210
+0002000, 10375647
+0002000, 10566682
+0002000, 10426787
+0002000, 10416647
+0002500, 16844756
+0002500, 12808527
+0002500, 13179843
+0002500, 13099013
+0002500, 13156147
+0005000, 24424723
+0005000, 24436030
+0005000, 24515253
+0005000, 24424837
+0005000, 24468688
+0010000, 47760632
+0010000, 48856720
+0010000, 49196258
+0010000, 48275583
+0010000, 47706903
+0020000, 94840592
+0020000, 94463072
+0020000, 94631887
+0020000, 94986202
+0020000, 95462095
+0050000, 242764140
+0050000, 233270055
+0050000, 238135830
+0050000, 234319920
+0050000, 241165230
+0100000, 475619670
+0100000, 472328718
+0100000, 466762545
+0100000, 486616283
+0100000, 471815430
+0200000, 936755970
+0200000, 938811765
+0200000, 943384350
+0200000, 940773135
+0200000, 936041482
+0500000, 2338350288
+0500000, 2349988072
+0500000, 2355230400
+0500000, 2335178347
+0500000, 2343157125
+1000000, 4685258992
+1000000, 4692103275
+1000000, 4701080565
+1000000, 4705671922
+1000000, 4681277325

Added: vendor/elsa/current/elkhound/asfsdf/efa.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/efa.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/efa.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+../efa.in/0000500.in: cycles: 3602372
+../efa.in/0000500.in: cycles: 3413044
+../efa.in/0000500.in: cycles: 3409554
+../efa.in/0000500.in: cycles: 3567939
+../efa.in/0000500.in: cycles: 3445549
+../efa.in/0001000.in: cycles: 5893168
+../efa.in/0001000.in: cycles: 7736205
+../efa.in/0001000.in: cycles: 5864206
+../efa.in/0001000.in: cycles: 6072278
+../efa.in/0001000.in: cycles: 5876330
+../efa.in/0001500.in: cycles: 8822207
+../efa.in/0001500.in: cycles: 8467045
+../efa.in/0001500.in: cycles: 8000135
+../efa.in/0001500.in: cycles: 7976734
+../efa.in/0001500.in: cycles: 8180892
+../efa.in/0002000.in: cycles: 10382210
+../efa.in/0002000.in: cycles: 10375647
+../efa.in/0002000.in: cycles: 10566682
+../efa.in/0002000.in: cycles: 10426787
+../efa.in/0002000.in: cycles: 10416647
+../efa.in/0002500.in: cycles: 16844756
+../efa.in/0002500.in: cycles: 12808527
+../efa.in/0002500.in: cycles: 13179843
+../efa.in/0002500.in: cycles: 13099013
+../efa.in/0002500.in: cycles: 13156147
+../efa.in/0005000.in: cycles: 24424723
+../efa.in/0005000.in: cycles: 24436030
+../efa.in/0005000.in: cycles: 24515253
+../efa.in/0005000.in: cycles: 24424837
+../efa.in/0005000.in: cycles: 24468688
+../efa.in/0010000.in: cycles: 47760632
+../efa.in/0010000.in: cycles: 48856720
+../efa.in/0010000.in: cycles: 49196258
+../efa.in/0010000.in: cycles: 48275583
+../efa.in/0010000.in: cycles: 47706903
+../efa.in/0020000.in: cycles: 94840592
+../efa.in/0020000.in: cycles: 94463072
+../efa.in/0020000.in: cycles: 94631887
+../efa.in/0020000.in: cycles: 94986202
+../efa.in/0020000.in: cycles: 95462095
+../efa.in/0050000.in: cycles: 242764140
+../efa.in/0050000.in: cycles: 233270055
+../efa.in/0050000.in: cycles: 238135830
+../efa.in/0050000.in: cycles: 234319920
+../efa.in/0050000.in: cycles: 241165230
+../efa.in/0100000.in: cycles: 475619670
+../efa.in/0100000.in: cycles: 472328718
+../efa.in/0100000.in: cycles: 466762545
+../efa.in/0100000.in: cycles: 486616283
+../efa.in/0100000.in: cycles: 471815430
+../efa.in/0200000.in: cycles: 936755970
+../efa.in/0200000.in: cycles: 938811765
+../efa.in/0200000.in: cycles: 943384350
+../efa.in/0200000.in: cycles: 940773135
+../efa.in/0200000.in: cycles: 936041482
+../efa.in/0500000.in: cycles: 2338350288
+../efa.in/0500000.in: cycles: 2349988072
+../efa.in/0500000.in: cycles: 2355230400
+../efa.in/0500000.in: cycles: 2335178347
+../efa.in/0500000.in: cycles: 2343157125
+../efa.in/1000000.in: cycles: 4685258992
+../efa.in/1000000.in: cycles: 4692103275
+../efa.in/1000000.in: cycles: 4701080565
+../efa.in/1000000.in: cycles: 4705671922
+../efa.in/1000000.in: cycles: 4681277325

Added: vendor/elsa/current/elkhound/asfsdf/efa.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/efa.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/efa.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+0000500, 20082205
+0000500, 20397000
+0000500, 20265000
+0000500, 20049199
+0000500, 20009402
+0001000, 39390465
+0001000, 39024007
+0001000, 38781728
+0001000, 39001867
+0001000, 38756895
+0001500, 57667140
+0001500, 56580833
+0001500, 57166710
+0001500, 57145065
+0001500, 58233780
+0002000, 75206745
+0002000, 75557033
+0002000, 85096920
+0002000, 78950475
+0002000, 75778545
+0002500, 113005658
+0002500, 118383915
+0002500, 112738118
+0002500, 112515277
+0002500, 121288403
+0005000, 230798782
+0005000, 234235425
+0005000, 226620457
+0005000, 245898953
+0005000, 233611192
+0010000, 517186703
+0010000, 516489180
+0010000, 516013192
+0010000, 519726210
+0010000, 514849425
+0020000, 1092321030
+0020000, 1083544365
+0020000, 1095053317
+0020000, 1092971287
+0020000, 1086921510
+0050000, 2712677453
+0050000, 2686555065
+0050000, 2690419170
+0050000, 2693230185
+0050000, 2693112495

Added: vendor/elsa/current/elkhound/asfsdf/efa.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/efa.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/efa.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,70 @@
+../efa.in/0000500.in: cycles: 20082205
+../efa.in/0000500.in: cycles: 20397000
+../efa.in/0000500.in: cycles: 20265000
+../efa.in/0000500.in: cycles: 20049199
+../efa.in/0000500.in: cycles: 20009402
+../efa.in/0001000.in: cycles: 39390465
+../efa.in/0001000.in: cycles: 39024007
+../efa.in/0001000.in: cycles: 38781728
+../efa.in/0001000.in: cycles: 39001867
+../efa.in/0001000.in: cycles: 38756895
+../efa.in/0001500.in: cycles: 57667140
+../efa.in/0001500.in: cycles: 56580833
+../efa.in/0001500.in: cycles: 57166710
+../efa.in/0001500.in: cycles: 57145065
+../efa.in/0001500.in: cycles: 58233780
+../efa.in/0002000.in: cycles: 75206745
+../efa.in/0002000.in: cycles: 75557033
+../efa.in/0002000.in: cycles: 85096920
+../efa.in/0002000.in: cycles: 78950475
+../efa.in/0002000.in: cycles: 75778545
+../efa.in/0002500.in: cycles: 113005658
+../efa.in/0002500.in: cycles: 118383915
+../efa.in/0002500.in: cycles: 112738118
+../efa.in/0002500.in: cycles: 112515277
+../efa.in/0002500.in: cycles: 121288403
+../efa.in/0005000.in: cycles: 230798782
+../efa.in/0005000.in: cycles: 234235425
+../efa.in/0005000.in: cycles: 226620457
+../efa.in/0005000.in: cycles: 245898953
+../efa.in/0005000.in: cycles: 233611192
+../efa.in/0010000.in: cycles: 517186703
+../efa.in/0010000.in: cycles: 516489180
+../efa.in/0010000.in: cycles: 516013192
+../efa.in/0010000.in: cycles: 519726210
+../efa.in/0010000.in: cycles: 514849425
+../efa.in/0020000.in: cycles: 1092321030
+../efa.in/0020000.in: cycles: 1083544365
+../efa.in/0020000.in: cycles: 1095053317
+../efa.in/0020000.in: cycles: 1092971287
+../efa.in/0020000.in: cycles: 1086921510
+../efa.in/0050000.in: cycles: 2712677453
+failed
+../efa.in/0050000.in: cycles: 2686555065
+failed
+../efa.in/0050000.in: cycles: 2690419170
+failed
+../efa.in/0050000.in: cycles: 2693230185
+failed
+../efa.in/0050000.in: cycles: 2693112495
+failed
+../efa.in/0100000.in: failed
+../efa.in/0100000.in: failed
+../efa.in/0100000.in: failed
+../efa.in/0100000.in: failed
+../efa.in/0100000.in: failed
+../efa.in/0200000.in: failed
+../efa.in/0200000.in: failed
+../efa.in/0200000.in: failed
+../efa.in/0200000.in: failed
+../efa.in/0200000.in: failed
+../efa.in/0500000.in: failed
+../efa.in/0500000.in: failed
+../efa.in/0500000.in: failed
+../efa.in/0500000.in: failed
+../efa.in/0500000.in: failed
+../efa.in/1000000.in: failed
+../efa.in/1000000.in: failed
+../efa.in/1000000.in: failed
+../efa.in/1000000.in: failed
+../efa.in/1000000.in: failed

Added: vendor/elsa/current/elkhound/asfsdf/sssx.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/sssx.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/sssx.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+ 5: cycles:      298564
+10: cycles:    1 091220
+15: cycles:    5 895111
+20: cycles:   24 536822
+25: cycles:   71 899223
+30: cycles:  175 874242
+35: cycles:  392 732805
+40: cycles:  830 328802
+45: cycles: 1468 454070
+50: cycles: 2463 636060

Added: vendor/elsa/current/elkhound/asfsdf/sssx.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/sssx.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/sssx.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+ 5: cycles:   3 247020
+ 7: cycles:   6 102313
+10: cycles:  34 942777
+12: cycles: 138 589132
+14: cycles: 571 347922

Added: vendor/elsa/current/elkhound/asfsdf/ssx.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/ssx.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/ssx.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+ 5: cycles:     249842
+15: cycles:     521435
+25: cycles:   1 479563
+35: cycles:   4 580909
+45: cycles:   8 536117
+55: cycles:  16 167090
+65: cycles:  27 220080
+75: cycles:  48 466440
+85: cycles:  74 226510
+99: cycles: 140 182065

Added: vendor/elsa/current/elkhound/asfsdf/ssx.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/asfsdf/ssx.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asfsdf/ssx.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+ 5: cycles:   3 108 245
+ 7: cycles:   3 290 083
+ 9: cycles:   3 921 596
+11: cycles:   5 799 310
+13: cycles:   9 342 604
+15: cycles:  18 139 977
+17: cycles:  42 129 670
+19: cycles: 115 277 767
+21: cycles: 289 678 815

Added: vendor/elsa/current/elkhound/asockind.cc
===================================================================
--- vendor/elsa/current/elkhound/asockind.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asockind.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// asockind.cc            see license.txt for copyright and terms of use
+// code for asockind.h
+
+#include "asockind.h"    // this module
+#include "xassert.h"     // xassert
+
+string toString(AssocKind k)
+{
+  static char const * const arr[] = {
+    "AK_LEFT", 
+    "AK_RIGHT", 
+    "AK_NONASSOC", 
+    "AK_NEVERASSOC", 
+    "AK_SPLIT"
+  };
+  STATIC_ASSERT(TABLESIZE(arr) == NUM_ASSOC_KINDS);
+  xassert((unsigned)k < NUM_ASSOC_KINDS);
+  return string(arr[k]);
+}

Added: vendor/elsa/current/elkhound/asockind.h
===================================================================
--- vendor/elsa/current/elkhound/asockind.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/asockind.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// asockind.h            see license.txt for copyright and terms of use
+// AssocKind; pulled out on its own so I don't have dependency problems
+
+#ifndef ASOCKIND_H
+#define ASOCKIND_H
+
+#include "str.h"      // string
+  
+// specifies what to do when there is a shift/reduce conflict, and
+// the production and token have the same precedence; this is attached
+// to the token
+enum AssocKind {
+  AK_LEFT,            // disambiguate by reducing
+  AK_RIGHT,           // disambiguate by shifting
+  AK_NONASSOC,        // make it a parse-time syntax error
+  AK_NEVERASSOC,      // make it a parsgen-time specification error
+  AK_SPLIT,           // (GLR-specific) fork the parser
+
+  NUM_ASSOC_KINDS
+};
+
+string toString(AssocKind k);
+
+#endif // ASOCKIND_H

Added: vendor/elsa/current/elkhound/c/bcparse.cc
===================================================================
--- vendor/elsa/current/elkhound/c/bcparse.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/bcparse.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,161 @@
+// bcparse.cc            see license.txt for copyright and terms of use
+// driver for bison parser for c.gr
+
+#include "bcparse.h"    // this module
+#include "lexer2.h"     // Lexer2
+#include "lexer1.h"     // Lexer1
+#include "trace.h"      // traceProgress
+#include "syserr.h"     // xsyserror
+#include "cc_lang.h"    // CCLang
+#include "cyctimer.h"   // CycleTimer
+
+#include <stdio.h>      // printf
+#include <iostream.h>   // cout, etc.
+#include <string.h>     // strcmp
+
+// global list of L2 tokens for yielding to Bison
+CCLang cclang;
+Lexer2 lexer2(cclang);
+Lexer2Token const *lastTokenYielded = NULL;
+
+// parsing entry point
+int yyparse();
+
+
+#if 0     // previous interface
+// returns token types until EOF, at which point L2_EOF is returned
+int yylex()
+{
+  static ObjListIter<Lexer2Token> *iter = NULL;
+
+  if (!iter) {
+    // prepare to return tokens
+    iter = new ObjListIter<Lexer2Token>(lexer2.tokens);
+  }
+
+  if (!iter->isDone()) {
+    // grab type to return
+    lastTokenYielded = iter->data();
+    Lexer2TokenType ret = iter->data()->type;
+
+    // advance to next token
+    iter->adv();
+
+    // since my token reclassifier is hard to translate to
+    // Bison, I'll just yield variable names always, and only
+    // parse typedef-less C programs
+    if (ret == L2_NAME) {
+      ret = L2_VARIABLE_NAME;
+    }
+
+    // return one we just advanced past
+    return ret;
+  }
+  else {
+    // done; don't bother freeing things
+    lastTokenYielded = NULL;
+    return L2_EOF;
+  }
+}
+#endif // 0
+
+
+LexerInterface::NextTokenFunc nextToken;
+
+// returns token types until EOF, at which point L2_EOF is returned
+int yylex()
+{
+  int ret = lexer2.type;
+
+  // since my token reclassifier is hard to translate to
+  // Bison, I'll just yield variable names always, and only
+  // parse typedef-less C programs
+  if (ret == L2_NAME) {
+    ret = L2_VARIABLE_NAME;
+  }
+
+  if (ret != L2_EOF) {
+    // advance to next token
+    nextToken(&lexer2);
+  }
+
+  // return one we just advanced past
+  return ret;
+}
+
+
+void yyerror(char const *s)
+{
+  if (lastTokenYielded) {
+    printf("%s: ", toString(lastTokenYielded->loc).pcharc());
+  }
+  else {
+    printf("<eof>: ");
+  }
+  printf("%s\n", s);
+}
+
+
+int main(int argc, char *argv[])
+{
+  char const *progname = argv[0];
+
+  if (argc >= 2 &&
+      0==strcmp(argv[1], "-d")) {
+    #ifdef YYDEBUG
+      yydebug = 1;
+    #else
+      printf("debugging is disabled by NDEBUG\n");
+      return 2;
+    #endif
+
+    argc--;
+    argv++;
+  }
+
+  if (argc < 2) {
+    printf("usage: %s [-d] input.c\n", progname);
+    printf("  -d: turn on yydebug, so it prints shift/reduce actions\n");
+    return 0;
+  }
+
+  char const *inputFname = argv[1];
+
+  traceAddSys("progress");
+
+  SourceLocManager mgr;
+
+  traceProgress() << "lexical analysis stage 1...\n";
+  Lexer1 lexer1(inputFname);
+  {
+    FILE *input = fopen(inputFname, "r");
+    if (!input) {
+      xsyserror("fopen", inputFname);
+    }
+
+    lexer1_lex(lexer1, input);
+    fclose(input);
+
+    if (lexer1.errors > 0) {
+      printf("L1: %d error(s)\n", lexer1.errors);
+      return 2;
+    }
+  }
+
+  // do second phase lexer
+  traceProgress() << "lexical analysis stage 2...\n";
+  lexer2_lex(lexer2, lexer1, inputFname);
+  lexer2.beginReading();
+  nextToken = lexer2.getTokenFunc();
+
+  // start Bison-parser
+  traceProgress() << "starting parse..." << endl;
+  CycleTimer timer;
+  if (yyparse() != 0) {
+    cout << "yyparse returned with an error\n";
+    return 4;
+  }
+  traceProgress() << "finished parse (" << timer.elapsed() << ")\n";
+
+  return 0;
+}

Added: vendor/elsa/current/elkhound/c/bcparse.h
===================================================================
--- vendor/elsa/current/elkhound/c/bcparse.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/bcparse.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// bcparse.h            see license.txt for copyright and terms of use
+// decls shared between bcparse.cc and c.gr.gen.y
+
+#ifndef BCPARSE_H
+#define BCPARSE_H
+
+#include <stdlib.h>     // free
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// functions called by Bison-parser
+void yyerror(char const *msg);
+int yylex();
+
+// Bison-parser entry
+int yyparse();
+extern int yydebug;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // BCPARSE_H

Added: vendor/elsa/current/elkhound/c/c.ast
===================================================================
--- vendor/elsa/current/elkhound/c/c.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/c.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,509 @@
+// c.ast            see license.txt for copyright and terms of use
+// C abstract syntax
+
+// included in generated header
+verbatim {
+  #include "sobjlist.h"      // SObjList
+  #include "c_variable.h"    // Variable
+  #include "cc_flags.h"      // CVFlags, DeclFlags, etc. (r)
+  #include "c_type.h"        // Type, FunctonType, CompoundType
+
+  class Env;                 // cc_env.h
+  class AEnv;                // aenv.h
+  class AbsValue;            // absval.ast
+  class Predicate;           // predicate.ast
+} // end verbatim
+
+// included in generated source file
+impl_verbatim {
+  //#include "cc_type.h"       // Type
+}
+
+
+// ---------------- file -------------
+// an entire file (with included stuff) of toplevel forms
+class TranslationUnit (ASTList<TopForm> topForms) {
+  // type checker
+  public void tcheck(Env &env);
+
+  // abstract interpreter
+  public void vcgen(AEnv &env) const;
+}
+
+// a toplevel form
+class TopForm (SourceLoc loc) {
+  public void tcheck(Env &env);
+  pure_virtual void itcheck(Env &env);
+  pure_virtual void vcgen(AEnv &env) const;
+
+  -> TF_decl(Declaration decl);        // includes function prototypes
+
+  // functions with bodies
+  -> TF_func(DeclFlags dflags,         // static, extern, etc.
+             TypeSpecifier retspec,    // type specifier for return value
+             Declarator nameParams,    // 1. remainder of return value type
+                                       // 2. name of function
+                                       // 3. names/types of parameters
+             S_compound body) {        // body of function
+       public FunctionType const *ftype() const;
+       public StringRef name() const;
+
+       // list of all parameters, and then all locals
+       public SObjList<Variable> params;
+       public SObjList<Variable> locals;
+
+       // list of all global variables referenced in this function;
+       // also all the struct fields referenced, since they get
+       // modeled sort of like global variables too
+       public SObjList<Variable> globalRefs;
+
+       // list of all the path starting points
+       public SObjList<Statement> roots;
+
+       // total # of paths, the sum from all roots
+       public int numPaths;
+       ctor numPaths=0;
+
+       public void printExtras(ostream &os, int indent) const;   // tcheck.cc
+       custom debugPrint { printExtras(os, indent); }
+     }
+}
+
+impl_verbatim {
+  // pulled these out of line because Declaration appears lower in .h file
+  FunctionType const *TF_func::ftype() const
+    { return &( nameParams->var->type->asFunctionTypeC() ); }
+  StringRef TF_func::name() const { return nameParams->var->name; }
+}
+
+
+// --------------- types and declarators ---------------
+// variable declaration or definition, or function declaration
+class Declaration (
+  DeclFlags dflags,                    // typedef, virtual, extern, etc.
+  TypeSpecifier spec,                  // e.g. "int"
+  ASTList<Declarator> decllist         // e.g. "x=3, y"
+) {
+  public void tcheck(Env &env);        // adds declared variables to env
+  public void vcgen(AEnv &env) const;
+}
+
+// just one complete type; appears in parameter decls and in casts
+class ASTTypeId (
+  TypeSpecifier spec,      // "int"
+  Declarator decl          // this will be abstract sometimes
+) {
+  public Type const *tcheck(Env &env);
+
+  public Type const *type;       // result of first tcheck
+  ctor { type=NULL; };
+}
+
+// a name of an "atomic" type -- one to which type constructors
+// (e.g. '*') can be applied, but which itself is not built with type
+// constructors
+// that's not quite right -- typedef'd types need not be atomic
+class TypeSpecifier {
+  public enum CVFlags cv;
+  ctor { cv=CV_NONE; };
+
+  // yield the type named by the specifier; this type may of course
+  // get refined when the declarator is considered
+  pure_virtual Type const *tcheck(Env &env);
+
+  // apply the 'cv' information
+  protected Type const *applyCV(Env &env, Type const *base);
+
+  //pure_virtual void vcgen(AEnv &env) const;
+
+  -> TS_name(StringRef name);              // a typedef'd name
+
+  -> TS_simple(SimpleTypeId id);           // int or char or float or ..
+
+  -> TS_elaborated(                        // "class Foo"
+       TypeIntr keyword,
+       StringRef name
+     );
+
+  -> TS_classSpec(                         // "class { ... }"
+       TypeIntr keyword,                     // "class", "struct", "union"
+       StringRef /*nullable*/ name,          // user-provided name, if any
+       ASTList<Declaration> members          // the fields of the struct
+     );
+
+  -> TS_enumSpec(                          // "enum { ... }"
+       StringRef /*nullable*/ name,          // name of enum, if any
+       ASTList<Enumerator> elts              // elements of the enumeration
+     );
+}
+
+// a binding of a name to a constant value
+class Enumerator (
+  SourceLoc loc,                        // location
+  StringRef name,                       // name of this constant
+  Expression /*nullable*/ expr          // constant expr, or NULL for "next"
+) {
+  public Variable *var;                 // (owner) introduction record
+  ctor var=NULL;
+  dtor delete var;
+}
+
+
+// Syntactically, a Declarator is a thing which introduces a name of a
+// declared thing, and also optionally adds type constructors to the
+// base type of the specifier.  It may have an initializing
+// expression, depending on the context.
+class Declarator (
+  IDeclarator decl,                    // syntax of type designation
+  Initializer init                     // (nullable) optional data initializer
+) {
+  public Variable *var;                // (owner) computed information: name, type, etc.
+  ctor var=NULL;
+  dtor delete var;
+
+  // returns the type denoted by the combination of 'base' and the
+  // type constructors in this declarator
+  public Type const *tcheck(Env &env, Type const *base, DeclFlags dflags);
+
+  // 'init' must be evaluated before calling this
+  public void vcgen(AEnv &env, AbsValue *initVal) const;
+}
+
+
+// inner declarator; things recursively buried inside declarators;
+// cannot have initializers; the internal structure is not analyzed
+// once typechecking determines what type is denoted;
+// type constructors are encoded as a (possibly empty) list of pointer
+// constructors, then maybe a function or array type, recursively
+class IDeclarator {
+  public ASTList<PtrOperator> stars;   // pointer constructors, left to right
+
+  // external interface; adds 'stars' before calling 'itcheck'; the
+  // toplevel 'declarator' is passed along so we can reflect the meaning
+  // back into the 'var' field
+  public void tcheck(Env &env, Type const *base,
+                     DeclFlags dflags, Declarator *declarator);
+
+  // ultimate type attached to 'declarator' is the type denoted by the
+  // combination of 'base' and the type constructors in this
+  // declarator (recursively)
+  pure_virtual void itcheck(Env &env, Type const *base,
+                            DeclFlags dflags, Declarator *declarator);
+
+  // dig down and find the name being declared; may return NULL
+  pure_virtual StringRef getName() const;
+
+  // "x" (NULL means abstract declarator or anonymous parameter)
+  -> D_name(SourceLoc loc, StringRef /*nullable*/ name,
+            ThmprvAttr attr);
+
+  // "f(int)"
+  -> D_func(SourceLoc loc, IDeclarator base,
+            ASTList<ASTTypeId> params, ASTList<FuncAnnotation> ann) {
+       // variable synthesized to give a name to the return value
+       public Variable *result;        // (owner)
+       ctor result=NULL;
+       dtor delete result;
+     }
+
+  // "a[5]" or "b[]"
+  -> D_array(IDeclarator base, Expression /*nullable*/ size);
+
+  // "c : 2"
+  -> D_bitfield(StringRef /*nullable*/ name, Expression bits);
+}
+
+// each star is associated with one of these; it's here so I can expand
+// it to include C++'s '&'
+class PtrOperator (CVFlags cv);
+
+
+// ------------------- statements -----------------
+verbatim {
+  // arguably premature optimization, I encode 'next' pointers as the
+  // pointer itself, bitwise OR'd with 1 if it's a "continue" edge,
+  // and use void* as the abstract type; essentially, every Statement
+  // is regarded as actually being two distinct CFG nodes, one reached
+  // with continue==false and the other with continue==true (except
+  // that some nodes don't have a continue==true half)
+  typedef void *NextPtr;
+
+  inline NextPtr makeNextPtr(Statement const *next, bool isContinue)
+  {
+    return (NextPtr)((long)next | !!isContinue);
+  }
+
+  inline Statement const *nextPtrStmt(NextPtr np)
+  {
+    return (Statement const*)((long)np & ~1L);
+  }
+
+  // unfortunately I don't have a good way to enforce the flow
+  // of constness.. so whatever ("NC" == "non-const")
+  inline Statement *nextPtrStmtNC(NextPtr np)
+  {
+    return (Statement*)nextPtrStmt(np);
+  }
+
+  // this is true when the 'next' edge points at a looping construct,
+  // but the flow is interpreted as a 'continue', rather than starting
+  // the loop from scratch
+  inline bool nextPtrContinue(NextPtr np)
+  {
+    return (bool)((long)np & 1);
+  }
+
+  // prints like Statement::kindLocString, with a "(c)" appended
+  // if it's the continue==true half
+  string nextPtrString(NextPtr np);
+
+  // after working with this system a while, I think it's good, so I
+  // want more support for manipulating lists of NextPtrs
+  typedef VoidList NextPtrList;
+  #define FOREACH_NEXTPTR(list, itervar) \
+    for (VoidListIter itervar(list); !itervar.isDone(); itervar.adv())
+
+  // given a function node, return a list of all the CFG nodes,
+  // in reverse postorder w.r.t. some spanning tree
+  // (implemented in postorder.cc)
+  void reversePostorder(NextPtrList &order, TF_func const &func);
+}
+
+
+verbatim {
+  // list of the parameters to Statement::vcgen; abstracted into a
+  // macro to make it easier to add/remove/change parameters
+  //   env: abstract environment
+  //   isContinue: true if we reached this statement on a 'continue' edge
+  //   path: which expression path to follow inside the statement
+  //   next: which statement will be next; may imply a predicate
+  #define STMT_VCGEN_PARAMS AEnv &env, bool isContinue, int path, Statement const *next
+}
+class Statement (SourceLoc loc) {
+  public virtual void tcheck(Env &env);
+  pure_virtual void itcheck(Env &env);
+
+  pure_virtual void vcgen(STMT_VCGEN_PARAMS) const;
+  public void vcgenPath(AEnv &env, SObjList<Statement /*const*/> &path,
+                        int index, bool isContinue) const;
+
+  // given 'facts' known at the start of this node (reached via
+  // 'isContinue'), update 'facts' to reflect the obvious facts after
+  // execution flows through this node and down the 'succPtr' edge
+  pure_virtual void factFlow(SObjList<Expression> &facts, bool isContinue,
+                             NextPtr succPtr) const;
+
+  // embedded control flow successor edge (for some constructs, like
+  // 'if', some/all of the successors are already explicit)
+  public NextPtr next;
+  ctor next=NULL;
+
+  // retrieve list of all successors of this node, given how we
+  // got to this node ('isContinue'); 'dest' should be empty beforehand
+  public virtual void getSuccessors(NextPtrList &dest, bool isContinue) const;
+  public string successorsToString() const;
+
+  // e.g. "S_if at 4:5" -- kind, line, col
+  public string kindLocString() const;
+
+  // number of paths from this statement; counts all the various
+  // paths through expressions, *including* expressions within
+  // this node
+  public int numPaths;
+  ctor numPaths=0;
+
+  custom debugPrint {
+    ind(os, indent) << "numPaths=" << numPaths
+                    << ", succ=" << successorsToString()
+                    << endl;
+  }
+
+  -> S_skip();      // nop; used whenever optional Statement is not present
+  -> S_label(StringRef name, Statement s);
+  -> S_case(Expression expr, Statement s);
+  -> S_caseRange(Expression low, Expression high, Statement s);
+  -> S_default(Statement s);
+  -> S_expr(Expression expr);      // expression evaluated for side effect
+  -> S_compound(ASTList<Statement> stmts);
+  -> S_if(Expression cond, Statement thenBranch, Statement elseBranch) {
+       public virtual void getSuccessors(VoidList &dest, bool isContinue) const;
+     }
+  -> S_switch(Expression expr, Statement branches) {
+       // pointers to all of the cases (& default) in this switch
+       public SObjList<Statement> cases;
+       public virtual void getSuccessors(VoidList &dest, bool isContinue) const;
+     }
+  -> S_while(Expression cond, Statement body) {
+       public virtual void getSuccessors(VoidList &dest, bool isContinue) const;
+     }
+  -> S_doWhile(Statement body, Expression cond) {
+       public virtual void getSuccessors(VoidList &dest, bool isContinue) const;
+     }
+  -> S_for(Statement init, Expression cond,
+           Expression after, Statement body) {
+       public virtual void tcheck(Env &env);      // special handling of 'init'
+       public virtual void getSuccessors(VoidList &dest, bool isContinue) const;
+     }
+  -> S_break();
+  -> S_continue();
+  -> S_return(Expression /*nullable*/ expr);
+  -> S_goto(StringRef target);
+  -> S_decl(Declaration decl);
+
+  // theorem prover extensions
+  -> S_assert(Expression expr, bool pure);    // pure means don't look at it during inference
+  -> S_assume(Expression expr);
+  -> S_invariant(Expression expr) {
+       // this is the set of facts inferred automatically for this
+       // invariant point; it's a set of serf pointers into the AST
+       public SObjList<Expression> inferFacts;
+
+       // retrieve a predicate expressing the conjunction of expr and
+       // inferFacts
+       public Predicate *vcgenPredicate(AEnv &env) const;
+     }
+  -> S_thmprv(Statement s);
+}
+
+
+// ----------------- expressions -----------------
+// C expressions
+class Expression {
+  // type check and yield the type of the expression; this type
+  // gets automatically stored in the 'type' field
+  public Type const *tcheck(Env &env);
+  pure_virtual Type const *itcheck(Env &env);
+  public Type const *type;
+  ctor type=NULL;
+
+  // record the # of paths through this expression; 0 means the
+  // expression has no side effects (so 1 path but it doesn't
+  // count in some situations)
+  public int numPaths;
+  ctor numPaths=0;
+  public void recordSideEffect()
+    { numPaths = max(numPaths, 1); };
+  public int numPaths1() const
+    { return max(numPaths, 1); };
+
+  // print numPaths and type
+  public string extrasToString() const;
+  custom debugPrint {
+    ind(os, indent) << extrasToString() << "\n";
+  }
+
+  // try to evaluate the expression as a constant integer;
+  // this can *only* be done after the expression has been tcheck'd
+  pure_virtual int constEval(Env &env) const;
+  protected int xnonconst() const;       // throws XNonConst
+
+  // unparse the expression
+  pure_virtual string toString() const;
+
+  // given the current abstract environment, return the abstract value
+  // representing this expression's result, and also update the environment
+  // to reflect any side effects
+  pure_virtual AbsValue *vcgen(AEnv &env, int path) const;
+
+  // similar to vcgen, but in a context where a boolean value is expected,
+  // so a predicate is yielded; the returned pointer is an owner pointer
+  pure_virtual Predicate *vcgenPred(AEnv &env, int path) const;
+
+  // use 'vcgen' and just say it's not equal to 0
+  public Predicate *vcgenPredDefault(AEnv &env, int path) const;
+
+  -> E_intLit(int i);
+  -> E_floatLit(float f);
+  -> E_stringLit(StringRef s);    // not quite right b/c can't handle embedded nuls
+  -> E_charLit(char c);
+  //-> E_structLit(ASTTypeId stype, ASTList<Initializer> init);
+
+  // variable reference; scopeName can be NULL, or the name of a type
+  // of which 'name' is a member; at some point 'scopeName' will need to
+  // be extended to permit nested qualifiers
+  -> E_variable(StringRef name, StringRef scopeName) {
+       public Variable *var;      // (serf) binding introduction of this name
+       ctor var=NULL;
+     }
+  -> E_funCall(Expression func, ASTList<Expression> args);
+
+  -> E_fieldAcc(Expression obj, StringRef fieldName) {
+       public CompoundType::Field const *field;
+       ctor field = NULL;
+     }
+
+  -> E_sizeof(Expression expr) {
+       public int size;     // size of the type of expr
+       ctor size=-1;
+     }
+
+  -> E_unary(UnaryOp op, Expression expr);
+  -> E_effect(EffectOp op, Expression expr);
+  -> E_binary(Expression e1, BinaryOp op, Expression e2);
+
+  -> E_addrOf(Expression expr);
+  -> E_deref(Expression ptr);
+
+  -> E_cast(ASTTypeId ctype, Expression expr);
+  -> E_cond(Expression cond, Expression th, Expression el);
+  //-> E_gnuCond(Expression cond, Expression el);
+  -> E_comma(Expression e1, Expression e2);
+  -> E_sizeofType(ASTTypeId atype) {
+       public int size;     // size of the type
+       ctor size=-1;
+     }
+
+  -> E_new(ASTTypeId atype);
+
+  // this is a simple assignment if op==BIN_ASSIGN, otherwise it's an
+  // incremental assignment, like a += 3 (e.g. for op=BIN_PLUS)
+  -> E_assign(Expression target, BinaryOp op, Expression src);
+
+  // thmprv extensions a quantifier binds some declared variables,
+  // which are then interpreted as either universally (forall=true) or
+  // existentially (forall=false) quantified in 'pred'
+  -> E_quantifier(ASTList<Declaration> decls, Expression pred, bool forall);
+}
+
+
+// animals which appear after declarations to assign initial values
+class Initializer {
+  // when a label is present it modifies which element of the
+  // surrounding structure is being initialized
+  public InitLabel *label;      // (nullable) gnu: range or field label
+  ctor { label = NULL; };
+
+  // check that the initializer is well-typed, given the type of
+  // the thing it initializes
+  pure_virtual void tcheck(Env &env, Type const *type);
+
+  // compute an abstract value for this initializer
+  pure_virtual AbsValue *vcgen(AEnv &env, Type const *type, int path) const;
+
+  -> IN_expr(Expression e);
+  -> IN_compound(ASTList<Initializer> inits);
+}
+
+// gnu extension to attach particular elements of an initializer list
+// to particular fields of the structure or array being initialized
+class InitLabel {
+  -> IL_element(Expression index);
+  -> IL_range(Expression low, Expression high);   // inclusive
+  -> IL_field(StringRef name);
+  -> IL_elementField(Expression index, StringRef name);
+}
+
+
+// -------------- annotations ---------------
+class FuncAnnotation {
+  // the precondition can have some bindings before the predicate
+  -> FA_precondition(ASTList<Declaration> decls, Expression expr);
+  -> FA_postcondition(Expression expr);
+}
+
+// Typically a name will have associated with it a list of attributes,
+// which is wrapped up into a single attribute with the name "attr".
+// Each of these attributes can then be just a name (with empty args)
+// or a name with some attr args (and so on recursively).  It's wrapped
+// like this so unattributed names can have a simple NULL*.
+class ThmprvAttr(StringRef name, ASTList<ThmprvAttr> args);

Added: vendor/elsa/current/elkhound/c/c.gr
===================================================================
--- vendor/elsa/current/elkhound/c/c.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/c.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1613 @@
+// c.gr            see license.txt for copyright and terms of use
+// grammar for C
+
+// this is derived from the C++ grammar by commenting-out
+// some rules, and has not been maintained in a while
+
+// 1/08/03: commented-out all of the unreachable nonterminals
+// because bison-1.875 spews massive warnings when it sees them
+
+
+verbatim [
+
+#include "strtable.h"     // StringRef (r)
+#include "c_type.h"       // type identifiers like ST_CHAR (r)
+#include "lexer2.h"       // lexer2's token ids for classify()
+#include "cparse.h"       // ParseEnv
+#include "trace.h"        // trace
+#include "c.ast.gen.h"    // C abstract syntax
+
+#ifdef NDEBUG
+  #define D(msg)
+#else
+  #define D(msg) \
+    trace("c") << msg << endl
+#endif
+
+]
+
+context_class CParse : public UserActions, public ParseEnv {
+public:
+  CParse(StringTable &table, CCLang &lang)
+    : ParseEnv(table, lang) {}
+
+  // when this is the last element in a parameter list, the function
+  // is a vararg function
+  ASTTypeId *ellipsisTypeId()
+  {
+    return new ASTTypeId(new TS_simple(ST_ELLIPSIS),
+                         new Declarator(new D_name(SL_UNKNOWN, NULL, NULL), NULL));
+  }
+};
+
+
+terminals {
+  // grab list generated by lexer
+  include("c.tok")
+
+  token[int] L2_INT_LITERAL ;
+
+  token[float*] L2_FLOAT_LITERAL ;
+
+  token[char] L2_CHAR_LITERAL ;
+
+  token[StringRef] L2_NAME {
+    // every time I pull an L2_NAME from the lexer, this code is
+    // run to possibly reclassify the token kind; the semantic
+    // value is passed (and ParseEnv is available as context), but
+    // the same semantic value will be used
+
+    // I mark this, and all places the deal with resolving the
+    // type-name vs variable-name ambiguity, with "TYPE/NAME"
+    fun classify(s) [
+      if (isType(s)) {
+        return L2_TYPE_NAME;
+      }
+      else {
+        return L2_VARIABLE_NAME;
+      }
+    ]
+  }
+
+  token[StringRef] L2_TYPE_NAME;
+  token[StringRef] L2_VARIABLE_NAME;
+
+  token[StringRef] L2_STRING_LITERAL ;
+
+  precedence {
+    // high precedence
+    prec  200 L2_PREFER_REDUCE;
+    prec  190 "const" "volatile" "owner_ptr_qualifier" "__attribute__" "else";
+
+    right 120 ".*" "->*";
+    left  110 "*" "/" "%";
+    left  100 "+" "-";
+    left   90 "<<" ">>";
+    left   80 "<" ">" "<=" ">=";
+    left   70 "==" "!=";
+    left   60 "&";
+    left   50 "^";
+    left   40 "|";
+    left   30 "&&";
+    left   20 "||";
+    right  10 "==>";    // ESC's user manual specifies a precedence but not an associativity for "==>"
+
+    prec    1 L2_PREFER_SHIFT;
+    // low precedence
+  }
+}
+
+
+nonterm[TranslationUnit*] File -> EnterScope t:TranslationUnit LeaveScope
+  [ return t; ]
+
+// scoping
+nonterm EnterScope -> empty    [
+  D("entering scope");
+  enterScope();
+]
+
+nonterm LeaveScope -> empty     [
+  D("exiting scope");
+  leaveScope();
+]
+
+
+// ------------- identifier ambiguity -------------------
+// identifiers can play two primary roles, and this is the
+// source of problems parsing C and C++
+
+// name of a type; introduced by class, struct, union, enum, typedef
+nonterm[StringRef] TypeName 
+  -> n:L2_TYPE_NAME     [ return n; ]
+
+// name of a variable or function; introduced by a declaration
+nonterm[StringRef] VariableName
+  -> n:L2_VARIABLE_NAME [ return n; ]
+
+// names for situations where it does not matter what its previous
+// meaning may have been
+nonterm[StringRef] AnyName {
+  -> n:VariableName     [ return n; ]
+  -> n:TypeName         [ return n; ]
+}
+
+
+// ---------------- higher-level syntax -----------------
+// the section labels that follow (like "A.3") are from the
+// C++ standard document (should track down a proper reference..)
+
+// ------ A.3 Basic Concepts ------
+nonterm[TranslationUnit*] TranslationUnit {
+  -> empty                                [ return new TranslationUnit(NULL); ]
+
+  -> t:TranslationUnit d:Declaration      [ t->topForms.append(d); return t; ]
+
+  // allow assembly at toplevel for gnu compatibility
+  -> t:TranslationUnit a:GNUAsmStatement  [ return t; ]    // drop 'asm' for now
+
+  // gnu extension: allow random semicolons at toplevel
+  -> t:TranslationUnit ";"                [ return t; ]
+}
+
+// ------ A.4 Expressions ------
+nonterm[Expression*] PrimaryExpression {
+  -> e:Literal
+       [ return e; ]
+
+  //-> "this" ;
+
+  -> "(" e:Expression ")"
+       [ return e; ]
+
+  -> e:PQVarName
+       [ return new E_variable(e, NULL /*scope*/); ]
+
+  // qualified variable; a special case of what PQVarName originally covered
+  -> scope:TypeName "::" name:AnyName
+       [ return new E_variable(name, scope); ]
+
+  -> e:ThmprvPredicate
+       [ return e; ]
+
+  // GNU extension
+  //-> "(" s:CompoundStatement ")" ;
+
+  // gnu extension: "constructor expression"
+  // (notation for literal struct values)
+  // e.g.:
+  //   struct Foo { int x; int y; };
+  //   struct Foo myfoo;
+  //   myfoo = (struct Foo) { 4, 5 };        <-- here
+  // which would assign x=4 and y=5 in 'myfoo'
+  //-> "(" t:TypeId ")" i:CompoundInitializer
+  //     [ return new E_structLit(t, i); ]
+}
+
+nonterm[Expression*] Literal {
+  -> i:L2_INT_LITERAL    [ return new E_intLit(i); ]
+  -> f:L2_FLOAT_LITERAL  [ E_floatLit *ret = new E_floatLit(*f); delete f; return ret; ]
+  -> s:StringLiteral     [ return new E_stringLit(s); ]
+  -> c:L2_CHAR_LITERAL   [ return new E_charLit(c); ]
+  -> L2_TRUE             [ return new E_intLit(1); ]
+  -> L2_FALSE            [ return new E_intLit(0); ]
+}
+
+// gnu: this is to handle gnu's f'd up pseduo-symbols, which
+// have the annoying property that they have to concatenate
+// with string literals (so I can't just, say, declare them
+// to be char* and be done with it)
+nonterm[StringRef] StringLiteral {
+  -> s:L2_STRING_LITERAL  [ return s; ]
+  //-> StringLiteral L2_STRING_LITERAL ;
+  //-> StringLiteral "__FUNCTION__" ;
+  //-> StringLiteral "__PRETTY_FUNCTION__" ;
+}
+
+
+// possibly-qualified name; essentially spec's id-expression
+// missing: template-id because I don't know what that is
+nonterm[StringRef] PQVarName {
+  -> n:VariableName   [ return n; ]
+
+  //-> OperatorFunctionId ;
+  //-> ConversionFunctionId ;
+  //-> "~" TypeName ;
+  //-> q:Qualifier rhs:PQVarName ;
+}
+
+//  nonterm Qualifier {
+//    -> "::" ;
+//    -> TypeName "::" ;
+//  }
+
+
+nonterm[Expression*] PostfixExpression {
+  -> e:PrimaryExpression 
+       [ return e; ]
+
+  // array access
+  -> a:PostfixExpression "[" e:Expression "]"
+       //[ return new E_arrayAcc(a, e); ]
+       [ return new E_deref(new E_binary(a, BIN_PLUS, e)); ]
+
+  // fn call
+  -> f:PostfixExpression "(" e:ExpressionListOpt ")"
+       [ return new E_funCall(f, e); ]
+
+  // field access
+  -> p:PostfixExpression "."  n:PQVarName
+       [ return new E_fieldAcc(p, n); ]
+
+  // deref + field access
+  -> p:PostfixExpression "->" n:PQVarName
+       [ return new E_fieldAcc(new E_deref(p), n); ]
+
+  -> p:PostfixExpression "++" 
+       [ return new E_effect(EFF_POSTINC, p); ]
+  -> p:PostfixExpression "--"
+       [ return new E_effect(EFF_POSTDEC, p); ]
+
+  // pulled these two because other rules supercede them
+  //-> PostfixExpression "." PseudoDestructorName           ; // explicit dtor call
+  //-> PostfixExpression "->" PseudoDestructorName          ;
+
+  //-> "dynamic_cast"     "<" TypeId ">" "(" e:Expression ")" ;   // casts
+  //-> "static_cast"      "<" TypeId ">" "(" e:Expression ")" ;
+  //-> "reinterpret_cast" "<" TypeId ">" "(" e:Expression ")" ;
+  //-> "const_cast"       "<" TypeId ">" "(" e:Expression ")" ;
+
+  // removed for now since I don't know much about them
+  //-> "typeid" "(" Expression ")"                          ;   // RTTI
+  //-> "typeid" "(" TypeId ")"                              ;
+}
+
+
+nonterm[ASTList<Expression>*] ExpressionList {
+  -> a:AssignmentExpression
+       [ return new ASTList<Expression>(a); ]
+  -> e:ExpressionList "," a:AssignmentExpression
+       [ e->append(a); return e; ]
+}
+
+nonterm[ASTList<Expression>*] ExpressionListOpt {
+  -> empty               [ return new ASTList<Expression>(); ]
+  -> e:ExpressionList    [ return e; ]
+}
+
+// I am pulling these out since PQVarName can be ~class
+//PseudoDestructorName -> "~" ClassName
+//PseudoDestructorName -> Qualifier PseudoDestructorName
+
+nonterm[Expression*] UnaryExpression {
+  -> e:PostfixExpression         [ return e; ]
+
+  -> "++" e:CastExpression       [ return new E_effect(EFF_PREINC, e); ]
+  -> "--" e:CastExpression       [ return new E_effect(EFF_PREDEC, e); ]
+
+  // size of expression
+  -> "sizeof" e:UnaryExpression  [ return new E_sizeof(e); ]
+
+  //-> e:DeleteExpression ;
+
+  // dereference, addrof
+  -> "*" e:CastExpression        [ return new E_deref(e); ]
+  -> "&" e:CastExpression        [ return new E_addrOf(e); ]
+
+  // other unary operators
+  -> "+" e:CastExpression        [ return new E_unary(UNY_PLUS, e); ]
+  -> "-" e:CastExpression        [ return new E_unary(UNY_MINUS, e); ]
+  -> "!" e:CastExpression        [ return new E_unary(UNY_NOT, e); ]
+  -> "~" e:CastExpression        [ return new E_unary(UNY_BITNOT, e); ]
+                                               
+  // size of type
+  -> "sizeof" "(" t:TypeId ")"   [ return new E_sizeofType(t); ]
+
+  -> e:NewExpression             [ return e; ]
+}
+
+
+// for now, no new-placement or "::" in front
+// I've changed the syntax slightly to correct what I think is a mistake
+// (my syntax allows array of ptr to fn, whereas std syntax doesn't -- TOVERIFY)
+nonterm[E_new*] NewExpression {
+  // I tried making the 't' here a TypeId, but that introduces an
+  // LALR(1) conflict because then "new char * 6" could either be
+  // "(new char) * 6" or "(new (char*)) 6" -- neither makes sense but
+  // the parser doesn't know that
+  
+  // there's still an LALR(1) shift/reduce conflict involving __attribute__,
+  // but I haven't spent enough time staring at the parser dump to figure
+  // out why, so I'll rely on GLR to deal with it;
+  // TODO: design a way to query the parsgen to figure out where a given
+  // lookahead symbol comes from originally (tracing by hand I get myself
+  // stuck in long loops)
+
+  -> "new" t:TypeSpecifier /*NewDeclaratorOpt NewInitializerOpt*/
+       [ return new E_new(new ASTTypeId(t,              
+           // declarator which doesn't modify type:
+           new Declarator(new D_name(loc, NULL, NULL), NULL))); ]
+  -> "new" "(" t:TypeId ")" /*NewDeclaratorOpt NewInitializerOpt*/
+       [ return new E_new(t); ]
+}
+
+// NewDeclaratorOpt is, as a regular expression:
+//   (PtrOperator)*  ("[" Expression "]")?  ("[" ConstExpression "]")*
+//  nonterm NewDeclaratorOpt {
+//    -> empty ;
+//    -> PtrOperator NewDeclaratorOpt ;
+//    -> DirectNewDeclarator ;        // commit to at least one "[" ... "]"
+//  }
+//  nonterm DirectNewDeclarator {
+//    -> "[" Expression "]" ;
+//    -> DirectNewDeclarator "[" ConstantExpression "]" ;
+//  }
+
+//  nonterm NewInitializerOpt {
+//    -> empty ;
+//    -> "(" ExpressionListOpt ")" ;
+//  }
+
+//  // omitting possibility of initial "::"
+//  nonterm DeleteExpression {
+//    -> "delete" e:CastExpression ;
+//    -> "delete" "[" "]" e:CastExpression ;
+//  }
+
+nonterm[Expression*] CastExpression {
+  -> e:UnaryExpression 
+       [ return e; ]
+  -> "(" t:TypeId ")" e:CastExpression 
+       [ return new E_cast(t, e); ]
+}
+
+// ++++ binary operator expression ++++
+// primary expressions
+nonterm[Expression*] BinaryExpression {
+  -> e:CastExpression                                    [ return e; ]
+
+  -> left:BinaryExpression "*"  right:BinaryExpression   [ return new E_binary(left, BIN_MULT, right); ]
+  -> left:BinaryExpression "/"  right:BinaryExpression   [ return new E_binary(left, BIN_DIV, right); ]
+  -> left:BinaryExpression "%"  right:BinaryExpression   [ return new E_binary(left, BIN_MOD, right); ]
+  -> left:BinaryExpression "+"  right:BinaryExpression   [ return new E_binary(left, BIN_PLUS, right); ]
+  -> left:BinaryExpression "-"  right:BinaryExpression   [ return new E_binary(left, BIN_MINUS, right); ]
+  -> left:BinaryExpression "<<" right:BinaryExpression   [ return new E_binary(left, BIN_LSHIFT, right); ]
+  -> left:BinaryExpression ">>" right:BinaryExpression   [ return new E_binary(left, BIN_RSHIFT, right); ]
+  -> left:BinaryExpression "<"  right:BinaryExpression   [ return new E_binary(left, BIN_LESS, right); ]
+  -> left:BinaryExpression ">"  right:BinaryExpression   [ return new E_binary(left, BIN_GREATER, right); ]
+  -> left:BinaryExpression "<=" right:BinaryExpression   [ return new E_binary(left, BIN_LESSEQ, right); ]
+  -> left:BinaryExpression ">=" right:BinaryExpression   [ return new E_binary(left, BIN_GREATEREQ, right); ]
+  -> left:BinaryExpression "==" right:BinaryExpression   [ return new E_binary(left, BIN_EQUAL, right); ]
+  -> left:BinaryExpression "!=" right:BinaryExpression   [ return new E_binary(left, BIN_NOTEQUAL, right); ]
+  -> left:BinaryExpression "&"  right:BinaryExpression   [ return new E_binary(left, BIN_BITAND, right); ]
+  -> left:BinaryExpression "^"  right:BinaryExpression   [ return new E_binary(left, BIN_BITXOR, right); ]
+  -> left:BinaryExpression "|"  right:BinaryExpression   [ return new E_binary(left, BIN_BITOR, right); ]
+
+  -> left:BinaryExpression "&&" right:BinaryExpression   [ return new E_binary(left, BIN_AND, right); ]
+  -> left:BinaryExpression "||" right:BinaryExpression   [ return new E_binary(left, BIN_OR, right); ]
+  
+  // theorem prove extensions
+  -> left:BinaryExpression "==>" right:BinaryExpression  [ return new E_binary(left, BIN_IMPLIES, right); ]
+}
+
+
+nonterm[Expression*] ConditionalExpression {
+  -> e:BinaryExpression 
+       [ return e; ]
+
+  -> cond:BinaryExpression "?" th:Expression ":" el:AssignmentExpression 
+       [ return new E_cond(cond, th, el); ]
+
+  // wtf?  gnu...
+  // linux driver code has "expr ? : expr" ...
+  // according to Marat, "e1 ? : e2" is the same as "e1 ? e1 : e2",
+  // except that e1 is only evaluated once
+  //-> cond:BinaryExpression "?" ":" el:AssignmentExpression
+  //     [ return new E_gnuCond(cond, el); ]
+}
+
+// why is conditional not allowed on left side of = ?  can I confirm
+// that in another language spec?  clearly both alternatives would have
+// to be like-typed lvalues, but...
+nonterm[Expression*] AssignmentExpression {
+  -> e:ConditionalExpression 
+       [ return e; ]
+
+  -> e1:BinaryExpression op:AssignmentOperator e2:AssignmentExpression
+       [ return new E_assign(e1, op, e2); ]
+}
+
+nonterm[enum BinaryOp] AssignmentOperator {
+  -> "*="  [ return BIN_MULT; ]
+  -> "/="  [ return BIN_DIV; ]
+  -> "%="  [ return BIN_MOD; ]
+  -> "+="  [ return BIN_PLUS; ]
+  -> "-="  [ return BIN_MINUS; ]
+  -> ">>=" [ return BIN_RSHIFT; ]
+  -> "<<=" [ return BIN_LSHIFT; ]
+  -> "&="  [ return BIN_BITAND; ]
+  -> "^="  [ return BIN_BITXOR; ]
+  -> "|="  [ return BIN_BITOR; ]
+  -> "="   [ return BIN_ASSIGN; ]
+}
+
+
+// this is the same definition as ExpressionList, and perhaps it
+// makes sense to collapse them?  the meaning of ',' is quite
+// different in the two cases.. does that matter?
+// update: now that I'm doing translation too, the difference
+// in the meanings is great enough that I think they should be
+// separate, as they are
+nonterm[Expression*] Expression {
+  -> ae:AssignmentExpression 
+       [ return ae; ]
+
+  -> e:Expression "," ae:AssignmentExpression 
+       [ return new E_comma(e, ae); ]
+}
+
+nonterm[Expression*] ExpressionOpt {
+  // empty expression is a nop
+  -> empty         [ return new E_intLit(1); ]
+  -> e:Expression  [ return e; ]
+}
+
+// this is an expression with the additional requirement that
+// it be entirely evaluable to an int at compile time
+// (the name exists simply to help document that fact; the grammar
+// cannot enforce it)
+nonterm[Expression*] ConstantExpression -> e:ConditionalExpression 
+  [ return e; ]
+
+
+// ------ A.5 Statements ------
+// labeled-statement
+nonterm[Statement*] Statement {
+  -> n:L2_VARIABLE_NAME ":" s:Statement 
+       [ return new S_label(loc, n, s); ]
+
+  // I need a disambiguation here other than prec/assoc..
+  //-> "case" e:ConstantExpression ":" s:Statement
+  //     [ return new S_case(e, s); ]
+
+  // had to add this variant because I found linux kernel
+  // code that has "case:" immediately followed by "}"; I still
+  // prefer the above when I can, so as to minimize the use of this
+  -> "case" e:ConstantExpression ":"   precedence(L2_PREFER_SHIFT)
+       [ return new S_case(loc, e, new S_skip(loc)); ]
+
+  // gnu extension
+  -> "case" low:ConstantExpression "..." high:ConstantExpression ":"
+       [ return new S_caseRange(loc, low, high, new S_skip(loc)); ]
+
+  -> "default" ":" s:Statement
+       [ return new S_default(loc, s); ]
+
+  // expression-statement
+  -> s:ExpressionStatement
+       [ return s; ]
+
+  // compound-statement
+  -> s:CompoundStatement
+       [ return s; ]
+
+  // selection-statement
+  // (prefer to shift "else" over reducing by this rule)
+  -> "if" "(" e:Condition ")" s:Statement     precedence(L2_PREFER_SHIFT)
+       [ return new S_if(loc, e, s, new S_skip(loc)); ]
+
+  // if-then-else preferred over if-then when ambiguous
+  -> "if" "(" e:Condition ")" s1:Statement "else" s2:Statement
+       [ return new S_if(loc, e, s1, s2); ]
+
+  -> "switch" "(" e:Condition ")" s:Statement
+       [ return new S_switch(loc, e, s); ]
+
+  -> "while" "(" e:Condition ")" s:Statement
+       [ return new S_while(loc, e, s); ]
+
+  -> "do" s:Statement "while" "(" e:Expression ")" ";"
+       [ return new S_doWhile(loc, s, e); ]
+
+  // this is a special-purpose rule intended for use with (unexpanded)
+  // macros that, internally, contain a for loop; it is *not* part of
+  // the C or C++ languages!
+  //-> L2_NAME "(" e:ExpressionList ")" s:CompoundStatement {
+  //  fun typeCheck = NULL;       // TODO: implement?  eliminate?
+  //}
+
+  // I might like to rework this so both semicolons appear here instead
+  // of buried in ForInitStatement.  this is also a good rule to use
+  // inline alternatives
+  -> "for" "(" s1:ForInitStatement c:ConditionOpt ";" e:ExpressionOpt ")" s2:Statement
+       [ return new S_for(loc, s1, c, e, s2); ]
+
+  -> "break" ";"                        [ return new S_break(loc); ]
+
+  -> "continue" ";"                     [ return new S_continue(loc); ]
+
+  -> "return" e:Expression ";"          [ return new S_return(loc, e); ]
+
+  -> "return" ";"                       [ return new S_return(loc, NULL); ]
+
+  -> "goto" n:L2_VARIABLE_NAME ";"      [ return new S_goto(loc, n); ]
+
+  // declaration-statement
+  -> d:BlockDeclaration                 [ return new S_decl(loc, d); ]
+
+  // try-block
+  //-> s:TryBlock ;
+
+  // GNU extensions
+  -> GNUAsmStatement                    [ return new S_skip(loc); ]
+
+  // theorem prover extensions
+  -> "thmprv_assert"      e:Expression ";"   [ return new S_assert(loc, e, false /*pure*/); ]
+  -> "thmprv_pure_assert" e:Expression ";"   [ return new S_assert(loc, e, true /*pure*/); ]
+  -> "thmprv_assume"      e:Expression ";"   [ return new S_assume(loc, e); ]
+  -> "thmprv_invariant"   e:Expression ";"   [ return new S_invariant(loc, e); ]
+  -> "thmprv_let"         s:Statement        [ return new S_thmprv(loc, s); ]
+}
+
+nonterm[Statement*] ExpressionStatement {
+  -> ";"                [ return new S_skip(loc); ]
+  -> e:Expression ";"   [ return new S_expr(loc, e); ]
+}
+
+nonterm[S_compound*] CompoundStatement {
+  // I must enter scope immediately upon seeing the open-brace, so
+  // that if the first token of the first statement changes or queries
+  // the scope, it's in the new one
+  -> EnterScope "{" seq:StatementSeqOpt LeaveScope "}"
+       [ return new S_compound(loc, seq); ]
+}
+
+nonterm[ASTList<Statement>*] StatementSeqOpt {
+  -> empty
+       [ return new ASTList<Statement>(); ]
+  -> seq:StatementSeqOpt s:Statement
+       [ seq->append(s); return seq; ]
+}
+
+// the guard of e.g. an 'if' statement
+nonterm[Expression*] Condition {
+  -> e:Expression      [ return e; ]
+
+  // C++ allows variable declarations in some interesting places...
+  //-> spec:TypeSpecifier decl:Declarator "=" e:AssignmentExpression ;
+}
+
+nonterm[Expression*] ConditionOpt {
+  // an empty condition (e.g. in a for loop) is interpreted as true
+  -> empty             [ return new E_intLit(1); ]
+  -> c:Condition       [ return c; ]
+}
+
+nonterm[Statement*] ForInitStatement {
+  -> s:ExpressionStatement     [ return s; ]
+  //-> s:SimpleDeclaration ;    // C++
+}
+
+
+// ----- A.6 Declarations ------
+//nonterm[ASTList<Declaration>*] DeclarationSeqOpt {
+//  -> empty
+//       [ return new ASTList<Declaration>(); ]
+//  -> seq:DeclarationSeqOpt d:Declaration
+//       [ seq->append(d); return seq; ]
+//} 
+
+nonterm[TopForm*] Declaration {
+  -> d:BlockDeclaration      [ return new TF_decl(loc, d); ]
+  -> d:FunctionDefinition    [ return d; ]
+  //-> TemplateDeclaration ;
+  //-> d:LinkageSpecification ;
+}
+
+// C++ has other alternatives..
+nonterm[Declaration*] BlockDeclaration {
+  -> d:SimpleDeclaration     [ return d; ]
+}
+
+// is the DeclSpecifierSeq optional for implicit-int??
+//   no, it's for constructors, destructors, and conversion operators,
+//   all of which are C++ only, so the DeclSpecifierSeq is now mandatory
+// ok, why is the InitDeclaratorList optional?
+//   for declaring classes and enums
+nonterm[Declaration*] SimpleDeclaration {
+  //e.g.: int                x                     ;
+  -> spec:DeclSpecifier list:InitDeclaratorListOpt ";"
+       [ spec->decllist.steal(list); return spec; ]
+
+  -> "typedef" spec:DeclSpecifier list:TypedefDeclaratorList ";"
+       [
+         spec->dflags = (DeclFlags)(spec->dflags | DF_TYPEDEF);
+         spec->decllist.steal(list);
+         return spec;
+       ]
+
+  // gnu; specifically for linux printk declaration
+  //-> GNUAttribute decl:SimpleDeclaration ;
+}
+
+
+// old:
+//DeclSpecifier -> StorageClassOpt CVQualifiersOpt TypeSpecifier
+//CVQualifiersOpt -> "const" CVQualifiersOpt | "volatile" CVQualifiersOpt | empty
+// now I'm folding CVQualifier into TypeSpecifier; in particular, this allows
+// the TypeId in a cast expression to contain a "const"
+
+// I return a Declaration object with an empty decllist, as a proxy
+// for returning dflags and spec as a pair
+nonterm[Declaration*] DeclSpecifier {
+  -> "inline" m:DeclModifier s:TypeSpecifier
+       [ return new Declaration((DeclFlags)(DF_INLINE | m), s, NULL); ]
+
+  -> m:DeclModifier "inline" s:TypeSpecifier
+       [ return new Declaration((DeclFlags)(DF_INLINE | m), s, NULL); ]
+
+  -> m:DeclModifier s:TypeSpecifier
+       [ return new Declaration(m, s, NULL); ]
+
+  -> "inline" s:TypeSpecifier
+       [ return new Declaration(DF_INLINE, s, NULL); ]
+
+  -> s:TypeSpecifier 
+       [ return new Declaration(DF_NONE, s, NULL); ]
+}
+
+// my analysis (informal and ad-hoc) indicates that none of these can
+// be used together; "inline" is pulled out because it can be used
+// with "virtual", "static", "friend", and possibly "extern"; I
+// consider all this preferable to just allowing a "word soup"
+nonterm[enum DeclFlags] DeclModifier {
+  -> "virtual"     [ return DF_VIRTUAL;  ]
+  -> "friend"      [ return DF_FRIEND;   ]
+  -> "mutable"     [ return DF_MUTABLE;  ]
+  -> "auto"        [ return DF_AUTO;     ]
+  -> "register"    [ return DF_REGISTER; ]
+  -> "static"      [ return DF_STATIC;   ]
+  -> "extern"      [ return DF_EXTERN;   ]
+
+  -> "thmprv_predicate"   [ return DF_PREDICATE; ]
+}
+
+
+nonterm[TypeSpecifier*] TypeSpecifier {
+  // the existence of this production is part of why parsing C is hard
+  -> n:PQTypeName 
+       [ return new TS_name(n); ]
+
+  -> s:SimpleTypeSpecifier            // int
+       [ return new TS_simple(s); ]
+
+  // pulled this because it causes shift/reduce conflicts; on input
+  //   unsigned . const ...
+  // I don't know whether to reduce the 'unsigned' as a type by itself,
+  // or shift the 'const' in expectation of finding 'char' after it
+  // 9/25/01 16:28: I'm putting it back in and we'll see if magic GLR will work
+  // 9/26/01 00:13: pulling again until I can find a good way to suppress the conflict report
+  //-> s:SimpleCVTypeSpecifier          // unsigned const char  (not good style, IMO)
+  //     [
+  //       TS_simple *ret = new TS_simple((SimpleTypeId)(s & ST_BITMASK));
+  //       ret->cv = (CVFlags)(s & CV_ALL);
+  //       return ret;
+  //     ]
+
+  -> s:ElaboratedTypeSpecifier        // class foo  or  enum bar
+       [ return s; ]
+
+  -> s:ClassSpecifier                 // class { ... }
+       [ return s; ]
+  -> s:EnumSpecifier                  // enum { ... }
+       [ return s; ]
+
+  // the following 3 rules create an ambiguity because they don't
+  // say how to parse things like "const int const"; so assign
+  // all of them precedence higher than const/volatile/attribute,
+  // so we'll just prefer reducing always
+
+  -> q:CVQualifier s:TypeSpecifier  precedence(L2_PREFER_REDUCE)   // const int
+       [ s->cv = (CVFlags)(s->cv | q); return s; ]
+  -> s:TypeSpecifier q:CVQualifier  precedence(L2_PREFER_REDUCE)   // int const
+       [ s->cv = (CVFlags)(s->cv | q); return s; ]
+
+  // yet another attempt to find a good place for this
+  -> s:TypeSpecifier GNUAttribute   precedence(L2_PREFER_REDUCE)
+       [ return s; ]      // drop attr for now
+}
+
+
+nonterm[TS_elaborated*] ElaboratedTypeSpecifier {
+  -> k:ClassKeyword n:AnyName   [
+       declareClassTag(n);
+       return new TS_elaborated(k, n);
+     ]
+  -> "enum" n:AnyName           [ return new TS_elaborated(TI_ENUM, n); ]
+}
+
+
+// this list comes from Table 7 (p.109) of the C++ standard
+// NOTE: this deviates from the language spec, which allows other
+// decl-specifiers to mix with the tokens here; I do not
+nonterm[enum SimpleTypeId] SimpleTypeSpecifier {
+  -> "char"                     [ return ST_CHAR; ]
+  -> "unsigned" "char"          [ return ST_UNSIGNED_CHAR; ]
+  -> "signed" "char"            [ return ST_SIGNED_CHAR; ]
+  -> "bool"                     [ return ST_BOOL; ]
+  -> "unsigned"                 [ return ST_UNSIGNED_INT; ]
+  -> "unsigned" "int"           [ return ST_UNSIGNED_INT; ]
+  -> "signed"                   [ return ST_INT; ]
+  -> "signed" "int"             [ return ST_INT; ]
+  -> "int"                      [ return ST_INT; ]
+  -> "unsigned" "short" "int"   [ return ST_UNSIGNED_SHORT_INT; ]
+  -> "unsigned" "short"         [ return ST_UNSIGNED_SHORT_INT; ]
+  -> "unsigned" "long" "int"    [ return ST_UNSIGNED_LONG_INT; ]
+  -> "unsigned" "long"          [ return ST_UNSIGNED_LONG_INT; ]
+  -> "signed" "long" "int"      [ return ST_LONG_INT; ]
+  -> "signed" "long"            [ return ST_LONG_INT; ]
+  -> "long" "int"               [ return ST_LONG_INT; ]
+  -> "long"                     [ return ST_LONG_INT; ]
+  -> "signed" "long" "long"     [ return ST_LONG_LONG; ]
+  -> "long" "long"              [ return ST_LONG_LONG; ]
+  -> "unsigned" "long" "long"   [ return ST_UNSIGNED_LONG_LONG; ]
+  -> "signed" "short" "int"     [ return ST_SHORT_INT; ]
+  -> "signed" "short"           [ return ST_SHORT_INT; ]
+  -> "short" "int"              [ return ST_SHORT_INT; ]
+  -> "short"                    [ return ST_SHORT_INT; ]
+  -> "wchar_t"                  [ return ST_WCHAR_T; ]
+  -> "float"                    [ return ST_FLOAT; ]
+  -> "double"                   [ return ST_DOUBLE; ]
+  -> "long" "double"            [ return ST_LONG_DOUBLE; ]
+  -> "void"                     [ return ST_VOID; ]
+}
+
+
+// I had been separating these into typedef/enum/class names, but
+// the parser can never distinguish, so the grammar shouldn't suggest
+// that it can
+nonterm[StringRef] PQTypeName {
+  -> n:TypeName         [ return n; ]
+  //-> TemplateId ;
+  //-> Qualifier n:PQTypeName ;
+}
+
+// the C++ standard allows "const" and "volatile" to be arbitrarily
+// interleaved with the words of a simple-type-specifier.. so I've
+// created this set of alternative type specifiers which have at
+// least one CV qualifier buried in them
+//
+// technically, I'm still missing things like
+//   unsigned const short volatile int
+// but yikes, I pity the fool with such code!
+//
+// I really should just fold these into the above, but my dislike for
+// the interleaving thing makes me try to keep the above decls more
+// or less "pure".. but I'll probably merge them at some point
+//
+// I return an 'int' here because it's an OR of CVFlags and SimpleTypeId
+//  nonterm[int] SimpleCVTypeSpecifier {
+//    -> "unsigned" q:CVQualifierSeq "char"         [ return q | ST_UNSIGNED_CHAR; ]
+//    -> "signed" q:CVQualifierSeq "char"           [ return q | ST_SIGNED_CHAR; ]
+//    -> "unsigned" q:CVQualifierSeq "int"          [ return q | ST_UNSIGNED_INT; ]
+//    -> "signed" q:CVQualifierSeq "int"            [ return q | ST_INT; ]
+//    -> "unsigned" q:CVQualifierSeq "short" "int"  [ return q | ST_UNSIGNED_SHORT_INT; ]
+//    -> "unsigned" "short" q:CVQualifierSeq "int"  [ return q | ST_UNSIGNED_SHORT_INT; ]
+//    -> "unsigned" q:CVQualifierSeq "short"        [ return q | ST_UNSIGNED_SHORT_INT; ]
+//    -> "unsigned" q:CVQualifierSeq "long" "int"   [ return q | ST_UNSIGNED_LONG_INT; ]
+//    -> "unsigned" "long" q:CVQualifierSeq "int"   [ return q | ST_UNSIGNED_LONG_INT; ]
+//    -> "unsigned" q:CVQualifierSeq "long"         [ return q | ST_UNSIGNED_LONG_INT; ]
+//    -> "signed" q:CVQualifierSeq "long" "int"     [ return q | ST_LONG_INT; ]
+//    -> "signed" "long" q:CVQualifierSeq "int"     [ return q | ST_LONG_INT; ]
+//    -> "signed" q:CVQualifierSeq "long"           [ return q | ST_LONG_INT; ]
+//    -> "long" q:CVQualifierSeq "int"              [ return q | ST_LONG_INT; ]
+//    -> "signed" q:CVQualifierSeq "long" "long"    [ return q | ST_LONG_LONG; ]
+//    -> "unsigned" q:CVQualifierSeq "long" "long"  [ return q | ST_UNSIGNED_LONG_LONG; ]
+//    -> "signed" q:CVQualifierSeq "short" "int"    [ return q | ST_SHORT_INT; ]
+//    -> "signed" "short" q:CVQualifierSeq "int"    [ return q | ST_SHORT_INT; ]
+//    -> "signed" q:CVQualifierSeq "short"          [ return q | ST_SHORT_INT; ]
+//    -> "short" q:CVQualifierSeq "int"             [ return q | ST_SHORT_INT; ]
+//    -> "long" q:CVQualifierSeq "double"           [ return q | ST_LONG_DOUBLE; ]
+//  }
+
+
+nonterm[TS_enumSpec*] EnumSpecifier {
+  -> "enum" "{" list:EnumeratorListOpt "}"
+       [ return new TS_enumSpec(NULL /*name*/, list); ]
+  -> "enum" n:AnyName "{" list:EnumeratorListOpt "}"
+       [ return new TS_enumSpec(n, list); ]
+}
+
+
+nonterm[ASTList<Enumerator>*] EnumeratorList {
+  -> def:EnumeratorDefinition
+       [ return new ASTList<Enumerator>(def); ]
+  -> list:EnumeratorList "," def:EnumeratorDefinition
+       [ list->append(def); return list; ]
+}
+
+nonterm[ASTList<Enumerator>*] EnumeratorListOpt {
+  -> empty 
+       [ return new ASTList<Enumerator>(); ]
+
+  -> list:EnumeratorList CommaOpt   // CommaOpt is GNU extension (??)
+       [ return list; ]
+}
+
+
+nonterm[Enumerator*] EnumeratorDefinition {
+  -> name:AnyName 
+       [ return new Enumerator(loc, name, NULL /*expr*/); ]
+  -> name:AnyName "=" expr:ConstantExpression
+       [ return new Enumerator(loc, name, expr); ]
+}
+
+
+//nonterm AsmDefinition -> "asm" "(" L2_STRING_LITERAL ")" ";" ;
+
+//nonterm LinkageSpecification {
+//  -> "extern" L2_STRING_LITERAL "{" d:DeclarationSeqOpt "}" ;
+//  -> "extern" L2_STRING_LITERAL d:Declaration ;
+//} 
+
+// ------ A.7 Declarators ------
+// -- declarator --
+// a declarator is the "x" in a declaration like "int x"
+
+nonterm[ASTList<Declarator>*] InitDeclaratorList {
+  -> d:InitDeclarator
+       [ return new ASTList<Declarator>(d); ]
+  -> list:InitDeclaratorList "," d:InitDeclarator
+       [ list->append(d); return list; ]
+}
+
+nonterm[ASTList<Declarator>*] InitDeclaratorListOpt {
+  -> empty
+       [ return new ASTList<Declarator>(); ]
+  -> list:InitDeclaratorList
+       [ return list; ]
+}
+
+
+nonterm[Declarator*] InitDeclarator {
+  -> d:Declarator                       // (int)  x
+       [ return new Declarator(d, NULL); ]
+
+  -> d:Declarator i:Initializer         // (int)  x = 5
+       [ return new Declarator(d, i); ]
+}
+
+nonterm[Initializer*] Initializer {
+  -> "=" i:InitializerClause 
+       [ return i; ]
+
+  // this causes an ambiguity with
+  //   int fileno(FILE *f);
+  // because it could be multiplication.. handling it isn't that
+  // hard, but for now let's just take out this rule
+  //-> "(" ExpressionList ")" ;          // ctor args
+}
+
+nonterm[Initializer*] InitializerClause {
+  -> e:AssignmentExpression              // scalar
+       [ return new IN_expr(e); ]
+  -> c:CompoundInitializer               // array/structure initializer
+       [ return new IN_compound(c); ]
+}
+
+
+// gnu extensions: labeled elements in initializers
+// (*potentially* labeled)
+nonterm[Initializer*] LabeledInitializerClause {
+  // no label
+  -> init:InitializerClause
+       [ return init; ]
+
+  // initialize a specific element of the array
+  -> "[" index:ConstantExpression "]" "=" init:InitializerClause
+       [ init->label = new IL_element(index); return init; ]
+
+  // initialize a range (inclusive) of elements of the array
+  -> "[" lo:ConstantExpression "..." hi:ConstantExpression "]" "=" init:InitializerClause
+       [ init->label = new IL_range(lo, hi); return init; ]
+
+  // intialize a named element of a structure
+  -> "." field:PQVarName "=" init:InitializerClause
+       [ init->label = new IL_field(field); return init; ]
+
+  // initialize a field of a specific element of the array
+  -> "[" index:ConstantExpression "]" "." field:PQVarName "=" init:InitializerClause
+       [ init->label = new IL_elementField(index, field); return init; ]
+}
+
+nonterm[ASTList<Initializer>*] CompoundInitializer {
+  // array/structure initializer
+  -> "{" list:InitializerList CommaOpt "}"  [ return list; ]
+
+  // zero whatever it is
+  -> "{" "}"  [ return new ASTList<Initializer>(); ]
+}
+
+// useful syntactic quirk
+nonterm CommaOpt {
+  -> empty ;
+  -> "," ;
+}
+
+
+nonterm[ASTList<Initializer>*] InitializerList {
+  -> init:LabeledInitializerClause
+       [ return new ASTList<Initializer>(init); ]
+  -> list:InitializerList "," init:LabeledInitializerClause
+       [ list->append(init); return list; ]
+}
+
+
+// perhaps confusing name correspondence:
+//   The AST name "Declarator" corresponds to the grammar name
+//   "InitDeclarator"; the AST name "IDeclarator" (inner declarator)
+//   corresponds to the grammar name "Declarator"
+// this name shift simply reflects the different interests of the
+// parser vs. subsequent phases of analysis
+nonterm[IDeclarator*] Declarator {
+  // (PtrOperator)* DirectDeclarator
+  -> p:PtrOperator d:Declarator
+       [ d->stars.prepend(p); return d; ]
+
+  // I'm still looking for the right place to put GNUAttribute ...
+  -> d:DirectDeclarator GNUAttribute         // GNU extension
+       [ return d; ]
+  -> d:DirectDeclarator
+       [ return d; ]
+}
+
+nonterm[IDeclarator*] DirectDeclarator {
+  // it doesn't matter how this was classified before, because
+  // a declarator binds a new name, so it shadows any prior definitions
+  -> n:AnyName a:ThmprvAttr
+       [ return new D_name(loc, n, a); ]
+
+  // function declarator; the return type comes from the type
+  // specifier that preceeds this
+  -> d:DirectDeclarator "(" args:ParameterDeclarationClause ")" /*q:CVQualifierSeqOpt*/
+  // ^^^ name of fn ^^^     ^^^^^^^^^^ arguments ^^^^^^^^^^     ^^^^^ const? ^^^^^^
+                                               ann:FuncAnnotationsOpt
+       [ return new D_func(loc, d, args, ann); ]
+
+  // array of specified size
+  -> d:DirectDeclarator "[" sz:ConstantExpression "]"
+       [ return new D_array(d, sz); ]
+
+  // array of unspecified size
+  -> d:DirectDeclarator "[" "]"
+       [ return new D_array(d, NULL); ]
+
+  // precedence grouping
+  -> "(" d:Declarator ")"
+       [ return d; ]
+}
+
+
+nonterm[PtrOperator*] PtrOperator {
+  // c++ std mentions something with "::" as well, I don't know what that means
+  -> "*" q:CVQualifierSeqOpt   [ return new PtrOperator(q); ]
+
+  //-> "&" ;
+}
+
+
+nonterm[enum CVFlags] CVQualifierSeqOpt {
+  -> empty                       [ return CV_NONE; ]
+  -> s:CVQualifierSeq            [ return s; ]
+}
+
+nonterm[enum CVFlags] CVQualifierSeq {
+  -> q:CVQualifier                       [ return q; ]
+  -> q:CVQualifier s:CVQualifierSeq      [ return (CVFlags)(q | s); ]
+}
+
+nonterm[enum CVFlags] CVQualifier {
+  -> "const"                 [ return CV_CONST; ]
+  -> "volatile"              [ return CV_VOLATILE; ]
+  -> "owner_ptr_qualifier"   [ return CV_OWNER; ]
+}
+
+
+// -- declarators in typedefs --
+// these are separated out because the parser wants to track the
+// introduction of type names
+nonterm[ASTList<Declarator>*] TypedefDeclaratorList {
+  -> d:TypedefDeclarator              
+       [ return new ASTList<Declarator>(new Declarator(d, NULL)); ]
+  -> list:TypedefDeclaratorList "," d:TypedefDeclarator
+       [ list->append(new Declarator(d, NULL)); return list; ]
+}
+
+nonterm[IDeclarator*] TypedefDeclarator {
+  -> p:PtrOperator d:TypedefDeclarator
+       [ d->stars.append(p); return d; ]
+  -> d:DirectTypedefDeclarator
+       [ return d; ]
+}
+
+nonterm[IDeclarator*] DirectTypedefDeclarator {
+  // changed from VariableName because this is a binding introduction
+  // so it doesn't matter what its previous association might have been
+  -> n:AnyName [
+       // TYPE/NAME
+       D("defined new typedef name " << n);
+       addType(n);
+       return new D_name(loc, n, NULL);
+     ]
+
+  -> d:DirectTypedefDeclarator "(" args:ParameterDeclarationClause ")" //CVQualifierSeqOpt
+                                               ann:FuncAnnotationsOpt
+       [ return new D_func(loc, d, args, ann); ]
+  -> d:DirectTypedefDeclarator "[" sz:ConstantExpression "]" 
+       [ return new D_array(d, sz); ]
+  -> d:DirectTypedefDeclarator "[" "]" 
+       [ return new D_array(d, NULL); ]
+  -> "(" d:TypedefDeclarator ")"
+       [ return d; ]
+}
+
+
+// -- type-id --
+// a type-id is like a declaration of one thing, but without the variable name;
+// it is, for example, what appears inside the parens of a typecast
+nonterm[ASTTypeId*] TypeId {
+  -> spec:TypeSpecifier decl:AbstractDeclaratorOpt
+       [ return new ASTTypeId(spec, new Declarator(decl, NULL)); ]
+
+  // gnu extension
+  //-> "__typeof__" "(" e:Expression ")" ;
+}
+
+nonterm[IDeclarator*] AbstractDeclaratorOpt {
+  -> empty                 [ return new D_name(loc, NULL, NULL); ]
+  -> d:AbstractDeclarator  [ return d; ]
+}
+
+// an abstract declarator (not opt) must have *some* ground syntax in it
+nonterm[IDeclarator*] AbstractDeclarator {
+  -> p:PtrOperator d:AbstractDeclaratorOpt
+       [ d->stars.append(p); return d; ]
+
+  -> d:DirectAbstractDeclarator
+       [ return d; ]
+}
+
+nonterm[IDeclarator*] DirectAbstractDeclaratorOpt {
+  -> empty                       [ return new D_name(loc, NULL, NULL); ]
+  -> d:DirectAbstractDeclarator  [ return d; ]
+}
+
+// this also must have some ground syntax
+nonterm[IDeclarator*] DirectAbstractDeclarator {
+  // this is where abstract declarators differ from regular declarators;
+  // for a declarator, this rule is "-> PQVarName"
+  // update: this approach, while conceptually elegant, leads to an ambiguity
+  // for the input "int()" between int and fn returning int
+  //-> empty ;
+
+  // function
+  -> d:DirectAbstractDeclarator "(" args:ParameterDeclarationClause ")" //q:CVQualifierSeqOpt
+                                               ann:FuncAnnotationsOpt
+       [ return new D_func(loc, d, args, ann); ]
+
+  // grammar hack: support missing function name part at this level, rather
+  // than using DirectAbstractDeclaratorOpt, to effect one extra token
+  // of lookahead
+  //-> "(" args:ParameterDeclarationClause ")" q:CVQualifierSeqOpt ;
+  // however, this postpones the ambiguity until it arises in
+  //   typedef int x;
+  //   int foo(int (x));
+  // is the argument an int, or a function accepting an 'x'?
+  // the rule is complicated, depending on x's previous declaration
+  // status.. I'll sidestep the whole issue by accepting a smaller language
+
+  -> d:DirectAbstractDeclaratorOpt "[" sz:ConstantExpression "]"  // array of specified size
+       [ return new D_array(d, sz); ]
+
+  -> d:DirectAbstractDeclaratorOpt "[" "]"                        // array of unspecified size
+       [ return new D_array(d, NULL); ]
+
+  -> "(" d:AbstractDeclarator ")"                                 // precedence grouping
+       [ return d; ]
+}
+
+
+nonterm[ASTList<ASTTypeId>*] ParameterDeclarationClause {
+  -> p:ParameterDeclarationList              // some args
+       [ return p; ]
+  -> empty                                   // no args
+       [ return new ASTList<ASTTypeId>(); ]
+  -> "..."                                   // all args are optional
+       [ return new ASTList<ASTTypeId>(ellipsisTypeId()); ]
+  -> p:ParameterDeclarationList "..."        // args plus optionally more
+       [ p->append(ellipsisTypeId()); return p; ]
+  -> p:ParameterDeclarationList "," "..."    // same; alternative syntax
+       [ p->append(ellipsisTypeId()); return p; ]
+}
+
+nonterm[ASTList<ASTTypeId>*] ParameterDeclarationList {
+  -> d:ParameterDeclaration 
+       [ return new ASTList<ASTTypeId>(d); ]
+  -> list:ParameterDeclarationList "," d:ParameterDeclaration 
+       [ list->append(d); return list; ]
+}
+
+nonterm[ASTTypeId*] ParameterDeclaration {
+  -> RegisterOpt s:TypeSpecifier d:Declarator
+       [ return new ASTTypeId(s, new Declarator(d, NULL)); ]
+  -> RegisterOpt s:TypeSpecifier d:AbstractDeclaratorOpt
+       [ return new ASTTypeId(s, new Declarator(d, NULL)); ]
+
+  //-> s:DeclSpecifier d:Declarator "=" AssignmentExpression ;
+  //-> s:DeclSpecifier d:AbstractDeclarator "=" AssignmentExpression ;
+}
+
+// old code uses the keyword "register" in the parameter declarations, but I
+// will ignore it when that happens
+nonterm RegisterOpt {
+  -> empty;
+  -> "register";
+}
+
+
+// -- function definition --
+nonterm[TF_func*] FunctionDefinition {
+  // I am wary of letting the declspecifier be optional, because it seems
+  // to me that may introduce more ambiguities.. but it truly is missing
+  // in ctors and dtors; so my idea now is to only permit it when the
+  // declarator declares a function type (can't be more specific since there
+  // aren't good syntactic clues for ctors)
+
+  // return type      name/params   body
+  -> r:DeclSpecifier  d:Declarator  b:FunctionBody
+       [
+         TF_func *ret = new TF_func(loc, r->dflags, r->spec, new Declarator(d, NULL), b);
+         r->spec = NULL;    // stole it above
+         delete r;          // was just a carrier of dflags/spec
+         return ret;
+       ]
+
+  // return type      name/params   body
+  //-> ExplicitOpt      d:Declarator  FunctionBody ;         // {c,d}tor
+
+  // return type      name/params   body
+  //-> ExplicitOpt      d:Declarator  ":" MemInitializerList FunctionBody ;  // ctor
+}
+
+nonterm[S_compound*] FunctionBody -> s:CompoundStatement
+  [ return s; ]
+
+//  nonterm ExplicitOpt {
+//    -> "explicit" ;
+//    -> empty ;
+//  }
+
+
+// ------ A.8 Classes ------
+// I'm going to use the "class" terminology throughout, even though
+// C only has "struct" and "union"
+nonterm[TS_classSpec*] ClassSpecifier ->
+  k:ClassKeyword n:ClassNameOpt /*base:BaseClauseOpt*/
+    "{" memb:MemberDeclarationSeqOpt "}"
+  [
+    return new TS_classSpec(k, n, memb);
+  ]
+
+nonterm[StringRef] ClassNameOpt {
+  -> empty     [ return NULL; ]
+  -> n:AnyName [
+       declareClassTag(n);
+       return n;
+     ]
+}
+
+nonterm[enum TypeIntr] ClassKeyword {
+  -> "class"       [ return TI_CLASS; ]
+  -> "struct"      [ return TI_STRUCT; ]
+  -> "union"       [ return TI_UNION; ]
+}
+
+
+nonterm[ASTList<Declaration>*] MemberDeclarationSeqOpt {
+  -> empty
+       [ return new ASTList<Declaration>(); ]
+
+  -> list:MemberDeclarationSeqOpt decl:MemberDeclaration
+       [ list->append(decl); return list; ]
+
+  //-> AccessSpecifier ":" MemberDeclarationSeqOpt ;
+}
+
+//  nonterm AccessSpecifier {
+//    -> "public" ;
+//    -> "private" ;
+//    -> "protected" ;
+//  }
+
+nonterm[Declaration*] MemberDeclaration {
+  -> spec:DeclSpecifier list:MemberDeclaratorList ";"      // member fn or data
+       [ spec->decllist.steal(list); return spec; ]
+
+  //-> FunctionDefinition ";" ;                    // inline fn
+  //-> FunctionDefinition ;                        // syntactic tweak
+  //-> ExplicitOpt VirtualOpt d:Declarator ";" ;   // ctor, dtor, conv op
+
+  // note above that "explicit" and "virtual" can't be mixed because the former
+  // is for ctors only and the latter can't be used with ctors (so a later stage
+  // of processing will filter it out)
+}
+
+// very similar to InitDeclaratorList
+nonterm[ASTList<Declarator>*] MemberDeclaratorList {
+  -> d:MemberDeclarator
+       [ return new ASTList<Declarator>(new Declarator(d, NULL)); ]
+  -> list:MemberDeclaratorList "," d:MemberDeclarator
+       [ list->append(new Declarator(d, NULL)); return list; ]
+}
+
+nonterm[IDeclarator*] MemberDeclarator {
+  -> d:Declarator
+       [ return d; ]
+
+  //-> Declarator "=" ConstantExpression ;   // pure; and member inits??
+
+  // unnamed bitfield
+  -> ":" e:ConstantExpression
+       [ return new D_bitfield(NULL /*name*/, e); ]
+  -> ":" e:ConstantExpression GNUAttribute
+       [ return new D_bitfield(NULL /*name*/, e); ]
+
+  // named bitfield
+  -> n:AnyName ":" e:ConstantExpression GNUAttribute
+       [ return new D_bitfield(n, e); ]
+  -> n:AnyName ":" e:ConstantExpression
+       [ return new D_bitfield(n, e); ]
+}
+
+
+// ------ A.9 Derived classes ------
+//  nonterm BaseClauseOpt {
+//    -> empty ;
+//    -> ":" BaseSpecifierList ;
+//  }
+
+//  nonterm BaseSpecifierList {
+//    -> BaseSpecifier ;
+//    -> BaseSpecifierList "," BaseSpecifier ;
+//  }
+
+//  nonterm BaseSpecifier -> VirtualOpt AccessSpecifierOpt PQClassName ;
+//  nonterm VirtualOpt {
+//    -> empty ;
+//    -> "virtual" ;
+//  }
+//  nonterm AccessSpecifierOpt {
+//    -> empty ;
+//    -> AccessSpecifier ;
+//  }
+
+//  nonterm PQClassName {
+//    -> TypeName ;
+//    -> Qualifier PQClassName ;
+//  }
+
+
+// ------ A.10 Special member functions ------
+//  nonterm ConversionFunctionId -> "operator" ConversionTypeId ;
+//  nonterm ConversionTypeId -> TypeSpecifier ConversionDeclaratorOpt ;
+//  nonterm ConversionDeclaratorOpt {
+//    -> empty ;
+//    -> PtrOperator ConversionDeclaratorOpt ;
+//  }
+
+//  nonterm MemInitializerList {
+//    -> MemInitializer ;
+//    -> MemInitializer "," MemInitializerList ;
+//  }
+
+//  // std has a separate rule for base class ctor call, but that's not
+//  // a useful parsing distinction, so it just creates gratuitous
+//  // ambiguities, and I've eliminated it
+//  nonterm MemInitializer -> AnyName "(" ExpressionListOpt ")" ;     // member init
+
+
+// ------ A.11 Overloading ------
+//  nonterm OperatorFunctionId -> "operator" Operator ;
+
+//  nonterm Operator {
+//    -> "new" ;
+//    -> "delete" ;
+//    -> "new" "[" "]" ;
+//    -> "delete" "[" "]" ;
+
+//    -> "*"  ;
+//    -> "/"  ;
+//    -> "%"  ;
+//    -> "+"  ;
+//    -> "-"  ;
+//    -> "<<" ;
+//    -> ">>" ;
+//    -> "<"  ;
+//    -> ">"  ;
+//    -> "<=" ;
+//    -> ">=" ;
+//    -> "==" ;
+//    -> "!=" ;
+//    -> "&"  ;
+//    -> "^"  ;
+//    -> "|"  ;
+//    -> "&&" ;
+//    -> "||" ;
+
+//    -> AssignmentOperator   ;
+
+//    -> "!" ;
+//    -> "~" ;
+//    -> "," ;
+//    -> "++" ;
+//    -> "--" ;
+//    -> "->" ;
+//    -> "(" ")" ;
+//    -> "[" "]" ;
+//  }
+
+
+// ------ A.12 Templates ------
+//TemplateParameterList -> TemplateParameter
+//TemplateParameterList -> TemplateParameterList "," TemplateParameter
+
+//TemplateParameter -> TypeParameter | ParameterDeclaration
+
+
+//  nonterm TemplateId {
+//    -> TypeName "<" TemplateArgumentList ">" ;
+//    -> TypeName "<" ">" ;
+//  }
+
+//  nonterm TemplateArgumentList {
+//    -> TemplateArgument ;
+//    -> TemplateArgumentList "," TemplateArgument ;
+//  }
+
+//  nonterm TemplateArgument {
+//    // where I have Literal the std has AssignmentExpression...
+//    // std also mentions IdExpression here, which is my PQVarName.....
+//    -> Literal ;
+//    -> TypeId ;
+//  }
+
+
+// ------ A.13 Exception handling ------
+//  nonterm TryBlock -> "try" s:CompoundStatement h:HandlerSeq ;
+
+//  nonterm HandlerSeq {
+//    -> h:Handler ;
+//    -> h:Handler seq:HandlerSeq ;
+//  }
+
+//  nonterm Handler
+//    -> "catch" "(" d:ExceptionDeclaration ")" s:CompoundStatement ;
+
+//  nonterm ExceptionDeclaration {
+//    -> s:TypeSpecifier d:Declarator ;          // named exception object
+
+//    -> TypeSpecifier AbstractDeclaratorOpt     ;  // unnamed exception object
+//    -> "..."                                ;  // anything
+//  }
+
+//  nonterm ThrowExpression {
+//    -> "throw" ;
+//    -> "throw" e:AssignmentExpression ;
+//  }
+
+
+// ------------------- GNU extensions -------------------
+// just enough to get past them ..
+
+// all operators/punctuators except "(" and ")"
+nonterm GNUExprOp {
+  -> "[" ;
+  -> "]" ;
+  -> "->" ;
+  -> "::" ;
+  -> "." ;
+  -> "!" ;
+  -> "~" ;
+  -> "+" ;
+  -> "-" ;
+  -> "++" ;
+  -> "--" ;
+  -> "&" ;
+  -> "*" ;
+  -> ".*" ;
+  -> "->*" ;
+  -> "/" ;
+  -> "%" ;
+  -> "<<" ;
+  -> ">>" ;
+  -> "<" ;
+  -> "<=" ;
+  -> ">" ;
+  -> ">=" ;
+  -> "==" ;
+  -> "!=" ;
+  -> "^" ;
+  -> "|" ;
+  -> "&&" ;
+  -> "||" ;
+  -> "?" ;
+  -> ":" ;
+  -> "=" ;
+  -> "*=" ;
+  -> "/=" ;
+  -> "%=" ;
+  -> "+=" ;
+  -> "-=" ;
+  -> "&=" ;
+  -> "^=" ;
+  -> "|=" ;
+  -> "<<=" ;
+  -> ">>=" ;
+  -> "," ;
+  -> "..." ;
+  -> ";" ;
+  -> "{" ;
+  -> "}" ;
+}
+
+// all of them, I guess..
+nonterm GNUExprKeyword {
+  -> "asm" ;
+  -> "auto" ;
+  -> "break" ;
+  -> "bool" ;
+  -> "case" ;
+  -> "catch" ;
+  -> "cdecl" ;
+  -> "char" ;
+  -> "class" ;
+  -> "const" ;
+  -> "const_cast" ;
+  -> "continue" ;
+  -> "default" ;
+  -> "delete" ;
+  -> "do" ;
+  -> "double" ;
+  -> "dynamic_cast" ;
+  -> "else" ;
+  -> "enum" ;
+  -> "explicit" ;
+  -> "extern" ;
+  -> "float" ;
+  -> "for" ;
+  -> "friend" ;
+  -> "goto" ;
+  -> "if" ;
+  -> "inline" ;
+  -> "int" ;
+  -> "long" ;
+  -> "mutable" ;
+  -> "new" ;
+  -> "operator" ;
+  -> "pascal" ;
+  -> "private" ;
+  -> "protected" ;
+  -> "public" ;
+  -> "register" ;
+  -> "reinterpret_cast" ;
+  -> "return" ;
+  -> "short" ;
+  -> "signed" ;
+  -> "sizeof" ;
+  -> "static" ;
+  -> "static_cast" ;
+  -> "struct" ;
+  -> "switch" ;
+  -> "template" ;
+  -> "this" ;
+  -> "throw" ;
+  -> "try" ;
+  -> "typedef" ;
+  -> "typeid" ;
+  -> "union" ;
+  -> "unsigned" ;
+  -> "virtual" ;
+  -> "void" ;
+  -> "volatile" ;
+  -> "wchar_t" ;
+  -> "while" ;
+  -> "__typeof__" ;
+}
+
+nonterm GNUAttribute -> "__attribute__" "(" "(" GNUExprSeq ")" ")";
+
+// recognize grouping only
+nonterm GNUExprSeq {
+  -> empty ;
+  -> GNUExpr GNUExprSeq ;
+}
+
+nonterm GNUExpr {
+  -> "(" GNUExprSeq ")" ;
+  -> AnyName ;
+  -> GNUExprOp ;
+  -> GNUExprKeyword ;
+  -> L2_INT_LITERAL ;
+  -> L2_STRING_LITERAL ;
+}
+
+nonterm GNUAsmStatement {
+  -> "asm" "(" GNUExprSeq ")" ";" ;
+  -> "asm" "volatile" "(" GNUExprSeq ")" ";" ;
+}
+
+
+// ----------------- thmprv extensions ----------------
+nonterm[ASTList<FuncAnnotation>*] FuncAnnotationsOpt {
+  -> empty                              
+       [ return new ASTList<FuncAnnotation>(); ]
+  -> list:FuncAnnotationsOpt ann:FuncAnnotation  
+       [ list->append(ann); return list; ]
+}
+
+nonterm[FuncAnnotation*] FuncAnnotation {
+  -> "thmprv_pre" "(" d:FADeclListOpt e:Expression ")"
+       [ return new FA_precondition(d, e); ]
+  -> "thmprv_post" "(" e:Expression ")"
+       [ return new FA_postcondition(e); ]
+}
+
+nonterm[ASTList<Declaration>*] FADeclListOpt {
+  -> empty
+       [ return new ASTList<Declaration>(); ]
+  -> list:FADeclList
+       [ return list; ]
+}
+
+// syntax "thmprv_bind" is to disambiguate a declaration (which always
+// starts with a TypeName) from a qualified variable expression (which
+// also starts with a TypeName)
+nonterm[ASTList<Declaration>*] FADeclList {
+  // ambiguity will result in a cancelled reduction here when the
+  // parser speculates a leading TypeName is for a qualified variable;
+  // note that no sharing will have been introduced
+  fun del(list) [ delete list; ]
+
+  -> /*"thmprv_bind"*/ d:SimpleDeclaration
+       [ return new ASTList<Declaration>(d); ]
+  -> list:FADeclList /*"thmprv_bind"*/ d:SimpleDeclaration
+       [ list->append(d); return list; ]
+}
+
+nonterm[ThmprvAttr*] ThmprvAttr {
+  -> empty
+       [ return NULL; ]
+  -> "thmprv_attr" "(" list:ThmprvAttrList ")"
+       [ return new ThmprvAttr(strRefAttr, list); ]
+}
+
+nonterm[ASTList<ThmprvAttr>*] ThmprvAttrList {
+  -> o:OneThmprvAttr
+       [ return new ASTList<ThmprvAttr>(o); ]
+  -> list:ThmprvAttrList "," o:OneThmprvAttr
+       [ list->append(o); return list; ]
+}
+
+nonterm[ThmprvAttr*] OneThmprvAttr {
+  -> name:AnyName
+       [ return new ThmprvAttr(name, NULL /*args*/); ]
+  -> name:AnyName "(" args:ThmprvAttrList ")"
+       [ return new ThmprvAttr(name, args); ]
+}
+
+nonterm[Expression*] ThmprvPredicate {
+  -> "thmprv_forall" "(" d:FADeclList e:Expression ")"
+       [ return new E_quantifier(d, e, true /*forall*/); ]
+  -> "thmprv_exists" "(" d:FADeclList e:Expression ")"
+       [ return new E_quantifier(d, e, false /*forall*/); ]
+}

Added: vendor/elsa/current/elkhound/c/c_env.cc
===================================================================
--- vendor/elsa/current/elkhound/c/c_env.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/c_env.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,753 @@
+// c_env.cc            see license.txt for copyright and terms of use
+// code for c_env.h
+
+#include "c_env.h"       // this module
+#include "trace.h"       // tracingSys
+#include "ckheap.h"      // heapCheck
+#include "strtable.h"    // StringTable
+#include "cc_lang.h"     // CCLang
+
+
+// --------------------- CFGEnv -----------------------
+CFGEnv::CFGEnv()
+{
+  // make empty top frames
+  pushNexts();
+  pushBreaks();
+}
+
+CFGEnv::~CFGEnv()
+{}
+
+
+// -------- nexts -------
+void CFGEnv::pushNexts()
+{
+  pendingNexts.push(new SObjList<Statement>());
+}
+
+void CFGEnv::addPendingNext(Statement *source)
+{
+  pendingNexts.top()->prepend(source);    // O(n)
+}
+
+void CFGEnv::popNexts()
+{
+  SObjList<Statement> *top = pendingNexts.pop();
+  pendingNexts.top()->concat(*top);    // empties 'top'
+  delete top;
+}
+
+void CFGEnv::clearNexts()
+{
+  pendingNexts.top()->removeAll();
+}
+
+void CFGEnv::resolveNexts(Statement *target, bool isContinue)
+{
+  SMUTATE_EACH_OBJLIST(Statement, *(pendingNexts.top()), iter) {
+    iter.data()->next = makeNextPtr(target, isContinue);
+  }
+  clearNexts();
+}
+
+
+// -------- breaks --------
+void CFGEnv::pushBreaks()
+{
+  breaks.push(new SObjList<S_break>());
+}
+
+void CFGEnv::addBreak(S_break *source)
+{
+  breaks.top()->prepend(source);     // O(n)
+}
+
+void CFGEnv::popBreaks()
+{
+  // all topmost breaks become pending nexts
+  SMUTATE_EACH_OBJLIST(S_break, *(breaks.top()), iter) {
+    addPendingNext(iter.data());
+  }
+  breaks.delPop();
+}
+
+
+// -------- labels --------
+void CFGEnv::addLabel(StringRef name, S_label *target)
+{
+  labels.add(name, target);
+}
+
+void CFGEnv::addPendingGoto(StringRef name, S_goto *source)
+{
+  gotos.add(name, source);
+}
+
+void CFGEnv::resolveGotos()
+{                                     
+  // go over all the gotos and find their corresponding target
+  for (StringSObjDict<S_goto>::Iter iter(gotos);
+       !iter.isDone(); iter.next()) {    
+    S_label *target = labels.queryif(iter.key().c_str());
+    if (target) {
+      iter.value()->next = makeNextPtr(target, false);
+    }
+    else {
+      err(stringc << "goto to undefined label: " << iter.key());
+    }
+  }
+  
+  // empty both dictionaries
+  labels.empty();
+  gotos.empty();
+}
+
+
+// -------- switches --------
+void CFGEnv::pushSwitch(S_switch *sw)
+{
+  switches.push(sw);
+}
+
+S_switch *CFGEnv::getCurrentSwitch()
+{
+  return switches.top();
+}
+
+void CFGEnv::popSwitch()
+{
+  switches.pop();
+}
+
+
+// --------- loops ----------
+void CFGEnv::pushLoop(Statement *loop)
+{
+  loops.push(loop);
+}
+
+Statement *CFGEnv::getCurrentLoop()
+{
+  return loops.top();
+}
+
+void CFGEnv::popLoop()
+{
+  loops.pop();
+}
+
+
+// -------- end --------
+void CFGEnv::verifyFunctionEnd()
+{
+  xassert(pendingNexts.count() == 1);
+  xassert(pendingNexts.top()->count() == 0);
+  
+  xassert(breaks.count() == 1);
+  xassert(breaks.top()->count() == 0);
+  
+  xassert(labels.size() == 0);
+  xassert(gotos.size() == 0);
+
+  xassert(switches.count() == 0);
+  xassert(loops.count() == 0);
+}
+
+
+// --------------------- ScopedEnv ---------------------
+ScopedEnv::ScopedEnv()
+{}
+
+ScopedEnv::~ScopedEnv()
+{}
+
+
+// --------------------------- Env ----------------------------
+Env::Env(StringTable &table, CCLang &alang)
+  : scopes(),
+    typedefs(),
+    compounds(),
+    enums(),
+    enumerators(),
+    errors(0),
+    warnings(0),
+    compoundStack(),
+    currentFunction(NULL),
+    locationStack(),
+    inPredicate(false),
+    strTable(table),
+    lang(alang)
+{
+  enterScope();
+
+  #if 0
+  declareVariable("__builtin_constant_p", DF_BUILTIN,
+    makeFunctionType_1arg(
+      getSimpleType(ST_INT),                          // return type
+      CV_NONE,
+      getSimpleType(ST_INT), "potentialConstant"),    // arg type
+      true /*initialized*/);
+  #endif // 0
+}
+
+
+Env::~Env()
+{
+  // explicitly free things, for easier debugging of dtor sequence
+  scopes.deleteAll();
+  typedefs.empty();
+  compounds.empty();
+  enums.empty();
+  enumerators.empty();
+}
+
+
+void Env::enterScope()
+{
+  scopes.prepend(new ScopedEnv());
+}
+
+void Env::leaveScope()
+{
+  scopes.deleteAt(0);
+}
+
+
+// NOTE: the name lookup rules in this code have not been
+// carefully checked against what the standard requires,
+// so they are likely wrong; I intend to go through and
+// make them correct at some point
+
+
+// ---------------------------- variables ---------------------------
+void Env::addVariable(StringRef name, Variable *decl)
+{
+  // convenience
+  Type const *type = decl->type;
+  DeclFlags flags = decl->flags;
+
+  // shouldn't be using this interface to add typedefs
+  xassert(!(flags & DF_TYPEDEF));
+
+  // special case for adding compound type members
+  if (compoundStack.isNotEmpty()) {
+    addCompoundField(compoundStack.first(), decl);
+    return;
+  }
+
+  Variable *prev = getVariable(name, true /*inner*/);
+  if (prev) {
+    // if the old decl and new are the same array type,
+    // except the old was missing a size, replace the
+    // old with the new
+    if (type->isArrayType() &&
+        prev->type->isArrayType()) {
+      ArrayType const *arr = &( type->asArrayTypeC() );
+      ArrayType const *parr = &( prev->type->asArrayTypeC() );
+      if (arr->eltType->equals(parr->eltType) &&
+          arr->hasSize &&
+          !parr->hasSize) {
+        // replace old with new
+        prev->type = type;
+      }
+    }
+
+    // no way we allow it if the types don't match
+    if (!type->equals(prev->type)) {
+      errThrow(stringc
+        << "conflicting declaration for `" << name
+        << "'; previous type was `" << prev->type->toString()
+        << "', this type is `" << type->toString() << "'");
+    }
+
+    // TODO: this is all wrong.. I didn't want more than one Variable
+    // to exist for a given name, but this function allows more than
+    // one....
+
+    // but it's ok if:
+    //   - both were functions, or
+    //   - one is extern, or
+    //   - both were static
+    // (TODO: what are the real rules??)
+    // and, there can be at most one initializer (why did I comment that out?)
+    if ( ( type->isFunctionType() ||
+           ((flags & DF_EXTERN) || (prev->flags & DF_EXTERN)) ||
+           ((flags & DF_STATIC) && (prev->flags & DF_STATIC))
+         )
+         //&& (!prev->isInitialized() || !initialized)
+       ) {
+      // ok
+      // at some point I'm going to have to deal with merging the
+      // information, but for now.. skip it
+
+      // merging for functions: pre/post
+      // disabled: there's a problem because the parameter names don't
+      // get symbolically evaluated right
+      if (type->isFunctionType()) {
+        FunctionType const *prevFn = &( prev->type->asFunctionTypeC() );
+        FunctionType const *curFn = &( type->asFunctionTypeC() );
+
+        // if a function has a prior declaration or definition, then
+        // I want all later occurrences to *not* have pre/post, but
+        // rather to inherit that of the prior definition.  this way
+        // nobody gets to use the function before a precondition is
+        // attached.  (may change this later, somehow)
+        // update: now just checking..
+        if (!curFn->precondition != !prevFn->precondition  || 
+            !curFn->postcondition != !prevFn->postcondition) {
+          warn("pre/post-condition different after first introduction");
+        }
+
+        // transfer the prior pre/post to the current one
+        // NOTE: this is a problem if the names of parameters are different
+        // in the previous declaration
+        //decl->type = prev->type;     // since 'curFn' is const, just point 'decl' elsewhere..
+      }
+    }
+    else {
+      err(stringc << "duplicate variable decl: " << name);
+    }
+  }
+
+  else /*not already mapped*/ {
+    if (isGlobalEnv()) {
+      decl->flags = (DeclFlags)(decl->flags | DF_GLOBAL);
+    }
+
+    scopes.first()->variables.add(name, decl);
+  }
+}
+
+
+Variable *Env::getVariable(StringRef name, bool innerOnly)
+{
+  // TODO: add enums to what we search
+
+  MUTATE_EACH_OBJLIST(ScopedEnv, scopes, iter) {
+    Variable *v;
+    if (iter.data()->variables.query(name, v)) {
+      return v;
+    }
+    
+    if (innerOnly) {
+      return NULL;    // don't look beyond the first
+    }
+  }
+
+  return NULL;
+}
+
+
+// ------------------- typedef -------------------------
+void Env::addTypedef(StringRef name, Type const *type)
+{       
+  Type const *prev = getTypedef(name);
+  if (prev) {
+    // in C++, saying 'struct Foo { ... }' implicitly creates
+    // "typedef struct Foo Foo;" -- but then in C programs
+    // it's typical to do this explicitly as well.  apparently g++
+    // does what I'm about to do: permit it when the typedef names
+    // the same type
+    if (lang.tagsAreTypes && prev->equals(type)) {
+      // allow it, like g++ does
+      return;
+    }
+    else {
+      errThrow(stringc <<
+        "conflicting typedef for `" << name <<
+        "' as type `" << type->toCString() <<
+        "'; previous type was `" << prev->toCString() <<
+        "'");
+    }
+  }
+  typedefs.add(name, const_cast<Type*>(type));
+}
+
+
+Type const *Env::getTypedef(StringRef name)
+{
+  Type *t;
+  if (typedefs.query(name, t)) {
+    return t;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+// ----------------------- compounds -------------------
+CompoundType *Env::addCompound(StringRef name, CompoundType::Keyword keyword)
+{
+  if (name && compounds.isMapped(name)) {
+    errThrow(stringc << "compound already declared: " << name);
+  }
+
+  CompoundType *ret = new CompoundType(keyword, name);
+  //grabAtomic(ret);
+  if (name) {
+    compounds.add(name, ret);
+  }
+
+  return ret;
+}
+
+
+void Env::addCompoundField(CompoundType *ct, Variable *decl)
+{
+  if (ct->getNamedField(decl->name)) {
+    errThrow(stringc << "field already declared: " << decl->name);
+  }
+
+  ct->addField(decl->name, decl->type, decl);
+  decl->setFlag(DF_MEMBER);
+}
+
+
+CompoundType *Env::getCompound(StringRef name)
+{
+  CompoundType *e;
+  if (name && compounds.query(name, e)) {
+    return e;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+CompoundType *Env::getOrAddCompound(StringRef name, CompoundType::Keyword keyword)
+{
+  CompoundType *ret = getCompound(name);
+  if (!ret) {
+    return addCompound(name, keyword);
+  }
+  else {
+    if (ret->keyword != keyword) {
+      errThrow(stringc << "keyword mismatch for compound " << name);
+    }
+    return ret;
+  }
+}
+
+
+// ---------------------- enums ---------------------
+EnumType *Env::addEnum(StringRef name)
+{
+  if (name && enums.isMapped(name)) {
+    errThrow(stringc << "enum already declared: " << name);
+  }
+
+  EnumType *ret = new EnumType(name);
+  if (name) {
+    enums.add(name, ret);
+  }
+  return ret;
+}
+
+
+EnumType *Env::getEnum(StringRef name)
+{
+  EnumType *ret;
+  if (name && enums.query(name, ret)) {
+    return ret;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+EnumType *Env::getOrAddEnum(StringRef name)
+{
+  EnumType *ret = getEnum(name);
+  if (!ret) {
+    return addEnum(name);
+  }
+  else {
+    return ret;
+  }
+}
+
+
+// ------------------ enumerators ---------------------
+EnumType::Value *Env::addEnumerator(StringRef name, EnumType *et, int value,
+                                    Variable *decl)
+{
+  if (enumerators.isMapped(name)) {
+    errThrow(stringc << "duplicate enumerator: " << name);
+  }
+
+  EnumType::Value *ret = et->addValue(name, value, decl);
+  enumerators.add(name, ret);
+  return ret;
+}
+
+
+EnumType::Value *Env::getEnumerator(StringRef name)
+{
+  EnumType::Value *ret;
+  if (enumerators.query(name, ret)) {
+    return ret;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+// -------------------- type construction ------------------
+CVAtomicType *Env::makeType(AtomicType const *atomic)
+{
+  return makeCVType(atomic, CV_NONE);
+}
+
+
+CVAtomicType *Env::makeCVType(AtomicType const *atomic, CVFlags cv)
+{
+  CVAtomicType *ret = new CVAtomicType(atomic, cv);
+  grab(ret);
+  return ret;
+}
+
+
+Type const *Env::applyCVToType(CVFlags cv, Type const *baseType)
+{
+  if (baseType->isError()) {
+    return baseType;
+  }
+
+  if (cv == CV_NONE) {
+    // keep what we've got
+    return baseType;
+  }
+
+  // the idea is we're trying to apply 'cv' to 'baseType'; for
+  // example, we could have gotten baseType like
+  //   typedef unsigned char byte;     // baseType == unsigned char
+  // and want to apply const:
+  //   byte const b;                   // cv = CV_CONST
+  // yielding final type
+  //   unsigned char const             // return value from this fn
+
+  // first, check for special cases
+  switch (baseType->getTag()) {
+    case Type::T_ATOMIC: {
+      CVAtomicType const &atomic = baseType->asCVAtomicTypeC();
+      if ((atomic.cv | cv) == atomic.cv) {
+        // the given type already contains 'cv' as a subset,
+        // so no modification is necessary
+        return baseType;
+      }
+      else {
+        // we have to add another CV, so that means creating
+        // a new CVAtomicType with the same AtomicType as 'baseType'
+        CVAtomicType *ret = new CVAtomicType(atomic);
+        grab(ret);
+
+        // but with the new flags added
+        ret->cv = (CVFlags)(ret->cv | cv);
+
+        return ret;
+      }
+      break;
+    }
+
+    case Type::T_POINTER: {
+      // logic here is nearly identical to the T_ATOMIC case
+      PointerType const &ptr = baseType->asPointerTypeC();
+      if (ptr.op == PO_REFERENCE) {
+        return NULL;     // can't apply CV to references
+      }
+      if ((ptr.cv | cv) == ptr.cv) {
+        return baseType;
+      }
+      else {
+        PointerType *ret = new PointerType(ptr);
+        grab(ret);
+        ret->cv = (CVFlags)(ret->cv | cv);
+        return ret;
+      }
+      break;
+    }
+
+    default:    // silence warning
+    case Type::T_FUNCTION:
+    case Type::T_ARRAY:
+      // can't apply CV to either of these (function has CV, but
+      // can't get it after the fact)
+      return NULL;
+  }
+}
+
+
+ArrayType const *Env::setArraySize(ArrayType const *type, int size)
+{
+  ArrayType *ret = new ArrayType(type->eltType, size);
+  grab(ret);
+  return ret;
+}
+
+
+Type const *Env::makePtrOperType(PtrOper op, CVFlags cv, Type const *type)
+{
+  if (type->isError()) {
+    return type;
+  }
+
+  PointerType *ret = new PointerType(op, cv, type);
+  grab(ret);
+  return ret;
+}
+
+
+FunctionType *Env::makeFunctionType(Type const *retType/*, CVFlags cv*/)
+{
+  FunctionType *ret = new FunctionType(retType/*, cv*/);
+  grab(ret);
+  return ret;
+}
+
+
+#if 0
+FunctionType *Env::makeFunctionType_1arg(
+  Type const *retType, CVFlags cv,
+  Type const *arg1Type, char const *arg1Name)
+{
+  FunctionType *ret = makeFunctionType(retType/*, cv*/);
+  ret->addParam(new Parameter(arg1Type, arg1Name));
+  return ret;
+}    
+#endif // 0
+
+
+ArrayType *Env::makeArrayType(Type const *eltType, int size)
+{
+  ArrayType *ret = new ArrayType(eltType, size);
+  grab(ret);
+  return ret;
+}
+
+ArrayType *Env::makeArrayType(Type const *eltType)
+{
+  ArrayType *ret = new ArrayType(eltType);
+  grab(ret);
+  return ret;
+}
+
+
+void Env::checkCoercible(Type const *src, Type const *dest)
+{
+  if (dest->asRval()->isOwnerPtr()) {
+    // can only assign owners into owner owners (whereas it's
+    // ok to assign an owner into a serf)
+    if (!src->asRval()->isOwnerPtr()) {
+      err(stringc
+        << "cannot convert `" << src->toString()
+        << "' to `" << dest->toString());
+    }
+  }
+
+  // just say yes
+}
+
+Type const *Env::promoteTypes(BinaryOp op, Type const *t1, Type const *t2)
+{
+  // yes yes yes
+  return t1;
+}
+
+
+// --------------------- error/warning reporting ------------------
+Type const *Env::err(char const *str)
+{
+  cout << ::toString(currentLoc()) << ": error: " << str << endl;
+  errors++;
+  return fixed(ST_ERROR);
+}
+
+
+void Env::warn(char const *str)
+{
+  cout << ::toString(currentLoc()) << ": warning: " << str << endl;
+  warnings++;
+}
+
+
+void Env::errLoc(SourceLoc loc, char const *str)
+{
+  pushLocation(loc);
+  err(str);
+  popLocation();
+}
+
+void Env::warnLoc(SourceLoc loc, char const *str)
+{
+  pushLocation(loc);
+  warn(str);
+  popLocation();
+}
+
+
+void Env::errThrow(char const *str)
+{
+  err(str);
+  THROW(XError(str));
+}
+
+
+void Env::errIf(bool condition, char const *str)
+{
+  if (condition) {
+    errThrow(str);
+  }
+}
+
+
+// ------------------- translation context -------------------
+Type const *Env::getCurrentRetType()
+{
+  return currentFunction->nameParams->var->type
+           ->asFunctionTypeC().retType;
+}
+
+
+void Env::pushLocation(SourceLoc loc)
+{
+  locationStack.push(loc);
+}
+
+
+SourceLoc Env::currentLoc() const
+{
+  if (locationStack.isEmpty()) {
+    return SL_UNKNOWN;      // no loc info
+  }
+  else {
+    return locationStack.top();
+  }
+}
+
+
+// ---------------------- debugging ---------------------
+string Env::toString() const
+{
+  stringBuilder sb;
+
+  // for now, just the variables
+  FOREACH_OBJLIST(ScopedEnv, scopes, sc) {
+    StringSObjDict<Variable>::IterC iter(sc.data()->variables);
+    for (; !iter.isDone(); iter.next()) {
+      sb << iter.value()->toString() << " ";
+    }
+  }
+
+  return sb;
+}
+
+
+void Env::selfCheck() const
+{}
+
+

Added: vendor/elsa/current/elkhound/c/c_env.h
===================================================================
--- vendor/elsa/current/elkhound/c/c_env.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/c_env.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,385 @@
+// c_env.h            see license.txt for copyright and terms of use
+// Env class, which is the compile-time C environment
+
+#ifndef C_ENV_H
+#define C_ENV_H
+
+#include "c_type.h"       // Type, AtomicType, etc. (r)
+#include "strobjdict.h"   // StrObjDict
+#include "strsobjdict.h"  // StrSObjDict
+#include "owner.h"        // Owner
+#include "exc.h"          // xBase
+#include "sobjlist.h"     // SObjList
+#include "objstack.h"     // ObjStack
+#include "sobjstack.h"    // SObjStack
+#include "c.ast.gen.h"    // C ast components
+#include "c_variable.h"   // Variable (r)
+#include "array.h"        // ArrayStack
+
+class StringTable;        // strtable.h
+class CCLang;             // cc_lang.h
+
+
+// thrown by some error functions
+class XError : public xBase {
+public:
+  XError(char const *msg) : xBase(msg) {}
+  XError(XError const &obj) : xBase(obj) {}
+};
+
+
+#if 0
+// mapping from name to type, for purpose of storage instantiation
+class Variable {
+public:     // data
+  DeclFlags declFlags;       // inline, etc.
+  Declarator *declarator;    // (serf, non-null) AST declarator node that introduced this name
+
+public:     // funcs
+  Variable(DeclFlags d, Declarator *decl);
+  ~Variable();
+
+  // pull name or type out of the declarator
+  StringRef getType() const { return declarator->name; }
+  Type const *getType() const { return declarator->type; }
+
+  // some ad-hoc thing
+  string toString() const;
+
+  // ML eval() format
+  //MLValue toMLValue() const;
+
+  bool isGlobal() const { return declFlags & DF_GLOBAL; }
+  //bool isInitialized() const { return declFlags & DF_INITIALIZED; }
+  //void sayItsInitialized() { declFlags = (DeclFlags)(declFlags | DF_INITIALIZED); }
+};
+#endif // 0
+
+
+// elements of the environment necessary for constructing the CFG
+class CFGEnv {
+private:    // data
+  ObjStack< SObjList<Statement> > pendingNexts;
+
+  ObjStack< SObjList<S_break> > breaks;
+
+  StringSObjDict<S_label> labels;       // goto targets
+  StringSObjDict<S_goto> gotos;         // goto sources
+
+  SObjStack<S_switch> switches;
+  SObjStack<Statement> loops;
+
+public:     // funcs
+  CFGEnv();
+  virtual ~CFGEnv();
+
+  // must be defined in child class
+  virtual Type const *err(char const *str)=0;
+
+  // manipulate a stack of lists of nodes whose 'next' link
+  // needs to be set
+  void pushNexts();          // push an empty top
+  void addPendingNext(Statement *source);
+  void popNexts();           // merge two topmost frames
+  void clearNexts();         // clear top
+  void resolveNexts(Statement *target, bool isContinue);
+
+  // manipulate a stack of lists of 'break' nodes whose 'next'
+  // link needs to be set
+  void pushBreaks();         // push empty top
+  void addBreak(S_break *source);
+  void popBreaks();          // resolve all at top, and pop frame
+
+  // manipulate lists of sources and targets of gotos
+  void addLabel(StringRef name, S_label *target);
+  void addPendingGoto(StringRef name, S_goto *source);
+  void resolveGotos();
+
+  // maintain a stack of nested switch statements
+  void pushSwitch(S_switch *sw);
+  S_switch *getCurrentSwitch();
+  void popSwitch();
+
+  // stack of nested loops
+  void pushLoop(Statement *loop);
+  Statement *getCurrentLoop();
+  void popLoop();
+
+  // check data structures for conditions which should hold between funcs
+  void verifyFunctionEnd();
+};
+
+
+// elements of the environment which are scoped
+class ScopedEnv {
+public:
+  // variables: map name -> Type
+  StringSObjDict<Variable> variables;
+
+public:
+  ScopedEnv();
+  ~ScopedEnv();
+};
+
+
+// C++ compile-time binding environment
+class Env : public CFGEnv {
+private:    // data
+  // ----------- fundamental maps ---------------
+  // list of active scopes; element 0 is the innermost scope
+  ObjList<ScopedEnv> scopes;
+
+  // typedefs: map name -> Type
+  StringSObjDict<Type /*const*/> typedefs;
+
+  // compounds: map name -> CompoundType
+  StringSObjDict<CompoundType> compounds;
+
+  // enums: map name -> EnumType
+  StringSObjDict<EnumType> enums;
+
+  // enumerators: map name -> EnumType::Value
+  StringSObjDict<EnumType::Value> enumerators;
+
+  // -------------- miscellaneous ---------------
+  // count of reported errors
+  int errors;
+  int warnings;
+
+  // stack of compounds being constructed
+  SObjList<CompoundType> compoundStack;
+
+  // current function
+  TF_func *currentFunction;
+
+  // stack of source locations considered 'current'
+  ArrayStack<SourceLoc> locationStack;
+
+public:     // data
+  // true in predicate expressions
+  bool inPredicate;
+
+  // string table for making up new names
+  StringTable &strTable;
+
+  // language options
+  CCLang &lang;
+
+private:    // funcs
+  void grab(Type const *t) {}
+  void grabAtomic(AtomicType const *t) {}
+
+  Env(Env&);               // not allowed
+
+public:     // funcs
+  // empty toplevel environment
+  Env(StringTable &table, CCLang &lang);
+  ~Env();
+
+  // scope manipulation
+  void enterScope();
+  void leaveScope();
+
+  // misc
+  StringRef str(char const *s) const { return strTable.add(s); }
+  
+  // ------------- variables -------------
+  // add a new variable to the innermost scope; it is an error
+  // if a variable by this name already exists; 'decl' actually
+  // has the name too, but I leave the 'name' parameter since
+  // conceptually we're binding the name
+  void addVariable(StringRef name, Variable *decl);
+
+  // return the associated Variable structure for a variable;
+  // return NULL if no such variable; if 'innerOnly' is set, we
+  // only look in the innermost scope
+  Variable *getVariable(StringRef name, bool innerOnly=false);
+
+  // ----------- typedefs -------------
+  // add a new typedef; error to collide;
+  // after this call, the program can use 'name' as an alias for 'type'
+  void addTypedef(StringRef name, Type const *type);
+
+  // return named type or NULL if no mapping
+  Type const *getTypedef(StringRef name);
+
+  // -------------- compounds --------------
+  // add a new compound; error to collide
+  CompoundType *addCompound(StringRef name, CompoundType::Keyword keyword);
+
+  // add a new field to an existing compound; error to collide
+  void addCompoundField(CompoundType *ct, Variable *decl);
+
+  // lookup, and return NULL if doesn't exist
+  CompoundType *getCompound(StringRef name);
+
+  // lookup a compound type; if it doesn't exist, declare a new
+  // incomplete type, using 'keyword'; if it does, but the keyword
+  // is different from its existing declaration, return NULL
+  CompoundType *getOrAddCompound(StringRef name, CompoundType::Keyword keyword);
+
+  // ----------------- enums -----------------------
+  // create a new enum type; error to collide
+  EnumType *addEnum(StringRef name);
+
+  // lookup an enum; return NULL if not declared
+  EnumType *getEnum(StringRef name);
+
+  EnumType *getOrAddEnum(StringRef name);
+
+  // ------------------ enumerators -------------------
+  // add an enum value
+  EnumType::Value *addEnumerator(StringRef name, EnumType *et, 
+                                 int value, Variable *decl);
+
+  // lookup; return NULL if no such variable
+  EnumType::Value *getEnumerator(StringRef name);
+
+
+  // ------------------ error/warning reporting -----------------
+  // report an error ('str' should *not* have a newline)
+  virtual Type const *err(char const *str);    // returns fixed(ST_ERROR)
+  void warn(char const *str);
+
+  // versions which explicitly specify a location
+  void errLoc(SourceLoc loc, char const *str);
+  void warnLoc(SourceLoc loc, char const *str);
+
+  // report an error, and throw an exception
+  void errThrow(char const *str);
+
+  // if 'condition' is true, report error 'str' and also throw an exception
+  void errIf(bool condition, char const *str);
+
+  // # reported errors
+  int getErrors() const { return errors; }
+
+
+  // ------------------- translation context ----------------
+  void pushStruct(CompoundType *ct)     { compoundStack.prepend(ct); }
+  void popStruct()                      { compoundStack.removeAt(0); }
+
+  void setCurrentFunction(TF_func *f)   { currentFunction = f; }
+  TF_func *getCurrentFunction()         { return currentFunction; }
+  Type const *getCurrentRetType();
+
+  bool isGlobalEnv() const              { return scopes.count() <= 1; }
+
+  void pushLocation(SourceLoc loc);
+  void popLocation()                    { locationStack.pop(); }
+  SourceLoc currentLoc() const;
+
+
+  // --------------- type construction -----------------
+  // given an AtomicType, wrap it in a CVAtomicType
+  // with no const or volatile qualifiers
+  CVAtomicType *makeType(AtomicType const *atomic);
+
+  // given an AtomicType, wrap it in a CVAtomicType
+  // with specified const or volatile qualifiers
+  CVAtomicType *makeCVType(AtomicType const *atomic, CVFlags cv);
+
+  // given a type, qualify it with 'cv'; return NULL
+  // if the base type cannot be so qualified
+  Type const *applyCVToType(CVFlags cv, Type const *baseType);
+
+  // given an array type with no size, return one that is
+  // the same except its size is as specified
+  ArrayType const *setArraySize(ArrayType const *type, int size);
+
+  // make a ptr-to-'type' type; returns generic Type instead of
+  // PointerType because sometimes I return fixed(ST_ERROR)
+  Type const *makePtrOperType(PtrOper op, CVFlags cv, Type const *type);
+  Type const *makePtrType(Type const *type)
+    { return makePtrOperType(PO_POINTER, CV_NONE, type); }
+  Type const *makeRefType(Type const *type)
+    { return makePtrOperType(PO_REFERENCE, CV_NONE, type); }
+
+  // make a function type; initially, its parameter list is
+  // empty, but can be built up by modifying the returned object
+  FunctionType *makeFunctionType(Type const *retType/*, CVFlags cv*/);
+
+  #if 0
+  // sometimes it's handy to specify all args at once
+  FunctionType *makeFunctionType_1arg(
+    Type const *retType, CVFlags cv,
+    Type const *arg1Type, char const *arg1name);
+  #endif // 0
+
+  // make an array type, either of known or unknown size
+  ArrayType *makeArrayType(Type const *eltType, int size);
+  ArrayType *makeArrayType(Type const *eltType);
+
+  // map a simple type into its CVAtomicType (with no const or
+  // volatile) representative
+  CVAtomicType const *getSimpleType(SimpleTypeId st);
+
+
+  // --------------- type checking ----------------
+  // type manipulation arising from expression semantics
+  void checkCoercible(Type const *src, Type const *dest);
+  Type const *promoteTypes(BinaryOp op, Type const *t1, Type const *t2);
+
+  
+  // -------------- debugging -------------
+  string toString() const;
+  void selfCheck() const;
+};
+
+
+#if 0
+// --------------------- TypeEnv ------------------
+// toplevel environment that owns all the types
+class TypeEnv {
+private:     // data
+  ArrayMap<Type> types;               // TypeId -> Type*
+  ArrayMap<AtomicType> atomicTypes;   // AtomicTypeId -> AtomicType*
+
+public:
+  TypeEnv();
+  ~TypeEnv();
+
+  int numTypes() const { return types.count(); }
+  TypeId grab(Type *type);
+  Type *lookup(TypeId id) { return types.lookup(id); }
+  Type const *lookupC(TypeId id) const { return types.lookupC(id); }
+
+  int numAtomicTypes() const { return atomicTypes.count(); }
+  AtomicTypeId grabAtomic(AtomicType *type);
+  AtomicType *lookupAtomic(AtomicTypeId id) { return atomicTypes.lookup(id); }
+  AtomicType const *lookupAtomicC(AtomicTypeId id) const { return atomicTypes.lookupC(id); }
+  
+  void empty() { types.empty(); atomicTypes.empty(); }
+};
+
+
+// ------------------ VariableEnv ---------------
+// something to own variable decls; current plan is to have
+// one for globals and then one for each function body
+class VariableEnv {
+private:
+  ArrayMap<Variable> vars;
+
+public:
+  VariableEnv();
+  ~VariableEnv();
+
+  int numVars() const { return vars.count(); }
+  VariableId grab(Variable * /*owner*/ var);
+  Variable *lookup(VariableId id) { return vars.lookup(id); }
+  Variable const *lookupC(VariableId id) const { return vars.lookupC(id); }
+  Variable *&lookupRef(VariableId id) { return vars.lookupRef(id); }
+  void empty() { vars.empty(); }
+  
+  // only for use by the iterator macro
+  ArrayMap<Variable> const &getVars() const { return vars; }
+};
+
+
+#define FOREACH_VARIABLE(env, var) \
+  FOREACH_ARRAYMAP(Variable, (env).getVars(), var)
+
+#endif // 0
+
+
+#endif // C_ENV_H

Added: vendor/elsa/current/elkhound/c/c_type.cc
===================================================================
--- vendor/elsa/current/elkhound/c/c_type.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/c_type.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1063 @@
+// c_type.cc            see license.txt for copyright and terms of use
+// code for c_type.h
+
+#include "c_type.h"     // this module
+#include "trace.h"      // tracingSys
+#include <assert.h>     // assert
+
+
+#if 0
+MLValue mlStorage(DeclFlags df)
+{
+  // storage = NoStorage | Static | Register | Extern
+
+  // not quite a perfect map .. but until it matters
+  // somewhere I'm leaving it as-is
+
+  if (df & DF_STATIC) {
+    return mlTuple0(storage_Static);
+  }
+  if (df & DF_REGISTER) {
+    return mlTuple0(storage_Register);
+  }
+  if (df & DF_EXTERN) {
+    return mlTuple0(storage_Extern);
+  }
+  return mlTuple0(storage_NoStorage);
+}
+#endif // 0
+
+
+string makeIdComment(int id)
+{
+  if (tracingSys("type-ids")) {
+    return stringc << "/""*" << id << "*/";
+                     // ^^ this is to work around an Emacs highlighting bug
+  }
+  else {
+    return "";
+  }
+}
+
+
+// ------------------ AtomicType -----------------
+ALLOC_STATS_DEFINE(AtomicType)
+
+AtomicType::AtomicType()
+  //: id(NULL_ATOMICTYPEID)
+{
+  ALLOC_STATS_IN_CTOR
+}
+
+
+AtomicType::~AtomicType()
+{
+  ALLOC_STATS_IN_DTOR
+}
+
+
+CAST_MEMBER_IMPL(AtomicType, SimpleType)
+CAST_MEMBER_IMPL(AtomicType, CompoundType)
+CAST_MEMBER_IMPL(AtomicType, EnumType)
+
+
+bool AtomicType::equals(AtomicType const *obj) const
+{
+  // all of the AtomicTypes are unique-representation,
+  // so pointer equality suffices
+  return this == obj;
+}
+
+
+template <class T>
+string recurseCilString(T const *type, int depth)
+{
+  depth--;
+  xassert(depth >= 0);     // otherwise we started < 1
+  if (depth == 0) {
+    // just print the id
+    return stringc << "id " << type->getId();
+  }
+  else {
+    // print id in a comment but go on to print the
+    // type one level deeper
+    return stringc << makeIdComment(type->getId()) << " "
+                   << type->toCilString(depth);
+  }
+}
+
+
+string AtomicType::toString(int depth) const
+{
+  return stringc << recurseCilString(this, depth+1)
+                 << " /""* " << toCString() << " */";
+}
+
+
+// ------------------ SimpleType -----------------
+SimpleType const SimpleType::fixed[NUM_SIMPLE_TYPES] = {
+  SimpleType(ST_CHAR),
+  SimpleType(ST_UNSIGNED_CHAR),
+  SimpleType(ST_SIGNED_CHAR),
+  SimpleType(ST_BOOL),
+  SimpleType(ST_INT),
+  SimpleType(ST_UNSIGNED_INT),
+  SimpleType(ST_LONG_INT),
+  SimpleType(ST_UNSIGNED_LONG_INT),
+  SimpleType(ST_LONG_LONG),
+  SimpleType(ST_UNSIGNED_LONG_LONG),
+  SimpleType(ST_SHORT_INT),
+  SimpleType(ST_UNSIGNED_SHORT_INT),
+  SimpleType(ST_WCHAR_T),
+  SimpleType(ST_FLOAT),
+  SimpleType(ST_DOUBLE),
+  SimpleType(ST_LONG_DOUBLE),
+  SimpleType(ST_VOID),
+  SimpleType(ST_ELLIPSIS),
+  SimpleType(ST_CDTOR),
+  SimpleType(ST_ERROR),
+  SimpleType(ST_DEPENDENT),
+};
+
+string SimpleType::toCString() const
+{
+  return simpleTypeName(type);
+}
+
+
+string SimpleType::toCilString(int) const
+{
+  return toCString();
+}
+
+
+int SimpleType::reprSize() const
+{
+  return simpleTypeReprSize(type);
+}
+
+
+#if 0
+#define MKTAG(n,t) MAKE_ML_TAG(typ, n, t)
+MKTAG(0, TVoid)
+MKTAG(1, TInt)
+MKTAG(2, TBitfield)
+MKTAG(3, TFloat)
+MKTAG(4, Typedef)
+MKTAG(5, TPtr)
+MKTAG(6, TArray)
+MKTAG(7, TStruct)
+MKTAG(8, TUnion)
+MKTAG(9, TEnum)
+MKTAG(10, TFunc)
+#undef MKTAG
+
+#define MKTAG(n,t) MAKE_ML_TAG(ikind, n, t)
+MKTAG(0, IChar)
+MKTAG(1, ISChar)
+MKTAG(2, IUChar)
+MKTAG(3, IInt)
+MKTAG(4, IUInt)
+MKTAG(5, IShort)
+MKTAG(6, IUShort)
+MKTAG(7, ILong)
+MKTAG(8, IULong)
+MKTAG(9, ILongLong)
+MKTAG(10, IULongLong)
+#undef MKTAG
+
+#define MKTAG(n,t) MAKE_ML_TAG(fkind, n, t)
+MKTAG(0, FFloat)
+MKTAG(1, FDouble)
+MKTAG(2, FLongDouble)
+#undef MKTAG
+
+
+MLValue SimpleType::toMLValue(int, CVFlags cv) const
+{
+  // TVoid * attribute list
+  // TInt of ikind * attribute list
+
+  MLValue attrs = cvToMLAttrs(cv);
+
+  #define TUP(t,i) return mlTuple2(typ_##t, mlTuple0(ikind_##i), attrs)
+  switch (type) {
+    default: xfailure("bad tag");
+    case ST_CHAR:               TUP(TInt, IChar);
+    case ST_UNSIGNED_CHAR:      TUP(TInt, IUChar);
+    case ST_SIGNED_CHAR:        TUP(TInt, ISChar);
+    case ST_BOOL:               TUP(TInt, IInt);        // ...
+    case ST_INT:                TUP(TInt, IInt);
+    case ST_UNSIGNED_INT:       TUP(TInt, IUInt);
+    case ST_LONG_INT:           TUP(TInt, ILong);
+    case ST_UNSIGNED_LONG_INT:  TUP(TInt, IULong);
+    case ST_LONG_LONG:          TUP(TInt, ILongLong);
+    case ST_UNSIGNED_LONG_LONG: TUP(TInt, IULongLong);
+    case ST_SHORT_INT:          TUP(TInt, IShort);
+    case ST_UNSIGNED_SHORT_INT: TUP(TInt, IUShort);
+    case ST_WCHAR_T:            TUP(TInt, IShort);      // ...
+  #undef TUP
+  #define TUP(t,i) return mlTuple2(typ_##t, mlTuple0(fkind_##i), attrs)
+    case ST_FLOAT:              TUP(TFloat, FFloat);
+    case ST_DOUBLE:             TUP(TFloat, FDouble);
+    case ST_LONG_DOUBLE:        TUP(TFloat, FLongDouble);
+    case ST_VOID:               return mlTuple1(typ_TVoid, attrs);
+  }
+  #undef TUP
+}
+#endif // 0
+
+
+string SimpleType::uniqueName() const
+{
+  return simpleTypeName(type);
+}
+
+
+// ------------------ NamedAtomicType --------------------
+NamedAtomicType::NamedAtomicType(StringRef n)
+  : name(n)
+{}
+
+NamedAtomicType::~NamedAtomicType()
+{}
+
+
+string NamedAtomicType::uniqueName() const
+{
+  // 'a' for atomic
+  return stringc << "a" << (long)this /*id*/ << "_" << name;
+}
+
+
+#if 0
+MLValue NamedAtomicType::toMLValue(int depth, CVFlags cv) const
+{
+  // we break the circularity at the entry to named atomics;
+  // we'll emit typedefs for all of them beforehand
+  xassert(depth >= 1);
+  depth--;
+
+  if (depth == 0) {
+    // Typedef of string * int * typ ref * attribute list
+
+    return mlTuple4(typ_Typedef,
+                    mlString(uniqueName()),
+                    mlInt(id),
+                    mlRef(mlNil()),      // to be set in a post-process
+                    cvToMLAttrs(cv));
+  }
+  else {
+    // full info
+    return toMLContentsValue(depth, cv);
+  }
+}
+#endif // 0
+
+
+// ------------------ CompoundType -----------------
+CompoundType::CompoundType(Keyword k, StringRef n)
+  : NamedAtomicType(n),
+    fields(),
+    fieldIndex(),
+    fieldCounter(0),
+    forward(true),
+    keyword(k)
+{}
+
+CompoundType::~CompoundType()
+{}
+
+
+#if 0
+void CompoundType::makeComplete(Env *parentEnv, TypeEnv *te,
+                                VariableEnv *ve)
+{
+  xassert(!env);     // shouldn't have already made one yet
+  env = new Env(parentEnv, te, ve);
+}
+#endif // 0
+
+
+STATICDEF char const *CompoundType::keywordName(Keyword k)
+{
+  switch (k) {
+    default:          xfailure("bad keyword");
+    case K_STRUCT:    return "struct";
+    case K_CLASS:     return "class";
+    case K_UNION:     return "union";
+  }
+}
+
+
+string CompoundType::toCString() const
+{
+  return stringc << keywordName(keyword) << " "
+                 << (name? name : "(anonymous)");
+}
+
+
+// watch out for circular pointers (recursive types) here!
+// (already bitten once ..)
+string CompoundType::toStringWithFields() const
+{
+  stringBuilder sb;
+  sb << toCString();
+  if (isComplete()) {
+    sb << " { ";
+    FOREACH_OBJLIST(Field, fields, iter) {
+      Field const *f = iter.data();
+      sb << f->type->toCString(f->name) << "; ";
+    }
+    sb << "};";
+  }
+  else {
+    sb << ";";
+  }
+  return sb;
+}
+
+
+string CompoundType::toCilString(int depth) const
+{
+  return "(todo)";
+
+  #if 0
+  if (!isComplete()) {
+    // this is a problem for my current type-printing
+    // strategy, since I'm likely to print this even
+    // when later I will get complete type info ..
+    return "incomplete";
+  }
+
+  stringBuilder sb;
+  sb << keywordName(keyword) << " " << name << " {\n";
+
+  // iterate over fields
+  // TODO2: this is not in the declared order ..
+  StringSObjDict<Variable> &vars = env->getVariables();
+  StringSObjDict<Variable>::Iter iter(vars);
+  for (; !iter.isDone(); iter.next()) {
+    Variable const *var = iter.value();
+    sb << "  " << var->name << ": "
+       << var->type->toString(depth-1) << ";\n";
+  }
+
+  sb << "}";
+  return sb;
+  #endif // 0
+}
+
+
+#if 0
+MLValue CompoundType::toMLContentsValue(int depth, CVFlags cv) const
+{
+  // TStruct of string * fieldinfo list * int * attribute list
+  // TUnion of string * fieldinfo list * int * attribute list
+
+  // build up field list
+  MLValue fields = mlNil();
+  if (isComplete()) {
+    StringSObjDict<Variable>::Iter iter(env->getVariables());
+    for (; !iter.isDone(); iter.next()) {
+      fields = mlCons(mlRecord4(
+                        "fstruct", mlString(name),
+                        "fname", mlString(iter.value()->name),
+                        "typ", iter.value()->type->toMLValue(depth),
+                        "fattr", mlRef(mlNil())
+                      ), fields);
+    }
+  }
+
+  // attributes
+  MLValue att = cvToMLAttrs(cv);
+  if (!isComplete()) {
+    att = mlCons(mlString("INCOMPLETE"), att);
+  }
+
+  // assemble into a single tuple
+  return mlTuple4(keyword==K_STRUCT? typ_TStruct : typ_TUnion,
+                  mlString(name),
+                  fields,
+                  mlInt(id),
+                  att);
+}
+#endif // 0
+
+
+int CompoundType::reprSize() const
+{
+  int total = 0;
+  FOREACH_OBJLIST(Field, fields, iter) {
+    int membSize = iter.data()->type->reprSize();
+    if (keyword == K_UNION) {
+      // representation size is max over field sizes
+      total = max(total, membSize);
+    }
+    else {
+      // representation size is sum over field sizes
+      total += membSize;
+    }
+  }
+  return total;
+}
+
+
+int CompoundType::numFields() const
+{
+  return fields.count();
+}
+
+CompoundType::Field const *CompoundType::getNthField(int index) const
+{
+  return fields.nthC(index);
+}
+
+CompoundType::Field const *CompoundType::getNamedField(StringRef name) const
+{
+  Field *f;
+  if (fieldIndex.query(name, f)) {
+    return f;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+CompoundType::Field *CompoundType::
+  addField(StringRef name, Type const *type, Variable *decl)
+{
+  xassert(!fieldIndex.isMapped(name));
+
+  Field *f = new Field(name, fieldCounter++, type, this, decl);
+  fields.append(f);
+  fieldIndex.add(name, f);
+
+  return f;
+}
+
+
+// ---------------- EnumType ------------------
+EnumType::~EnumType()
+{}
+
+
+string EnumType::toCString() const
+{
+  return stringc << "enum " << (name? name : "(anonymous)");
+}
+
+
+string EnumType::toCilString(int depth) const
+{
+  // TODO2: get fields
+  return toCString();
+}
+
+
+#if 0
+MLValue EnumType::toMLContentsValue(int, CVFlags cv) const
+{
+  // TEnum of string * (string * int) list * int * attribute list
+
+  return mlTuple4(typ_TEnum,
+                  mlString(name),
+                  mlNil(),        // TODO2: get enum elements
+                  mlInt(id),
+                  cvToMLAttrs(cv));
+}
+#endif // 0
+
+
+int EnumType::reprSize() const
+{
+  // this is the usual choice
+  return simpleTypeReprSize(ST_INT);
+}
+
+
+EnumType::Value *EnumType::addValue(StringRef name, int value, Variable *decl)
+{
+  xassert(!valueIndex.isMapped(name));
+
+  Value *v = new Value(name, this, value, decl);
+  values.append(v);
+  valueIndex.add(name, v);
+
+  return v;
+}
+
+
+EnumType::Value const *EnumType::getValue(StringRef name) const
+{
+  Value *v;
+  if (valueIndex.query(name, v)) {
+    return v;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+// ---------------- EnumType::Value --------------
+EnumType::Value::Value(StringRef n, EnumType const *t, int v, Variable *d)
+  : name(n), type(t), value(v), decl(d)
+{}
+
+EnumType::Value::~Value()
+{}
+
+
+// --------------- Type ---------------
+ALLOC_STATS_DEFINE(Type)
+
+Type::Type()
+  //: id(NULL_TYPEID)
+{
+  ALLOC_STATS_IN_CTOR
+}
+
+Type::~Type()
+{
+  ALLOC_STATS_IN_DTOR
+}
+
+
+CAST_MEMBER_IMPL(Type, CVAtomicType)
+CAST_MEMBER_IMPL(Type, PointerType)
+CAST_MEMBER_IMPL(Type, FunctionType)
+CAST_MEMBER_IMPL(Type, ArrayType)
+
+
+bool Type::equals(Type const *obj) const
+{
+  if (getTag() != obj->getTag()) {
+    return false;
+  }
+
+  switch (getTag()) {
+    default: xfailure("bad tag");
+    #define C(tag,type) \
+      case tag: return ((type const*)this)->innerEquals((type const*)obj);
+    C(T_ATOMIC, CVAtomicType)
+    C(T_POINTER, PointerType)
+    C(T_FUNCTION, FunctionType)
+    C(T_ARRAY, ArrayType)
+    #undef C
+  }
+}
+
+
+string Type::idComment() const
+{
+  return makeIdComment(getId());
+}
+
+
+string Type::toCString() const
+{
+  return stringc << idComment() << leftString() << rightString();
+}
+
+string Type::toCString(char const *name) const
+{
+  return stringc << idComment()
+                 << leftString() << " " << (name? name : "/*anon*/")
+                 << rightString();
+
+  // removing the space causes wrong output:
+  //   int (foo)(intz)
+  //               ^^
+}
+
+string Type::rightString() const
+{
+  return "";
+}
+
+
+string Type::toString(int depth) const
+{
+  return toCString();
+  //return stringc << recurseCilString(this, depth+1)
+  //               << " /""* " << toCString() << " */";
+}
+
+
+bool Type::isSimpleType() const
+{
+  if (isCVAtomicType()) {
+    AtomicType const *at = asCVAtomicTypeC().atomic;
+    return at->isSimpleType();
+  }
+  else {
+    return false;
+  }
+}
+
+SimpleType const &Type::asSimpleTypeC() const
+{
+  return asCVAtomicTypeC().atomic->asSimpleTypeC();
+}
+
+bool Type::isSimple(SimpleTypeId id) const
+{
+  return isSimpleType() &&
+         asSimpleTypeC().type == id;
+}
+
+bool Type::isIntegerType() const
+{
+  return isSimpleType() &&
+         simpleTypeInfo(asSimpleTypeC().type).isInteger;
+}
+
+
+bool Type::isCompoundTypeOf(CompoundType::Keyword keyword) const
+{
+  CompoundType const *ct = ifCompoundType();
+  return ct && ct->keyword == keyword;
+}
+
+CompoundType const *Type::ifCompoundType() const
+{
+  if (isCVAtomicType()) {
+    AtomicType const *at = asCVAtomicTypeC().atomic;
+    if (at->isCompoundType()) {
+      return &( at->asCompoundTypeC() );
+    }
+  }
+  return NULL;
+}
+
+bool Type::isOwnerPtr() const
+{
+  return isPointer() && ((asPointerTypeC().cv & CV_OWNER) != 0);
+}
+
+bool Type::isPointer() const
+{
+  return isPointerType() && asPointerTypeC().op == PO_POINTER;
+}
+
+bool Type::isReference() const
+{
+  return isPointerType() && asPointerTypeC().op == PO_REFERENCE;
+}
+
+Type const *Type::asRval() const
+{
+  if (isReference()) {
+    // note that due to the restriction about stacking reference
+    // types, unrolling more than once is never necessary
+    return asPointerTypeC().atType;
+  }
+  else {
+    return this;
+  }
+}
+
+
+// ----------------- CVAtomicType ----------------
+CVAtomicType const CVAtomicType::fixed[NUM_SIMPLE_TYPES] = {
+  CVAtomicType(&SimpleType::fixed[ST_CHAR],               CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_UNSIGNED_CHAR],      CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_SIGNED_CHAR],        CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_BOOL],               CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_INT],                CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_UNSIGNED_INT],       CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_LONG_INT],           CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_UNSIGNED_LONG_INT],  CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_LONG_LONG],          CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_UNSIGNED_LONG_LONG], CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_SHORT_INT],          CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_UNSIGNED_SHORT_INT], CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_WCHAR_T],            CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_FLOAT],              CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_DOUBLE],             CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_LONG_DOUBLE],        CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_VOID],               CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_ELLIPSIS],           CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_CDTOR],              CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_ERROR],              CV_NONE),
+  CVAtomicType(&SimpleType::fixed[ST_DEPENDENT],          CV_NONE),
+};
+
+
+bool CVAtomicType::innerEquals(CVAtomicType const *obj) const
+{
+  return atomic->equals(obj->atomic) &&
+         cv == obj->cv;
+}
+
+
+string cvToString(CVFlags cv)
+{
+  if (cv != CV_NONE) {
+    return stringc << " " << toString(cv);
+  }
+  else {
+    return string("");
+  }
+}
+
+
+string CVAtomicType::atomicIdComment() const
+{
+  return makeIdComment(atomic->getId());
+}
+
+
+string CVAtomicType::leftString() const
+{
+  return stringc << atomicIdComment()
+                 << atomic->toCString() << cvToString(cv);
+}
+
+
+string CVAtomicType::toCilString(int depth) const
+{
+  return stringc << cvToString(cv) << " atomic "
+                 << recurseCilString(atomic, depth);
+}
+
+
+#if 0
+MLValue CVAtomicType::toMLValue(int depth) const
+{
+  return atomic->toMLValue(depth, cv);
+}
+#endif // 0
+
+
+int CVAtomicType::reprSize() const
+{
+  return atomic->reprSize();
+}
+
+
+// ------------------- PointerType ---------------
+PointerType::PointerType(PtrOper o, CVFlags c, Type const *a)
+  : op(o), cv(c), atType(a)
+{
+  // since references are always immutable, it makes no sense to
+  // apply const or volatile to them
+  xassert(op==PO_REFERENCE? cv==CV_NONE : true);
+
+  // it also makes no sense to stack reference operators underneath
+  // other indirections (i.e. no ptr-to-ref, nor ref-to-ref)
+  xassert(!a->isReference());
+}
+
+bool PointerType::innerEquals(PointerType const *obj) const
+{
+  return op == obj->op &&
+         cv == obj->cv &&
+         atType->equals(obj->atType);
+}
+
+
+string PointerType::leftString() const
+{
+  return stringc << atType->leftString()
+                 << (op==PO_POINTER? "*" : "&")
+                 << cvToString(cv);
+}
+
+string PointerType::rightString() const
+{
+  return atType->rightString();
+}
+
+
+string PointerType::toCilString(int depth) const
+{
+  return stringc << cvToString(cv)
+                 << (op==PO_POINTER? "ptrto " : "refto ")
+                 << recurseCilString(atType, depth);
+}
+
+
+#if 0
+MLValue PointerType::toMLValue(int depth) const
+{
+  // TPtr of typ * attribute list
+
+  return mlTuple2(typ_TPtr,
+                  atType->toMLValue(depth),
+                  cvToMLAttrs(cv));
+}
+#endif // 0
+
+
+int PointerType::reprSize() const
+{
+  // a typical value .. (architecture-dependent)
+  return 4;
+}
+
+
+// -------------------- FunctionType::Param -----------------
+FunctionType::Param::~Param()
+{}
+
+
+string FunctionType::Param::toString() const
+{
+  return type->toCString(name);
+}
+
+
+// -------------------- FunctionType -----------------
+FunctionType::FunctionType(Type const *r/*, CVFlags c*/)
+  : retType(r),
+    //cv(c),
+    params(),
+    acceptsVarargs(false),
+    precondition(NULL),
+    postcondition(NULL),
+    result(NULL)
+{}
+
+
+FunctionType::~FunctionType()
+{}
+
+
+bool FunctionType::innerEquals(FunctionType const *obj) const
+{
+  if (retType->equals(obj->retType) &&
+      //cv == obj->cv &&
+      acceptsVarargs == obj->acceptsVarargs) {
+    // so far so good, try the parameters
+    ObjListIter<Param> iter1(params);
+    ObjListIter<Param> iter2(obj->params);
+    for (; !iter1.isDone() && !iter2.isDone();
+         iter1.adv(), iter2.adv()) {
+      // parameter names do not have to match, but
+      // the types do
+      if (iter1.data()->type->equals(iter2.data()->type)) {
+        // ok
+      }
+      else {
+        return false;
+      }
+    }
+
+    return iter1.isDone() == iter2.isDone();
+  }
+  else {
+    return false;
+  }
+}
+
+
+void FunctionType::addParam(Param *param)
+{
+  params.append(param);
+}
+
+
+string FunctionType::leftString() const
+{
+  // return type and start of enclosing type's description
+  return stringc << retType->leftString() << " (";
+}
+
+string FunctionType::rightString() const
+{
+  // finish enclosing type
+  stringBuilder sb;
+  sb << ")";
+
+  // arguments
+  sb << "(";
+  int ct=0;
+  FOREACH_OBJLIST(Param, params, iter) {
+    if (ct++ > 0) {
+      sb << ", ";
+    }
+    sb << iter.data()->toString();
+  }
+
+  if (acceptsVarargs) {
+    if (ct++ > 0) {
+      sb << ", ";
+    }
+    sb << "...";
+  }
+
+  sb << ")";
+
+  // qualifiers
+  //sb << cvToString(cv);
+
+  // finish up the return type
+  sb << retType->rightString();
+
+  return sb;
+}
+
+
+string FunctionType::toCilString(int depth) const
+{
+  stringBuilder sb;
+  sb << "func " /*<< cvToString(cv) << " "*/;
+  if (acceptsVarargs) {
+    sb << "varargs ";
+  }
+  sb << "(";
+
+  int ct=0;
+  FOREACH_OBJLIST(Param, params, iter) {
+    if (++ct > 1) {
+      sb << ", ";
+    }
+    sb << iter.data()->name << ": "
+       << recurseCilString(iter.data()->type, depth);
+  }
+
+  sb << ") -> " << recurseCilString(retType, depth);
+
+  return sb;
+}
+
+
+#if 0
+MLValue FunctionType::toMLValue(int depth) const
+{
+  // TFunc of typ * typ list * bool * attribute list
+
+  // build up argument type list
+  MLValue args = mlNil();
+  FOREACH_OBJLIST(Parameter, params, iter) {
+    args = mlCons(iter.data()->type->toMLValue(depth),
+                  args);
+  }
+
+  return mlTuple4(typ_TFunc,
+                  retType->toMLValue(depth),
+                  args,
+                  mlBool(acceptsVarargs),
+                  cvToMLAttrs(cv));
+}
+#endif // 0
+
+
+int FunctionType::reprSize() const
+{
+  // thinking here about how this works when we're summing
+  // the fields of a class with member functions ..
+  return 0;
+}
+
+
+// -------------------- ArrayType ------------------
+bool ArrayType::innerEquals(ArrayType const *obj) const
+{
+  if (!( eltType->equals(obj->eltType) &&
+         hasSize == obj->hasSize )) {
+    return false;
+  }
+
+  if (hasSize) {
+    return size == obj->size;
+  }
+  else {
+    return true;
+  }
+}
+
+
+string ArrayType::leftString() const
+{
+  return eltType->leftString();
+}
+
+string ArrayType::rightString() const
+{
+  stringBuilder sb;
+
+  if (hasSize) {
+    sb << "[" << size << "]";
+  }
+  else {
+    sb << "[]";
+  }
+
+  sb << eltType->rightString();
+
+  return sb;
+}
+
+
+string ArrayType::toCilString(int depth) const
+{
+  stringBuilder sb;
+  sb << "array [";
+  if (hasSize) {
+    sb << size;
+  }
+  sb << "] of " << recurseCilString(eltType, depth);
+  return sb;
+}
+
+
+#if 0
+MLValue ArrayType::toMLValue(int depth) const
+{
+  // TArray of typ * exp option * attribute list
+
+  // size
+  MLValue mlSize;
+  if (hasSize) {
+    // since the array type is currently an arbitrary
+    // expression, but I just store an int (because I
+    // evaluate sizeof at parse time), construct an
+    // expression now
+    Owner<CilExpr> e; e = newIntLit(NULL /*extra*/, size);
+    mlSize = mlSome(e->toMLValue());
+  }
+  else {
+    mlSize = mlNone();
+  }
+
+  return mlTuple3(typ_TArray,
+                  eltType->toMLValue(depth),
+                  mlSize,
+                  mlNil());    // no attrs for arrays
+}
+#endif // 0
+
+
+int ArrayType::reprSize() const
+{
+  if (hasSize) {
+    return eltType->reprSize() * size;
+  }
+  else {
+    // or should I throw an exception ..?
+    cout << "warning: reprSize of a sizeless array\n";
+    return 0;
+  }
+}
+
+
+// ------------------ test -----------------
+void cc_type_checker()
+{
+  #ifndef NDEBUG
+  // verify the fixed[] arrays
+  // it turns out this is probably redundant, since the compiler will
+  // complain if I leave out an entry, now that the classes do not have
+  // default constructors! yes!
+  for (int i=0; i<NUM_SIMPLE_TYPES; i++) {
+    assert(SimpleType::fixed[i].type == i);
+
+    SimpleType const *st = (SimpleType const*)(CVAtomicType::fixed[i].atomic);
+    assert(st && st->type == i);
+  }
+  #endif // NDEBUG
+}

Added: vendor/elsa/current/elkhound/c/c_type.h
===================================================================
--- vendor/elsa/current/elkhound/c/c_type.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/c_type.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,426 @@
+// c_type.h            see license.txt for copyright and terms of use
+// compile-type representation of C types
+// see types.txt
+
+#ifndef C_TYPE_H
+#define C_TYPE_H
+
+#include "str.h"          // string
+#include "objlist.h"      // ObjList
+#include "cc_flags.h"     // CVFlags, DeclFlags, SimpleTypeId
+#include "strtable.h"     // StringRef
+#include "strsobjdict.h"  // StrSObjDict
+
+// below, the type language refers to the AST language in exactly
+// one place: function pre/post conditions; the type language treats
+// these opaquely; it is important to prevent the type language from
+// depending on the AST language (NOTE: c.ast #includes this file,
+// so I can't #include c.ast.gen.h here)
+class FA_precondition;    // c.ast
+class FA_postcondition;   // c.ast
+
+class Variable;           // c_variable.h
+
+// fwd in this file
+class SimpleType;
+class CompoundType;
+class EnumType;
+class CVAtomicType;
+class PointerType;
+class FunctionType;
+class ArrayType;
+class Type;
+
+// static data consistency checker
+void cc_type_checker();
+
+// --------------------- atomic types --------------------------
+// interface to types that are atomic in the sense that no
+// modifiers can be stripped away; see types.txt
+class AtomicType {
+public:     // types
+  enum Tag { T_SIMPLE, T_COMPOUND, T_ENUM, NUM_TAGS };
+
+public:     // funcs
+  AtomicType();
+  virtual ~AtomicType();
+
+  // stand-in if I'm not really using ids..
+  long getId() const { return (long)this; }
+
+  virtual Tag getTag() const = 0;
+  bool isSimpleType() const { return getTag() == T_SIMPLE; }
+  bool isCompoundType() const { return getTag() == T_COMPOUND; }
+  bool isEnumType() const { return getTag() == T_ENUM; }
+
+  CAST_MEMBER_FN(SimpleType)
+  CAST_MEMBER_FN(CompoundType)
+  CAST_MEMBER_FN(EnumType)
+
+  // this is type equality, *not* coercibility -- e.g. if
+  // we say "extern type1 x" and then "extern type2 x" we
+  // will allow it only if type1==type2
+  bool equals(AtomicType const *obj) const;
+
+  // print in C notation
+  virtual string toCString() const = 0;
+
+  // print in a Cil notation, using integer ids
+  // for all references to other types
+  virtual string toCilString(int depth=1) const = 0;
+
+  // print in Cil with C notation in comments
+  string toString(int depth=1) const;
+
+  // name of this type for references in Cil output
+  virtual string uniqueName() const = 0;
+
+  // size this type's representation occupies in memory
+  virtual int reprSize() const = 0;
+
+  ALLOC_STATS_DECLARE
+};
+
+
+// represents one of C's built-in types;
+// there are exactly as many of these objects as there are built-in types
+class SimpleType : public AtomicType {
+public:     // data
+  SimpleTypeId type;
+
+  // global read-only array for each built-in type
+  static SimpleType const fixed[NUM_SIMPLE_TYPES];
+
+public:     // funcs
+  SimpleType(SimpleTypeId t) : type(t) {}
+
+  virtual Tag getTag() const { return T_SIMPLE; }
+  virtual string toCString() const;
+  virtual string toCilString(int depth) const;
+  virtual string uniqueName() const;
+  virtual int reprSize() const;
+};
+
+
+// elements common to structs and enums
+class NamedAtomicType : public AtomicType {
+public:     // data
+  StringRef name;          // (nullable) user-assigned name of this struct or enum
+
+public:
+  NamedAtomicType(StringRef name);
+  ~NamedAtomicType();
+
+  // globally unique name derived from 'name' and 'id'
+  virtual string uniqueName() const;
+};
+
+
+// C++ class member access modes
+enum AccessMode {
+  AM_PUBLIC,
+  AM_PROTECTED,
+  AM_PRIVATE,
+  NUM_ACCESS_MODES
+};
+
+// represent a user-defined compound type
+class CompoundType : public NamedAtomicType {
+public:      // types
+  // NOTE: keep these consistent with TypeIntr (in file c.ast)
+  enum Keyword { K_STRUCT, K_CLASS, K_UNION, NUM_KEYWORDS };
+
+  // one of these for each field in the struct
+  class Field {
+  public:
+    StringRef name;                  // programmer-given name
+    int const index;                 // first field is 0, next is 1, etc.
+    Type const *type;                // declared field type
+    CompoundType const *compound;    // (serf) compound in which this appears
+
+    // I include a pointer to the introduction; since I want
+    // to keep the type language independent of the AST language, I
+    // will continue to store redundant info, regarding 'decl' as
+    // something which might go away at some point
+    Variable *decl;                  // (nullable serf)
+
+  public:
+    Field(StringRef n, int i, Type const *t, CompoundType const *c, Variable *d)
+      : name(n), index(i), type(t), compound(c), decl(d) {}
+  };
+
+private:     // data
+  ObjList<Field> fields;               // fields in this type
+  StringSObjDict<Field> fieldIndex;    // dictionary for name lookup
+  int fieldCounter;                    // # of fields
+
+public:      // data
+  bool forward;               // true when it's only fwd-declared
+  Keyword const keyword;      // keyword used to introduce the type
+
+public:      // funcs
+  // create an incomplete (forward-declared) compound
+  CompoundType(Keyword keyword, StringRef name);
+  ~CompoundType();
+
+  bool isComplete() const { return !forward; }
+  bool nunFields() const { return fieldCounter; }
+
+  static char const *keywordName(Keyword k);
+
+  virtual Tag getTag() const { return T_COMPOUND; }
+  virtual string toCString() const;
+  virtual string toCilString(int depth) const;
+  virtual int reprSize() const;
+
+  string toStringWithFields() const;
+  string keywordAndName() const { return toCString(); }
+
+  int numFields() const;
+  Field const *getNthField(int index) const;         // must exist
+  Field const *getNamedField(StringRef name) const;  // returns NULL if doesn't exist
+
+  Field *addField(StringRef name, Type const *type,
+                  /*nullable*/ Variable *d);
+};
+
+
+// represent an enumerated type
+class EnumType : public NamedAtomicType {
+public:     // types
+  // represent a single value in an enum
+  class Value {
+  public:
+    StringRef name;           // the thing whose name is being defined
+    EnumType const *type;     // enum in which it was declared
+    int value;                // value it's assigned to
+
+    // similar to fields, I keep a record of where this came from
+    Variable *decl;           // (nullable serf)
+
+  public:
+    Value(StringRef n, EnumType const *t, int v, Variable *d);
+    ~Value();
+  };
+
+public:     // data
+  ObjList<Value> values;              // values in this enumeration
+  StringSObjDict<Value> valueIndex;   // name-based lookup
+  int nextValue;                      // next value to assign to elements automatically
+
+public:     // funcs
+  EnumType(StringRef n) : NamedAtomicType(n), nextValue(0) {}
+  ~EnumType();
+
+  virtual Tag getTag() const { return T_ENUM; }
+  virtual string toCString() const;
+  virtual string toCilString(int depth) const;
+  virtual int reprSize() const;
+
+  Value *addValue(StringRef name, int value, /*nullable*/ Variable *d);
+  Value const *getValue(StringRef name) const;
+};
+
+
+// ------------------- constructed types -------------------------
+// generic constructed type
+class Type {
+public:     // types
+  enum Tag { T_ATOMIC, T_POINTER, T_FUNCTION, T_ARRAY };
+
+private:    // funcs
+  string idComment() const;
+
+public:     // funcs
+  Type();
+  virtual ~Type();
+
+  long getId() const { return (long)this; }
+
+  virtual Tag getTag() const = 0;
+  bool isCVAtomicType() const { return getTag() == T_ATOMIC; }
+  bool isPointerType() const { return getTag() == T_POINTER; }
+  bool isFunctionType() const { return getTag() == T_FUNCTION; }
+  bool isArrayType() const { return getTag() == T_ARRAY; }
+
+  CAST_MEMBER_FN(CVAtomicType)
+  CAST_MEMBER_FN(PointerType)
+  CAST_MEMBER_FN(FunctionType)
+  CAST_MEMBER_FN(ArrayType)
+
+  // like above, this is (structural) equality, not coercibility;
+  // internally, this calls the innerEquals() method on the two
+  // objects, once their tags have been established to be equal
+  bool equals(Type const *obj) const;
+
+  // print the type, with an optional name like it was a declaration
+  // for a variable of that type
+  string toCString() const;
+  string toCString(char const *name) const;
+
+  // the left/right business is to allow us to print function
+  // and array types in C's syntax
+  virtual string leftString() const = 0;
+  virtual string rightString() const;    // default: returns ""
+
+  // same alternate syntaxes as AtomicType
+  virtual string toCilString(int depth=1) const = 0;
+  string toString(int depth=1) const;
+
+  // size of representation
+  virtual int reprSize() const = 0;
+
+  // some common queries
+  bool isSimpleType() const;
+  SimpleType const &asSimpleTypeC() const;
+  bool isSimple(SimpleTypeId id) const;
+  bool isIntegerType() const;            // any of the simple integer types
+  bool isUnionType() const { return isCompoundTypeOf(CompoundType::K_UNION); }
+  bool isStructType() const { return isCompoundTypeOf(CompoundType::K_STRUCT); }
+  bool isCompoundTypeOf(CompoundType::Keyword keyword) const;
+  bool isVoid() const { return isSimple(ST_VOID); }
+  bool isError() const { return isSimple(ST_ERROR); }
+  CompoundType const *ifCompoundType() const;     // NULL or corresp. compound
+  bool isOwnerPtr() const;
+
+  // pointer/reference stuff
+  bool isPointer() const;                // as opposed to reference or non-pointer
+  bool isReference() const;
+  bool isLval() const { return isReference(); }    // C terminology
+  Type const *asRval() const;            // if I am a reference, return referrent type
+
+  ALLOC_STATS_DECLARE
+};
+
+
+// essentially just a wrapper around an atomic type, but
+// also with optional const/volatile flags
+class CVAtomicType : public Type {
+public:     // data
+  AtomicType const *atomic;    // (serf) underlying type
+  CVFlags cv;                  // const/volatile
+
+  // global read-only array of non-const, non-volatile built-ins
+  static CVAtomicType const fixed[NUM_SIMPLE_TYPES];
+
+private:    // funcs
+  string atomicIdComment() const;
+
+public:     // funcs
+  CVAtomicType(AtomicType const *a, CVFlags c)
+    : atomic(a), cv(c) {}
+  CVAtomicType(CVAtomicType const &obj)
+    : DMEMB(atomic), DMEMB(cv) {}
+
+  bool innerEquals(CVAtomicType const *obj) const;
+
+  virtual Tag getTag() const { return T_ATOMIC; }
+  virtual string leftString() const;
+  virtual string toCilString(int depth) const;
+  virtual int reprSize() const;
+};
+
+inline Type const *fixed(SimpleTypeId id)
+  { return &CVAtomicType::fixed[id]; }
+
+
+// "*" vs "&"
+enum PtrOper {
+  PO_POINTER, PO_REFERENCE
+};
+
+// type of a pointer or reference
+class PointerType : public Type {
+public:
+  PtrOper op;                  // "*" or "&"
+  CVFlags cv;                  // const/volatile, if "*"; refers to pointer *itself*
+  Type const *atType;          // (serf) type of thing pointed-at
+
+public:
+  PointerType(PtrOper o, CVFlags c, Type const *a);
+  PointerType(PointerType const &obj)
+    : DMEMB(op), DMEMB(cv), DMEMB(atType) {}
+
+  bool innerEquals(PointerType const *obj) const;
+
+  virtual Tag getTag() const { return T_POINTER; }
+  virtual string leftString() const;
+  virtual string rightString() const;
+  virtual string toCilString(int depth) const;
+  virtual int reprSize() const;
+};
+
+
+// type of a function
+class FunctionType : public Type {
+public:     // types
+  // formal parameter to a function or function type
+  class Param {
+  public:
+    StringRef name;              // can be NULL to mean unnamed
+    Type const *type;            // (serf) type of the parameter
+
+    // I can't interpret the precondition or postcondition
+    // unless I know the Variable that gave rise to each parameter
+    Variable *decl;              // (serf)
+
+  public:
+    Param(StringRef n, Type const *t, Variable *d)
+      : name(n), type(t), decl(d) {}
+    ~Param();
+
+    string toString() const;
+  };
+
+public:     // data
+  Type const *retType;         // (serf) type of return value
+  //CVFlags cv;                  // const/volatile for class member fns
+  ObjList<Param> params;       // list of function parameters
+  bool acceptsVarargs;         // true if add'l args are allowed
+
+  // thmprv extensions
+  FA_precondition *precondition;     // (serf) precondition predicate
+  FA_postcondition *postcondition;   // (serf) postcondition predicate
+  Variable *result;                  // required to interpret postcondition
+
+public:     // funcs
+  FunctionType(Type const *retType/*, CVFlags cv*/);
+  virtual ~FunctionType();
+
+  bool innerEquals(FunctionType const *obj) const;
+
+  // append a parameter to the parameters list
+  void addParam(Param *param);
+
+  virtual Tag getTag() const { return T_FUNCTION; }
+  virtual string leftString() const;
+  virtual string rightString() const;
+  virtual string toCilString(int depth) const;
+  virtual int reprSize() const;
+};
+
+
+// type of an array
+class ArrayType : public Type {
+public:
+  Type const *eltType;         // (serf) type of the elements
+  bool hasSize;                // true if a size is specified
+  int size;                    // specified size, if 'hasSize'
+
+public:
+  ArrayType(Type const *e, int s)
+    : eltType(e), hasSize(true), size(s) {}
+  ArrayType(Type const *e)
+    : eltType(e), hasSize(false), size(-1) {}
+
+  bool innerEquals(ArrayType const *obj) const;
+
+  virtual Tag getTag() const { return T_ARRAY; }
+  virtual string leftString() const;
+  virtual string rightString() const;
+  virtual string toCilString(int depth) const;
+  virtual int reprSize() const;
+};
+
+
+#endif // C_TYPE_H

Added: vendor/elsa/current/elkhound/c/c_variable.cc
===================================================================
--- vendor/elsa/current/elkhound/c/c_variable.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/c_variable.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// c_variable.cc            see license.txt for copyright and terms of use
+// code for c_variable.h
+
+#include "c_variable.h"    // this module
+#include "c_type.h"        // Type
+
+
+// ---------------------- Variable --------------------
+Variable::Variable(SourceLoc L, StringRef n, Type const *t, DeclFlags f)
+  : loc(L),
+    name(n),
+    type(t),
+    flags(f)
+{
+  xassert(type);        // (just a stab in the dark debugging effort)
+}
+
+Variable::~Variable()
+{}
+
+
+string Variable::toString() const
+{
+  // The purpose of this method is to print the name and type
+  // of this Variable object, in a debugging context.  It is
+  // not necessarily intended to print them in a way consistent
+  // with the C syntax that might give rise to the Variable.
+  // If more specialized printing is desired, do that specialized
+  // printing from outside (by directly accessing 'name', 'type',
+  // 'flags', etc.).
+  return type->toCString(name? name : "");
+}

Added: vendor/elsa/current/elkhound/c/c_variable.h
===================================================================
--- vendor/elsa/current/elkhound/c/c_variable.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/c_variable.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+// c_variable.h                       see license.txt for copyright and terms of use
+// information about a name, for C only (not C++)
+//
+// Every binding introduction (e.g. declaration) of a name will own
+// one of these to describe the introduced name; every reference to
+// that name will be annotated with a pointer to the Variable hanging
+// off the introduction.
+//
+// The name 'variable' is a slight misnomer; it's used for naming:
+//   - local and global variables
+//   - logic variables (in the thmprv context)
+//   - function names
+//   - function parameters
+//   - structure fields
+//   - enumeration values
+//   - typedef'd names (though these are translated-away early on)
+//
+// I've decided that, rather than AST nodes trying to own Variables,
+// Variables will live in a separate pool (like types) so the AST
+// nodes can properly share them at will.
+
+#ifndef C_VARIABLE_H
+#define C_VARIABLE_H
+
+#include "srcloc.h"       // SourceLoc
+#include "strtable.h"     // StringRef
+#include "cc_flags.h"     // DeclFlags
+#include "sobjlist.h"     // SObjList
+
+class Type;               // c_type.h
+
+class Variable {
+public:    // data
+  // for now, there's only one location, and it's the definition
+  // location if that exists, else the declaration location; there
+  // are significant advantages to storing *two* locations (first
+  // declaration, and definition), but I haven't done that yet
+  SourceLoc loc;          // location of the name in the source text
+
+  StringRef name;         // name introduced (possibly NULL for abstract declarators)
+  Type const *type;       // type of the variable
+  DeclFlags flags;        // various flags
+
+public:    // funcs
+  Variable(SourceLoc L, StringRef n,
+           Type const *t, DeclFlags f);
+  ~Variable();
+
+  bool hasFlag(DeclFlags f) const { return (flags & f) != 0; }
+  void setFlag(DeclFlags f) { flags = (DeclFlags)(flags | f); }
+  void addFlags(DeclFlags f) { setFlag(f); }
+  void clearFlag(DeclFlags f) { flags = (DeclFlags)(flags & ~f); }
+
+  // some convenient interpretations of 'flags'
+  bool hasAddrTaken() const { return flags & DF_ADDRTAKEN; }
+  bool isGlobal() const { return flags & DF_GLOBAL; }
+
+  // some ad-hoc thing
+  string toString() const;
+};
+
+inline string toString(Variable const *v) { return v->toString(); }
+
+
+#endif // C_VARIABLE_H

Added: vendor/elsa/current/elkhound/c/cc_flags.cc
===================================================================
--- vendor/elsa/current/elkhound/c/cc_flags.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/cc_flags.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,298 @@
+// cc_flags.cc            see license.txt for copyright and terms of use
+// code for cc_flags.h
+
+#include "cc_flags.h"     // this module
+#include "macros.h"       // STATIC_ASSERT
+#include "xassert.h"      // xassert
+#include "trace.h"        // tracingSys
+
+
+// -------------------- TypeIntr -------------------------
+char const * const typeIntrNames[NUM_TYPEINTRS] = {
+  "struct",
+  "class",
+  "union",
+  "enum"
+};
+
+#define MAKE_TOSTRING(T, limit, array)        \
+  string toString(T index)                    \
+  {                                           \
+    xassert((unsigned)index < limit);         \
+    return string(array[index]);              \
+  }
+
+MAKE_TOSTRING(TypeIntr, NUM_TYPEINTRS, typeIntrNames)
+
+
+// ---------------- CVFlags -------------
+#ifdef MLVALUE
+MAKE_ML_TAG(attribute, 0, AId)
+MAKE_ML_TAG(attribute, 1, ACons)
+
+MLValue cvToMLAttrs(CVFlags cv)
+{
+  // AId of string
+
+  MLValue list = mlNil();
+  if (cv & CV_CONST) {
+    list = mlCons(mlTuple1(attribute_AId, mlString("const")), list);
+  }
+  if (cv & CV_VOLATILE) {
+    list = mlCons(mlTuple1(attribute_AId, mlString("volatile")), list);
+  }
+  if (cv & CV_OWNER) {
+    list = mlCons(mlTuple1(attribute_AId, mlString("owner")), list);
+  }
+  return list;
+}
+#endif // MLVALUE
+
+
+char const * const cvFlagNames[NUM_CVFLAGS] = {
+  "const",
+  "volatile",
+  "owner"
+};
+
+
+string bitmapString(int bitmap, char const * const *names, int numflags)
+{
+  stringBuilder sb;
+  int count=0;
+  for (int i=0; i<numflags; i++) {
+    if (bitmap & (1 << i)) {
+      if (count++) {
+        sb << " ";
+      }
+      sb << names[i];
+    }
+  }
+
+  return sb;
+}
+
+string toString(CVFlags cv)
+{
+  return bitmapString(cv >> CV_SHIFT_AMOUNT, cvFlagNames, NUM_CVFLAGS);
+}
+
+
+// ------------------- DeclFlags --------------
+char const * const declFlagNames[NUM_DECLFLAGS] = {
+  "auto",           // 0
+  "register",
+  "static",
+  "extern",
+  "mutable",        // 4
+  "inline",
+  "virtual",
+  "explicit",
+  "friend",
+  "typedef",        // 9
+
+  "<enumerator>",
+  "<global>",
+  "<initialized>",
+  "<builtin>",
+  "<logic>",        // 14
+  "<addrtaken>",
+  "<parameter>",
+  "<universal>",
+  "<existential>",
+  "<member>",       // 19
+  "<definition>",
+  "<inline_defn>",
+  "<implicit>",
+  "<forward>",
+
+  "<predicate>",    // 24
+};
+
+
+string toString(DeclFlags df)
+{ 
+  // make sure I haven't added a flag without adding a string for it
+  xassert(declFlagNames[NUM_DECLFLAGS-1] != NULL);
+
+  return bitmapString(df, declFlagNames, NUM_DECLFLAGS);
+}
+
+
+// ---------------------- SimpleTypeId --------------------------
+bool isValid(SimpleTypeId id)
+{
+  return 0 <= id && id <= NUM_SIMPLE_TYPES;
+}
+
+
+static SimpleTypeInfo const simpleTypeInfoArray[] = {
+  //name                   size  int?
+  { "char",                1,    true    },
+  { "unsigned char",       1,    true    },
+  { "signed char",         1,    true    },
+  { "bool",                4,    true    },
+  { "int",                 4,    true    },
+  { "unsigned int",        4,    true    },
+  { "long int",            4,    true    },
+  { "unsigned long int",   4,    true    },
+  { "long long",           8,    true    },
+  { "unsigned long long",  8,    true    },
+  { "short int",           2,    true    },
+  { "unsigned short int",  2,    true    },
+  { "wchar_t",             2,    true    },
+  { "float",               4,    false   },
+  { "double",              8,    false   },
+  { "long double",         10,   false   },
+  { "void",                1,    false   },    // gnu: sizeof(void) is 1
+  { "...",                 0,    false   },
+  { "/*cdtor*/",           0,    false   },    // dsw: don't want to print <cdtor>
+  { "<error>",             0,    false   },
+  { "<dependent>",         0,    false   },
+};
+
+SimpleTypeInfo const &simpleTypeInfo(SimpleTypeId id)
+{
+  STATIC_ASSERT(TABLESIZE(simpleTypeInfoArray) == NUM_SIMPLE_TYPES);
+  xassert(isValid(id));
+  return simpleTypeInfoArray[id];
+}
+
+
+// ------------------------ UnaryOp -----------------------------
+char const * const unaryOpNames[NUM_UNARYOPS] = {
+  "+",
+  "-",
+  "!",
+  "~"
+};
+
+MAKE_TOSTRING(UnaryOp, NUM_UNARYOPS, unaryOpNames)
+
+
+char const * const effectOpNames[NUM_EFFECTOPS] = {
+  "++/*postfix*/",
+  "--/*postfix*/",
+  "++/*prefix*/",
+  "--/*prefix*/",
+};
+
+MAKE_TOSTRING(EffectOp, NUM_EFFECTOPS, effectOpNames)
+
+bool isPostfix(EffectOp op)
+{
+  return op <= EFF_POSTDEC;
+}
+
+
+// ---------------------- BinaryOp -------------------------
+char const * const binaryOpNames[NUM_BINARYOPS] = {
+  "==",
+  "!=",
+  "<",
+  ">",
+  "<=",
+  ">=",
+
+  "*",
+  "/",
+  "%",
+  "+",
+  "-",
+  "<<",
+  ">>",
+  "&",
+  "^",
+  "|",
+  "&&",
+  "||",
+
+  "=",
+
+  ".*",
+  "->*",
+
+  "==>"
+};
+
+MAKE_TOSTRING(BinaryOp, NUM_BINARYOPS, binaryOpNames)
+
+bool isPredicateCombinator(BinaryOp op)
+{
+  return op==BIN_AND || op==BIN_OR || op==BIN_IMPLIES;
+}
+
+bool isRelational(BinaryOp op)
+{
+  return BIN_EQUAL <= op && op <= BIN_GREATEREQ;
+}
+
+
+// ------------------- AccessKeyword -------------------
+char const * const accessKeywordNames[NUM_ACCESS_KEYWORDS] = {
+  "public",
+  "protected",
+  "private",
+  "unspecified"
+};
+
+MAKE_TOSTRING(AccessKeyword, NUM_ACCESS_KEYWORDS, accessKeywordNames)
+
+
+// -------------------- CastKeyword --------------------
+char const * const castKeywordNames[NUM_CAST_KEYWORDS] = {
+  "dynamic_cast",
+  "static_cast",
+  "reinterpret_cast",
+  "const_cast"
+};
+
+MAKE_TOSTRING(CastKeyword, NUM_CAST_KEYWORDS, castKeywordNames)
+
+
+// -------------------- OverloadableOp --------------------
+char const * const overloadableOpNames[NUM_OVERLOADABLE_OPS] = {
+  ",",
+  "->",
+  "()",
+  "[]"
+};
+
+MAKE_TOSTRING(OverloadableOp, NUM_OVERLOADABLE_OPS, overloadableOpNames)
+
+
+// ------------------------ UberModifiers ---------------------
+char const * const uberModifierNames[UM_NUM_FLAGS] = {
+  "auto",
+  "register",
+  "static",
+  "extern",
+  "mutable",
+  "inline",
+  "virtual",
+  "explicit",
+  "friend",
+  "typedef",
+
+  "const",
+  "volatile",
+  
+  "char",
+  "wchar_t",
+  "bool",
+  "short",
+  "int",
+  "long",
+  "signed",
+  "unsigned",
+  "float",
+  "double",
+  "void",
+  "long long"
+};
+
+string toString(UberModifiers m)
+{
+  xassert(uberModifierNames[UM_NUM_FLAGS-1] != NULL);
+  return bitmapString(m, uberModifierNames, UM_NUM_FLAGS);
+}

Added: vendor/elsa/current/elkhound/c/cc_flags.h
===================================================================
--- vendor/elsa/current/elkhound/c/cc_flags.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/cc_flags.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,334 @@
+// cc_flags.h            see license.txt for copyright and terms of use
+// enumerated flags for parsing C
+
+#ifndef CC_FLAGS_H
+#define CC_FLAGS_H
+
+#include "str.h"     // string
+
+// ----------------------- TypeIntr ----------------------
+// type introducer keyword
+// NOTE: keep consistent with CompoundType::Keyword (cc_type.h)
+enum TypeIntr {
+  TI_STRUCT,
+  TI_CLASS,
+  TI_UNION,
+  TI_ENUM,
+  NUM_TYPEINTRS
+};
+
+extern char const * const typeIntrNames[NUM_TYPEINTRS];    // "struct", ...
+string toString(TypeIntr tr);
+
+
+// --------------------- CVFlags ---------------------
+// set: which of "const" and/or "volatile" is specified;
+// I leave the lower 8 bits to represent SimpleTypeId, so I can
+// freely OR them together during parsing;
+// values in common with UberModifier must line up
+enum CVFlags {
+  CV_NONE     = 0x0000,
+  CV_CONST    = 0x0400,
+  CV_VOLATILE = 0x0800,
+  CV_OWNER    = 0x1000,     // experimental extension
+  CV_ALL      = 0x1C00,
+
+  CV_SHIFT_AMOUNT = 10,     // shift right this many bits before counting for cvFlagNames
+  NUM_CVFLAGS = 3           // # bits set to 1 in CV_ALL
+};
+
+extern char const * const cvFlagNames[NUM_CVFLAGS];      // 0="const", 1="volatile", 2="owner"
+string toString(CVFlags cv);
+
+inline CVFlags operator| (CVFlags f1, CVFlags f2)
+  { return (CVFlags)((int)f1 | (int)f2); }
+inline CVFlags& operator|= (CVFlags &f1, CVFlags f2)
+  { return f1 = f1 | f2; }
+
+
+// ----------------------- DeclFlags ----------------------
+// set of declaration modifiers present;
+// these modifiers apply to variable names;
+// they're now also being used for Variable (variable.h) flags;
+// values in common with UberModifiers must line up
+enum DeclFlags {
+  DF_NONE        = 0x00000000,
+
+  // syntactic declaration modifiers
+  DF_AUTO        = 0x00000001,
+  DF_REGISTER    = 0x00000002,
+  DF_STATIC      = 0x00000004,
+  DF_EXTERN      = 0x00000008,
+  DF_MUTABLE     = 0x00000010,
+  DF_INLINE      = 0x00000020,
+  DF_VIRTUAL     = 0x00000040,
+  DF_EXPLICIT    = 0x00000080,
+  DF_FRIEND      = 0x00000100,
+  DF_TYPEDEF     = 0x00000200,
+  DF_SOURCEFLAGS = 0x000003FF,    // all flags that come from keywords in the source
+
+  // flags on Variables
+  DF_ENUMERATOR  = 0x00000400,    // true for values in an 'enum' (enumerators in the terminology of the C++ standard)
+  DF_GLOBAL      = 0x00000800,    // set for globals, unset for locals
+  DF_INITIALIZED = 0x00001000,    // true if has been declared with an initializer (or, for functions, with code)
+  DF_BUILTIN     = 0x00002000,    // true for e.g. __builtin_constant_p -- don't emit later
+  DF_LOGIC       = 0x00004000,    // true for logic variables
+  DF_ADDRTAKEN   = 0x00008000,    // true if it's address has been (or can be) taken
+  DF_PARAMETER   = 0x00010000,    // true if this is a function parameter
+  DF_UNIVERSAL   = 0x00020000,    // (requires DF_LOGIC) universally-quantified variable
+  DF_EXISTENTIAL = 0x00040000,    // (requires DF_LOGIC) existentially-quantified
+  DF_MEMBER      = 0x00080000,    // true for members of classes (data, static data, functions)
+  DF_DEFINITION  = 0x00100000,    // set once we've seen this Variable's definition
+  DF_INLINE_DEFN = 0x00200000,    // set for inline function definitions on second pass of tcheck
+  DF_IMPLICIT    = 0x00400000,    // set for C++ implicit typedefs
+  DF_FORWARD     = 0x00800000,    // for syntax which only provides a forward declaration
+
+  // syntactic declaration extensions
+  DF_PREDICATE   = 0x01000000,    // Simplify-declared predicate (i.e. DEFPRED)
+
+  ALL_DECLFLAGS  = 0x01FFFFFF,
+  NUM_DECLFLAGS  = 25             // # bits set to 1 in ALL_DECLFLAGS
+};
+
+extern char const * const declFlagNames[NUM_DECLFLAGS];      // 0="inline", 1="virtual", 2="friend", ..
+string toString(DeclFlags df);
+
+inline DeclFlags operator| (DeclFlags f1, DeclFlags f2)
+  { return (DeclFlags)((int)f1 | (int)f2); }
+inline DeclFlags& operator|= (DeclFlags &f1, DeclFlags f2)
+  { return f1 = f1 | f2; }
+inline DeclFlags operator& (DeclFlags f1, DeclFlags f2)
+  { return (DeclFlags)((int)f1 & (int)f2); }
+inline DeclFlags operator~ (DeclFlags f)
+  { return (DeclFlags)((~(int)f) & ALL_DECLFLAGS); }
+
+// ------------------------- SimpleTypeId ----------------------------
+// C's built-in scalar types; the representation deliberately does
+// *not* imply any orthogonality of properties (like long vs signed);
+// separate query functions can determine such properties, or signal
+// when it is meaningless to query a given property of a given type
+// (like whether a floating-point type is unsigned)
+enum SimpleTypeId {
+  ST_CHAR,
+  ST_UNSIGNED_CHAR,
+  ST_SIGNED_CHAR,
+  ST_BOOL,
+  ST_INT,
+  ST_UNSIGNED_INT,
+  ST_LONG_INT,
+  ST_UNSIGNED_LONG_INT,
+  ST_LONG_LONG,                      // GNU extension
+  ST_UNSIGNED_LONG_LONG,             // GNU extension
+  ST_SHORT_INT,
+  ST_UNSIGNED_SHORT_INT,
+  ST_WCHAR_T,
+  ST_FLOAT,
+  ST_DOUBLE,
+  ST_LONG_DOUBLE,
+  ST_VOID,
+  ST_ELLIPSIS,                       // used to encode vararg functions
+  ST_CDTOR,                          // "return type" for ctors and dtors
+  ST_ERROR,                          // this type is returned for typechecking errors
+  ST_DEPENDENT,                      // depdenent on an uninstantiated template parameter type
+  NUM_SIMPLE_TYPES,
+  ST_BITMASK = 0xFF                  // for extraction for OR with CVFlags
+};
+
+// info about each simple type
+struct SimpleTypeInfo {
+  char const *name;       // e.g. "unsigned char"
+  int reprSize;           // # of bytes to store
+  bool isInteger;         // ST_INT, etc., but not e.g. ST_FLOAT
+};
+
+bool isValid(SimpleTypeId id);                          // bounds check
+SimpleTypeInfo const &simpleTypeInfo(SimpleTypeId id);
+
+inline char const *simpleTypeName(SimpleTypeId id)
+  { return simpleTypeInfo(id).name; }
+inline int simpleTypeReprSize(SimpleTypeId id)
+  { return simpleTypeInfo(id).reprSize; }
+inline string toString(SimpleTypeId id)
+  { return string(simpleTypeName(id)); }
+
+
+// ---------------------------- UnaryOp ---------------------------
+enum UnaryOp {
+  UNY_PLUS,      // +
+  UNY_MINUS,     // -
+  UNY_NOT,       // !
+  UNY_BITNOT,    // ~
+  NUM_UNARYOPS
+};
+
+extern char const * const unaryOpNames[NUM_UNARYOPS];     // "+", ...
+string toString(UnaryOp op);
+
+
+// unary operator with a side effect
+enum EffectOp {
+  EFF_POSTINC,   // ++ (postfix)
+  EFF_POSTDEC,   // -- (postfix)
+  EFF_PREINC,    // ++
+  EFF_PREDEC,    // --
+  NUM_EFFECTOPS
+};
+
+extern char const * const effectOpNames[NUM_EFFECTOPS];   // "++", ...
+string toString(EffectOp op);
+bool isPostfix(EffectOp op);
+
+
+// ------------------------ BinaryOp --------------------------
+enum BinaryOp {
+  // the relationals come first, and in this order, to correspond
+  // to RelationOp in predicate.ast
+  BIN_EQUAL,     // ==
+  BIN_NOTEQUAL,  // !=
+  BIN_LESS,      // <
+  BIN_GREATER,   // >
+  BIN_LESSEQ,    // <=
+  BIN_GREATEREQ, // >=
+
+  BIN_MULT,      // *
+  BIN_DIV,       // /
+  BIN_MOD,       // %
+  BIN_PLUS,      // +
+  BIN_MINUS,     // -
+  BIN_LSHIFT,    // <<
+  BIN_RSHIFT,    // >>
+  BIN_BITAND,    // &
+  BIN_BITXOR,    // ^
+  BIN_BITOR,     // |
+  BIN_AND,       // &&
+  BIN_OR,        // ||
+
+  BIN_ASSIGN,    // = (used to denote simple assignments in AST, as opposed to (say) "+=")
+
+  // C++ operators
+  BIN_DOT_STAR,    // .*
+  BIN_ARROW_STAR,  // ->*
+
+  // theorem prover extension
+  BIN_IMPLIES,   // ==>
+
+  NUM_BINARYOPS
+};
+
+extern char const * const binaryOpNames[NUM_BINARYOPS];   // "*", ..
+string toString(BinaryOp op);
+
+bool isPredicateCombinator(BinaryOp op);     // &&, ||, ==>
+bool isRelational(BinaryOp op);              // == thru >=
+
+
+// ---------------- access control ------------
+enum AccessKeyword {
+  AK_PUBLIC,
+  AK_PROTECTED,
+  AK_PRIVATE,
+  AK_UNSPECIFIED,      // not explicitly specified; typechecking changes it later
+  
+  NUM_ACCESS_KEYWORDS
+};
+
+extern char const * const accessKeywordNames[NUM_ACCESS_KEYWORDS];
+string toString(AccessKeyword key);
+
+// ---------------- cast keywords -------------
+enum CastKeyword {
+  CK_DYNAMIC,
+  CK_STATIC,
+  CK_REINTERPRET,
+  CK_CONST,
+
+  NUM_CAST_KEYWORDS
+};
+
+extern char const * const castKeywordNames[NUM_CAST_KEYWORDS];
+string toString(CastKeyword key);
+
+
+// --------------- overloadable operators --------
+// these are just the operators that are overloadable
+// but aren't already listed in one of the lists above
+enum OverloadableOp {
+  OVL_COMMA,      // ,
+  OVL_ARROW,      // ->
+  OVL_PARENS,     // ( )
+  OVL_BRACKETS,   // [ ]
+
+  NUM_OVERLOADABLE_OPS
+};
+
+extern char const * const overloadableOpNames[NUM_OVERLOADABLE_OPS];
+string toString(OverloadableOp op);
+
+
+// -------------------- uber modifiers -----------------
+// the uber modifiers are a superset of all the keywords which
+// can appear in a type specifier; see cc.gr, nonterm DeclSpecifier
+enum UberModifiers {
+  UM_NONE         = 0,
+
+  // decl flags
+  UM_AUTO         = 0x00000001,
+  UM_REGISTER     = 0x00000002,
+  UM_STATIC       = 0x00000004,
+  UM_EXTERN       = 0x00000008,
+  UM_MUTABLE      = 0x00000010,
+
+  UM_INLINE       = 0x00000020,
+  UM_VIRTUAL      = 0x00000040,
+  UM_EXPLICIT     = 0x00000080,
+
+  UM_FRIEND       = 0x00000100,
+  UM_TYPEDEF      = 0x00000200,
+
+  UM_DECLFLAGS    = 0x000003FF,
+
+  // cv-qualifier
+  UM_CONST        = 0x00000400,
+  UM_VOLATILE     = 0x00000800,
+
+  UM_CVFLAGS      = 0x00000C00,
+
+  // type keywords
+  UM_CHAR         = 0x00001000,
+  UM_WCHAR_T      = 0x00002000,
+  UM_BOOL         = 0x00004000,
+  UM_SHORT        = 0x00008000,
+  UM_INT          = 0x00010000,
+  UM_LONG         = 0x00020000,
+  UM_SIGNED       = 0x00040000,
+  UM_UNSIGNED     = 0x00080000,
+  UM_FLOAT        = 0x00100000,
+  UM_DOUBLE       = 0x00200000,
+  UM_VOID         = 0x00400000,
+  UM_LONG_LONG    = 0x00800000,    // GNU extension
+
+  UM_TYPEKEYS     = 0x00FFF000,
+
+  UM_ALL_FLAGS    = 0x00FFFFFF,
+  UM_NUM_FLAGS    = 24             // # bits set in UM_ALL_FLAGS
+};
+
+// string repr.
+extern char const * const uberModifierNames[UM_NUM_FLAGS];
+string toString(UberModifiers m);
+
+// select particular subsets
+inline DeclFlags uberDeclFlags(UberModifiers m)
+  { return (DeclFlags)(m & UM_DECLFLAGS); }
+inline CVFlags uberCVFlags(UberModifiers m)
+  { return (CVFlags)(m & UM_CVFLAGS); }
+
+// two more related functions, uberSimpleType and uberCombine,
+// are declared in ccparse.h
+
+// I do *not* define operators to combine the flags with | and &
+// because I want those operations to always be done by dedicated
+// functions like 'uberDeclFlags'
+
+
+#endif // CC_FLAGS_H

Added: vendor/elsa/current/elkhound/c/cc_lang.cc
===================================================================
--- vendor/elsa/current/elkhound/c/cc_lang.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/cc_lang.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// cc_lang.cc            see license.txt for copyright and terms of use
+// code for cc_lang.h, and default language settings
+
+// at the moment there are laughably few settings -- that
+// will change!
+
+#include "cc_lang.h"     // this module
+
+void CCLang::ANSI_C()
+{
+  tagsAreTypes = false;
+  recognizeCppKeywords = false;
+}
+
+void CCLang::ANSI_Cplusplus()
+{
+  tagsAreTypes = true;
+  recognizeCppKeywords = true;
+}
+

Added: vendor/elsa/current/elkhound/c/cc_lang.h
===================================================================
--- vendor/elsa/current/elkhound/c/cc_lang.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/cc_lang.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// cc_lang.h            see license.txt for copyright and terms of use
+// language options that the parser (etc.) is sensitive to
+
+#ifndef CCLANG_H
+#define CCLANG_H
+
+class CCLang {
+public:
+  // when this is true, and the parser sees "struct Foo { ... }",
+  // it will pretend it also saw "typedef struct Foo Foo;" -- i.e.,
+  // the structure (or class) tag name is treated as a type name
+  // by itself
+  bool tagsAreTypes;
+
+  // when true, recognize C++ keywords in input stream
+  bool recognizeCppKeywords;
+
+public:
+  CCLang() { ANSI_C(); }
+
+  void ANSI_C();            // settings for ANSI C
+  void ANSI_Cplusplus();    // settings for ANSI C++
+};
+
+#endif // CCLANG_H

Added: vendor/elsa/current/elkhound/c/configure.pl
===================================================================
--- vendor/elsa/current/elkhound/c/configure.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/configure.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,142 @@
+#!/usr/bin/perl -w
+# configure script for C parser
+
+use strict 'subs';
+
+# default location of smbase relative to this package
+$SMBASE = "../../smbase";
+$req_smcv = 1.03;            # required sm_config version number
+$thisPackage = "elkhound/c";
+
+# -------------- BEGIN common block ---------------
+# do an initial argument scan to find if smbase is somewhere else
+for (my $i=0; $i < @ARGV; $i++) {
+  my ($d) = ($ARGV[$i] =~ m/-*smbase=(.*)/);
+  if (defined($d)) {
+    $SMBASE = $d;
+  }
+}
+
+# try to load the sm_config module
+eval {
+  push @INC, ($SMBASE);
+  require sm_config;
+};
+if ($@) {
+  die("$@" .     # ends with newline, usually
+      "\n" .
+      "I looked for smbase in \"$SMBASE\".\n" .
+      "\n" .
+      "You can explicitly specify the location of smbase with the -smbase=<dir>\n" .
+      "command-line argument.\n");
+}
+
+# check version number
+$smcv = get_sm_config_version();
+if ($smcv < $req_smcv) {
+  die("This package requires version $req_smcv of sm_config, but found\n" .
+      "only version $smcv.\n");
+}
+# -------------- END common block ---------------
+
+
+# defaults
+$AST = "../../ast";
+$ELKHOUND = "..";
+
+
+sub usage {
+  standardUsage();
+
+  print(<<"EOF");
+package options:
+  -ast=<dir>:        specify where the ast system is [$AST]
+  -elkhound=<dir>:   specify where the elkhound system is [$ELKHOUND]
+EOF
+}
+
+
+# -------------- BEGIN common block 2 -------------
+# global variables holding information about the current command-line
+# option being processed
+$option = "";
+$value = "";
+
+# process command-line arguments
+foreach $optionAndValue (@ARGV) {
+  # ignore leading '-' characters, and split at first '=' (if any)
+  ($option, $value) =
+    ($optionAndValue =~ m/^-*([^-][^=]*)=?(.*)$/);
+                      #      option     = value
+
+  my $arg = $option;
+
+  if (handleStandardOption()) {
+    # handled by sm_config.pm
+  }
+  # -------------- END common block 2 -------------
+
+  elsif ($arg eq "ast") {
+    $AST = $tmp;
+  }
+  elsif ($arg eq "elkhound") {
+    $ELKHOUND = $tmp;
+  }
+
+  else {
+    die "unknown option: $arg\n";
+  }
+}
+
+finishedOptionProcessing();
+
+
+# ------------------ check for needed components ----------------
+test_smbase_presence();
+
+test_CXX_compiler();
+
+# ast
+if (! -f "$AST/asthelp.h") {
+  die "I cannot find asthelp.h in `$AST'.\n" .
+      "The ast system is required for elsa.\n" .
+      "If it's in a different location, use the -ast=<dir> option.\n";
+}
+
+# elkhound
+if (! -f "$ELKHOUND/glr.h") {
+  die "I cannot find glr.h in `$ELKHOUND'.\n" .
+      "The elkhound system is required for elsa.\n" .
+      "If it's in a different location, use the -elkhound=<dir> option.\n";
+}
+
+
+# ------------------ config.summary -----------------
+$summary = getStandardConfigSummary();
+
+$summary .= <<"OUTER_EOF";
+cat <<EOF
+  AST:         $AST
+  ELKHOUND:    $ELKHOUND
+EOF
+OUTER_EOF
+
+writeConfigSummary($summary);
+
+
+# ------------------- config.status ------------------
+writeConfigStatus("AST" => "$AST",
+                  "ELKHOUND" => "$ELKHOUND");
+
+
+# ----------------- final actions -----------------
+# run the output file generator
+run("./config.status");
+
+print("\nYou can now run make, usually called 'make' or 'gmake'.\n");
+
+exit(0);
+
+
+# silence warnings
+pretendUsed($thisPackage);


Property changes on: vendor/elsa/current/elkhound/c/configure.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/c/cparse.cc
===================================================================
--- vendor/elsa/current/elkhound/c/cparse.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/cparse.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,75 @@
+// cparse.cc            see license.txt for copyright and terms of use
+// code for cparse.h
+
+#include <iostream.h>    // cout
+
+#include "cparse.h"      // this module
+#include "cc_lang.h"     // CCLang
+#include "trace.h"       // trace
+
+ParseEnv::ParseEnv(StringTable &table, CCLang &L)
+  : str(table), 
+    intType(table.add("int")),
+    strRefAttr(table.add("attr")),
+    types(),
+    lang(L)
+{}
+
+ParseEnv::~ParseEnv()
+{}
+
+
+static char const *identity(void *data)
+{
+  return (char const*)data;
+}
+
+void ParseEnv::enterScope()
+{
+  types.prepend(new StringHash(identity));
+}
+
+void ParseEnv::leaveScope()
+{
+  delete types.removeAt(0);
+}
+
+void ParseEnv::addType(StringRef type)
+{
+  StringHash *h = types.first();
+  if (h->get(type)) {
+    // this happens for C++ code which has both the implicit
+    // and explicit typedefs (and/or, explicit 'class Foo' mentions
+    // in places)
+    //cout << "duplicate entry for " << type << " -- will ignore\n";
+  }
+  else {
+    h->add(type, (void*)type);
+  }
+}
+
+bool ParseEnv::isType(StringRef name)
+{
+  if (name == intType) {
+    return true;
+  }
+
+  FOREACH_OBJLIST(StringHash, types, iter) {
+    if (iter.data()->get(name)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+void ParseEnv::declareClassTag(StringRef tagName)
+{
+  // TYPE/NAME
+  if (lang.tagsAreTypes) {
+    #ifndef NDEBUG
+    trace("cc") << "defined new struct/class tag as type " << tagName << endl;
+    #endif
+    addType(tagName);
+  }
+}

Added: vendor/elsa/current/elkhound/c/cparse.h
===================================================================
--- vendor/elsa/current/elkhound/c/cparse.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/cparse.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// cparse.h            see license.txt for copyright and terms of use
+// data structures used during parsing of C code
+
+#ifndef CPARSE_H
+#define CPARSE_H
+
+#include "strhash.h"       // StringHash
+#include "strtable.h"      // StringTable
+#include "objlist.h"       // ObjList
+#include "c.ast.gen.h"     // C AST, for action function signatures
+
+class CCLang;
+
+// parsing action state
+class ParseEnv {
+public:
+  StringTable &str;               // string table
+  StringRef intType;              // "int"
+  StringRef strRefAttr;           // "attr"
+  ObjList<StringHash> types;      // stack of hashes which identify names of types
+  CCLang &lang;                   // language options
+
+public:
+  ParseEnv(StringTable &table, CCLang &lang);
+  ~ParseEnv();
+
+  void enterScope();
+  void leaveScope();
+  void addType(StringRef type);
+  bool isType(StringRef name);
+
+  void declareClassTag(StringRef tagName);
+};
+
+#endif // CPARSE_H

Added: vendor/elsa/current/elkhound/c/exprequal.cc
===================================================================
--- vendor/elsa/current/elkhound/c/exprequal.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/exprequal.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,221 @@
+// exprequal.cc            see license.txt for copyright and terms of use
+// compare expressions for structural equality
+
+#include "exprequal.h"         // this module
+
+#include "c.ast.gen.h"         // C AST stuff
+#include "ohashtbl.h"          // OwnerHashTable
+#include "c_type.h"            // Type::equals
+
+
+// ------------------- VariablePair ---------------
+struct VariablePair {
+public:    // data
+  Variable const *varL;      // hash key
+  Variable const *varR;      // variable equivalent to varL
+
+public:
+  VariablePair(Variable const *vL, Variable const *vR)
+    : varL(vL), varR(vR) {}
+};
+
+void const *variablePairKey(VariablePair *vp)
+{
+  return vp->varL;
+}
+
+
+// ---------------- expression comparison --------------
+bool equalExpr(OwnerHashTable<VariablePair> &equiv,
+               Expression const *left, Expression const *right);
+
+bool equalExpressions(Expression const *left, Expression const *right)
+{
+  // map of variable equivalences, for determining equality of expressions
+  // that locally declare variables (forall); initially empty
+  OwnerHashTable<VariablePair> equiv(variablePairKey,
+    HashTable::lcprngHashFn, HashTable::pointerEqualKeyFn);
+
+  return equalExpr(equiv, left, right);
+}
+
+
+// simultaneous deconstruction..
+bool equalExpr(OwnerHashTable<VariablePair> &equiv,
+               Expression const *left, Expression const *right)
+{
+  // unlike in ML, I can do toplevel tag comparisons easily here
+  if (left->kind() != right->kind()) {
+    return false;
+  }
+
+  // I had been using _L as a variable name, but that causes problems
+  // on some cygwin and solaris installations, so I changed it to LLL
+  #define DOUBLECASEC(type)                       \
+    ASTNEXTC(type, LLL)                           \
+    type const &L = *LLL;                         \
+    type const &R = *(right->as##type##C());
+
+  // performance note: in general, I try to discover that the nodes are
+  // not equal by examining data within the nodes, and only when that
+  // data matches do I invoke the recursive call to equalExpr
+
+  // since the tags are equal, a switch on the left's type also
+  // analyzes right's type
+  ASTSWITCHC(Expression, left) {
+    ASTCASEC(E_intLit, LLL)     // note this expands to an "{" among other things
+      E_intLit const &L = *LLL;
+      E_intLit const &R = *(right->asE_intLitC());
+      return L.i == R.i;
+
+    DOUBLECASEC(E_floatLit)       return L.f == R.f;
+    DOUBLECASEC(E_stringLit)      return L.s == R.s;
+    DOUBLECASEC(E_charLit)        return L.c == R.c;
+
+    DOUBLECASEC(E_variable)
+      if (L.var == R.var) {
+        return true;
+      }
+
+      // check the equivalence map
+      VariablePair *vp = equiv.get(L.var);
+      if (vp && vp->varR == R.var) {
+        // this is the equivalent variable in the right expression,
+        // so we say these variable references *are* equal
+        return true;
+      }
+      else {
+        // either L.var has no equivalence mapping, or else it does
+        // but it's not equivalent to R.var
+        return false;
+      }
+
+    DOUBLECASEC(E_funCall)
+      if (L.args.count() != R.args.count() ||
+          !equalExpr(equiv, L.func, R.func)) {
+        return false;
+      }
+      ASTListIter<Expression> iterL(L.args);
+      ASTListIter<Expression> iterR(R.args);
+      for (; !iterL.isDone(); iterL.adv(), iterR.adv()) {
+        if (!equalExpr(equiv, iterL.data(), iterR.data())) {
+          return false;
+        }
+      }
+      return true;
+
+    DOUBLECASEC(E_fieldAcc)
+      return L.fieldName == R.fieldName &&
+             equalExpr(equiv, L.obj, R.obj);
+
+    DOUBLECASEC(E_sizeof)
+      return L.size == R.size;
+
+    DOUBLECASEC(E_unary)
+      return L.op == R.op &&
+             equalExpr(equiv, L.expr, R.expr);
+
+    DOUBLECASEC(E_effect)
+      return L.op == R.op &&
+             equalExpr(equiv, L.expr, R.expr);
+
+    DOUBLECASEC(E_binary)
+      // for now I don't consider associativity and commutativity;
+      // I'll rethink this if I encounter code where it's helpful
+      return L.op == R.op &&
+             equalExpr(equiv, L.e1, R.e1) &&
+             equalExpr(equiv, L.e2, R.e2);
+
+    DOUBLECASEC(E_addrOf)
+      return equalExpr(equiv, L.expr, R.expr);
+
+    DOUBLECASEC(E_deref)
+      return equalExpr(equiv, L.ptr, R.ptr);
+
+    DOUBLECASEC(E_cast)
+      return L.type->equals(R.type) &&
+             equalExpr(equiv, L.expr, R.expr);
+
+    DOUBLECASEC(E_cond)
+      return equalExpr(equiv, L.cond, R.cond) &&
+             equalExpr(equiv, L.th, R.th) &&
+             equalExpr(equiv, L.el, R.el);
+
+    DOUBLECASEC(E_comma)
+      // I don't expect comma exprs in among those I'm comparing, but
+      // may as well do the full comparison..
+      return equalExpr(equiv, L.e1, R.e1) &&
+             equalExpr(equiv, L.e2, R.e2);
+
+    DOUBLECASEC(E_sizeofType)
+      return L.size == R.size;
+
+    DOUBLECASEC(E_assign)
+      return L.op == R.op &&
+             equalExpr(equiv, L.target, R.target) &&
+             equalExpr(equiv, L.src, R.src);
+
+    DOUBLECASEC(E_quantifier)
+      if (L.forall != R.forall ||
+          L.decls.count() != R.decls.count()) {
+        return false;
+      }
+
+      // verify the declarations are structurally identical
+      // (i.e. "int x,y;" != "int x; int y;") and all declared
+      // variables have the same type
+      bool ret;
+      SObjList<Variable /*const*/> addedEquiv;
+      ASTListIter<Declaration> outerL(L.decls);
+      ASTListIter<Declaration> outerR(R.decls);
+      for (; !outerL.isDone(); outerL.adv(), outerR.adv()) {
+        if (outerL.data()->decllist.count() !=
+            outerR.data()->decllist.count()) {
+          ret = false;
+          goto cleanup;
+        }
+
+        ASTListIter<Declarator> innerL(outerL.data()->decllist);
+        ASTListIter<Declarator> innerR(outerR.data()->decllist);
+        for (; !innerL.isDone(); innerL.adv(), innerR.adv()) {
+          Variable const *varL = innerL.data()->var;
+          Variable const *varR = innerR.data()->var;
+
+          if (!varL->type->equals(varR->type)) {
+            ret = false;     // different types
+            goto cleanup;
+          }
+
+          // in expectation of all variables being of same type,
+          // add these variables to the equivalence map
+          equiv.add(varL, new VariablePair(varL, varR));       
+          
+          // keep track of what gets added
+          addedEquiv.prepend(const_cast<Variable*>(varL));
+        }
+      }
+
+      // when we get here, we know all the variables have the
+      // same types, and the equiv map has been extended with the
+      // equivalent pairs; so check equality of the bodies
+      ret = equalExpr(equiv, L.pred, R.pred);
+
+    cleanup:
+      // remove the equivalences we added
+      while (addedEquiv.isNotEmpty()) {
+        delete equiv.remove(addedEquiv.removeFirst());
+      }
+
+      return ret;
+             
+    ASTDEFAULTC
+      xfailure("bad expr tag");
+      return false;   // silence warning
+
+    ASTENDCASEC
+  }
+  
+  #undef DOUBLECASEC
+}
+
+

Added: vendor/elsa/current/elkhound/c/exprequal.h
===================================================================
--- vendor/elsa/current/elkhound/c/exprequal.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/exprequal.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// exprequal.h            see license.txt for copyright and terms of use
+// entry for exprequal.cc
+
+#ifndef EXPREQUAL_H
+#define EXPREQUAL_H
+
+class Expression;
+bool equalExpressions(Expression const *left, Expression const *right);
+
+#endif // EXPREQUAL_H

Added: vendor/elsa/current/elkhound/c/exprvisit.cc
===================================================================
--- vendor/elsa/current/elkhound/c/exprvisit.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/exprvisit.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,67 @@
+// exprvisit.cc            see license.txt for copyright and terms of use
+// code for exprvisit.h
+
+#include "exprvisit.h"       // this module
+
+#include "c.ast.gen.h"       // C AST definitions
+
+void walkExpression(ExpressionVisitor &vis, Expression const *root)
+{     
+  // visit the current node
+  vis.visitExpr(root);
+
+  ASTSWITCHC(Expression, root) {
+    ASTCASEC(E_funCall, e)
+      walkExpression(vis, e->func);
+      FOREACH_ASTLIST(Expression, e->args, iter) {
+        walkExpression(vis, iter.data());
+      }
+
+    ASTNEXTC(E_fieldAcc, e)
+      walkExpression(vis, e->obj);
+
+    ASTNEXTC(E_sizeof, e)     
+      // this is potentially bad since, e.g. if I'm searching for
+      // modifications to variables, it doesn't hurt inside sizeof..
+      // need walk cancellation semantics, but whatever
+      walkExpression(vis, e->expr);
+
+    ASTNEXTC(E_unary, e)
+      walkExpression(vis, e->expr);
+
+    ASTNEXTC(E_effect, e)     
+      walkExpression(vis, e->expr);
+
+    ASTNEXTC(E_binary, e)
+      walkExpression(vis, e->e1);
+      walkExpression(vis, e->e2);
+
+    ASTNEXTC(E_addrOf, e)
+      walkExpression(vis, e->expr);
+
+    ASTNEXTC(E_deref, e)
+      walkExpression(vis, e->ptr);
+
+    ASTNEXTC(E_cast, e)
+      walkExpression(vis, e->expr);
+
+    ASTNEXTC(E_cond, e)
+      walkExpression(vis, e->cond);
+      walkExpression(vis, e->th);
+      walkExpression(vis, e->el);
+
+    ASTNEXTC(E_comma, e)
+      walkExpression(vis, e->e1);
+      walkExpression(vis, e->e2);
+
+    ASTNEXTC(E_assign, e)
+      walkExpression(vis, e->target);
+      walkExpression(vis, e->src);
+
+    ASTNEXTC(E_quantifier, e)
+      walkExpression(vis, e->pred);
+
+    ASTENDCASECD
+  }
+}
+

Added: vendor/elsa/current/elkhound/c/exprvisit.h
===================================================================
--- vendor/elsa/current/elkhound/c/exprvisit.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/exprvisit.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// exprvisit.h            see license.txt for copyright and terms of use
+// Expression visitor
+
+#ifndef EXPRVISIT_H
+#define EXPRVISIT_H
+
+class Expression;
+
+// interface for clients to implement
+class ExpressionVisitor {
+public:
+  virtual ~ExpressionVisitor() {}
+  virtual void visitExpr(Expression const *expr) = 0;
+};
+
+// outer driver to visit an expression tree
+void walkExpression(ExpressionVisitor &vis, Expression const *root);
+
+#endif // EXPRVISIT_H

Added: vendor/elsa/current/elkhound/c/lexer1.cc
===================================================================
--- vendor/elsa/current/elkhound/c/lexer1.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/lexer1.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,137 @@
+// lexer1.cc            see license.txt for copyright and terms of use
+// non-parser code for Lexer 1, declared in lexer1.h
+
+#include "lexer1.h"       // this module
+#include "typ.h"          // staticAssert, TABLESIZE
+#include "trace.h"        // tracing stuff
+#include "strutil.h"      // encodeWithEscapes
+
+#include <stdio.h>        // printf
+#include <assert.h>       // assert
+#include <ctype.h>        // isprint
+
+
+// -------------------- Lexer1Token -----------------------------
+Lexer1Token::Lexer1Token(Lexer1TokenType aType, char const *aText,
+               	         int aLength, SourceLoc aLoc)
+  : type(aType),
+    text(substring(aText, aLength)),           // makes a copy
+    length(aLength),
+    loc(aLoc)
+{}
+
+Lexer1Token::~Lexer1Token()
+{
+  // 'text' deallocates its string
+}
+
+
+// map Lexer1TokenType to a string
+char const *l1Tok2String(Lexer1TokenType tok)
+{
+  char const *map[] = {
+    "L1_IDENTIFIER",
+    "L1_INT_LITERAL",
+    "L1_FLOAT_LITERAL",
+    "L1_STRING_LITERAL",
+    "L1_UDEF_QUAL",             // dsw: user-defined qualifier: $tainted
+    "L1_CHAR_LITERAL",
+    "L1_OPERATOR",
+    "L1_PREPROCESSOR",
+    "L1_WHITESPACE",
+    "L1_COMMENT",
+    "L1_ILLEGAL"
+  };
+  assert(TABLESIZE(map) == NUM_L1_TOKENS);
+
+  assert(tok >= L1_IDENTIFIER && tok < NUM_L1_TOKENS);
+  return map[tok];
+}
+
+
+void Lexer1Token::print() const
+{
+  char const *fname;
+  int line, col;
+  sourceLocManager->decodeLineCol(loc, fname, line, col);
+
+  printf("[L1] Token at line %d, col %d: %s \"%s\"\n",
+         line, col, l1Tok2String(type),
+         encodeWithEscapes(text.c_str(), length).c_str());
+}
+
+
+// -------------------- Lexer1 -----------------------------
+Lexer1::Lexer1(char const *fname)
+  : allowMultilineStrings(true),    // GNU extension
+    loc(sourceLocManager->encodeBegin(fname)),
+    errors(0),
+    tokens(),
+    tokensMut(tokens)
+{}
+
+Lexer1::~Lexer1()
+{
+  // tokens list is deallocated
+}
+
+
+// eventually I want this to store the errors in a list of objects...
+void Lexer1::error(char const *msg)
+{
+  char const *fname;
+  int line, col;
+  sourceLocManager->decodeLineCol(loc, fname, line, col);
+
+  printf("[L1] Error at line %d, col %d: %s\n", line, col, msg);
+  errors++;
+}
+
+
+void Lexer1::emit(Lexer1TokenType toktype, char const *tokenText, int length)
+{
+  // construct object to represent this token
+  Lexer1Token *tok = new Lexer1Token(toktype, tokenText, length, loc);
+
+  // (debugging) print it
+  if (tracingSys("lexer1")) {
+    tok->print();
+  }
+
+  // illegal tokens should be noted
+  if (toktype == L1_ILLEGAL) {
+    error(stringb("illegal token: `" << tokenText << "'"));
+  }
+
+  // add it to our running list of tokens
+  tokensMut.append(tok);
+
+  // update line and column counters
+  loc = sourceLocManager->advText(loc, tokenText, length);
+}
+
+
+// ------------------- testing -----------------------
+#ifdef TEST_LEXER1
+
+int main(int argc, char **argv)
+{
+  while (traceProcessArg(argc, argv)) {}
+
+  if (argc < 2) {
+    printf("usage: lexer1 <file>\n");
+    return 0;
+  }
+
+  Lexer1 lexer(argv[1]); 
+  lexer1_lex(lexer, fopen(argv[1], "r"));
+
+  printf("%d token(s), %d error(s)\n",
+         lexer.tokens.count(), lexer.errors);
+
+  return 0;
+}
+
+#endif // TEST_LEXER1
+
+

Added: vendor/elsa/current/elkhound/c/lexer1.h
===================================================================
--- vendor/elsa/current/elkhound/c/lexer1.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/lexer1.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,82 @@
+// lexer1.h            see license.txt for copyright and terms of use
+// Lexer 1: tokenize a single file, no translations
+// see lexer1.txt
+
+#ifndef __LEXER1_H
+#define __LEXER1_H
+
+#include "objlist.h"   // ObjList
+#include "srcloc.h"    // SourceLoc
+
+#include <stdio.h>     // FILE
+
+// type of each L1 token
+enum Lexer1TokenType {
+  L1_IDENTIFIER,
+  L1_INT_LITERAL,
+  L1_FLOAT_LITERAL,
+  L1_STRING_LITERAL,
+  L1_UDEF_QUAL,                 // dsw: user-defined qualifier
+  L1_CHAR_LITERAL,
+  L1_OPERATOR,
+  L1_PREPROCESSOR,
+  L1_WHITESPACE,
+  L1_COMMENT,
+  L1_ILLEGAL,
+  NUM_L1_TOKENS
+};
+
+
+// unit of output from L1
+class Lexer1Token {
+public:
+  Lexer1TokenType type;         // kind of token
+  string text;                  // token's text, null-terminated
+  int length;                   // length of text (somewhat redundant, but whatever)
+  SourceLoc loc;                // location in input stream
+
+public:
+  Lexer1Token(Lexer1TokenType aType, char const *aText, int aLength,
+              SourceLoc aLoc);
+  ~Lexer1Token();
+
+  // debugging
+  void print() const;
+};
+
+
+// L1 lexing state
+class Lexer1 {
+public:
+  // lexer options
+  bool allowMultilineStrings;             // true if newlines don't need to be escaped
+
+  // lexing input state
+  SourceLoc loc;                          // current location
+  int errors;	                          // # of errors encountered so far
+
+  // lexing results
+  ObjList<Lexer1Token> tokens;            // list of tokens produced
+  ObjListMutator<Lexer1Token> tokensMut;  // for appending to the 'tokens' list
+
+public:
+  Lexer1(char const *fname);
+  ~Lexer1();
+
+  // called by parser
+  void error(char const *msg);
+  void emit(Lexer1TokenType toktype, char const *text, int length);
+};
+
+
+// external interface to lexer; parses the entire token
+// stream into 'lexer' object
+int lexer1_lex(Lexer1 &lexer, FILE *inputFile);
+
+
+// utilites
+void printEscaped(char const *p, int len);
+
+
+
+#endif // __LEXER1_H

Added: vendor/elsa/current/elkhound/c/lexer1.lex
===================================================================
--- vendor/elsa/current/elkhound/c/lexer1.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/lexer1.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,339 @@
+/* lexer1.lex            see license.txt for copyright and terms of use
+   flex scanner for Lexer 1 of C++ compiler
+   see lexer1.txt for specification */
+
+/******************/
+/* C declarations */
+/******************/
+
+  #include "lexer1.h"        /* Lexer 1 stuff */
+
+
+/****************/
+/* flex options */
+/****************/
+
+%option noyywrap
+%option nounput
+%option outfile="lexer1yy.cc"
+%option prefix="lexer1_"
+
+
+/********************/
+/* C++ declarations */
+/********************/
+
+  #include "growbuf.h"       // GrowBuffer
+  GrowBuffer collector;      // place to assemble big tokens
+
+  // used for 2nd and 3rd arguments to lexer1Emit
+  #define COLLECTOR (char*)collector.getDataC(), collector.getDataLen()
+  
+  // declare the interface to the lexer
+  #define YY_DECL int lexer1_inner_lex(Lexer1 &lexer)
+  
+  // this works around a problem with cygwin & fileno
+  #define YY_NEVER_INTERACTIVE 1
+
+
+/***************/
+/* sub-regexps */
+/***************/
+
+/* newline */
+NL            "\n"
+
+/* anything but newline */
+NOTNL         .
+
+/* any of 256 source characters */
+ANY           ({NOTNL}|{NL})
+
+/* backslash */
+BACKSL        "\\"
+
+/* beginnging of line (must be start of a pattern) */
+BOL           ^
+
+/* end of line (would like EOF to qualify also, but flex doesn't allow it */
+EOL           {NL}
+
+/* letter or underscore */
+LETTER        [A-Za-z_]
+
+/* letter or underscore or digit */
+ALNUM         [A-Za-z_0-9]
+
+/* decimal digit */
+DIGIT         [0-9]
+
+/* sequence of decimal digits */
+DIGITS        ({DIGIT}+)
+
+/* sign of a number */
+SIGN          ("+"|"-")
+
+/* integer suffix */
+/* added 'LL' option for GNU long long compatibility.. */
+ELL_SUFFIX    [lL]([lL]?)
+INT_SUFFIX    ([uU]{ELL_SUFFIX}?|{ELL_SUFFIX}[uU]?)
+
+/* floating-point suffix letter */
+FLOAT_SUFFIX  [flFL]
+
+/* normal string character: any but quote, newline, or backslash */
+STRCHAR       [^\"\n\\]
+
+/* (start of) an escape sequence */
+ESCAPE        ({BACKSL}{ANY})
+
+/* double quote */
+QUOTE         [\"]
+
+/* normal character literal character: any but single-quote, newline, or backslash */
+CCCHAR        [^\'\n\\]
+
+/* single quote */
+TICK          [\']
+
+/* space or tab */
+SPTAB         [ \t]
+
+/* preprocessor "character" -- any but escaped newline */
+PPCHAR        ([^\\\n]|{BACKSL}{NOTNL})
+
+
+/********************/
+/* start conditions */
+/********************/
+
+%x ST_C_COMMENT
+%x ST_STRING
+
+
+/**************************/
+/* token definition rules */
+/**************************/
+%%
+
+  /* identifier: e.g. foo */
+{LETTER}{ALNUM}* {
+  lexer.emit(L1_IDENTIFIER, yytext, yyleng);
+}
+
+  /* integer literal; dec, oct, or hex */
+[1-9][0-9]*{INT_SUFFIX}?           |
+[0][0-7]*{INT_SUFFIX}?             |
+[0][xX][0-9A-Fa-f]+{INT_SUFFIX}?   {
+  lexer.emit(L1_INT_LITERAL, yytext, yyleng);
+}
+
+  /* floating literal */
+{DIGITS}"."{DIGITS}?([eE]{SIGN}?{DIGITS})?{FLOAT_SUFFIX}?   |
+{DIGITS}"."?([eE]{SIGN}?{DIGITS})?{FLOAT_SUFFIX}?	    |
+"."{DIGITS}([eE]{SIGN}?{DIGITS})?{FLOAT_SUFFIX}?	    {
+  lexer.emit(L1_FLOAT_LITERAL, yytext, yyleng);
+}
+
+  /* ----- string literal ------- */
+  /* intial */
+"L"?{QUOTE}   {
+  collector.setFromBlock(yytext, yyleng);
+  BEGIN(ST_STRING);
+}
+
+  /* continuation */
+<ST_STRING>({STRCHAR}|{ESCAPE})*   {
+  collector.append(yytext, yyleng);
+}
+
+  /* final */
+<ST_STRING>{QUOTE} {
+  collector.append(yytext, yyleng);
+  lexer.emit(L1_STRING_LITERAL, COLLECTOR);
+  BEGIN(INITIAL);
+}
+
+  /* dsw: user-defined qualifier; example: $tainted */
+\${ALNUM}+ {
+  lexer.emit(L1_UDEF_QUAL, yytext, yyleng);
+}
+
+  /* final, error */
+<ST_STRING>{EOL}   |
+<ST_STRING><<EOF>> {
+  if (yytext[0] == '\n') {
+    collector.append(yytext, yyleng);
+  }
+  else {
+    // when matching <<EOF>>, yytext[0]=0 and yyleng=1 (possibly
+    // a bug in flex; its man page doesn't specify what it does), so we
+    // get an extra NUL in the collected token, which I don't want
+  }
+  
+  if (!lexer.allowMultilineStrings) {
+    lexer.error("unterminated string literal");
+    lexer.emit(L1_STRING_LITERAL, COLLECTOR);
+    BEGIN(INITIAL);
+  }
+
+  if (yytext[0] != '\n') {
+    yyterminate();     	  // flex man page says to do this for <<EOF>>
+  }
+}
+
+
+  /* character literal */
+"L"?{TICK}({CCCHAR}|{ESCAPE})*{TICK}   {
+  lexer.emit(L1_CHAR_LITERAL, yytext, yyleng);
+}
+
+
+  /* operator */
+  /* extensions for theorem prover: "==>" */
+"("|")"|"["|"]"|"->"|"::"|"."|"!"|"~"|"+"|"-"|"++"|"--"|"&"|"*"  |
+".*"|"->*"|"/"|"%"|"<<"|">>"|"<"|"<="|">"|">="     	         |
+"=="|"!="|"^"|"|"|"&&"|"||"|"?"|":"|"="|"*="|"/="|"%="|"+="      |
+"-="|"&="|"^="|"|="|"<<="|">>="|","|"..."|";"|"{"|"}"|"==>"      {
+  lexer.emit(L1_OPERATOR, yytext, yyleng);
+}
+
+  /* preprocessor */
+  /* technically, if this isn't at the start of a line (possibly after
+   * some whitespace, it should be an error.. I'm not sure right now how
+   * I want to deal with that (I originally was using '^', but that
+   * interacts badly with the whitespace rule) */
+"#"{PPCHAR}*({BACKSL}{NL}{PPCHAR}*)*   {
+  lexer.emit(L1_PREPROCESSOR, yytext, yyleng);
+}
+
+  /* whitespace */
+  /* 10/20/02: added '\r' to accomodate files coming from Windows */
+[ \t\n\f\v\r]+  {
+  lexer.emit(L1_WHITESPACE, yytext, yyleng);
+}
+
+  /* C++ comment */
+  /* we don't match the \n because that way this works at EOF */
+"//"{NOTNL}*    {
+  lexer.emit(L1_COMMENT, yytext, yyleng);
+}
+
+  /* ------- C comment --------- */
+  /* initial */
+"/""*"     {
+  collector.setFromBlock(yytext, yyleng);
+  BEGIN(ST_C_COMMENT);
+}
+
+  /* continuation */
+<ST_C_COMMENT>([^*]|"*"[^/])*   {
+  collector.append(yytext, yyleng);
+}
+
+  /* final */
+<ST_C_COMMENT>"*/"     {
+  collector.append(yytext, yyleng);
+  lexer.emit(L1_COMMENT, COLLECTOR);
+  BEGIN(INITIAL);
+}
+
+  /* final, error */
+<ST_C_COMMENT><<EOF>>     {
+  lexer.error("unterminated /**/ comment");
+  lexer.emit(L1_COMMENT, COLLECTOR);
+  BEGIN(INITIAL);
+}
+
+  /* illegal */
+.  {
+  lexer.emit(L1_ILLEGAL, yytext, yyleng);
+}
+
+
+%%
+/**************/
+/* extra code */
+/**************/
+
+
+/* wrapper around main lex routine to do init */
+int lexer1_lex(Lexer1 &lexer, FILE *inputFile)
+{
+  yyrestart(inputFile);
+  
+  // this collects all the tokens
+  int ret = lexer1_inner_lex(lexer);
+             
+  // prevent leaking the big buffer
+  // 9/07/03: but this doesn't work with flex-2.5.31, and isn't worth the
+  // hassle to portablize, since lexer1 is obsolete anyway
+  //yy_delete_buffer(yy_current_buffer);
+
+  return ret;
+}
+
+
+
+/*********/
+/* trash */
+/*********/
+#if 0
+
+  /* Notes
+   *
+   * 1) Contrary to usual lexer practice, I want this lexer to match potentially huge
+   *    tokens, like entire blocks of C comments.  This is because I want those
+   *    to become single L1 tokens, and it's easier to let flex create them
+   *    (inefficiently) than to go write code to do so efficiently.  I'd reconsider
+   *    if I decided some tool (like an editor) would rather break comments up into
+   *    smaller pieces.
+   *
+   * 2) To avoid backtracking over these large tokens, they all have rules to cover
+   *    all the possible endings, including <<EOF>>.
+   */
+
+{QUOTE}({STRCHAR}|{ESCAPE})*{QUOTE}   {
+  lexer.emit(L1_STRING_LITERAL);
+}
+
+  /* unterminated string literal */
+{QUOTE}({STRCHAR}|{ESCAPE})*{EOL}     |
+{QUOTE}({STRCHAR}|{ESCAPE})*<<EOF>>   {
+  lexer.emit(L1_STRING_LITERAL);
+}
+
+
+  /* unterminated character literal */
+{TICK}({CCCHAR}|{ESCAPE})*{EOL}     |
+{TICK}({CCCHAR}|{ESCAPE})*<<EOF>>   {
+  lexer.error("unterminated character literal");
+  lexer.emit(L1_CHAR_LITERAL);
+}
+
+%x ST_PREPROC
+
+  /* ------- preprocessor ---------- */
+  /* initial */
+{BOL}{SPTAB}*"#"    {
+  collector.setFromBlock(yytext, yyleng);
+  BEGIN(ST_PREPROC);
+}
+
+  /* continuation */
+<ST_PREPROC>({BACKSL}{NL}|{PPCHAR})+     {
+  collector.append(yytext, yyleng);
+}
+
+  /* final */
+<ST_PREPROC>{EOL}   |
+<ST_PREPROC><<EOF>> {
+  collector.append(yytext, yyleng);
+  lexer.emit(L1_PREPROCESSOR, COLLECTOR);
+  BEGIN(INITIAL);
+}
+
+
+#endif // 0
+
+

Added: vendor/elsa/current/elkhound/c/lexer1yy.cc
===================================================================
--- vendor/elsa/current/elkhound/c/lexer1yy.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/lexer1yy.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1961 @@
+#define yy_create_buffer lexer1__create_buffer
+#define yy_delete_buffer lexer1__delete_buffer
+#define yy_scan_buffer lexer1__scan_buffer
+#define yy_scan_string lexer1__scan_string
+#define yy_scan_bytes lexer1__scan_bytes
+#define yy_flex_debug lexer1__flex_debug
+#define yy_init_buffer lexer1__init_buffer
+#define yy_flush_buffer lexer1__flush_buffer
+#define yy_load_buffer_state lexer1__load_buffer_state
+#define yy_switch_to_buffer lexer1__switch_to_buffer
+#define yyin lexer1_in
+#define yyleng lexer1_leng
+#define yylex lexer1_lex
+#define yyout lexer1_out
+#define yyrestart lexer1_restart
+#define yytext lexer1_text
+
+#line 19 "lexer1yy.cc"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define yywrap() 1
+#define YY_SKIP_YYWRAP
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 25
+#define YY_END_OF_BUFFER 26
+static yyconst short int yy_accept[115] =
+    {   0,
+        0,    0,   22,   22,    9,    9,   26,   24,   19,   19,
+       14,    8,   18,   24,   15,   14,   24,   14,   14,   14,
+       17,   14,   14,   15,    3,    2,   16,   15,   16,   15,
+       16,    1,    1,   16,   16,   22,   25,    9,   12,   10,
+       25,   19,   16,   18,    0,   11,   17,    0,   13,    0,
+       14,   14,   15,    0,    7,   21,   20,    5,    3,    6,
+        0,    6,    3,    3,    0,    2,    2,    2,   15,   16,
+       15,    1,    8,    0,   22,    0,   23,    9,    0,   18,
+        0,    7,   20,    5,    0,    5,    0,    6,    3,    3,
+        3,    4,    2,    2,    2,   18,    0,    0,    7,    0,
+
+        5,    0,    5,    3,    4,    4,    2,    0,    5,    4,
+        4,    4,    4,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        2,    2,    2,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    7,    8,    9,   10,   11,
+       12,   13,   14,   15,   16,   17,   18,   19,   20,   20,
+       20,   20,   20,   20,   20,   21,   21,   22,   23,   24,
+       25,   26,   27,    1,   28,   28,   28,   28,   29,   30,
+       31,   31,   31,   31,   31,   32,   31,   31,   31,   31,
+       31,   31,   31,   31,   33,   31,   31,   34,   31,   31,
+       35,   36,   37,   38,   31,    1,   28,   28,   28,   28,
+
+       29,   30,   31,   31,   31,   31,   31,   39,   31,   31,
+       31,   31,   31,   31,   31,   31,   33,   31,   31,   34,
+       31,   31,   40,   41,   42,   43,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[44] =
+    {   0,
+        1,    1,    2,    1,    3,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    4,    4,
+        4,    1,    1,    1,    1,    1,    1,    4,    4,    4,
+        5,    4,    4,    5,    1,    1,    1,    1,    4,    1,
+        1,    1,    1
+    } ;
+
+static yyconst short int yy_base[126] =
+    {   0,
+        0,    0,  240,  239,   41,   42,  250,  303,   46,   48,
+      223,  303,  211,    0,  221,   43,   43,  303,  220,   40,
+      303,   41,   42,   51,   63,   86,  221,   46,  217,   47,
+      303,    0,   76,  216,   33,  223,  215,  196,  303,  303,
+       82,   86,  303,  176,  203,    0,  303,   65,  303,  200,
+      303,  187,  303,  169,  107,  303,    0,  128,  143,  151,
+      124,  303,   78,   59,   93,    0,  102,   92,  129,  127,
+      117,    0,  303,   84,  120,  111,  303,   73,  127,   72,
+      145,  303,    0,  172,  168,  303,  131,  175,   71,  303,
+      123,  146,   67,  303,  124,   63,   87,  154,  178,  199,
+
+      303,  202,  205,  303,  195,  137,  303,  210,  219,   27,
+      303,  177,  303,  303,  258,  263,  268,  270,  275,  277,
+      282,  287,  292,  297,   52
+    } ;
+
+static yyconst short int yy_def[126] =
+    {   0,
+      114,    1,  115,  115,  116,  116,  114,  114,  114,  114,
+      114,  114,  117,  118,  114,  114,  119,  114,  114,  114,
+      114,  114,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  120,  120,  114,  114,  121,  121,  122,  114,  114,
+      122,  114,  114,  117,  117,  118,  114,  119,  114,  119,
+      114,  114,  114,  114,  114,  114,  123,  114,   25,  114,
+      114,  114,  114,  114,  114,   26,  114,  114,  114,  114,
+      114,  120,  114,  119,  121,  121,  114,  122,  122,  124,
+      114,  114,  123,  114,  114,  114,  114,  114,  114,  114,
+      114,  125,  114,  114,  114,  124,  124,  114,  114,  114,
+
+      114,  114,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,    0,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114
+    } ;
+
+static yyconst short int yy_nxt[347] =
+    {   0,
+        8,    9,   10,   11,   12,   13,   14,   15,   16,   17,
+       18,   18,   19,   20,   21,   22,   23,   24,   25,   26,
+       26,   27,   21,   28,   29,   30,   31,   32,   32,   32,
+       32,   33,   32,   32,   18,    8,   18,   34,   32,   21,
+       35,   21,   18,   39,   39,   40,   40,   42,   42,   42,
+       42,   43,   49,   51,   53,   92,   51,   47,   54,  111,
+       55,   55,   55,   56,   43,   47,   52,   47,   57,   69,
+       53,   53,   71,   43,   49,   43,   41,   41,   50,   58,
+       73,   59,   59,   60,   78,   74,   78,   42,   42,   80,
+       91,   61,   62,   49,   63,   64,   65,   91,   97,   94,
+
+       50,   63,   58,   90,   66,   66,   66,   97,   79,   89,
+       90,   92,   92,   92,   61,   62,   89,   67,   68,   50,
+       92,   92,   92,   95,   67,   55,   55,   55,  114,   78,
+       95,   78,   76,   93,   94,   81,   82,   87,   82,   87,
+       93,   47,   88,   88,   88,   82,   84,   84,   84,   88,
+       88,   88,   47,   47,  104,  107,   85,   86,   98,   86,
+       98,  104,  107,   99,   99,   99,   86,   58,  112,   60,
+       60,   60,   99,   99,   99,  112,  114,  105,  106,   61,
+       62,  102,   62,  102,  105,   47,  103,  103,  103,   62,
+       84,   84,   84,   88,   88,   88,   99,   99,   99,   53,
+
+      100,  101,   48,  101,   62,   80,   62,   82,  113,   82,
+      101,   45,  108,   62,  108,  113,   82,  109,  109,  109,
+      103,  103,  103,  103,  103,  103,  110,  111,  109,  109,
+      109,   79,   77,  110,   86,   76,   86,  109,  109,  109,
+       47,   70,   51,   86,   43,   43,   45,   43,  101,  114,
+      101,   37,   37,  114,  114,  114,  114,  101,   36,   36,
+       36,   36,   36,   38,   38,   38,   38,   38,   44,  114,
+       44,   44,   44,   46,   46,   48,  114,   48,   48,   48,
+       72,   72,   75,   75,   75,   75,   75,   78,  114,  114,
+       78,   78,   83,  114,   83,   83,   83,   96,  114,   96,
+
+       96,   96,    7,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114,  114
+    } ;
+
+static yyconst short int yy_chk[347] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    5,    6,    5,    6,    9,    9,   10,
+       10,   16,   17,   20,   23,  125,   22,   35,   23,  110,
+       23,   23,   23,   24,   20,   22,   22,   16,   24,   28,
+       28,   30,   30,   35,   48,   24,    5,    6,   17,   25,
+       33,   25,   25,   25,   41,   33,   41,   42,   42,   97,
+       64,   25,   25,   74,   25,   25,   25,   64,   96,   93,
+
+       48,   25,   26,   89,   26,   26,   26,   80,   78,   63,
+       63,   65,   65,   65,   26,   26,   63,   26,   26,   74,
+       65,   65,   65,   68,   26,   55,   55,   55,   76,   79,
+       68,   79,   75,   67,   67,   55,   55,   61,   55,   61,
+       67,   71,   61,   61,   61,   55,   58,   58,   58,   87,
+       87,   87,   70,   69,   91,   95,   58,   58,   81,   58,
+       81,   91,   95,   81,   81,   81,   58,   60,  106,   60,
+       60,   60,   98,   98,   98,  106,   59,   92,   92,   60,
+       60,   85,   60,   85,   92,   54,   85,   85,   85,   60,
+       84,   84,   84,   88,   88,   88,   99,   99,   99,   52,
+
+       84,   84,   50,   84,   88,   45,   88,   99,  112,   99,
+       84,   44,  100,   88,  100,  112,   99,  100,  100,  100,
+      102,  102,  102,  103,  103,  103,  105,  105,  108,  108,
+      108,   38,   37,  105,  103,   36,  103,  109,  109,  109,
+       34,   29,   27,  103,   19,   15,   13,   11,  109,    7,
+      109,    4,    3,    0,    0,    0,    0,  109,  115,  115,
+      115,  115,  115,  116,  116,  116,  116,  116,  117,    0,
+      117,  117,  117,  118,  118,  119,    0,  119,  119,  119,
+      120,  120,  121,  121,  121,  121,  121,  122,    0,    0,
+      122,  122,  123,    0,  123,  123,  123,  124,    0,  124,
+
+      124,  124,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114,  114,  114,  114,  114,  114,
+      114,  114,  114,  114,  114,  114
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lexer1.lex"
+#define INITIAL 0
+/* lexer1.lex            see license.txt for copyright and terms of use
+   flex scanner for Lexer 1 of C++ compiler
+   see lexer1.txt for specification */
+/******************/
+/* C declarations */
+/******************/
+#include "lexer1.h"        /* Lexer 1 stuff */
+/****************/
+/* flex options */
+/****************/
+#define YY_NO_UNPUT 1
+/********************/
+/* C++ declarations */
+/********************/
+#include "growbuf.h"       // GrowBuffer
+GrowBuffer collector;      // place to assemble big tokens
+// used for 2nd and 3rd arguments to lexer1Emit
+#define COLLECTOR (char*)collector.getDataC(), collector.getDataLen()
+// declare the interface to the lexer
+#define YY_DECL int lexer1_inner_lex(Lexer1 &lexer)
+// this works around a problem with cygwin & fileno
+#define YY_NEVER_INTERACTIVE 1
+/***************/
+/* sub-regexps */
+/***************/
+/* newline */
+/* anything but newline */
+/* any of 256 source characters */
+/* backslash */
+/* beginnging of line (must be start of a pattern) */
+/* end of line (would like EOF to qualify also, but flex doesn't allow it */
+/* letter or underscore */
+/* letter or underscore or digit */
+/* decimal digit */
+/* sequence of decimal digits */
+/* sign of a number */
+/* integer suffix */
+/* added 'LL' option for GNU long long compatibility.. */
+/* floating-point suffix letter */
+/* normal string character: any but quote, newline, or backslash */
+/* (start of) an escape sequence */
+/* double quote */
+/* normal character literal character: any but single-quote, newline, or backslash */
+/* single quote */
+/* space or tab */
+/* preprocessor "character" -- any but escaped newline */
+/********************/
+/* start conditions */
+/********************/
+#define ST_C_COMMENT 1
+
+#define ST_STRING 2
+
+/**************************/
+/* token definition rules */
+/**************************/
+#line 556 "lexer1yy.cc"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 117 "lexer1.lex"
+
+
+  /* identifier: e.g. foo */
+#line 711 "lexer1yy.cc"
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 115 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 303 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 120 "lexer1.lex"
+{
+  lexer.emit(L1_IDENTIFIER, yytext, yyleng);
+}
+	YY_BREAK
+/* integer literal; dec, oct, or hex */
+case 2:
+#line 126 "lexer1.lex"
+case 3:
+#line 127 "lexer1.lex"
+case 4:
+YY_RULE_SETUP
+#line 127 "lexer1.lex"
+{
+  lexer.emit(L1_INT_LITERAL, yytext, yyleng);
+}
+	YY_BREAK
+/* floating literal */
+case 5:
+#line 133 "lexer1.lex"
+case 6:
+#line 134 "lexer1.lex"
+case 7:
+YY_RULE_SETUP
+#line 134 "lexer1.lex"
+{
+  lexer.emit(L1_FLOAT_LITERAL, yytext, yyleng);
+}
+	YY_BREAK
+/* ----- string literal ------- */
+/* intial */
+case 8:
+YY_RULE_SETUP
+#line 140 "lexer1.lex"
+{
+  collector.setFromBlock(yytext, yyleng);
+  BEGIN(ST_STRING);
+}
+	YY_BREAK
+/* continuation */
+case 9:
+YY_RULE_SETUP
+#line 146 "lexer1.lex"
+{
+  collector.append(yytext, yyleng);
+}
+	YY_BREAK
+/* final */
+case 10:
+YY_RULE_SETUP
+#line 151 "lexer1.lex"
+{
+  collector.append(yytext, yyleng);
+  lexer.emit(L1_STRING_LITERAL, COLLECTOR);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+/* dsw: user-defined qualifier; example: $tainted */
+case 11:
+YY_RULE_SETUP
+#line 158 "lexer1.lex"
+{
+  lexer.emit(L1_UDEF_QUAL, yytext, yyleng);
+}
+	YY_BREAK
+/* final, error */
+case 12:
+#line 164 "lexer1.lex"
+case YY_STATE_EOF(ST_STRING):
+#line 164 "lexer1.lex"
+{
+  if (yytext[0] == '\n') {
+    collector.append(yytext, yyleng);
+  }
+  else {
+    // when matching <<EOF>>, yytext[0]=0 and yyleng=1 (possibly
+    // a bug in flex; its man page doesn't specify what it does), so we
+    // get an extra NUL in the collected token, which I don't want
+  }
+  
+  if (!lexer.allowMultilineStrings) {
+    lexer.error("unterminated string literal");
+    lexer.emit(L1_STRING_LITERAL, COLLECTOR);
+    BEGIN(INITIAL);
+  }
+
+  if (yytext[0] != '\n') {
+    yyterminate();     	  // flex man page says to do this for <<EOF>>
+  }
+}
+	YY_BREAK
+/* character literal */
+case 13:
+YY_RULE_SETUP
+#line 187 "lexer1.lex"
+{
+  lexer.emit(L1_CHAR_LITERAL, yytext, yyleng);
+}
+	YY_BREAK
+/* operator */
+/* extensions for theorem prover: "==>" */
+case 14:
+#line 195 "lexer1.lex"
+case 15:
+#line 196 "lexer1.lex"
+case 16:
+#line 197 "lexer1.lex"
+case 17:
+YY_RULE_SETUP
+#line 197 "lexer1.lex"
+{
+  lexer.emit(L1_OPERATOR, yytext, yyleng);
+}
+	YY_BREAK
+/* preprocessor */
+/* technically, if this isn't at the start of a line (possibly after
+   * some whitespace, it should be an error.. I'm not sure right now how
+   * I want to deal with that (I originally was using '^', but that
+   * interacts badly with the whitespace rule) */
+case 18:
+YY_RULE_SETUP
+#line 206 "lexer1.lex"
+{
+  lexer.emit(L1_PREPROCESSOR, yytext, yyleng);
+}
+	YY_BREAK
+/* whitespace */
+/* 10/20/02: added '\r' to accomodate files coming from Windows */
+case 19:
+YY_RULE_SETUP
+#line 212 "lexer1.lex"
+{
+  lexer.emit(L1_WHITESPACE, yytext, yyleng);
+}
+	YY_BREAK
+/* C++ comment */
+/* we don't match the \n because that way this works at EOF */
+case 20:
+YY_RULE_SETUP
+#line 218 "lexer1.lex"
+{
+  lexer.emit(L1_COMMENT, yytext, yyleng);
+}
+	YY_BREAK
+/* ------- C comment --------- */
+/* initial */
+case 21:
+YY_RULE_SETUP
+#line 224 "lexer1.lex"
+{
+  collector.setFromBlock(yytext, yyleng);
+  BEGIN(ST_C_COMMENT);
+}
+	YY_BREAK
+/* continuation */
+case 22:
+YY_RULE_SETUP
+#line 230 "lexer1.lex"
+{
+  collector.append(yytext, yyleng);
+}
+	YY_BREAK
+/* final */
+case 23:
+YY_RULE_SETUP
+#line 235 "lexer1.lex"
+{
+  collector.append(yytext, yyleng);
+  lexer.emit(L1_COMMENT, COLLECTOR);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+/* final, error */
+case YY_STATE_EOF(ST_C_COMMENT):
+#line 242 "lexer1.lex"
+{
+  lexer.error("unterminated /**/ comment");
+  lexer.emit(L1_COMMENT, COLLECTOR);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+/* illegal */
+case 24:
+YY_RULE_SETUP
+#line 249 "lexer1.lex"
+{
+  lexer.emit(L1_ILLEGAL, yytext, yyleng);
+}
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 254 "lexer1.lex"
+ECHO;
+	YY_BREAK
+#line 990 "lexer1yy.cc"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 115 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 115 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 114);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+#endif	/* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+
+	return c;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b );
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+	{
+	int len;
+	for ( len = 0; yy_str[len]; ++len )
+		;
+
+	return yy_scan_bytes( yy_str, len );
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+	{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc( n );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < len; ++i )
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+	{
+	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 254 "lexer1.lex"
+
+/**************/
+/* extra code */
+/**************/
+
+
+/* wrapper around main lex routine to do init */
+int lexer1_lex(Lexer1 &lexer, FILE *inputFile)
+{
+  yyrestart(inputFile);
+  
+  // this collects all the tokens
+  int ret = lexer1_inner_lex(lexer);
+             
+  // prevent leaking the big buffer
+  // 9/07/03: but this doesn't work with flex-2.5.31, and isn't worth the
+  // hassle to portablize, since lexer1 is obsolete anyway
+  //yy_delete_buffer(yy_current_buffer);
+
+  return ret;
+}
+
+
+
+/*********/
+/* trash */
+/*********/
+#if 0
+
+  /* Notes
+   *
+   * 1) Contrary to usual lexer practice, I want this lexer to match potentially huge
+   *    tokens, like entire blocks of C comments.  This is because I want those
+   *    to become single L1 tokens, and it's easier to let flex create them
+   *    (inefficiently) than to go write code to do so efficiently.  I'd reconsider
+   *    if I decided some tool (like an editor) would rather break comments up into
+   *    smaller pieces.
+   *
+   * 2) To avoid backtracking over these large tokens, they all have rules to cover
+   *    all the possible endings, including <<EOF>>.
+   */
+
+{QUOTE}({STRCHAR}|{ESCAPE})*{QUOTE}   {
+  lexer.emit(L1_STRING_LITERAL);
+}
+
+  /* unterminated string literal */
+{QUOTE}({STRCHAR}|{ESCAPE})*{EOL}     |
+{QUOTE}({STRCHAR}|{ESCAPE})*<<EOF>>   {
+  lexer.emit(L1_STRING_LITERAL);
+}
+
+
+  /* unterminated character literal */
+{TICK}({CCCHAR}|{ESCAPE})*{EOL}     |
+{TICK}({CCCHAR}|{ESCAPE})*<<EOF>>   {
+  lexer.error("unterminated character literal");
+  lexer.emit(L1_CHAR_LITERAL);
+}
+
+%x ST_PREPROC
+
+  /* ------- preprocessor ---------- */
+  /* initial */
+{BOL}{SPTAB}*"#"    {
+  collector.setFromBlock(yytext, yyleng);
+  BEGIN(ST_PREPROC);
+}
+
+  /* continuation */
+<ST_PREPROC>({BACKSL}{NL}|{PPCHAR})+     {
+  collector.append(yytext, yyleng);
+}
+
+  /* final */
+<ST_PREPROC>{EOL}   |
+<ST_PREPROC><<EOF>> {
+  collector.append(yytext, yyleng);
+  lexer.emit(L1_PREPROCESSOR, COLLECTOR);
+  BEGIN(INITIAL);
+}
+
+
+#endif // 0
+
+

Added: vendor/elsa/current/elkhound/c/lexer2.cc
===================================================================
--- vendor/elsa/current/elkhound/c/lexer2.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/lexer2.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,779 @@
+// lexer2.cc            see license.txt for copyright and terms of use
+// code for lexer2.h
+
+#include "lexer2.h"      // this module
+#include "trace.h"       // tracingSys
+#include "strutil.h"     // encodeWithEscapes
+#include "exc.h"         // xformat
+#include "cc_lang.h"     // CCLang
+#include "glrconfig.h"   // SOURCELOC
+
+#include <stdlib.h>      // strtoul
+#include <string.h>      // strlen, strcmp
+
+// ------------------ token type descriptions ----------------------
+struct Lexer2TokenTypeDesc
+{
+  // type code; should equal index in l2TokTypes[] (but not checked)
+  Lexer2TokenType tokType;
+
+  // name as it appears in C code
+  char const *typeName;
+
+  // spelling for keywords and operators; descriptive name for others
+  char const *spelling;
+
+  // true for tokens where we emit spelling as Bison alias; also, this
+  // must be true for us to consider 'spelling' to mean a keyword or
+  // operator spelling as opposed to an L2_NAME
+  bool bisonSpelling;
+};
+
+// name it once, get both the symbol and the string
+#define N(name) name, #name
+
+Lexer2TokenTypeDesc const l2TokTypes[] = {
+  // eof
+  { N(L2_EOF),                  "EOF", false },
+
+  // name
+  { N(L2_NAME),                 "NAME", false },
+  { N(L2_TYPE_NAME),            "TYPE_NAME", false },
+  { N(L2_VARIABLE_NAME),        "VARIABLE_NAME", false },
+
+  // literals
+  { N(L2_INT_LITERAL),          "INT_LITERAL", false },
+  { N(L2_FLOAT_LITERAL),        "FLOAT_LITERAL", false },
+  { N(L2_STRING_LITERAL),       "STRING_LITERAL", false },
+  { N(L2_CHAR_LITERAL),         "CHAR_LITERAL", false },
+
+  // dsw: user-defined qualifiers
+  // FIX: false means what?
+  { N(L2_UDEF_QUAL),            "UDEF_QUAL", false },
+
+  // keywords
+  { N(L2_ASM),                  "asm", true },
+  { N(L2_AUTO),                 "auto", true },
+  { N(L2_BREAK),                "break", true },
+  { N(L2_BOOL),                 "bool", true },
+  { N(L2_CASE),                 "case", true },
+  { N(L2_CATCH),                "catch", true },
+  { N(L2_CDECL),                "cdecl", true },
+  { N(L2_CHAR),                 "char", true },
+  { N(L2_CLASS),                "class", true },
+  { N(L2_CONST),                "const", true },
+  { N(L2_CONST_CAST),           "const_cast", true },
+  { N(L2_CONTINUE),             "continue", true },
+  { N(L2_DEFAULT),              "default", true },
+  { N(L2_DELETE),               "delete", true },
+  { N(L2_DO),                   "do", true },
+  { N(L2_DOUBLE),               "double", true },
+  { N(L2_DYNAMIC_CAST),         "dynamic_cast", true },
+  { N(L2_ELSE),                 "else", true },
+  { N(L2_ENUM),                 "enum", true },
+  { N(L2_EXPLICIT),             "explicit", true },
+  { N(L2_EXPORT),               "export", true },
+  { N(L2_EXTERN),               "extern", true },
+  { N(L2_FALSE),                "false", true },
+  { N(L2_FLOAT),                "float", true },
+  { N(L2_FOR),                  "for", true },
+  { N(L2_FRIEND),               "friend", true },
+  { N(L2_GOTO),                 "goto", true },
+  { N(L2_IF),                   "if", true },
+  { N(L2_INLINE),               "inline", true },
+  { N(L2_INT),                  "int", true },
+  { N(L2_LONG),                 "long", true },
+  { N(L2_MUTABLE),              "mutable", true },
+  { N(L2_NAMESPACE),            "namespace", true },
+  { N(L2_NEW),                  "new", true },
+  { N(L2_OPERATOR),             "operator", true },
+  { N(L2_PASCAL),               "pascal", true },
+  { N(L2_PRIVATE),              "private", true },
+  { N(L2_PROTECTED),            "protected", true },
+  { N(L2_PUBLIC),               "public", true },
+  { N(L2_REGISTER),             "register", true },
+  { N(L2_REINTERPRET_CAST),     "reinterpret_cast", true },
+  { N(L2_RETURN),               "return", true },
+  { N(L2_SHORT),                "short", true },
+  { N(L2_SIGNED),               "signed", true },
+  { N(L2_SIZEOF),               "sizeof", true },
+  { N(L2_STATIC),               "static", true },
+  { N(L2_STATIC_CAST),          "static_cast", true },
+  { N(L2_STRUCT),               "struct", true },
+  { N(L2_SWITCH),               "switch", true },
+  { N(L2_TEMPLATE),             "template", true },
+  { N(L2_THIS),                 "this", true },
+  { N(L2_THROW),                "throw", true },
+  { N(L2_TRUE),                 "true", true },
+  { N(L2_TRY),                  "try", true },
+  { N(L2_TYPEDEF),              "typedef", true },
+  { N(L2_TYPEID),               "typeid", true },
+  { N(L2_TYPENAME),             "typename", true },
+  { N(L2_UNION),                "union", true },
+  { N(L2_UNSIGNED),             "unsigned", true },
+  { N(L2_USING),                "using", true },
+  { N(L2_VIRTUAL),              "virtual", true },
+  { N(L2_VOID),                 "void", true },
+  { N(L2_VOLATILE),             "volatile", true },
+  { N(L2_WCHAR_T),              "wchar_t", true },
+  { N(L2_WHILE),                "while", true },
+  
+  // operators
+  { N(L2_LPAREN),               "(", true },
+  { N(L2_RPAREN),               ")", true },
+  { N(L2_LBRACKET),             "[", true },
+  { N(L2_RBRACKET),             "]", true },
+  { N(L2_ARROW),                "->", true },
+  { N(L2_COLONCOLON),           "::", true },
+  { N(L2_DOT),                  ".", true },
+  { N(L2_BANG),                 "!", true },
+  { N(L2_TILDE),                "~", true },
+  { N(L2_PLUS),                 "+", true },
+  { N(L2_MINUS),                "-", true },
+  { N(L2_PLUSPLUS),             "++", true },
+  { N(L2_MINUSMINUS),           "--", true },
+  { N(L2_AND),                  "&", true },
+  { N(L2_STAR),                 "*", true },
+  { N(L2_DOTSTAR),              ".*", true },
+  { N(L2_ARROWSTAR),            "->*", true },
+  { N(L2_SLASH),                "/", true },
+  { N(L2_PERCENT),              "%", true },
+  { N(L2_LEFTSHIFT),            "<<", true },
+  { N(L2_RIGHTSHIFT),           ">>", true },
+  { N(L2_LESSTHAN),             "<", true },
+  { N(L2_LESSEQ),               "<=", true },
+  { N(L2_GREATERTHAN),          ">", true },
+  { N(L2_GREATEREQ),            ">=", true },
+  { N(L2_EQUALEQUAL),           "==", true },
+  { N(L2_NOTEQUAL),             "!=", true },
+  { N(L2_XOR),                  "^", true },
+  { N(L2_OR),                   "|", true },
+  { N(L2_ANDAND),               "&&", true },
+  { N(L2_OROR),                 "||", true },
+  { N(L2_QUESTION),             "?", true },
+  { N(L2_COLON),                ":", true },
+  { N(L2_EQUAL),                "=", true },
+  { N(L2_STAREQUAL),            "*=", true },
+  { N(L2_SLASHEQUAL),           "/=", true },
+  { N(L2_PERCENTEQUAL),         "%=", true },
+  { N(L2_PLUSEQUAL),            "+=", true },
+  { N(L2_MINUSEQUAL),           "-=", true },
+  { N(L2_ANDEQUAL),             "&=", true },
+  { N(L2_XOREQUAL),             "^=", true },
+  { N(L2_OREQUAL),              "|=", true },
+  { N(L2_LEFTSHIFTEQUAL),       "<<=", true },
+  { N(L2_RIGHTSHIFTEQUAL),      ">>=", true },
+  { N(L2_COMMA),                ",", true },
+  { N(L2_ELLIPSIS),             "...", true },
+  { N(L2_SEMICOLON),            ";", true },
+  { N(L2_LBRACE),               "{", true },
+  { N(L2_RBRACE),               "}", true },
+  
+  // extensions for parsing gnu
+  { N(L2___ATTRIBUTE__),        "__attribute__", true },
+  { N(L2___FUNCTION__),         "__FUNCTION__", true },
+  { N(L2___LABEL__),            "__label__", true },
+  { N(L2___PRETTY_FUNCTION__),  "__PRETTY_FUNCTION__", true },
+  { N(L2___TYPEOF__),           "__typeof__", true },
+  
+  // my own extension
+  { N(L2_OWNER),                "owner_ptr_qualifier", true },
+  
+  // additional tokens to help in specifying disambiguation
+  { N(L2_PREFER_REDUCE),        "PREFER_REDUCE", true },
+  { N(L2_PREFER_SHIFT),         "PREFER_SHIFT", true },
+                                                           
+  // theorem-prover extensions
+  { N(L2_THMPRV_ASSERT),        "thmprv_assert", true },
+  { N(L2_THMPRV_ASSUME),        "thmprv_assume", true },
+  { N(L2_THMPRV_INVARIANT),     "thmprv_invariant", true },
+  { N(L2_IMPLIES),              "==>", true },
+  { N(L2_THMPRV_PRE),           "thmprv_pre", true },
+  { N(L2_THMPRV_POST),          "thmprv_post", true },
+  { N(L2_THMPRV_LET),           "thmprv_let", true },
+  { N(L2_THMPRV_ATTR),          "thmprv_attr", true },
+  { N(L2_THMPRV_FORALL),        "thmprv_forall", true },
+  { N(L2_THMPRV_EXISTS),        "thmprv_exists", true },
+  { N(L2_THMPRV_PURE_ASSERT),   "thmprv_pure_assert", true },
+  { N(L2_THMPRV_BIND),          "thmprv_bind", true },
+  { N(L2_THMPRV_DECL),          "thmprv_decl", true },
+  { N(L2_THMPRV_PREDICATE),     "thmprv_predicate", true },
+};
+
+#undef N
+
+
+struct KeywordMap {
+  char const *spelling;     // token source value
+  Lexer2TokenType tokType;  // destination classification
+};
+
+// map of GNU keywords into ANSI keywords (I don't know and
+// don't care about whatever differences there may be)
+KeywordMap gnuKeywordMap[] = {
+  { "__asm__", L2_ASM },
+  { "__const__", L2_CONST },
+  { "__label__", L2___LABEL__ },
+  { "__inline__", L2_INLINE },
+  { "__signed__", L2_SIGNED },
+  { "__volatile__", L2_VOLATILE },
+  { "__FUNCTION__", L2___FUNCTION__ },
+  { "__PRETTY_FUNCTION__", L2___PRETTY_FUNCTION__ },
+
+  // ones that GNU c has
+  //{ "inline", L2_NAME },
+};
+
+// make C++ keywords not appear to be keywords; need to make this
+// dependent on some flag somewhere ..
+KeywordMap c_KeywordMap[] = {
+  { "bool", L2_NAME },
+  { "catch", L2_NAME },
+  { "class", L2_NAME },
+  { "complex", L2_NAME },
+  { "const_cast", L2_NAME },
+  { "delete", L2_NAME },
+  { "dynamic_cast", L2_NAME },
+  { "explicit", L2_NAME },
+  { "export", L2_NAME },
+  { "friend", L2_NAME },
+  { "mutable", L2_NAME },
+  { "namespace", L2_NAME },
+  { "new", L2_NAME },     // back to recognizing 'new'
+  { "operator", L2_NAME },
+  { "private", L2_NAME },
+  { "protected", L2_NAME },
+  { "public", L2_NAME },
+  { "reinterpret_cast", L2_NAME },
+  { "static_cast", L2_NAME },
+  { "template", L2_NAME },
+  { "this", L2_NAME },
+  { "throw", L2_NAME },
+  { "try", L2_NAME },
+  { "typename", L2_NAME },
+  { "using", L2_NAME },
+  { "virtual", L2_NAME },
+};
+
+
+Lexer2TokenType lookupKeyword(CCLang &lang, rostring keyword)
+{
+  // works?
+  STATIC_ASSERT(TABLESIZE(l2TokTypes) == L2_NUM_TYPES);
+
+  xassert(TABLESIZE(l2TokTypes) == L2_NUM_TYPES);
+
+  {loopi(TABLESIZE(gnuKeywordMap)) {
+    if (0==strcmp(gnuKeywordMap[i].spelling, keyword)) {
+      return gnuKeywordMap[i].tokType;
+    }
+  }}
+
+  if (!lang.recognizeCppKeywords) {
+    {loopi(TABLESIZE(c_KeywordMap)) {
+      if (0==strcmp(c_KeywordMap[i].spelling, keyword)) {
+        return c_KeywordMap[i].tokType;
+      }
+    }}
+  }
+
+  {loopi(L2_NUM_TYPES) {
+    if (l2TokTypes[i].bisonSpelling &&
+        0==strcmp(l2TokTypes[i].spelling, keyword)) {
+      return l2TokTypes[i].tokType;
+    }
+  }}
+
+  return L2_NAME;     // not found, so is user-defined name
+}
+
+char const *l2Tok2String(Lexer2TokenType type)
+{
+  xassert(TABLESIZE(l2TokTypes) == L2_NUM_TYPES);
+  xassert(type < L2_NUM_TYPES);
+
+  return l2TokTypes[type].spelling;
+}
+
+char const *l2Tok2SexpString(Lexer2TokenType type)
+{
+  xassert(TABLESIZE(l2TokTypes) == L2_NUM_TYPES);
+  xassert(type < L2_NUM_TYPES);
+
+  // for sexps let's use the L2_XXX names; among other things,
+  // that will prevent syntactic parentheses from being interpreted
+  // by the sexp reader (which probably wouldn't be all that
+  // terrible, but not what I want...)
+  return l2TokTypes[type].typeName;
+}
+
+
+// list of "%token" declarations for Bison
+void printBisonTokenDecls(bool spellings)
+{
+  loopi(L2_NUM_TYPES) {
+    //if (i == L2_EOF) {
+    //  continue;    // bison doesn't like me to define a token with code 0
+    //}
+    // but: now I'm using these for my own parser, and I want the 0
+
+    Lexer2TokenTypeDesc const &desc = l2TokTypes[i];
+    xassert(desc.tokType == i);    // check correspondence between index and tokType
+
+    printf("%%token %-20s %3d   ", desc.typeName, desc.tokType);
+    if (spellings && desc.bisonSpelling) {
+      printf("\"%s\"\n", desc.spelling);       // string token
+    }
+    else {
+      printf("\n");                            // no spelling.. testing..
+    }
+  }
+}
+
+
+// list of token declarations for my parser
+void printMyTokenDecls()
+{
+  printf("// this list automatically generated by lexer2\n"
+         "\n"
+         "// form:\n"
+         "//   <code> : <name> [<alias>] ;\n"
+         "\n");
+
+  loopi(L2_NUM_TYPES) {
+    Lexer2TokenTypeDesc const &desc = l2TokTypes[i];
+    xassert(desc.tokType == i);    // check correspondence between index and tokType
+
+    printf("  %3d : %-20s ", desc.tokType, desc.typeName);
+    if (desc.bisonSpelling) {
+      printf("\"%s\" ;\n", desc.spelling);       // string token alias
+    }
+    else {
+      printf(";\n");                             // no alias
+    }
+  }
+}
+
+
+// ----------------------- Lexer2Token -------------------------------
+Lexer2Token::Lexer2Token(Lexer2TokenType aType, SourceLoc aLoc)
+  : type(aType),
+    intValue(0),     // legal? apparently..
+    loc(aLoc),
+    sourceMacro(NULL)
+{}
+
+Lexer2Token::~Lexer2Token()
+{}
+
+
+string Lexer2Token::toString(bool asSexp) const
+{
+  return toStringType(asSexp, type);
+}
+
+string Lexer2Token::toStringType(bool asSexp, Lexer2TokenType type) const
+{
+  string tokType;
+  if (!asSexp) {
+    tokType = l2Tok2String(type);
+  }
+  else {
+    tokType = l2Tok2SexpString(type);
+  }
+
+  // get the literal value, if any
+  string litVal;
+  switch (type) {
+    case L2_NAME:
+    case L2_TYPE_NAME:
+    case L2_VARIABLE_NAME:
+    case L2_STRING_LITERAL:
+      litVal = stringc << strValue;
+      break;
+
+    case L2_INT_LITERAL:
+      litVal = stringc << intValue;
+      break;
+
+    default:
+      return tokType;
+  }
+
+  if (!asSexp) {
+    return stringc << tokType << "(" << litVal << ")";
+  }
+  else {
+    return stringc << "(" << tokType << " " << litVal << ")";
+  }
+}
+
+
+string Lexer2Token::unparseString() const
+{
+  switch (type) {
+    case L2_NAME:
+      return string(strValue);
+
+    case L2_STRING_LITERAL:
+      return stringc << quoted(strValue);
+
+    case L2_INT_LITERAL:
+      return stringc << intValue;
+
+    default:
+      return l2Tok2String(type);     // operators and keywords
+  }
+}
+
+
+void Lexer2Token::print() const
+{
+  printf("[L2] Token at %s: %s\n",
+         toString(loc).c_str(), toString().c_str());
+}
+
+
+void quotedUnescape(ArrayStack<char> &dest, rostring src,
+                    char delim, bool allowNewlines)
+{
+  // strip quotes or ticks
+  decodeEscapes(dest, substring(toCStr(src)+1, strlen(src)-2),
+                delim, allowNewlines);
+}
+
+
+// ------------------------- lexer 2 itself ----------------------------
+// jobs performed:
+//  - distinctions are drawn, e.g. keywords and operators
+//  - whitespace and comments are stripped
+//  - meaning is extracted, e.g. for integer literals
+// not performed yet:
+//  - preprocessor actions are performed: inclusion and macro expansion
+void lexer2_lex(Lexer2 &dest, Lexer1 const &src, char const *fname)
+{
+  // keep track of previous L2 token emitted so we can do token
+  // collapsing for string juxtaposition
+  Lexer2Token *prevToken = NULL;
+
+  #ifndef USE_RECLASSIFY
+    #define USE_RECLASSIFY 1    // if nobody tells me, it's probably enabled
+  #endif
+  bool const yieldVarName = !USE_RECLASSIFY || tracingSys("yieldVariableName");
+  bool const debugLexer2 = tracingSys("lexer2");
+
+  // iterate over all the L1 tokens
+  ObjListIter<Lexer1Token> L1_iter(src.tokens);
+  for (; !L1_iter.isDone(); L1_iter.adv()) {
+    // convenient renaming
+    Lexer1Token const *L1 = L1_iter.data();
+
+    if (L1->type == L1_PREPROCESSOR ||     // for now
+        L1->type == L1_WHITESPACE   ||
+        L1->type == L1_COMMENT      ||
+        L1->type == L1_ILLEGAL) {
+      continue;    // filter it out entirely
+    }
+
+    if (L1->type == L1_STRING_LITERAL         &&
+        prevToken != NULL                     &&
+        prevToken->type == L2_STRING_LITERAL) {
+      // coalesce adjacent strings (this is not efficient code..)
+      stringBuilder sb;
+      sb << prevToken->strValue;
+
+      ArrayStack<char> tempString;
+      quotedUnescape(tempString, L1->text, '"',
+                     src.allowMultilineStrings);
+      sb.append(tempString.getArray(), tempString.length());
+
+      prevToken->strValue = dest.idTable.add(sb);
+      continue;
+    }
+
+    // create the object for the yielded token; don't know the type
+    // yet at this point, so I use L2_NAME as a placeholder
+    Lexer2Token *L2 =
+      new Lexer2Token(L2_NAME, L1->loc);
+
+    try {
+      switch (L1->type) {
+        case L1_IDENTIFIER:                                   
+          // get either keyword's type, or L2_NAME
+          L2->type = lookupKeyword(dest.lang, L1->text);
+          if (L2->type == L2_NAME) {
+            // save name's text
+            L2->strValue = dest.idTable.add(L1->text.c_str());
+          }
+          break;
+
+        case L1_INT_LITERAL:
+          L2->type = L2_INT_LITERAL;
+          L2->intValue = strtoul(L1->text.c_str(), NULL /*endptr*/, 0 /*radix*/);
+          break;
+
+        case L1_FLOAT_LITERAL:
+          L2->type = L2_FLOAT_LITERAL;
+          L2->floatValue = new float(atof(L1->text.c_str()));
+          break;
+
+        case L1_STRING_LITERAL: {
+          L2->type = L2_STRING_LITERAL;
+
+          char const *srcText = L1->text.c_str();
+          if (*srcText == 'L') srcText++;
+
+          ArrayStack<char> tmp;
+          quotedUnescape(tmp, srcText, '"',
+                         src.allowMultilineStrings);
+
+          for (int i=0; i<tmp.length(); i++) {
+            if (tmp[i]==0) {
+              cout << "warning: literal string with embedded nulls not handled properly\n";
+              break;
+            }
+          }
+
+          L2->strValue = dest.idTable.add(tmp.getArray());
+          break;
+        }
+
+        case L1_UDEF_QUAL: {
+          L2->type = L2_UDEF_QUAL;
+          L2->strValue = dest.idTable.add(L1->text.c_str());
+          break;
+        }
+
+        case L1_CHAR_LITERAL: {
+          L2->type = L2_CHAR_LITERAL;
+
+          char const *srcText = L1->text.c_str();
+          if (*srcText == 'L') srcText++;
+
+          ArrayStack<char> tmp;
+          quotedUnescape(tmp, srcText, '\'',
+                         false /*allowNewlines*/);
+
+          if (tmp.length() != 1) {
+            xformat("character literal must have 1 char");
+          }
+
+          L2->charValue = tmp[0];
+          break;
+        }
+
+        case L1_OPERATOR:
+          L2->type = lookupKeyword(dest.lang, L1->text);      // operator's type
+          xassert(L2->type != L2_NAME);            // otherwise invalid operator text..
+          break;
+
+        default:
+          xfailure("unknown L1 type");
+      }
+    }
+    catch (xFormat &x) {
+      cout << toString(L1->loc) << ": " << x.cond() << endl;
+      continue;
+    }
+
+    // for testing the performance of the C parser against Bison, I
+    // want to disable the reclassifier, so I need to yield
+    // L2_VARIABLE_NAME directly
+    if (yieldVarName && (L2->type == L2_NAME)) {
+      L2->type = L2_VARIABLE_NAME;
+    }
+
+    // append this token to the running list
+    dest.addToken(L2);
+    prevToken = L2;
+
+    // (debugging) print it
+    if (debugLexer2) {
+      L2->print();
+    }
+  }
+
+  // final token
+  dest.addEOFToken();
+}
+
+
+// --------------------- Lexer2 ------------------
+Lexer2::Lexer2(CCLang &L)
+  : myIdTable(new StringTable()),
+    lang(L),
+    idTable(*myIdTable),      // hope this works..
+    tokens(),
+    tokensMut(tokens),
+    currentToken(tokens)
+{
+  init();
+}
+
+Lexer2::Lexer2(CCLang &L, StringTable &extTable)
+  : myIdTable(NULL),
+    lang(L),
+    idTable(extTable),
+    tokens(),
+    tokensMut(tokens),
+    currentToken(tokens)
+{
+  init();
+}
+
+void Lexer2::init()
+{
+  // init for predictable behavior; esp. for 'loc', which won't
+  // be further updated if source loc info is off
+  type = 0;
+  sval = 0;
+  loc = SL_UNKNOWN;
+}
+
+Lexer2::~Lexer2()
+{
+  if (myIdTable) {
+    delete myIdTable;
+  }
+}
+
+
+SourceLoc Lexer2::startLoc() const
+{
+  if (tokens.isNotEmpty()) {
+    return tokens.firstC()->loc;
+  }
+  else {
+    return SL_UNKNOWN;
+  }
+}
+
+
+inline void Lexer2::copyFields()
+{
+  type = currentToken.data()->type;
+  sval = currentToken.data()->sval;
+  SOURCELOC( loc = currentToken.data()->loc; )
+}
+
+
+void Lexer2::beginReading()
+{
+  currentToken.reset(tokens);
+  copyFields();
+}
+
+
+STATICDEF void Lexer2::nextToken(Lexer2 *ths)
+{
+  ths->currentToken.adv();
+  ths->copyFields();
+}
+       
+LexerInterface::NextTokenFunc Lexer2::getTokenFunc() const
+{
+  return (NextTokenFunc)&Lexer2::nextToken;
+}
+
+
+string Lexer2::tokenDesc() const
+{
+  return currentToken.data()->toStringType(false /*asSexp*/,
+                                           (Lexer2TokenType)LexerInterface::type);
+}
+
+
+string Lexer2::tokenKindDesc(int kind) const
+{                                            
+  return l2Tok2String((Lexer2TokenType)kind);
+}
+
+
+// ------------- experimental interface for (e.g.) bison ------------
+// this is defined by the bison-parser
+extern Lexer2Token const *yylval;
+
+char const *bison_hack_source_fname = NULL;
+
+// returns token types until EOF, at which point L2_EOF is returned
+Lexer2TokenType lexer2_gettoken()
+{
+  static Lexer1 *lexer1 = NULL;
+  static Lexer2 *lexer2 = NULL;
+  static ObjListIter<Lexer2Token> *iter = NULL;
+
+  if (!lexer1) {
+    // do first phase
+    lexer1 = new Lexer1(bison_hack_source_fname);
+    FILE *fp = fopen(bison_hack_source_fname, "r");
+    if (!fp) {
+      throw_XOpen(bison_hack_source_fname);
+    }
+    lexer1_lex(*lexer1, fp);
+
+    if (lexer1->errors > 0) {
+      printf("%d error(s)\n", lexer1->errors);
+      //return L2_EOF;   // done
+    }
+
+    // do second phase
+    lexer2 = new Lexer2(*new CCLang);
+    lexer2_lex(*lexer2, *lexer1, "<stdin>");
+
+    // prepare to return tokens
+    iter = new ObjListIter<Lexer2Token>(lexer2->tokens);
+  }
+
+  if (!iter->isDone()) {
+    // grab type to return
+    yylval = iter->data();
+    Lexer2TokenType ret = iter->data()->type;
+
+    // advance to next token
+    iter->adv();
+
+    // return one we just advanced past
+    return ret;
+  }
+  else {
+    // done; don't bother freeing things
+    yylval = NULL;
+    return L2_EOF;
+  }
+}
+
+
+// ----------------------- testing --------------------
+#ifdef TEST_LEXER2
+
+// no bison-parser present, so define it myself
+Lexer2Token const *yylval = NULL;
+
+int main(int argc, char **argv)
+{
+  SourceLocManager mgr;
+
+  if (argc > 1 && 0==strcmp(argv[1], "-bison")) {
+    printBisonTokenDecls(true /*spellings*/);
+    return 0;
+  }
+
+  if (argc > 1 && 0==strcmp(argv[1], "-myparser")) {
+    printMyTokenDecls();
+    return 0;
+  }
+
+  if (argc < 2) {
+    printf("usage: %s <file>\n", argv[0]);
+    return 0;
+  }
+  bison_hack_source_fname = argv[1];
+
+  while (lexer2_gettoken() != L2_EOF) {
+    yylval->print();
+  }
+
+  return 0;
+}
+
+#endif // TEST_LEXER2

Added: vendor/elsa/current/elkhound/c/lexer2.h
===================================================================
--- vendor/elsa/current/elkhound/c/lexer2.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/lexer2.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,302 @@
+// lexer2.h            see license.txt for copyright and terms of use
+// 2nd phase lexical analyzer; see lexer2.txt
+
+#ifndef __LEXER2_H
+#define __LEXER2_H
+
+#include "lexer1.h"       // Lexer1
+#include "srcloc.h"       // SourceLoc (r)
+#include "strtable.h"     // StringRef, StringTable
+#include "useract.h"      // SemanticValue
+#include "lexerint.h"     // LexerInterface
+
+class CCLang;             // cc_lang.h
+
+// this enumeration defines the terminal symbols that the parser
+// deals with
+enum Lexer2TokenType {
+  // I've avoided collapsing these onto fewer lines because
+  // it makes systematic modification (search & replace)
+  // more difficult
+
+  // end of file
+  L2_EOF=0,
+
+  // non-keyword name
+  L2_NAME,
+
+  // classified name (for e.g. cdecl2)
+  L2_TYPE_NAME,
+  L2_VARIABLE_NAME,
+
+  // literals
+  L2_INT_LITERAL,
+  L2_FLOAT_LITERAL,
+  L2_STRING_LITERAL,
+  L2_CHAR_LITERAL,
+
+  // dsw: user-defined qualifiers
+  L2_UDEF_QUAL,
+
+  // keywords
+  L2_ASM,
+  L2_AUTO,
+  L2_BREAK,
+  L2_BOOL,
+  L2_CASE,
+  L2_CATCH,
+  L2_CDECL,
+  L2_CHAR,
+  L2_CLASS,
+  L2_CONST,
+  L2_CONST_CAST,
+  L2_CONTINUE,
+  L2_DEFAULT,
+  L2_DELETE,
+  L2_DO,
+  L2_DOUBLE,
+  L2_DYNAMIC_CAST,
+  L2_ELSE,
+  L2_ENUM,
+  L2_EXPLICIT,
+  L2_EXPORT,
+  L2_EXTERN,
+  L2_FALSE,
+  L2_FLOAT,
+  L2_FOR,
+  L2_FRIEND,
+  L2_GOTO,
+  L2_IF,
+  L2_INLINE,
+  L2_INT,
+  L2_LONG,
+  L2_MUTABLE,
+  L2_NAMESPACE,
+  L2_NEW,
+  L2_OPERATOR,
+  L2_PASCAL,
+  L2_PRIVATE,
+  L2_PROTECTED,
+  L2_PUBLIC,
+  L2_REGISTER,
+  L2_REINTERPRET_CAST,
+  L2_RETURN,
+  L2_SHORT,
+  L2_SIGNED,
+  L2_SIZEOF,
+  L2_STATIC,
+  L2_STATIC_CAST,
+  L2_STRUCT,
+  L2_SWITCH,
+  L2_TEMPLATE,
+  L2_THIS,
+  L2_THROW,
+  L2_TRUE,
+  L2_TRY,
+  L2_TYPEDEF,
+  L2_TYPEID,
+  L2_TYPENAME,
+  L2_UNION,
+  L2_UNSIGNED,
+  L2_USING,
+  L2_VIRTUAL,
+  L2_VOID,
+  L2_VOLATILE,
+  L2_WCHAR_T,
+  L2_WHILE,
+
+  // operators
+  L2_LPAREN,
+  L2_RPAREN,
+  L2_LBRACKET,
+  L2_RBRACKET,
+  L2_ARROW,
+  L2_COLONCOLON,
+  L2_DOT,
+  L2_BANG,
+  L2_TILDE,
+  L2_PLUS,
+  L2_MINUS,
+  L2_PLUSPLUS,
+  L2_MINUSMINUS,
+  L2_AND,
+  L2_STAR,
+  L2_DOTSTAR,
+  L2_ARROWSTAR,
+  L2_SLASH,
+  L2_PERCENT,
+  L2_LEFTSHIFT,
+  L2_RIGHTSHIFT,
+  L2_LESSTHAN,
+  L2_LESSEQ,
+  L2_GREATERTHAN,
+  L2_GREATEREQ,
+  L2_EQUALEQUAL,
+  L2_NOTEQUAL,
+  L2_XOR,
+  L2_OR,
+  L2_ANDAND,
+  L2_OROR,
+  L2_QUESTION,
+  L2_COLON,
+  L2_EQUAL,
+  L2_STAREQUAL,
+  L2_SLASHEQUAL,
+  L2_PERCENTEQUAL,
+  L2_PLUSEQUAL,
+  L2_MINUSEQUAL,
+  L2_ANDEQUAL,
+  L2_XOREQUAL,
+  L2_OREQUAL,
+  L2_LEFTSHIFTEQUAL,
+  L2_RIGHTSHIFTEQUAL,
+  L2_COMMA,
+  L2_ELLIPSIS,
+  L2_SEMICOLON,
+  L2_LBRACE,
+  L2_RBRACE,
+
+  // GNU extensions
+  L2___ATTRIBUTE__,
+  L2___FUNCTION__,
+  L2___LABEL__,
+  L2___PRETTY_FUNCTION__,
+  L2___TYPEOF__,
+
+  // my extensions
+  L2_OWNER,
+
+  // dummy terminals used for precedence games
+  L2_PREFER_REDUCE,
+  L2_PREFER_SHIFT,
+
+  // theorem prover extensions
+  L2_THMPRV_ASSERT,
+  L2_THMPRV_ASSUME,
+  L2_THMPRV_INVARIANT,
+  L2_IMPLIES,
+  L2_THMPRV_PRE,
+  L2_THMPRV_POST,
+  L2_THMPRV_LET,
+  L2_THMPRV_ATTR,
+  L2_THMPRV_FORALL,
+  L2_THMPRV_EXISTS,
+  L2_THMPRV_PURE_ASSERT,
+  L2_THMPRV_BIND,
+  L2_THMPRV_DECL,
+  L2_THMPRV_PREDICATE,
+
+  L2_NUM_TYPES
+};
+
+// yield name as above from the int value
+char const *l2Tok2String(Lexer2TokenType type);
+
+
+// represent a unit of input to the parser
+class Lexer2Token {
+public:
+  // kind of token
+  Lexer2TokenType type;
+
+  // semantic value; 'sval' is essentially an owner until the parser
+  // reads it, and then it's a serf; so in fact it's treated as a serf
+  // throughout, with corresponding leak potential
+  union {
+    int intValue;                // for L2_INT_LITERALs
+    
+    // this is an owner pointer.. I'll fix this when I overhaul L2
+    float *floatValue;           // for L2_FLOAT_LITERALs
+
+    char charValue;              // for L2_CHAR_LITERALs
+    StringRef strValue;          // for L2_NAMEs and L2_STRING_LITERALs; refers to Lexer2::idTable
+    SemanticValue sval;          // union with above means we can extract from this
+  };
+
+  // TODO: handle strings with embedded nulls
+
+  // where token appears, or where macro reference which produced it appears
+  SourceLoc loc;
+
+  // macro definition that produced this token, or NULL
+  Lexer1Token *sourceMacro;      // (serf)
+
+public:
+  Lexer2Token(Lexer2TokenType type, SourceLoc loc);
+  ~Lexer2Token();
+
+  // debugging
+  void print() const;
+  string toString(bool asSexp=false) const;
+  string toStringType(bool asSexp, Lexer2TokenType type) const;
+  string unparseString() const;  // return the source text that generated this token
+};
+
+
+// lexing state
+class Lexer2 : public LexerInterface {
+private:
+  // locally-created string table, if we're not given one explicitly
+  StringTable *myIdTable;
+
+public:
+  // language options
+  CCLang &lang;
+
+  // storage of all the identifiers we encounter
+  StringTable &idTable;
+
+  // output token stream
+  ObjList<Lexer2Token> tokens;
+
+  // for appending new tokens
+  ObjListMutator<Lexer2Token> tokensMut;
+  
+  // for reading the token stream
+  ObjListIter<Lexer2Token> currentToken;
+
+private:            
+  // copy from currentToken to LexerInterface fields
+  void copyFields();
+
+  // shared piece of ctor
+  void init();
+
+public:
+  Lexer2(CCLang &lang);                                // table is created locally
+  Lexer2(CCLang &lang, StringTable &externalTable);    // table given externally
+  ~Lexer2();
+
+  SourceLoc startLoc() const;
+
+  void addToken(Lexer2Token *tok)
+    { tokensMut.append(tok); }
+  void addEOFToken()
+    { addToken(new Lexer2Token(L2_EOF, SL_UNKNOWN)); }
+               
+  // reset the 'currentToken' so the parser can begin reading tokens
+  void beginReading();
+
+  // get next token
+  static void nextToken(Lexer2 *ths);
+
+  // LexerInterface functions
+  virtual NextTokenFunc getTokenFunc() const;
+  virtual string tokenDesc() const;
+  virtual string tokenKindDesc(int kind) const;
+};
+
+
+// interface to 2nd phase lexical analysis
+// (will change; for now I'm only going to process single files)
+void lexer2_lex(Lexer2 &dest, Lexer1 const &src, char const *fname);
+
+
+// parser's interface to lexer2 (experimental)
+extern Lexer2Token const *yylval;      // semantic value for returned token, or NULL for L2_EOF
+extern "C" {
+  Lexer2TokenType lexer2_gettoken();
+}
+
+
+#endif // __LEXER2_H

Added: vendor/elsa/current/elkhound/c/main.cc
===================================================================
--- vendor/elsa/current/elkhound/c/main.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/main.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,156 @@
+// main.cc            see license.txt for copyright and terms of use
+// toplevel driver for the C parser
+
+#include <iostream.h>     // cout
+#include <stdlib.h>       // exit
+
+#include "trace.h"        // traceAddSys
+#include "parssppt.h"     // ParseTreeAndTokens, treeMain
+#include "srcloc.h"       // SourceLocManager
+#include "ckheap.h"       // malloc_stats
+#include "c_env.h"        // Env
+#include "c.ast.gen.h"    // C AST (r)
+#include "strutil.h"      // plural
+#include "cc_lang.h"      // CCLang
+#include "treeout.h"      // treeOut
+#include "parsetables.h"  // ParseTables
+#include "c.gr.gen.h"     // CParse
+#include "cyctimer.h"     // CycleTimer
+
+
+// no bison-parser present, so need to define this
+Lexer2Token const *yylval = NULL;
+
+
+void if_malloc_stats()
+{
+  if (tracingSys("malloc_stats")) {
+    malloc_stats();
+  }
+}
+
+
+void doit(int argc, char **argv)
+{
+  traceAddSys("progress");
+  //traceAddSys("parse-tree");
+
+  // this is useful for emacs' outline mode, because if the file
+  // doesn't begin with a heading, it collapses the starting messages
+  // and doesn't like to show them again
+  treeOut(1) << "beginning of output      -*- outline -*-\n";
+
+  if_malloc_stats();
+
+  SourceLocManager mgr;
+
+  // string table for storing parse tree identifiers
+  StringTable strTable;
+
+  // parsing language options
+  CCLang lang;
+  lang.ANSI_Cplusplus();
+
+
+  // --------------- parse --------------
+  TranslationUnit *unit;
+  {
+    SemanticValue treeTop;
+    ParseTreeAndTokens tree(lang, treeTop, strTable);
+
+    CParse *user = new CParse(strTable, lang);
+    tree.userAct = user;
+
+    traceProgress() << "building parse tables from internal data\n";
+    ParseTables *tables = user->makeTables();
+    tree.tables = tables;
+
+    CycleTimer timer;
+
+    if (!treeMain(tree, argc, argv,
+          "  additional flags for cparse:\n"
+          "    malloc_stats       print malloc stats every so often\n"
+          "    stopAfterParse     stop after parsing\n"
+          "    printAST           print AST after parsing\n"
+          "    stopAfterTCheck    stop after typechecking\n"
+          "    printTypedAST      print AST with type info\n"
+          "    tcheck             print typechecking info\n"
+          "")) {
+      // parse error
+      exit(2);
+    }
+
+    traceProgress() << "done parsing (" << timer.elapsed() << ")\n";
+
+    traceProgress(2) << "final parse result: " << treeTop << endl;
+    unit = (TranslationUnit*)treeTop;
+
+    //unit->debugPrint(cout, 0);
+
+    delete user;
+    delete tables;
+  }
+
+  checkHeap();
+
+  // print abstract syntax tree
+  if (tracingSys("printAST")) {
+    unit->debugPrint(cout, 0);
+  }
+
+  if (tracingSys("stopAfterParse")) {
+    return;
+  }
+
+                 
+  // --------- declarations provided automatically -------
+  Variable mem(HERE_SOURCELOC, strTable.add("mem"),
+               new PointerType(PO_POINTER, CV_NONE,
+                 &CVAtomicType::fixed[ST_INT]), DF_NONE);
+
+  // ---------------- typecheck -----------------
+  {
+    traceProgress() << "type checking...\n";
+    Env env(strTable, lang);
+    env.addVariable(mem.name, &mem);
+    unit->tcheck(env);
+    traceProgress(2) << "done type checking\n";
+
+    // print abstract syntax tree annotated with types
+    if (tracingSys("printTypedAST")) {
+      unit->debugPrint(cout, 0);
+    }
+
+    if (env.getErrors() != 0) {
+      int n = env.getErrors();
+      cout << "there " << plural(n, "was") << " " << env.getErrors() 
+           << " typechecking " << plural(n, "error") << "\n";
+      exit(4);
+    }
+
+    if (tracingSys("stopAfterTCheck")) {
+      return;
+    }
+  }
+
+
+  //malloc_stats();
+
+  // delete the tree
+  delete unit;
+  strTable.clear();
+
+  //checkHeap();
+  //malloc_stats();
+
+  traceRemoveAll();
+}
+
+int main(int argc, char **argv)
+{
+  doit(argc, argv);
+
+  //malloc_stats();
+
+  return 0;
+}

Added: vendor/elsa/current/elkhound/c/parssppt.cc
===================================================================
--- vendor/elsa/current/elkhound/c/parssppt.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/parssppt.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,169 @@
+// parssppt.cc            see license.txt for copyright and terms of use
+// code for parssppt.h
+
+#include "parssppt.h"     // this module
+#include "glr.h"          // toplevelParse
+#include "trace.h"        // traceProcessArg
+#include "syserr.h"       // xsyserror
+
+#include <stdlib.h>       // exit
+
+
+// ---------------------- ParseTree --------------------
+ParseTreeAndTokens::ParseTreeAndTokens(CCLang &L, SemanticValue &top)
+  : treeTop(top),
+    lexer2(L),
+    userAct(NULL),
+    tables(NULL)
+{}
+
+ParseTreeAndTokens::ParseTreeAndTokens(CCLang &L, SemanticValue &top,
+                                       StringTable &extTable)
+  : treeTop(top),
+    lexer2(L, extTable),
+    userAct(NULL),
+    tables(NULL)
+{}
+
+ParseTreeAndTokens::~ParseTreeAndTokens()
+{}
+
+
+// ---------------------- other support funcs ------------------
+// process the input file, and yield a parse graph
+bool glrParseNamedFile(GLR &glr, Lexer2 &lexer2, SemanticValue &treeTop,
+                       char const *inputFname)
+{
+  // do first phase lexer
+  traceProgress() << "lexical analysis...\n";
+  traceProgress(2) << "lexical analysis stage 1...\n";
+  Lexer1 lexer1(inputFname);
+  {
+    FILE *input = fopen(inputFname, "r");
+    if (!input) {
+      xsyserror("fopen", inputFname);
+    }
+
+    lexer1_lex(lexer1, input);
+    fclose(input);
+
+    if (lexer1.errors > 0) {
+      printf("L1: %d error(s)\n", lexer1.errors);
+      return false;
+    }
+  }
+
+  // do second phase lexer
+  traceProgress(2) << "lexical analysis stage 2...\n";
+  lexer2_lex(lexer2, lexer1, inputFname);
+
+  // parsing itself
+  lexer2.beginReading();
+  return glr.glrParse(lexer2, treeTop);
+}
+
+
+bool toplevelParse(ParseTreeAndTokens &ptree, char const *inputFname)
+{
+  // parse
+  xassert(ptree.userAct != NULL);    // must have been set by now
+  xassert(ptree.tables != NULL);
+
+  GLR glr(ptree.userAct, ptree.tables);
+
+  // parse input
+  return glrParseNamedFile(glr, ptree.lexer2, ptree.treeTop, inputFname);
+}
+
+
+// hack: need classifier to act like the one for Bison
+class SimpleActions : public TrivialUserActions {
+public:
+  virtual ReclassifyFunc getReclassifier();
+  static int reclassifyToken(UserActions *ths,
+    int oldTokenType, SemanticValue sval);
+};
+
+UserActions::ReclassifyFunc SimpleActions::getReclassifier()
+{
+  if (tracingSys("identityReclassify")) {
+    // don't reclassify anything
+    return &TrivialUserActions::reclassifyToken;
+  }
+  else {
+    // reclassify as if typedef's weren't possible
+    return &SimpleActions::reclassifyToken;
+  }
+}
+
+STATICDEF int SimpleActions::reclassifyToken(UserActions *, int type, SemanticValue)
+{
+  if (type == L2_NAME) {
+    return L2_VARIABLE_NAME;
+  }
+  else {
+    return type;
+  }
+}
+
+
+char *processArgs(int argc, char **argv, char const *additionalInfo) {
+  // remember program name
+  char const *progName = argv[0];
+
+  // process args
+  while (argc >= 2) {
+    if (traceProcessArg(argc, argv)) {
+      continue;
+    }
+#if 0
+    else if (0==strcmp(argv[1], "-sym") && argc >= 3) {
+      symOfInterestName = argv[2];
+      argc -= 2;
+      argv += 2;
+    }   
+#endif // 0
+    else {
+      break;     // didn't find any more options
+    }
+  }
+
+  if (argc != 2) {
+    cout << "usage: [env] " << progName << " [options] input-file\n"
+      "  env:\n"
+      "    SYM_OF_INTEREST symbol to watch during analysis\n"
+      "  options:\n"
+      "    -tr <sys>:      turn on tracing for the named subsystem\n"
+      //"    -sym <sym>: name the \"symbol of interest\"\n"
+      "  useful tracing flags:\n"
+      "    parse           print shift/reduce steps of parsing algorithm\n"
+      "    grammar         echo the grammar\n"
+      "    ambiguities     print ambiguities encountered during parsing\n"
+      "    conflict        SLR(1) shift/reduce conflicts (fork points)\n"
+      "    itemsets        print the sets-of-items DFA\n"
+      "    ... the complete list is in parsgen.txt ...\n"
+         << (additionalInfo? additionalInfo : "");
+    exit(argc==1? 0 : 2);    // error if any args supplied
+  }
+
+  return argv[1];
+}
+
+void maybeUseTrivialActions(ParseTreeAndTokens &ptree) 
+{
+  if (tracingSys("trivialActions")) {
+    // replace current actions with trivial actions
+    //delete ptree.userAct;      // the caller does this
+    ptree.userAct = new SimpleActions;
+    cout << "using trivial (er, simple..) actions\n";
+  }
+}
+
+// useful for simple treewalkers
+bool treeMain(ParseTreeAndTokens &ptree, int argc, char **argv,
+              char const *additionalInfo)
+{
+  char const *positionalArg = processArgs(argc, argv, additionalInfo);
+  maybeUseTrivialActions(ptree);
+  return toplevelParse(ptree, positionalArg);
+}

Added: vendor/elsa/current/elkhound/c/parssppt.h
===================================================================
--- vendor/elsa/current/elkhound/c/parssppt.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/parssppt.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,58 @@
+// parssppt.h            see license.txt for copyright and terms of use
+// parser-support routines, for use at runtime while processing
+// the generated Parse tree
+//
+// this module is primarily for use with the C and C++ grammars,
+// but has been pressed into service for a few other uses too;
+// new grammars and parsers should probably not use this
+
+#ifndef __PARSSPPT_H
+#define __PARSSPPT_H
+
+#include "lexer2.h"       // Lexer2
+#include "useract.h"      // SemanticValue, UserAction
+
+class ParseTables;
+
+
+// ----------------- helpers for analysis drivers ---------------
+// a self-contained parse tree (or parse DAG, as the case may be)
+class ParseTreeAndTokens {
+public:
+  // reference to place to store final semantic value
+  SemanticValue &treeTop;
+
+  // we need a place to put the ground tokens
+  Lexer2 lexer2;
+
+  // parse parameter
+  UserActions *userAct;            // (serf)
+
+  // parse tables (or NULL)
+  ParseTables *tables;             // (serf)
+
+public:
+  ParseTreeAndTokens(CCLang &lang, SemanticValue &top);
+  ParseTreeAndTokens(CCLang &lang, SemanticValue &top, StringTable &extTable);
+  ~ParseTreeAndTokens();
+};
+
+
+// dsw: what is this?
+//  // given grammar and input, yield a parse tree
+//  // returns false on error
+//  bool toplevelParse(ParseTreeAndTokens &ptree, char const *grammarFname,
+//                     char const *inputFname, char const *symOfInterestName);
+
+bool toplevelParse(ParseTreeAndTokens &ptree, char const *inputFname);
+
+char *processArgs(int argc, char **argv, char const *additionalInfo = NULL);
+
+void maybeUseTrivialActions(ParseTreeAndTokens &ptree);
+
+// useful for simple treewalkers; false on error
+bool treeMain(ParseTreeAndTokens &ptree, int argc, char **argv,
+              char const *additionalInfo = NULL);
+
+
+#endif // __PARSSPPT_H

Added: vendor/elsa/current/elkhound/c/paths.cc
===================================================================
--- vendor/elsa/current/elkhound/c/paths.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/paths.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,750 @@
+// paths.cc            see license.txt for copyright and terms of use
+// code for paths.h
+
+#include "paths.h"       // this module
+
+#include "c.ast.gen.h"   // C AST
+#include "sobjlist.h"    // SObjList
+#include "objlist.h"     // ObjList
+#include "c_env.h"       // Env
+#include "trace.h"       // tracingSys
+#include "treeout.h"     // treeOut
+
+
+// one thing to note about constness: when an AST node contains a field
+// to store the path count, the counting function is declared non-const;
+// but when the AST node does not store the count, the counting function
+// is declared to accept a const*
+
+
+// prototypes
+void findPathRoots(SObjList<Statement> &list, TF_func const *func);
+void findPathRoots(SObjList<Statement> &list, Statement const *stmt);
+int countPaths(Env &env, TF_func *func);
+int countPathsFrom(Env &env, SObjList<Statement> &path,
+                   Statement *node, bool isContinue);
+int countExprPaths(Initializer *init);
+void printPaths(TF_func const *func);
+void printPathFrom(SObjList<Statement /*const*/> &path, int index,
+                   Statement const *node, bool isContinue);
+void printPath(SObjList<Statement /*const*/> &path, char const *label);
+
+
+// watch for overflow
+static int mult(int a, int b)
+{
+  int r = a*b;
+  if (a>0 && b>0 && (r < a || r < b)) {
+    xfailure(stringc << "arithmetic overflow: " << a << " * " << b);
+  }
+  if (r > 1000) {
+    cout << r << " is more than 1000 paths!\n";
+  }
+  return r;
+}
+
+
+// --------------------- finding roots ----------------------
+void findPathRoots(SObjList<Statement> &list, TF_func const *func)
+{
+  list.reverse();
+  list.prepend(func->body);
+  findPathRoots(list, func->body);
+  list.reverse();
+}
+
+
+void findPathRoots(SObjList<Statement> &list, Statement const *stmt)
+{
+  ASTSWITCHC(Statement, stmt) {
+    ASTCASEC(S_label, l) {
+      findPathRoots(list, l->s);
+    }
+    ASTNEXTC(S_case, c) {
+      findPathRoots(list, c->s);
+    }
+    ASTNEXTC(S_caseRange, c) {
+      findPathRoots(list, c->s);
+    }
+    ASTNEXTC(S_default, d) {
+      findPathRoots(list, d->s);
+    }
+    ASTNEXTC(S_compound, c) {
+      FOREACH_ASTLIST(Statement, c->stmts, iter) {
+        findPathRoots(list, iter.data());
+      }
+    }
+    ASTNEXTC(S_if, i) {
+      findPathRoots(list, i->thenBranch);
+      findPathRoots(list, i->elseBranch);
+    }
+    ASTNEXTC(S_switch, s) {
+      findPathRoots(list, s->branches);
+    }
+    ASTNEXTC(S_while, w) {
+      findPathRoots(list, w->body);
+    }
+    ASTNEXTC(S_doWhile, d) {
+      findPathRoots(list, d->body);
+    }
+    ASTNEXTC(S_for, f) {
+      findPathRoots(list, f->init);
+      findPathRoots(list, f->body);
+    }
+    ASTNEXTC(S_invariant, i) {
+      list.prepend(const_cast<S_invariant*>(i));       // action!
+    }
+    ASTENDCASECD
+  }
+}
+
+
+// ------------------------ counting paths ------------------
+int countPaths(Env &env, TF_func *func)
+{
+  func->numPaths=0;
+
+  // enumerate the roots
+  findPathRoots(func->roots, func);
+
+  // enumerate all paths from each root
+  SMUTATE_EACH_OBJLIST(Statement, func->roots, iter) {
+    Statement *s = iter.data();
+
+    SObjList<Statement> path;
+    countPathsFrom(env, path, s, false /*isContinue*/);
+    func->numPaths += s->numPaths;
+  }
+
+  return func->numPaths;
+}
+
+
+// need the 'path' to detect circularity;
+// this function has similar structure to 'printPathFrom', below
+int countPathsFrom(Env &env, SObjList<Statement> &path,
+                   Statement *node, bool isContinue)
+{
+  if (node->kind() != Statement::S_INVARIANT &&
+      path.contains(node)) {
+    env.warnLoc(node->loc, "circular path");
+    if (tracingSys("circular")) {
+      // print the circular path
+      SFOREACH_OBJLIST(Statement, path, iter) {
+        cout << "  " << toString(iter.data()->loc) << endl;
+      }
+    }
+    return 1;
+  }
+
+  path.prepend(node);
+  int ret;
+
+  if (node->kind() == Statement::S_INVARIANT &&
+      path.count() > 1) {
+    // we've reached an invariant point, so the path stops here;
+    // but we don't change node->paths since that is for the #
+    // of paths from 'node' as a path *start*, not end
+    ret = 1;
+  }
+
+  else {
+    // retrieve all successors of this node
+    VoidList successors;
+    node->getSuccessors(successors, isContinue);
+
+    if (successors.isEmpty()) {
+      // this is a return statement (or otherwise end of function)
+      ret = 1;
+    }
+    else {
+      // initially, there are 0 paths from here
+      ret = 0;
+
+      // consider each choice
+      for (VoidListIter iter(successors); !iter.isDone(); iter.adv()) {
+        void *np = iter.data();
+        // unfortunately I can't easily parameterize a voidlist by whether
+        // my interpretation of a field of its contents is 'const' ...
+        Statement *s = const_cast<Statement*>(nextPtrStmt(np));
+        int ct = countPathsFrom(env, path, s, nextPtrContinue(np));
+
+        // add all paths from this successor to our total
+        ret += ct;
+      }
+    }
+
+    // now, every path through expressions in this statement will be
+    // (conservatively) considered to possibly be followed by any control
+    // flow path *from* this statement
+    ret = mult(ret, countExprPaths(node, isContinue));
+
+    // in this branch (only), we write the # of paths into the statement
+    node->numPaths = ret;
+  }
+
+  path.removeFirst();
+  return ret;
+}
+
+
+// ---------------------- printing paths ---------------------
+void printPaths(TF_func const *func)
+{
+  // enumerate all paths from each root
+  SFOREACH_OBJLIST(Statement, func->roots, iter) {
+    Statement const *s = iter.data();
+    cout << "root at " << toString(iter.data()->loc) << ":\n";
+
+    // the whole point of counting the paths was so I could
+    // so easily get a handle on all of them, to be able to
+    // write a nice loop like this:
+    for (int i=0; i < s->numPaths; i++) {
+      cout << "  path " << i << ":\n";
+      SObjList<Statement /*const*/> path;
+      printPathFrom(path, i, s, false /*isContinue*/);
+    }
+  }
+}
+
+
+int numPathsThrough(Statement const *stmt)
+{
+  // how many paths lead from 'stmt'?  usually just s->numPaths, but
+  // if it is a path cutpoint then there's exactly one path from 'stmt'
+  int ret = stmt->isS_invariant()? 1 : stmt->numPaths;
+  return ret;
+}
+
+
+// abstract the "4" slightly..
+//#define PATHOUT treeOut(4)
+// actually, I didn't want these as headings at all..
+#define PATHOUT cout << "  "
+
+// want 'path' to detect circularity (for debugging);
+// this function has similar structure to 'countPathsFrom', above
+void printPathFrom(SObjList<Statement /*const*/> &path, int index,
+                   Statement const *node, bool isContinue)
+{
+  // validate 'index'
+  int exprPaths = countExprPaths(node, isContinue);
+  xassert(exprPaths >= 1);
+  xassert(0 <= index && index < node->numPaths);
+    // this used to say node->numPaths * exprPaths, but it seems clear
+    // that numPaths *already* includes the contribution from exprPaths
+
+  // print this node
+  PATHOUT << toString(node->loc) << ": "
+          << node->kindName() << endl;
+
+  // debugging check
+  if (path.contains(node)) {
+    PATHOUT << "CIRCULAR path\n";
+    return;
+  }
+  path.prepend(const_cast<Statement*>(node));
+
+  // follow one expression path in this statement
+  printExprPath(index % exprPaths, node, isContinue);
+  index = index / exprPaths;
+
+  // retrieve all successors of this node
+  VoidList successors;
+  node->getSuccessors(successors, isContinue);
+
+  if (successors.isEmpty()) {
+    // this is a return statement (or otherwise end of function)
+    xassert(index == 0);
+    PATHOUT << "path ends at a return\n";
+  }
+  else {
+    // consider each choice
+    // largely COPIED to vcgen.cc:Statement::vcgenPath
+    for (VoidListIter iter(successors); !iter.isDone(); iter.adv()) {
+      void *np = iter.data();
+      Statement const *s = nextPtrStmt(np);
+      int pathsFromS = numPathsThrough(s);
+
+      // are we going to follow 's'?
+      if (index < pathsFromS) {
+        // yes; is 's' an invariant?
+        if (s->isS_invariant()) {
+          // terminate the path; print final node
+          PATHOUT << toString(s->loc) << ": "
+                  << s->kindName() << endl;
+          PATHOUT << "path ends at an invariant\n";
+        }
+        else {
+          // continue the path
+          printPathFrom(path, index, s, nextPtrContinue(np));
+        }
+        index = 0;       // remember that we found a path to follow
+        break;
+      }
+
+      else {
+        // no; factor out s's contribution to the path index
+        index -= pathsFromS;
+      }
+    }
+
+    // make sure we followed *some* path
+    xassert(index == 0);
+  }
+
+  path.removeFirst();
+}
+
+
+// --------- counting/print expression paths in statements ------------
+int countExprPaths(Statement const *stmt, bool isContinue)
+{
+  ASTSWITCHC(Statement, stmt) {
+    ASTCASEC(S_expr, e) {
+      return e->expr->numPaths1();
+    }
+    ASTNEXTC(S_if, i) {
+      return i->cond->numPaths1();
+    }
+    ASTNEXTC(S_switch, s) {
+      return s->expr->numPaths1();
+    }
+    ASTNEXTC(S_while, w) {
+      return w->cond->numPaths1();
+    }
+    ASTNEXTC(S_doWhile, d) {
+      if (isContinue) {
+        // enter at the guard, so as many paths as paths through guard
+        return d->cond->numPaths1();
+      }
+      else {
+        // enter at top, no expr is evaluated
+        return 1;
+      }
+    }
+    ASTNEXTC(S_for, f) {
+      if (isContinue) {
+        // enter just before inc and test
+        return mult(f->after->numPaths1(), f->cond->numPaths1());
+      }
+      else {
+        // enter at init, immediately apply guard
+        //return mult(countExprPaths(f->init, false), f->cond->numPaths1());
+        // UPDATE: my CFG does the init before the 'for'
+        return f->cond->numPaths1();
+      }
+    }
+    ASTNEXTC(S_return, r) {
+      if (r->expr) {
+        return r->expr->numPaths1();
+      }
+      else {
+        return 1;
+      }
+    }
+    ASTNEXTC(S_decl, d) {
+      // somewhat complicated because we need to dig around in the
+      // declaration for paths through initializing expressions
+      int ret = 1;
+      FOREACH_ASTLIST(Declarator, d->decl->decllist, dcltr) {
+        Initializer const *init = dcltr.data()->init;
+        if (init) {
+          ret = mult(ret, countExprPaths(init));
+        }
+      }
+      return ret;
+    }
+    ASTDEFAULTC {
+      // no expressions in the statement, only 1 path
+      return 1;
+    }
+    ASTENDCASEC
+  }
+}
+
+
+void printExprPath(int index, Statement const *stmt, bool isContinue)
+{
+  xassert(index >= 0);
+
+  ASTSWITCHC(Statement, stmt) {
+    ASTCASEC(S_expr, e) {
+      printPath(index, e->expr);
+    }
+    ASTNEXTC(S_if, i) {
+      printPath(index, i->cond);
+    }
+    ASTNEXTC(S_switch, s) {
+      printPath(index, s->expr);
+    }
+    ASTNEXTC(S_while, w) {
+      printPath(index, w->cond);
+    }
+    ASTNEXTC(S_doWhile, d) {
+      if (isContinue) {
+        // enter at the guard, so as many paths as paths through guard
+        printPath(index, d->cond);
+      }
+      else {
+        // enter at top, no expr is evaluated
+        xassert(index==0);
+      }
+    }
+    ASTNEXTC(S_for, f) {
+      int modulus = f->cond->numPaths1();
+      if (isContinue) {
+        // enter just before inc and test
+        printPath(index / modulus, f->after);
+        printPath(index % modulus, f->cond);
+      }
+      else {
+        // enter at init, immediately apply guard
+        //printExprPath(index / modulus, f->init, false);
+        // UPDATE: CFG does 'init' before 'for'
+        xassert(index < modulus);
+        printPath(index /* % modulus*/, f->cond);
+      }
+    }
+    ASTNEXTC(S_return, r) {
+      if (r->expr) {
+        printPath(index, r->expr);
+      }
+      else {
+        xassert(index==0);
+      }
+    }
+    ASTNEXTC(S_decl, d) {
+      // somewhat complicated because we need to dig around in the
+      // declaration for paths through initializing expressions
+      int paths = 1;
+      FOREACH_ASTLIST(Declarator, d->decl->decllist, dcltr) {
+        Initializer const *init = dcltr.data()->init;
+        if (init) {
+          paths = countExprPaths(init);
+          printExprPath(index % paths, init);
+          index = index / paths;
+        }
+      }
+
+      // if we entered the loop at all, this ensures the last iteration
+      // consumed all of 'index'; if we never entered the loop, this
+      // checks that index was 0
+      xassert(index < paths);
+    }
+    ASTDEFAULTC {
+      // no expressions in the statement, only 1 path
+      xassert(index==0);
+    }
+    ASTENDCASEC
+  }
+}
+
+
+// --------------- count/print paths through initializers --------------
+int countExprPaths(Initializer const *init)
+{
+  ASTSWITCHC(Initializer, init) {
+    ASTCASEC(IN_expr, ie) {
+      return ie->e->numPaths1();
+    }
+    ASTNEXTC(IN_compound, ic) {
+      int ret = 1;
+      FOREACH_ASTLIST(Initializer, ic->inits, iter) {
+        ret = mult(ret, countExprPaths(iter.data()));
+      }
+      return ret;
+    }
+    ASTDEFAULTC {
+      xfailure("bad code");
+      return 0;
+    }
+    ASTENDCASEC
+  }
+}
+
+
+void printExprPath(int index, Initializer const *init)
+{
+  ASTSWITCHC(Initializer, init) {
+    ASTCASEC(IN_expr, ie) {
+      printPath(index, ie->e);
+    }
+    ASTNEXTC(IN_compound, ic) {
+      // this loop is very similar to the one above for S_decl
+      int paths = 1;
+      FOREACH_ASTLIST(Initializer, ic->inits, iter) {
+        Initializer const *i = iter.data();
+        paths = countExprPaths(i);
+        printExprPath(index % paths, i);
+        index = index / paths;
+      }
+      xassert(index < paths);
+    }
+    ASTENDCASECD
+  }
+}
+
+
+// -------------- count/print paths through expressions --------------
+int countPaths(Env &env, Expression *ths)
+{
+  // default: 1 path, no side effects, is already set: 0
+  xassert(ths->numPaths == 0);
+  int numPaths = 0;
+
+  // don't bother counting paths in predicates, where everything
+  // is side-effect-free
+  if (env.inPredicate) {
+    return 0;
+  }
+
+  #define SIDE_EFFECT() numPaths = max(numPaths,1) /* user ; */
+
+  ASTSWITCH(Expression, ths) {
+    ASTCASE(E_funCall, ths) {
+      numPaths = ths->func->numPaths;
+
+      FOREACH_ASTLIST_NC(Expression, ths->args, iter) {
+        // compute # of paths
+        int argPaths = iter.data()->numPaths;
+        if (argPaths > 0) {
+          if (numPaths > 0) {
+            env.warn("more than one argument expression has side effects");
+            numPaths = mult(numPaths, argPaths);
+          }
+          else {
+            numPaths = argPaths;
+          }
+        }
+      }
+
+      // the call itself counts as a side-effecting expression (unless I
+      // add an annotation to declare something as "functional" ...)
+      SIDE_EFFECT();
+    }
+    ASTNEXT(E_fieldAcc, ths) {
+      numPaths = ths->obj->numPaths;
+    }
+    ASTNEXT(E_sizeof, ths) {
+      PRETEND_USED(ths);     // silence warning
+      numPaths = 0;
+    }
+    ASTNEXT(E_unary, ths) {
+      numPaths = ths->expr->numPaths;
+    }
+    ASTNEXT(E_effect, ths) {
+      numPaths = ths->expr->numPaths;
+      SIDE_EFFECT();
+    }
+    ASTNEXT(E_binary, ths) {
+      // there are at least as many paths as paths through left-hand side
+      numPaths = ths->e1->numPaths;
+
+      if (ths->e2->numPaths == 0) {
+        // if the RHS has no side effects, it contributes nothing to the
+        // paths computation, regardless of whether 'op' is short-circuit,
+        // so we just propagate the LHS's numPaths
+      }
+
+      else {
+        // if the RHS has a side effect, this expression as a whole might
+        // have a side effect
+        SIDE_EFFECT();
+
+        if (ths->op==BIN_AND || ths->op==BIN_OR) {
+          // path computation with short-circuit evaluation: for each LHS
+          // path, we could take any one of the RHS paths, *or* skip
+          // evaluating the RHS altogether
+          numPaths = mult(numPaths, (1 + ths->e2->numPaths));
+        }
+
+        else {
+          // path computation without short-circuit evaluation: we can
+          // take any combination of LHS and RHS paths
+          numPaths = mult(numPaths, ths->e2->numPaths);
+        }
+      }
+    }
+    ASTNEXT(E_addrOf, ths) {
+      numPaths = ths->expr->numPaths;
+    }
+    ASTNEXT(E_deref, ths) {
+      numPaths = ths->ptr->numPaths;
+    }
+    ASTNEXT(E_cast, ths) {
+      numPaths = ths->expr->numPaths;
+    }
+    ASTNEXT(E_cond, ths) {
+      // start with # of paths through conditional
+      numPaths = ths->cond->numPaths;
+
+      if (ths->th->numPaths == 0 && ths->el->numPaths == 0) {
+        // no side effects in either branch; we're good to go
+      }
+
+      else {
+        // since at least one branch as a side effect, let's say
+        // all three components have at least 1 path
+        SIDE_EFFECT();
+        int thenPaths = ths->th->numPaths1();
+        int elsePaths = ths->el->numPaths1();
+
+        // for every path through the conditional, we could either
+        // go through a 'then' path or an 'else' path
+        numPaths = mult(numPaths, thenPaths + elsePaths);
+      }
+    }
+    #if 0
+    ASTNEXT(E_gnuCond, ths) {
+      // degenerate form of E_cond
+      numPaths = ths->cond->numPaths;
+      if (ths->el->numPaths > 0) {
+        ths->recordSideEffect();
+        numPaths = mult(numPaths, 1 + ths->el->numPaths);
+      }
+    }    
+    #endif // 0
+    ASTNEXT(E_comma, ths) {
+      numPaths = ths->e1->numPaths;
+      if (ths->e2->numPaths > 0) {
+        numPaths = mult(max(numPaths,1), ths->e2->numPaths);
+      }
+    }
+    ASTNEXT(E_assign, ths) {
+      numPaths = ths->src->numPaths;              // start with paths through src
+      SIDE_EFFECT();                              // clearly this expr has a side effect
+      numPaths = mult(numPaths, ths->target->numPaths1());       // add paths through target
+    }
+    ASTNEXT(E_quantifier, ths) {
+      xfailure("shouldn't get here because only allowed in predicates");
+      PRETEND_USED(ths);
+    }
+    ASTENDCASED
+  }
+
+  return ths->numPaths = numPaths;
+
+  #undef SIDE_EFFECT
+}
+
+
+// print choice point decisions, and side effects
+void printPath(int index, Expression const *ths)
+{
+  xassert(0 <= index && index < ths->numPaths1());
+
+  ASTSWITCHC(Expression, ths) {
+    ASTCASEC(E_funCall, ths) {
+      PATHOUT << "call to " << ths->func->toString() << endl;
+
+      // 'func'
+      int subexpPaths = ths->func->numPaths1();
+      printPath(index % subexpPaths, ths->func);
+      index = index / subexpPaths;
+
+      // args
+      FOREACH_ASTLIST(Expression, ths->args, iter) {
+        subexpPaths = iter.data()->numPaths1();
+        printPath(index % subexpPaths, iter.data());
+        index = index / subexpPaths;
+      }
+      xassert(index < subexpPaths);
+    }
+    ASTNEXTC(E_fieldAcc, ths) {
+      printPath(index, ths->obj);
+    }
+    ASTNEXTC(E_sizeof, ths) {
+      PRETEND_USED(ths);     // silence warning
+    }
+    ASTNEXTC(E_unary, ths) {
+      printPath(index, ths->expr);
+    }
+    ASTNEXTC(E_effect, ths) {
+      PATHOUT << "side effect: " << ths->toString() << endl;
+      printPath(index, ths->expr);
+    }
+    ASTNEXTC(E_binary, ths) {
+      if (ths->e2->numPaths == 0) {
+        // if the RHS has no side effects, the encoding is more compact,
+        // and only the LHS is relevant
+        printPath(index, ths->e1);
+      }
+
+      else {
+        // print LHS
+        int modulus = ths->e1->numPaths1();
+        printPath(index % modulus, ths->e1);
+        index = index / modulus;
+
+        // consider operator
+        if (ths->op==BIN_AND || ths->op==BIN_OR) {
+          // print RHS *if* it's followed
+          if (index > 0) {
+            PATHOUT << "traversing into rhs of " << toString(ths->op) << endl;
+            printPath(index-1, ths->e2);
+          }
+          else {
+            PATHOUT << "short-circuiting rhs of " << toString(ths->op) << endl;
+          }
+        }
+
+        else {
+          // non-short-circuit: always evaluate RHS
+          printPath(index, ths->e2);
+        }
+      }
+    }
+    ASTNEXTC(E_addrOf, ths) {
+      printPath(index, ths->expr);
+    }
+    ASTNEXTC(E_deref, ths) {
+      printPath(index, ths->ptr);
+    }
+    ASTNEXTC(E_cast, ths) {
+      printPath(index, ths->expr);
+    }
+    ASTNEXTC(E_cond, ths) {
+      // condition
+      int modulus = ths->cond->numPaths1();
+      printPath(index % modulus, ths->cond);
+      index = index / modulus;
+
+      if (ths->th->numPaths == 0 && ths->el->numPaths == 0) {
+        // no side effects in either branch; we're good to go
+      }
+
+      else {
+        int thenPaths = ths->th->numPaths1();
+        int elsePaths = ths->el->numPaths1();
+
+        if (index < thenPaths) {
+          PATHOUT << "taking 'then' path through ?:\n";
+          printPath(index, ths->th);
+        }
+        else {
+          PATHOUT << "taking 'else' path through ?:\n";
+          printPath(index - elsePaths, ths->el);
+        }
+      }
+    }
+    #if 0
+    ASTNEXTC(E_gnuCond, ths) {
+      // degenerate form of E_cond
+      PATHOUT << "gnuCond unhandled for now: " << (void*)ths << "\n";
+    }
+    #endif // 0
+    ASTNEXTC(E_comma, ths) {
+      int modulus = ths->e1->numPaths1();
+      printPath(index % modulus, ths->e1);
+      printPath(index / modulus, ths->e2);
+    }
+    ASTNEXTC(E_assign, ths) {
+      PATHOUT << "side effect: " << ths->toString() << endl;
+      int modulus = ths->src->numPaths1();
+      printPath(index % modulus, ths->src);
+      printPath(index / modulus, ths->target);
+    }
+    ASTENDCASECD
+  }
+}

Added: vendor/elsa/current/elkhound/c/paths.h
===================================================================
--- vendor/elsa/current/elkhound/c/paths.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/paths.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// paths.h            see license.txt for copyright and terms of use
+// AST routines for enumerating paths
+
+// unfortunately it turns out that there is a /usr/include/paths.h
+// on some systems, so inclusion order is important..
+
+#ifndef PATHS_H
+#define PATHS_H
+
+#include "c.ast.gen.h"      // C AST elements
+#include "sobjlist.h"       // SObjList
+
+class Env;                  // cc_env.h
+
+// instrument the AST of a function to enable printing (among other
+// things) of paths; returns total # of paths in the function (in
+// addition to storing that info in the AST)
+int countPaths(Env &env, TF_func *func);
+
+// print all paths in this function
+void printPaths(TF_func const *func);
+void printPathFrom(SObjList<Statement /*const*/> &path, int index,
+                   Statement const *node, bool isContinue);
+
+// count/print for statements
+int countExprPaths(Statement const *stmt, bool isContinue);
+void printExprPath(int index, Statement const *stmt, bool isContinue);
+
+// count/print for inititializers
+int countExprPaths(Initializer const *init);
+void printExprPath(int index, Initializer const *init);
+
+// count/print for expressions
+int countPaths(Env &env, Expression *ths);
+void printPath(int index, Expression const *ths);
+
+// starting from a point above 'stmt', how many paths go into 'stmt'
+// (and possibly beyond)?
+int numPathsThrough(Statement const *stmt);
+
+#endif // PATHS_H

Added: vendor/elsa/current/elkhound/c/postorder.cc
===================================================================
--- vendor/elsa/current/elkhound/c/postorder.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/postorder.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,51 @@
+// postorder.cc            see license.txt for copyright and terms of use
+// given the AST for a function, compute a reverse postorder
+// enumeration of all the statements
+
+#include "c.ast.gen.h"     // C AST stuff, including decl for this module
+#include "sobjset.h"       // SObjSet
+
+// DFS from 'node', having arrived at node with 'isContinue'
+// disposition; 'seen' is those nodes either currently being
+// considered somewhere in the call chain ("gray"), or else finished
+// entirely ("black"), and 'seenCont' is the same thing but for the
+// continue==true halves of the nodes
+void rp_dfs(NextPtrList &order, Statement const *node, bool isContinue,
+            SObjSet<Statement const *> &seen, SObjSet<Statement const*> &seenCont)
+{
+  // we're now considering 'node'
+  (isContinue? seenCont : seen).add(node);     // C++ generalized lvalue!
+
+  // consider each of this node's successors
+  NextPtrList successors;
+  node->getSuccessors(successors, isContinue);
+
+  for (VoidListIter iter(successors); !iter.isDone(); iter.adv()) {
+    Statement const *succ = nextPtrStmt(iter.data());
+    bool succCont = nextPtrContinue(iter.data());
+
+    if ((succCont? seenCont : seen).contains(succ)) {
+      // we're already considering, or have already considered, this node;
+      // do nothing with it
+    }
+    else {
+      // visit this new child
+      rp_dfs(order, succ, succCont, seen, seenCont);
+    }
+  }
+
+  // since we're finished with this node, we would append it to compute
+  // the postorder; since we actually want reverse postorder, prepend
+  order.prepend(makeNextPtr(node, isContinue));
+}
+
+
+void reversePostorder(NextPtrList &order, TF_func const &func)
+{
+  xassert(order.isEmpty());
+
+  // DFS from the function start, computing the spanning tree implicitly,
+  // and the reverse postorder explicitly
+  SObjSet<Statement const*> seen, seenCont;
+  rp_dfs(order, func.body, false /*isContinue*/, seen, seenCont);
+}

Added: vendor/elsa/current/elkhound/c/stubs.cc
===================================================================
--- vendor/elsa/current/elkhound/c/stubs.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/stubs.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,97 @@
+// stubs.cc            see license.txt for copyright and terms of use
+// stub implementations of things that are part of my prototype verifier,
+// but I don't want to include in the parser generator release
+
+#include "c.ast.gen.h"      // C AST declarations
+
+AbsValue *IN_compound::vcgen(AEnv &, Type const *, int) const { return NULL; }
+AbsValue *IN_expr::vcgen(AEnv &, Type const *, int) const { return NULL; }
+
+AbsValue *E_quantifier::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_assign::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_new::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_sizeofType::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_comma::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_cond::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_cast::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_deref::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_addrOf::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_binary::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_effect::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_unary::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_sizeof::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_fieldAcc::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_funCall::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_variable::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_charLit::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_stringLit::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_floatLit::vcgen(AEnv &, int) const { return NULL; }
+AbsValue *E_intLit::vcgen(AEnv &, int) const { return NULL; }
+
+void S_thmprv::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_invariant::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_assume::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_assert::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_decl::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_goto::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_return::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_continue::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_break::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_for::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_doWhile::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_while::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_switch::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_if::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_compound::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_expr::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_default::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_caseRange::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_case::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_label::vcgen(AEnv &, bool, int, Statement const *) const {}
+void S_skip::vcgen(AEnv &, bool, int, Statement const *) const {}
+
+void TF_func::vcgen(AEnv &) const {}
+void TF_decl::vcgen(AEnv &) const {}
+
+Predicate *E_quantifier::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_assign::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_new::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_sizeofType::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_comma::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_cond::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_cast::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_deref::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_addrOf::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_binary::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_effect::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_unary::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_sizeof::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_fieldAcc::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_funCall::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_variable::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_charLit::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_stringLit::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_floatLit::vcgenPred(AEnv &, int) const { return NULL; }
+Predicate *E_intLit::vcgenPred(AEnv &, int) const { return NULL; }
+
+void S_thmprv::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_invariant::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_assume::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_assert::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_decl::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_goto::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_return::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_continue::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_break::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_for::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_doWhile::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_while::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_switch::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_if::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_compound::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_expr::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_default::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_caseRange::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_case::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_label::factFlow(SObjList<Expression> &, bool, void *) const {}
+void S_skip::factFlow(SObjList<Expression> &, bool, void *) const {}

Added: vendor/elsa/current/elkhound/c/tcheck.cc
===================================================================
--- vendor/elsa/current/elkhound/c/tcheck.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/tcheck.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1790 @@
+// tcheck.cc            see license.txt for copyright and terms of use
+// implementation of typechecker over C ast
+
+#include "c.ast.gen.h"      // C ast
+#include "c_type.h"         // Type, AtomicType, etc.
+#include "c_env.h"          // Env
+#include "strutil.h"        // quoted
+#include "trace.h"          // trace
+#include "paths.h"          // printPaths
+#include "cc_lang.h"        // CCLang
+
+#define IN_PREDICATE(env) Restorer<bool> restorer(env.inPredicate, true)
+
+
+void checkBoolean(Env &env, Type const *t, Expression const *e)
+{
+  // if a reference type is being used as an atomic, unwrap the reference
+  t = t->asRval();
+
+  if (t->isError() ||          // don't report errors for <error> type
+      t->isIntegerType() ||
+      t->isPointerType() ||
+      t->isArrayType()) {    // what the hey..
+    // ok
+  }
+  else {
+    env.err(stringc << "expression " << e->toString()
+                    << " has type " << t->toString()
+                    << " but is used like a number or pointer");
+  }
+}
+
+
+// verify 't' is an lval, and return the rvalue version
+Type const *checkLval(Env &env, Type const *t, Expression const *e)
+{
+  if (!t->isError() && !t->isLval()) {
+    env.err(stringc << "expression " << e->toString()
+                    << " has type " << t->toString()
+                    << " but is used like an lvalue");
+    return fixed(ST_ERROR);
+  }
+  else {
+    return t->asRval();
+  }
+}
+
+
+// ------------------ TranslationUnit -----------------
+void TranslationUnit::tcheck(Env &env)
+{
+  FOREACH_ASTLIST_NC(TopForm, topForms, iter) {
+    iter.data()->tcheck(env);
+  }
+}
+
+
+// --------------------- TopForm ---------------------
+void TopForm::tcheck(Env &env)
+{
+  env.pushLocation(loc);
+  itcheck(env);
+  env.popLocation();
+}
+
+
+void TF_decl::itcheck(Env &env)
+{
+  decl->tcheck(env);
+}
+
+
+void TF_func::itcheck(Env &env)
+{
+  // we're the current function
+  env.setCurrentFunction(this);
+
+  Type const *r = retspec->tcheck(env);
+  Type const *f = nameParams->tcheck(env, r, dflags);
+  xassert(f->isFunctionType());
+
+  // as a hack for my path-counting logic, make sure the
+  // function doesn't end with a looping construct
+  body->stmts.append(new S_skip(SL_UNKNOWN));
+
+  // put parameters into the environment
+  env.enterScope();
+  {
+    // dig inside the 'nameParams' to find the parameters
+    // (the downcast will succeed because isFunctionType succeeded, above)
+    D_func *fdecl = nameParams->decl->asD_func();
+
+    FOREACH_ASTLIST(ASTTypeId, fdecl->params, iter) {
+      Variable *var = iter.data()->decl->var;
+      if (var->name) {
+        env.addVariable(var->name, var);
+      }
+      params.prepend(var);
+    }
+    params.reverse();
+  }
+
+  // (TODO) verify the pre/post don't have side effects, and
+  // limit syntax somewhat
+  {
+    IN_PREDICATE(env);
+
+    // make bindings for precondition logic variables (they would
+    // have been added to the environment when typechecked above, 
+    // but then we closed that scope (why? not sure))
+    FA_precondition *pre = ftype()->precondition;
+    if (pre) {
+      FOREACH_ASTLIST_NC(Declaration, pre->decls, iter) {
+        FOREACH_ASTLIST_NC(Declarator, iter.data()->decllist, iter2) {
+          Variable *var = iter2.data()->var;
+          env.addVariable(var->name, var);
+        }
+      }
+
+      //checkBoolean(env, pre->expr->tcheck(env), pre->expr);
+    }
+                            
+    #if 0     // typechecking postconditions happens in D_func::tcheck
+    // and the postcondition
+    FA_postcondition *post = ftype()->postcondition;
+    if (post) {
+      env.enterScope();
+
+      // example of egcs' failure to disambiguate C++ ctor/prototype:
+      //Variable result(SL_UNKNOWN, env.strTable.add("result"),
+      //                r, DF_LOGIC);
+
+      // the postcondition has 'result' available, as the type
+      // of the return value
+      Variable *result = nameParams->decl->asD_func()->result;
+      if (! ftype()->retType->isVoid()) {
+        env.addVariable(result->name, result);
+      }
+
+      checkBoolean(env, post->expr->tcheck(env), post->expr);
+
+      env.leaveScope();
+    }
+    #endif // 0
+  }
+
+  // may as well check that things are as I expect *before* I muck with them
+  env.verifyFunctionEnd();
+
+  // check the body in the new environment
+  body->tcheck(env);
+
+  // when the local are added, they are prepended
+  locals.reverse();
+
+  // clean up
+  env.resolveGotos();
+  env.resolveNexts(NULL /*target*/, false /*isContinue*/);
+  env.leaveScope();
+
+  // let the environment verify everything got cleaned up properly
+  env.verifyFunctionEnd();
+
+  // instrument AST with path information
+  countPaths(env, this);
+
+  if (tracingSys("printPaths")) {
+    printPaths(this);
+  }
+
+  // ensure segfault if some later access occurs
+  env.setCurrentFunction(NULL);
+}
+
+
+template <class T, class Y>      // Y is type of thing printed
+void printSObjList(ostream &os, int indent, char const *label,
+                   SObjList<T> const &list, Y (*map)(T const *t))
+{
+  ind(os, indent) << label << ":";
+  SFOREACH_OBJLIST(T, list, iter) {
+    os << " " << map(iter.data());
+  }
+  os << "\n";
+}
+
+StringRef varName(Variable const *v)
+  { return v->name; }
+
+string stmtLoc(Statement const *s)
+{
+  char const *fname;
+  int line, col;
+  sourceLocManager->decodeLineCol(s->loc, fname, line, col);
+
+  return stringc << line << ":" << col;
+}
+
+
+void TF_func::printExtras(ostream &os, int indent) const
+{
+  printSObjList(os, indent, "params", params, varName);
+  printSObjList(os, indent, "locals", locals, varName);
+  printSObjList(os, indent, "globalRefs", globalRefs, varName);
+  printSObjList(os, indent, "roots", roots, stmtLoc);
+}
+
+
+// ------------------- Declaration ----------------------
+void Declaration::tcheck(Env &env)
+{
+  // check the declflags for sanity
+  // (for now, support only a very limited set)
+  {
+    DeclFlags df = (DeclFlags)(dflags & DF_SOURCEFLAGS);
+    if (df == DF_NONE ||
+        df == DF_TYPEDEF ||
+        df == DF_STATIC ||
+        df == DF_EXTERN ||
+        df == DF_UNIVERSAL ||
+        df == DF_EXISTENTIAL ||
+        df == DF_PREDICATE) {
+      // ok
+    }
+    else {
+      env.err(stringc << "unsupported dflags: " << toString(df));
+      dflags = (DeclFlags)(dflags & ~DF_SOURCEFLAGS);
+    }
+  }
+
+  // distinguish declarations of logic variables
+  if (env.inPredicate) {
+    dflags = (DeclFlags)(dflags | DF_LOGIC);
+  }
+
+  // compute the base type
+  Type const *base = spec->tcheck(env);
+
+  // apply this type to each of the declared entities
+  FOREACH_ASTLIST_NC(Declarator, decllist, iter) {
+    Declarator *d = iter.data();
+    d->tcheck(env, base, dflags);
+    
+    // we just declared a local variable, if we're in a function
+    TF_func *func = env.getCurrentFunction();
+    if (func) {
+      func->locals.prepend(d->var);
+    }
+  }
+}
+
+
+// --------------------- ASTTypeId ---------------------
+Type const *ASTTypeId::tcheck(Env &env)
+{
+  Type const *s = spec->tcheck(env);
+  return type = decl->tcheck(env, s, DF_NONE);
+}
+
+
+// ------------------- TypeSpecifier -------------------
+Type const *TypeSpecifier::applyCV(Env &env, Type const *base)
+{
+  Type const *ret = env.applyCVToType(cv, base);
+  env.errIf(!ret, stringc << "can't apply " << toString(cv)
+                          << " to " << base->toString());
+
+  return ret;
+}
+
+
+Type const *TS_name::tcheck(Env &env)
+{
+  Type const *base = env.getTypedef(name);
+  env.errIf(!base, stringc << "unknown typedef " << name);
+
+  return applyCV(env, base);
+}
+
+
+Type const *TS_simple::tcheck(Env &env)
+{
+  return applyCV(env, &CVAtomicType::fixed[id]);
+}
+
+
+Type const *TS_elaborated::tcheck(Env &env)
+{
+  AtomicType *ret;
+  if (keyword != TI_ENUM) {
+    ret = env.getOrAddCompound(name, (CompoundType::Keyword)keyword);
+    env.errIf(!ret, stringc << name << " already declared differently");
+  }
+  else {
+    ret = env.getOrAddEnum(name);
+  }
+
+  return env.makeCVType(ret, cv);
+}
+
+
+Type const *TS_classSpec::tcheck(Env &env)
+{
+  CompoundType *ct = env.getOrAddCompound(name, (CompoundType::Keyword)keyword);
+  if (name) {
+    env.errIf(!ct, stringc << name << " already declared differently");
+    env.errIf(ct->isComplete(), stringc << name << " already declared");
+  }
+  else {
+    xassert(ct);
+  }
+
+  // construct a Type
+  xassert(cv == CV_NONE);    // I think the syntax precludes any alternative
+  Type const *ret = env.makeCVType(ct, cv);
+
+  if (env.lang.tagsAreTypes && name) {
+    // C++: add an implicit typedef for the name
+    env.addTypedef(name, ret);
+  }
+
+  // fill in 'ct' with its fields
+  env.pushStruct(ct);      // declarations will go into 'ct'
+  FOREACH_ASTLIST_NC(Declaration, members, iter) {
+    iter.data()->tcheck(env);
+  }
+  env.popStruct();
+
+  return ret;
+}
+
+
+class XNonConst : public xBase {
+public:
+  Expression const *subexpr;     // on which it fails to be const
+
+public:
+  XNonConst() : xBase("non-const") {}
+  XNonConst(XNonConst const &obj) : xBase(obj), subexpr(obj.subexpr) {}
+  ~XNonConst();
+};
+
+XNonConst::~XNonConst()
+{}               
+
+
+int constEval(Env &env, Expression *expr)
+{
+  try {
+    return expr->constEval(env);
+  }
+  catch (XNonConst &x) {
+    env.err(stringc << expr->toString() << " is not const because "
+                    << x.subexpr->toString() << " is not const");
+    return 1;     // arbitrary (but not 0, for array sizes)
+  }
+}
+
+
+Type const *TS_enumSpec::tcheck(Env &env)
+{
+  if (name) {
+    EnumType *et = env.getEnum(name);
+    env.errIf(et, stringc << name << " already declared");
+  }
+
+  EnumType *et = env.addEnum(name);
+
+  // fill in 'et' with enumerators
+  int nextValue = 0;
+  FOREACH_ASTLIST_NC(Enumerator, elts, iter) {
+    Enumerator *e = iter.data();
+    if (e->expr) {
+      nextValue = constEval(env, e->expr);
+    }
+    
+    // make a record of the name introduction
+    Variable *var = new Variable(e->loc, name,
+                                 new CVAtomicType(et, CV_NONE), DF_NONE);
+    xassert(e->var == NULL);
+    e->var = var;
+
+    // add the value to the type, and put this enumerator into the
+    // environment so subsequent enumerators can refer to its value
+    env.addEnumerator(e->name, et, nextValue, var);
+
+    // if the next enumerator doesn't specify a value, use +1
+    nextValue++;
+  }
+  
+  return env.makeCVType(et, cv);
+}
+
+
+// -------------------- Declarator -------------------
+Type const *Declarator::tcheck(Env &env, Type const *base, DeclFlags dflags)
+{
+  // check the internal structure, eventually also setting 'var'
+  xassert(var == NULL);
+  decl->tcheck(env, base, dflags, this);
+  xassert(var != NULL);
+
+  if (init) {
+    // verify the initializer is well-typed, given the type
+    // of the variable it initializes
+    // TODO: make the variable not visible in the init?
+    init->tcheck(env, var->type);
+  }
+
+  return var->type;
+}
+
+
+void /*Type const * */IDeclarator::tcheck(Env &env, Type const *base,
+                                          DeclFlags dflags, Declarator *declarator)
+{
+  FOREACH_ASTLIST(PtrOperator, stars, iter) {
+    // the list is left-to-right, so the first one we encounter is
+    // the one to be most immediately applied to the base type:
+    //   int  * const * volatile x;
+    //   ^^^  ^^^^^^^ ^^^^^^^^^^
+    //   base  first    second
+    base = env.makePtrOperType(PO_POINTER, iter.data()->cv, base);
+  }
+
+  // call inner function
+  /*return*/ itcheck(env, base, dflags, declarator);
+}
+
+
+void /*Type const * */D_name::itcheck(Env &env, Type const *base,
+                                      DeclFlags dflags, Declarator *declarator)
+{
+  trace("tcheck")
+    << "found declarator name: " << (name? name : "(null)")
+    << ", type is " << base->toCString() << endl;
+
+  // construct a Variable: this is a binding introduction
+  Variable *var = new Variable(loc, name, base, dflags);
+
+  // annotate the declarator
+  xassert(declarator->var == NULL);     // otherwise leak
+  declarator->var = var;
+
+  // look at the attributes
+  if (attr) {
+    xassert(attr->name == env.str("attr"));
+    FOREACH_ASTLIST_NC(ThmprvAttr, attr->args, iter) {
+      ThmprvAttr *at = iter.data();
+      if (at->name == env.str("addrtaken")) {
+        var->setFlag(DF_ADDRTAKEN);
+        if (at->args.count() != 0) {
+          env.err(stringc << "addrtaken cannot have parameters");
+        }
+      }
+      else {
+        env.err(stringc << "unknown attribute " << at->name);
+      }
+    }
+  }
+
+  // one way this happens is in prototypes with unnamed arguments
+  if (!name) {
+    // skip the following
+  }
+  else {
+    if (dflags & DF_TYPEDEF) {
+      env.addTypedef(name, var->type);
+    }
+    else {
+      env.addVariable(name, var);
+    }
+  }
+
+  //return base;
+}
+
+
+void /*Type const * */D_func::itcheck(Env &env, Type const *rettype,
+                                      DeclFlags dflags, Declarator *declarator)
+{
+  // make the result variable
+  result = new Variable(loc, env.str("result"), rettype, DF_LOGIC);
+
+  FunctionType *ft = env.makeFunctionType(rettype);
+  ft->result = result;
+
+  // push a scope so the argument names aren't seen as colliding
+  // with names already around
+  env.enterScope();
+
+  // build the argument types
+  FOREACH_ASTLIST_NC(ASTTypeId, params, iter) {
+    ASTTypeId *ti = iter.data();
+
+    // handle "..."
+    if (ti->spec->kind() == TypeSpecifier::TS_SIMPLE &&
+        ti->spec->asTS_simple()->id == ST_ELLIPSIS) {
+      ft->acceptsVarargs = true;
+      break;
+    }
+
+    // compute the type of the parameter
+    Type const *paramType = ti->tcheck(env);
+
+    // mark the newly-created Variable structure as a parameter
+    ti->decl->var->setFlag(DF_PARAMETER);
+
+    // extract the name
+    StringRef /*nullable*/ paramName = ti->decl->var->name;
+
+    // add it to the type description
+    FunctionType::Param *param =
+      new FunctionType::Param(paramName, paramType, ti->decl->var);
+    ft->params.prepend(param);    // build in wrong order initially..
+  }
+
+  // correct the argument order; this preserves linear performance
+  ft->params.reverse();
+
+  // pass the annotations along via the type language
+  FOREACH_ASTLIST_NC(FuncAnnotation, ann, iter) {
+    ASTSWITCH(FuncAnnotation, iter.data()) {
+      ASTCASE(FA_precondition, pre) {
+        IN_PREDICATE(env);
+
+        // typecheck the precondition
+        FOREACH_ASTLIST_NC(Declaration, pre->decls, iter) {
+          iter.data()->tcheck(env);
+        }
+        checkBoolean(env, pre->expr->tcheck(env), pre->expr);
+
+        if (ft->precondition) {
+          env.err("function already has a precondition");
+        }
+        else {
+          ft->precondition = pre;
+        }
+      }
+
+      ASTNEXT(FA_postcondition, post) {
+        IN_PREDICATE(env);
+
+        // add the result variable to the environment, so the
+        // postcondition can refer to it
+        env.addVariable(result->name, result);
+
+        // typecheck the postcondition
+        checkBoolean(env, post->expr->tcheck(env), post->expr);
+
+        if (ft->postcondition) {
+          env.err("function already has a postcondition");
+        }
+        else {
+          ft->postcondition = post;
+        }
+      }
+
+      ASTENDCASED
+    }
+  }
+
+  // I think leaving the scope here (and then re-creating it in
+  // TF_func::tcheck) enforces proper scoping for *types* introduced
+  // in the parameter declaration list.. ?
+  env.leaveScope();
+
+  // pass the constructed function type to base's tcheck so it can
+  // further build upon the type
+  /*return*/ base->tcheck(env, ft, dflags, declarator);
+}
+
+
+void /*Type const * */D_array::itcheck(Env &env, Type const *elttype,  
+                                       DeclFlags dflags, Declarator *declarator)
+{
+  ArrayType *at;
+  if (size) {
+    at = env.makeArrayType(elttype, constEval(env, size));
+  }
+  else {
+    at = env.makeArrayType(elttype);
+  }
+
+  /*return*/ base->tcheck(env, at, dflags, declarator);
+}
+
+
+void /*Type const * */D_bitfield::itcheck(Env &env, Type const *base, 
+                                          DeclFlags dflags, Declarator *declarator)
+{
+  trace("tcheck")
+    << "found bitfield declarator name: "
+    << (name? name : "(null)") << endl;
+  xfailure("bitfields not supported yet");
+  //return NULL;    // silence warning
+}
+
+
+// ------------------- Declarator::getName ------------------------
+StringRef D_name::getName() const
+  { return name; }
+
+StringRef D_func::getName() const
+  { return base->getName(); }
+
+StringRef D_array::getName() const
+  { return base->getName(); }
+
+StringRef D_bitfield::getName() const
+  { return name; }
+
+
+// ----------------------- Statement ---------------------
+void Statement::tcheck(Env &env)
+{
+  env.pushLocation(loc);
+
+  // the default actions here are suitable for most kinds of
+  // statements, but there are exceptions which require special
+  // treatment, and that is elaborated below
+
+  // any pending 'next' pointers go here
+  env.resolveNexts(this /*target*/, false /*continue*/);
+
+  // my 'next' will go to whoever's (outer) tcheck is called next
+  env.addPendingNext(this /*source*/);
+
+  // do inner typecheck
+  itcheck(env);
+  
+  env.popLocation();
+}
+
+
+void S_skip::itcheck(Env &env)
+{}
+
+void S_label::itcheck(Env &env)
+{
+  env.addLabel(name, this);
+  s->tcheck(env);
+}
+
+
+void connectEnclosingSwitch(Env &env, Statement *stmt, char const *kind)
+{
+  S_switch *sw = env.getCurrentSwitch();
+  if (!sw) {
+    env.err(stringc << kind << " can only appear in the context of a 'switch'");
+  }
+  else {
+    sw->cases.append(stmt);
+  }
+}
+
+void S_case::itcheck(Env &env)
+{
+  connectEnclosingSwitch(env, this, "'case'");
+  s->tcheck(env);
+}
+
+void S_caseRange::itcheck(Env &env)
+{
+  connectEnclosingSwitch(env, this, "'case'");
+  s->tcheck(env);
+}
+
+void S_default::itcheck(Env &env)
+{
+  connectEnclosingSwitch(env, this, "'default'");
+  s->tcheck(env);
+}
+
+
+void S_expr::itcheck(Env &env)
+{
+  expr->tcheck(env);
+}
+
+void S_compound::itcheck(Env &env)
+{
+  env.enterScope();
+  FOREACH_ASTLIST_NC(Statement, stmts, iter) {
+    iter.data()->tcheck(env);
+  }
+  env.leaveScope();
+}
+
+void S_if::itcheck(Env &env)
+{
+  checkBoolean(env, cond->tcheck(env), cond);
+  thenBranch->tcheck(env);
+
+  // any pending 'next's should not be resolved as pointing into
+  // the 'else' clause, but instead as pointing at whatever follows
+  // the entire 'if' statement
+  env.pushNexts();
+
+  elseBranch->tcheck(env);
+
+  // merge current pending nexts with those saved above
+  env.popNexts();
+}
+
+void S_switch::itcheck(Env &env)
+{
+  // existing 'break's must be postponed
+  env.pushBreaks();
+
+  // any occurrances of 'case' will be relative to this switch
+  env.pushSwitch(this);
+  branches->tcheck(env);
+  env.popSwitch();
+
+  // any previous 'break's will resolve to whatever comes next
+  env.popBreaks();
+}
+
+
+void tcheckLoop(Env &env, Statement *loop, Expression *cond,
+                Statement *body)
+{
+  // existing 'break's must be postponed
+  env.pushBreaks();
+
+  checkBoolean(env, cond->tcheck(env), cond);
+
+  // any occurrances of 'continue' will be relative to this loop
+  env.pushLoop(loop);
+  body->tcheck(env);
+  env.popLoop();
+
+  // the body continues back into this loop
+  env.resolveNexts(loop /*target*/, true /*continue*/);
+
+  // any previous 'break's will resolve to whatever comes next
+  env.popBreaks();
+
+  // I want the loop's 'next' to point to what comes after; right now
+  // it points at the body (if anywhere; see S_for), and this will
+  // change it
+  env.addPendingNext(loop /*source*/);
+}
+
+void S_while::itcheck(Env &env)
+{
+  tcheckLoop(env, this, cond, body);
+}
+
+void S_doWhile::itcheck(Env &env)
+{
+  tcheckLoop(env, this, cond, body);
+}
+
+// override the *outer* tcheck for S_for so we can handle 'init'
+// correctly; it's easiest to understand how this works by looking at
+// Statement::tcheck simultaneously and comparing the sequence of
+// actions
+void S_for::tcheck(Env &env)
+{
+  env.pushLocation(loc);
+
+  // go immediately into 'init' so any pending 'next' pointers
+  // point directly at the initializer; effectively, this makes the
+  // system behave as if 'init' appeared syntactically just before
+  // the "for" loop
+  init->tcheck(env);
+
+  // the pending 'next' from the 'init' should point at me,
+  // as a non-continue edge
+  env.resolveNexts(this /*target*/, false /*continue*/);
+
+  // don't bother adding my 'next'; tcheckLoop will handle this,
+  // and its action would just override anything I did here
+
+  // check 'after'; it has no effect on CFG because it's an expression
+  after->tcheck(env);
+
+  // do the things that loops do
+  tcheckLoop(env, this, cond, body);
+
+  env.popLocation();
+}
+
+
+void S_for::itcheck(Env &env)
+{
+  xfailure("should not be called");
+
+  #if 0    // old; wrong because CFG edge for init is wrong
+  init->tcheck(env);
+  after->tcheck(env);
+
+  tcheckLoop(env, this, cond, body);
+  #endif // 0
+}
+
+
+void S_break::itcheck(Env &env)
+{
+  // add myself to the list of active breaks
+  env.addBreak(this);
+}
+
+void S_continue::itcheck(Env &env)
+{
+  Statement *loop = env.getCurrentLoop();
+  if (!loop) {
+    env.err("'continue' can only occur in the scope of a loop");
+  }
+  else {
+    // take myself off the list of pending nexts
+    env.clearNexts();
+
+    // point my next at the loop
+    next = makeNextPtr(loop, true /*continue*/);
+  }
+}
+
+void S_return::itcheck(Env &env)
+{
+  // ensure my 'next' is null
+  env.clearNexts();          
+  xassert(next == NULL);
+
+  Type const *rettype = env.getCurrentRetType();
+  if (expr) {
+    Type const *t = expr->tcheck(env);
+    env.checkCoercible(t, rettype);
+  }
+  else {
+    env.errIf(!rettype->isVoid(), "must supply return value for non-void function");
+  }
+}
+
+
+void S_goto::itcheck(Env &env)
+{
+  env.addPendingGoto(target, this);
+}
+
+
+void S_decl::itcheck(Env &env)
+{
+  decl->tcheck(env);
+}
+
+
+void S_assert::itcheck(Env &env)
+{
+  IN_PREDICATE(env);
+
+  Type const *type = expr->tcheck(env);
+  checkBoolean(env, type, expr);
+}
+
+void S_assume::itcheck(Env &env)
+{
+  IN_PREDICATE(env);
+
+  checkBoolean(env, expr->tcheck(env), expr);
+}
+
+void S_invariant::itcheck(Env &env)
+{
+  IN_PREDICATE(env);
+
+  checkBoolean(env, expr->tcheck(env), expr);
+}
+
+void S_thmprv::itcheck(Env &env)
+{
+  IN_PREDICATE(env);
+
+  s->tcheck(env);
+}
+
+
+// ------------------ Statement::getSuccessors ----------------
+void Statement::getSuccessors(VoidList &dest, bool /*isContinue*/) const
+{
+  if (nextPtrStmt(next)) {
+    dest.append(next);
+  }
+}
+
+
+void S_if::getSuccessors(VoidList &dest, bool /*isContinue*/) const
+{
+  // the 'next' field is ignored since it always points at
+  // the 'then' branch anyway
+
+  dest.append(makeNextPtr(thenBranch, false));
+  dest.append(makeNextPtr(elseBranch, false));
+}
+
+
+void S_switch::getSuccessors(VoidList &dest, bool /*isContinue*/) const
+{
+  xassert(dest.isEmpty());
+  SFOREACH_OBJLIST(Statement, cases, iter) {
+    dest.prepend(makeNextPtr(iter.data(), false));
+  }
+  dest.reverse();
+}
+
+
+void S_while::getSuccessors(VoidList &dest, bool isContinue) const
+{
+  Statement::getSuccessors(dest, isContinue);
+  dest.append(makeNextPtr(body, false));
+}
+
+
+void S_doWhile::getSuccessors(VoidList &dest, bool isContinue) const
+{
+  if (isContinue) {
+    // continue jumps to conditional, and can either go back
+    // to the top (body) or past loop (next)
+    Statement::getSuccessors(dest, isContinue);
+  }
+
+  // either way, doing the body is an option
+  dest.append(makeNextPtr(body, false));
+}
+
+
+void S_for::getSuccessors(VoidList &dest, bool isContinue) const
+{
+  // though the semantics of which expressions get evaluated
+  // are different depending on 'isContinue', the statement-level
+  // control flow options are the same
+  Statement::getSuccessors(dest, isContinue);
+  dest.append(makeNextPtr(body, false));
+}
+
+
+string Statement::successorsToString() const
+{
+  VoidList succNoCont;
+  getSuccessors(succNoCont, false);
+
+  VoidList succYesCont;
+  getSuccessors(succYesCont, true);
+
+  stringBuilder sb;
+  sb << "{";
+
+  for (VoidListIter iter(succYesCont); !iter.isDone(); iter.adv()) {
+    NextPtr np = iter.data();
+    
+    // a leading "(c)" means the successor edge is only present when
+    // this node is reached via continue; a trailing "(c)" means that
+    // successor is itself a continue edge; the algorithm assumes
+    // that 'succYesCont' is a superset of 'succNoCont'
+    Statement const *next = nextPtrStmt(np);
+    sb << (succNoCont.contains(np)? " " : " (c)")
+       << stmtLoc(next)
+       << (nextPtrContinue(np)? "(c)" : "");
+  }
+
+  sb << " }";
+  return sb;
+}
+
+
+string Statement::kindLocString() const
+{
+  return stringc << kindName() << "@" << stmtLoc(this);
+}
+
+
+string nextPtrString(NextPtr np)
+{
+  return stringc << nextPtrStmt(np)->kindLocString()
+                 << (nextPtrContinue(np)? "(c)" : "");
+}
+
+
+// ------------------ Expression::tcheck --------------------
+Type const *Expression::tcheck(Env &env)
+{
+  type = itcheck(env);
+  
+  // it's important we cound paths *after* typechecking, because
+  // the path counter will rely on the fact that all subexpressions
+  // have already had their paths counted
+  countPaths(env, this);
+
+  return type;
+}
+
+
+Type const *E_intLit::itcheck(Env &env)
+{
+  return fixed(ST_INT);
+}
+
+
+Type const *E_floatLit::itcheck(Env &env)
+{
+  return fixed(ST_FLOAT);
+}
+
+
+Type const *E_stringLit::itcheck(Env &env)
+{
+  return env.makePtrOperType(PO_POINTER, CV_NONE, fixed(ST_CHAR));
+}
+
+
+Type const *E_charLit::itcheck(Env &env)
+{
+  return fixed(ST_CHAR);
+}
+
+
+#if 0
+Type const *E_structLit::itcheck(Env &env)
+{
+  // the initializer itself is ignored
+  cout << "TODO: handle structure initializers\n";
+  return stype->tcheck(env);
+}
+#endif // 0
+
+
+// like Env::makeRefType, except we handle array types specially
+Type const *makeReference(Env &env, Type const *type)
+{
+  // I no longer want the coercion to be implicit
+  #if 0
+  if (type->isArrayType()) {
+    // implicit coercion to a pointer to the first element
+    return env.makePtrOperType(PO_POINTER, CV_NONE,
+                               type->asArrayTypeC().eltType);
+  }
+  else {
+    // since the name of a variable is an lvalue, return a reference type
+    return env.makeRefType(type);
+  }
+  #endif // 0
+
+  // since the name of a variable is an lvalue, return a reference type
+  return env.makeRefType(type);
+}
+
+Type const *E_variable::itcheck(Env &env)
+{
+  Variable *v;       // will point to the binding introduction
+
+  if (scopeName) {
+    // look up the scope qualifier; should be a typedef name (since in C++
+    // all class and struct tags are automatically typedef names too)
+    Type const *scopeType = env.getTypedef(scopeName);
+    if (!scopeType) {
+      return env.err(stringc << "unknown type in qualifier: " << scopeName);
+    }
+
+    // the type should be a struct (an enum would be conceivable, but
+    // redundant..)
+    CompoundType const *ct = scopeType->ifCompoundType();
+    if (!ct || (ct->keyword == CompoundType::K_UNION)) {
+      return env.err(stringc << "qualifier must be struct or class, in " 
+                             << toString());
+    }
+
+    // look up the field the user asked for
+    CompoundType::Field const *f = ct->getNamedField(name);
+    if (!f) {
+      return env.err(stringc << "unknown field: " << toString());
+    }
+    v = f->decl;
+    xassert(v);    // I think this should be non-null by now
+  }
+
+  else {           // no scope qualifier
+    v = env.getVariable(name);
+    if (!v) {
+      return env.err(stringc << "undeclared variable: " << name);
+    }
+  }
+
+  // connect this name reference to its binding introduction
+  var = v;
+
+  if (v->hasFlag(DF_LOGIC) &&
+      !env.inPredicate) {
+    env.err(stringc << name << " cannot be referenced outside a predicate");
+  }
+
+  // if this is a global, annotate the current function to say
+  // it is referenced
+  if (v->hasFlag(DF_GLOBAL) || v->hasFlag(DF_MEMBER)) {
+    TF_func *f = env.getCurrentFunction();
+    if (f) {                          // might not be in a function
+      f->globalRefs.appendUnique(v);    // append if not already present
+    }
+  }
+
+  // if it's a field, then we're actually talking about its offset
+  // (as long as we don't have static fields..)
+  if (v->hasFlag(DF_MEMBER)) {
+    return fixed(ST_INT);
+  }
+
+  // see makeReference's definition above
+  return makeReference(env, v->type);
+}
+
+
+Type const *typeError(Env &env, Expression const *expr, 
+                      Type const *type, char const *msg)
+{
+  if (type->isError()) {
+    return type;      // no need to report error twice
+  }
+  else {
+    return env.err(
+      stringc << "expression `" << expr->toString()
+              << "', type `" << type->toString()
+              << "': " << msg);
+  }
+}
+
+
+Type const *E_funCall::itcheck(Env &env)
+{
+  Type const *maybe = func->tcheck(env)->asRval();
+  if (!maybe->isFunctionType()) {
+    return typeError(env, func, maybe, "must be function type");
+  }
+  FunctionType const *ftype = &( maybe->asFunctionTypeC() );
+
+  if (env.inPredicate) {
+    env.errIf(!func->isE_variable(),
+      "within predicates, function applications must be simple");
+  }
+
+  ObjListIter<FunctionType::Param> param(ftype->params);
+
+  // check argument types
+  FOREACH_ASTLIST_NC(Expression, args, iter) {
+    Type const *atype = iter.data()->tcheck(env);
+    if (!param.isDone()) {
+      env.checkCoercible(atype, param.data()->type);
+      param.adv();
+    }
+    else if (!ftype->acceptsVarargs) {
+      env.err("too many arguments");
+      break;    // won't check remaining arguments..
+    }
+    else {
+      // we can only portably pass built-in types across
+      // a varargs boundary
+      checkBoolean(env, atype->asRval(), iter.data());
+    }
+  }
+  if (!param.isDone()) {
+    env.err("too few arguments");
+  }
+
+  return ftype->retType;
+}
+
+
+Type const *E_fieldAcc::itcheck(Env &env)
+{
+  Type const *lhstype = obj->tcheck(env);
+  bool lval = lhstype->isLval();     // e.g. a structure literal is not an lval
+  lhstype = lhstype->asRval();
+
+  CompoundType const *ctype;
+
+  // OWNER: treat all access to owner pointer fields as if they were
+  // accesses to struct OwnerPtrMeta
+  if (lhstype->isOwnerPtr()) {
+    // get the special declaration of owner metadata
+    ctype = env.getCompound(env.str("OwnerPtrMeta"));
+    if (!ctype) {
+      return env.err("can't find struct OwnerPtrMeta");
+    }
+  }
+  else {
+    try {
+      ctype = &( lhstype->asCVAtomicTypeC().atomic->asCompoundTypeC() );
+    }
+    catch (...) {
+      return env.err(stringc << obj->toString() << " is not a compound type");
+    }
+  }
+
+  // get corresponding Field; this sets the 'field' member of E_fieldAcc
+  field = ctype->getNamedField(fieldName);
+  if (!field) {
+    env.err(stringc << "no field named " << fieldName);
+    return fixed(ST_ERROR);
+  }
+
+  // field reference is an lval if the LHS was an lval
+  if (lval) {
+    return makeReference(env, field->type);
+  }
+  else {
+    if (field->type->isArrayType()) {
+      env.err("I don't know how to handle array accesses inside non-lval structs");
+      return fixed(ST_ERROR);
+    }
+    else {
+      // the field's type, as a non-lvalue
+      return field->type;
+    }
+  }
+}
+
+
+Type const *E_sizeof::itcheck(Env &env)
+{
+  size = expr->tcheck(env)->reprSize();
+  return fixed(ST_INT);
+}
+
+
+Type const *E_unary::itcheck(Env &env)
+{
+  Type const *t = expr->tcheck(env)->asRval();
+
+  // just about any built-in will do...
+  checkBoolean(env, t, expr);
+
+  // assume these unary operators to not widen their argument
+  return t;
+}
+
+Type const *E_effect::itcheck(Env &env)
+{
+  Type const *t = checkLval(env, expr->tcheck(env), expr);
+  checkBoolean(env, t, expr);
+
+  if (env.inPredicate) {
+    env.err("cannot have side effects in predicates");
+  }
+
+  return t;
+}
+
+
+// given 't' an array type, yield the type of a pointer to t's
+// first element; also, construct a cast node and replace 'nodePtr'
+// with it; 'nodePtr' should already have been typechecked
+Type const *coerceArrayToPointer(Env &env, Type const *t, Expression *&nodePtr)
+{
+  ArrayType const &at = t->asArrayTypeC();
+
+  // make the proper type
+  t = env.makePtrType(at.eltType);
+
+  // stick it into an ASTTypeId node; rather than construct the
+  // proper syntax, I'll just set the 'type' field and leave the
+  // syntax parts blank
+  ASTTypeId *typeId = new ASTTypeId(NULL, NULL);
+  typeId->type = t;
+
+  // construct the cast node, and fill in its fields manually
+  // instead of calling tcheck, because 'ptr' has already been
+  // checked and I don't want to repeat that (I think I assume
+  // it happens only once somewhere...)
+  E_cast *newNode = new E_cast(typeId, nodePtr);
+  newNode->type = t;
+  newNode->numPaths = nodePtr->numPaths;
+  nodePtr = newNode;
+  
+  return t;
+}
+
+
+Type const *E_binary::itcheck(Env &env)
+{
+  Type const *t1 = e1->tcheck(env)->asRval();
+  if (t1->isArrayType()) {
+    t1 = coerceArrayToPointer(env, t1, e1);
+  }
+
+  Type const *t2 = e2->tcheck(env)->asRval();
+
+  if (!env.inPredicate && op >= BIN_IMPLIES) {
+    // this restriction is useful because it means I don't have to
+    // do path analysis for this operator
+    env.err(stringc << "the " << ::toString(op)
+                    << " operator can only be used in predicates");
+  }
+
+  checkBoolean(env, t1, e1);     // pointer is acceptable here..
+  checkBoolean(env, t2, e2);
+
+  if (isRelational(op) || isPredicateCombinator(op)) {
+    return fixed(ST_INT);        // really want 'bool' ..
+  }
+  else {
+    // e.g. (short,long) -> long
+    return env.promoteTypes(op, t1, t2);
+  }
+}
+
+
+Type const *E_addrOf::itcheck(Env &env)
+{
+  Type const *t = checkLval(env, expr->tcheck(env), expr);
+
+  if (expr->isE_variable()) {
+    // mark the variable as having its address taken
+    Variable *v = expr->asE_variable()->var;
+    if (!v->isGlobal()) {
+      // for locals, we infer DF_ADDRTAKEN simply by scanning the
+      // body of the function
+      v->setFlag(DF_ADDRTAKEN);
+    }
+    else {
+      // for globals, we require that DF_ADDRTAKEN be specified by
+      // an attribute, for it to be legal to take that global's
+      // address, so we have a consistent view across compilation
+      // units                                 
+      //
+      // I allow a tracing flag to suppress this error since I want
+      // to parse c.in4d with my C++ grammar, which doesn't have
+      // the thmprv_attr stuff...
+      if (!v->hasFlag(DF_ADDRTAKEN) &&
+          !tracingSys("suppressAddrOfError")) {
+        env.err(stringc << "you have to mark the global " << v->name
+                        << " as thmprv_attr(addrtaken) if you take its address");
+      }
+    }
+  }
+
+  return env.makePtrOperType(PO_POINTER, CV_NONE, t);
+}
+
+                              
+Type const *E_deref::itcheck(Env &env)
+{
+  Type const *t = ptr->tcheck(env)->asRval();
+  if (t->isArrayType()) {
+    t = coerceArrayToPointer(env, t, ptr);
+  }
+
+  if (!t->isPointer()) {
+    env.err(stringc << "can only dereference pointers, not " << t->toCString());
+    return fixed(ST_ERROR);
+  }
+
+  return env.makeRefType(t->asPointerTypeC().atType);
+}
+
+
+Type const *E_cast::itcheck(Env &env)
+{
+  // let's just allow any cast at all; strips lvalue-ness
+  expr->tcheck(env)->asRval();
+  return ctype->tcheck(env);
+}
+
+
+Type const *E_cond::itcheck(Env &env)
+{
+  checkBoolean(env, cond->tcheck(env), cond);
+
+  Type const *t = th->tcheck(env);
+  Type const *e = el->tcheck(env);
+
+  // require both alternatives be primitive too..
+  checkBoolean(env, t, th);
+  checkBoolean(env, e, el);
+
+  return env.promoteTypes(BIN_PLUS, t, e);
+}
+
+
+#if 0
+Type const *E_gnuCond::itcheck(Env &env)
+{
+  Type const *c = cond->tcheck(env);
+  Type const *e = el->tcheck(env);
+
+  checkBoolean(env, c, cond);
+  checkBoolean(env, e, el);
+
+  return env.promoteTypes(BIN_PLUS, c, e);
+}
+#endif // 0
+
+
+Type const *E_comma::itcheck(Env &env)
+{
+  e1->tcheck(env);
+  e2->tcheck(env);
+
+  return e2->type;
+}
+
+
+Type const *E_sizeofType::itcheck(Env &env)
+{
+  size = atype->tcheck(env)->asRval()->reprSize();
+  return fixed(ST_INT);
+}
+
+
+Type const *E_new::itcheck(Env &env)
+{
+  return env.makePtrType(atype->tcheck(env));
+}
+
+
+Type const *E_assign::itcheck(Env &env)
+{
+  Type const *stype = src->tcheck(env)->asRval();
+  Type const *ttype = checkLval(env, target->tcheck(env), target);
+
+  if (env.inPredicate) {
+    env.err(stringc << "cannot have side effects in predicates: " << toString());
+  }
+
+  if (op != BIN_ASSIGN) {
+    // TODO: this isn't quite right.. I should first compute
+    // the promotion of stype,ttype, then verify this can
+    // in turn be coerced back to ttype.. (?)
+
+    // they both need to be integers or pointers
+    checkBoolean(env, stype, src);
+    checkBoolean(env, ttype, target);
+  }
+
+  env.checkCoercible(stype, ttype);
+
+  return ttype;    // not sure whether to return ttype or stype here..
+}
+
+
+Type const *E_quantifier::itcheck(Env &env)
+{
+  if (!env.inPredicate) {
+    env.err("forall is only allowed inside thmprv predicates");
+  }
+
+  // add declared variables to the environment
+  env.enterScope();
+  FOREACH_ASTLIST_NC(Declaration, decls, iter) {
+    Declaration *d = iter.data();
+
+    // mark all these as universal/existential
+    d->dflags = (DeclFlags)
+      (d->dflags | (forall? DF_UNIVERSAL : DF_EXISTENTIAL));
+
+    d->tcheck(env);
+  }
+
+  // typecheck the predicate
+  Type const *type = pred->tcheck(env)->asRval();
+  
+  // I really want this to be an int.. in fact I want it to be
+  // bool, but that type doesn't exist (yet?)
+  if (!type->isSimple(ST_INT)) {
+    env.err(stringc << "type of " << (forall? "forall" : "exists")
+                    << " predicate should be int, not "
+                    << type->toString());
+  }
+
+  // remove declared variables
+  env.leaveScope();
+
+  return type;
+}
+
+
+string Expression::extrasToString() const
+{
+  stringBuilder sb;
+  sb << "paths=" << numPaths << ", type: ";
+  if (type) {
+    sb << type->toCString();
+  }
+  else {
+    // for when we print a tree before/during typechecking
+    sb << "(null)";
+  }
+  return sb;
+}
+
+
+// -------------------- Expression::constEval ----------------------
+int Expression::xnonconst() const
+{
+  XNonConst x;
+  x.subexpr = this;
+  throw x;
+}
+
+
+int E_intLit::constEval(Env &env) const
+{
+  return i;
+}
+
+int E_charLit::constEval(Env &env) const
+{
+  return c;
+}
+
+
+int E_sizeof::constEval(Env &env) const
+{
+  return size;
+}
+
+int E_unary::constEval(Env &env) const
+{
+  int v = expr->constEval(env);
+  switch (op) {
+    default:         xfailure("bad op");
+    case UNY_PLUS:   return v;
+    case UNY_MINUS:  return -v;
+    case UNY_NOT:    return !v;
+    case UNY_BITNOT: return ~v;
+  }
+}
+
+int E_effect::constEval(Env &env) const
+{
+  return xnonconst();
+}
+
+
+int E_binary::constEval(Env &env) const
+{
+  int v1 = e1->constEval(env);
+  int v2 = e2->constEval(env);
+  switch (op) {
+    case BIN_MULT:      return v1 *  v2;
+    case BIN_DIV:       return v1 /  v2;
+    case BIN_MOD:       return v1 %  v2;
+    case BIN_PLUS:      return v1 +  v2;
+    case BIN_MINUS:     return v1 -  v2;
+    case BIN_LSHIFT:    return v1 << v2;
+    case BIN_RSHIFT:    return v1 >> v2;
+    case BIN_LESS:      return v1 <  v2;
+    case BIN_GREATER:   return v1 >  v2;
+    case BIN_LESSEQ:    return v1 <= v2;
+    case BIN_GREATEREQ: return v1 >= v2;
+    case BIN_EQUAL:     return v1 == v2;
+    case BIN_NOTEQUAL:  return v1 != v2;
+    case BIN_BITAND:    return v1 &  v2;
+    case BIN_BITXOR:    return v1 ^  v2;
+    case BIN_BITOR:     return v1 |  v2;
+    case BIN_AND:       return v1 && v2;
+    case BIN_OR:        return v1 || v2;
+    case BIN_IMPLIES:   return (!v1) || v2;
+
+    default:            xfailure("bad operator");
+                        return 0;   // silence warning
+  }
+}
+
+
+int E_cast::constEval(Env &env) const
+{
+  return expr->constEval(env);
+}
+
+
+int E_sizeofType::constEval(Env &env) const
+{
+  return size;
+}
+
+
+int E_floatLit::constEval(Env &env) const { return xnonconst(); }
+int E_stringLit::constEval(Env &env) const { return xnonconst(); }
+//int E_structLit::constEval(Env &env) const { return xnonconst(); }
+int E_variable::constEval(Env &env) const { return xnonconst(); }
+int E_funCall::constEval(Env &env) const { return xnonconst(); }
+int E_fieldAcc::constEval(Env &env) const { return xnonconst(); }
+int E_addrOf::constEval(Env &env) const { return xnonconst(); }
+int E_deref::constEval(Env &env) const { return xnonconst(); }
+int E_cond::constEval(Env &env) const { return xnonconst(); }
+//int E_gnuCond::constEval(Env &env) const { return xnonconst(); }
+int E_comma::constEval(Env &env) const { return xnonconst(); }
+int E_assign::constEval(Env &env) const { return xnonconst(); }
+int E_new::constEval(Env &env) const { return xnonconst(); }
+int E_quantifier::constEval(Env &env) const { return xnonconst(); }
+
+
+// -------------------- Expression::toString --------------------
+// TODO: these routines dramatically under-parenthesize the output..
+// not sure how/if to improve the situation easily
+
+string E_intLit::toString() const
+  { return stringc << i; }
+string E_floatLit::toString() const
+  { return stringc << f; }
+string E_stringLit::toString() const
+  { return stringc << quoted(s); }
+string E_charLit::toString() const
+  { return stringc << "'" << c << "'"; }
+//string E_structLit::toString() const
+//  { return stringc << "(..some type..){ ... }"; }
+
+string E_variable::toString() const
+{
+  if (!scopeName) {
+    return stringc << name;
+  }
+  else {
+    return stringc << scopeName << "::" << name;
+  }
+}
+
+string E_funCall::toString() const
+{
+  stringBuilder sb;
+  sb << func->toString() << "(";
+
+  int count=0;
+  FOREACH_ASTLIST(Expression, args, iter) {
+    if (count++) {
+      sb << ", ";
+    }
+    sb << iter.data()->toString();
+  }
+  sb << ")";
+  return sb;
+}
+
+string E_fieldAcc::toString() const
+  { return stringc << obj->toString() << "." << fieldName; }
+string E_sizeof::toString() const
+  { return stringc << "sizeof(" << expr->toString() << ")"; }
+string E_unary::toString() const
+  { return stringc << ::toString(op) << expr->toString(); }
+
+string E_effect::toString() const
+{ 
+  if (isPostfix(op)) {
+    return stringc << expr->toString() << ::toString(op);
+  }
+  else {
+    return stringc << ::toString(op) << expr->toString(); 
+  }
+}
+
+string E_binary::toString() const
+  { return stringc << e1->toString() << ::toString(op) << e2->toString(); }
+string E_addrOf::toString() const
+  { return stringc << "&" << expr->toString(); }
+string E_deref::toString() const
+  { return stringc << "*(" << ptr->toString() << ")"; }
+string E_cast::toString() const
+  { return stringc << "(" << type->toCString() << ")" << expr->toString(); }
+string E_cond::toString() const
+  { return stringc << cond->toString() << "?" << th->toString() << ":" << el->toString(); }
+//string E_gnuCond::toString() const
+//  { return stringc << cond->toString() << "?:" << el->toString(); }
+string E_comma::toString() const
+  { return stringc << e1->toString() << ", " << e2->toString(); }
+string E_sizeofType::toString() const
+  { return stringc << "sizeof(..some type..)"; }
+
+string E_new::toString() const
+{
+  return stringc << "new (" << type->asPointerTypeC().atType->toString() << ")";
+}
+
+string E_assign::toString() const
+{
+  if (op == BIN_ASSIGN) {
+    return stringc << target->toString() << " = " << src->toString();
+  }
+  else {
+    return stringc << target->toString() << " " << ::toString(op)
+                   << "= " << src->toString();
+  }
+}
+
+string E_quantifier::toString() const
+{
+  stringBuilder sb;
+  sb << (forall? "thmprv_forall(" : "thmprv_exists(");
+
+  FOREACH_ASTLIST(Declaration, decls, outer) {
+    FOREACH_ASTLIST(Declarator, outer.data()->decllist, inner) {
+      Variable *var = inner.data()->var;
+
+      sb << var->type->toCString(var->name) << "; ";
+    }
+  }
+
+  sb << pred->toString() << ")";
+  return sb;
+}
+
+
+/*
+  E_intLit
+  E_floatLit
+  E_stringLit
+  E_charLit
+  E_variable
+  E_arrayAcc
+  E_funCall
+  E_fieldAcc
+  E_sizeof
+  E_unary 
+  E_effect
+  E_binary
+  E_addrOf
+  E_deref
+  E_cast
+  E_cond
+  E_comma
+  E_sizeofType
+  E_assign
+*/
+
+
+// ------------------------- Initializer ---------------------------
+void IN_expr::tcheck(Env &env, Type const *type)
+{
+  Type const *t = e->tcheck(env);
+  env.checkCoercible(t, type);
+}
+
+void IN_compound::tcheck(Env &env, Type const *type)
+{
+  // for now, ignore labels
+  
+  if (type->isArrayType()) {
+    ArrayType const &at = type->asArrayTypeC();
+
+    // every element should correspond to the element type
+    FOREACH_ASTLIST_NC(Initializer, inits, iter) {
+      iter.data()->tcheck(env, at.eltType);
+    }
+
+    // check size restriction
+    if (at.hasSize && inits.count() > at.size) {
+      env.err(stringc << "initializer has " << inits.count()
+                      << " elements but array only has " << at.size
+                      << " elements");
+    }
+  }
+
+  else if (type->isCVAtomicType() &&
+           type->asCVAtomicTypeC().atomic->isCompoundType()) {
+    CompoundType const &ct = type->asCVAtomicTypeC().atomic->asCompoundTypeC();
+    
+    if (ct.keyword == CompoundType::K_UNION) {
+      env.err("I don't know how to initialize unions");
+      return;
+    }        
+
+    // iterate simultanously over fields and initializers, establishing
+    // correspondence
+    int field = 0;
+    FOREACH_ASTLIST_NC(Initializer, inits, iter) {
+      if (field >= ct.numFields()) {
+        env.err(stringc
+          << "too many initializers; " << ct.keywordAndName()
+          << " only has " << ct.numFields() << " fields, but "
+          << inits.count() << " initializers are present");
+        return;
+      }
+
+      CompoundType::Field const *f = ct.getNthField(field);
+
+      // check this initializer against the field it initializes
+      iter.data()->tcheck(env, f->type);
+      
+      field++;
+    }
+
+    // in C, it's ok to leave out initializers, since all data can
+    // be initialized to 0; so we don't complain if field is still
+    // less than ct.numFields()
+  }
+
+  else {
+    env.err(stringc << "you can't use a compound initializer to initialize "
+                    << type->toString());
+  }
+}

Added: vendor/elsa/current/elkhound/c/treeout.cc
===================================================================
--- vendor/elsa/current/elkhound/c/treeout.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/treeout.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// treeout.cc            see license.txt for copyright and terms of use
+// code for treeout.h
+
+#include "treeout.h"     // this module
+
+// print heading to stdout, with some indication of tree level
+ostream &treeOut(int level)
+{
+  while (level--) {
+    cout << "*";
+  }
+  cout << " ";
+  return cout;
+}

Added: vendor/elsa/current/elkhound/c/treeout.h
===================================================================
--- vendor/elsa/current/elkhound/c/treeout.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c/treeout.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// treeout.h            see license.txt for copyright and terms of use
+// interface for printing trees; very small right now
+
+// the idea is to print ascii marked in a way that Emacs' outline
+// mode can read and display it as a tree
+
+#ifndef TREEOUT_H
+#define TREEOUT_H
+
+#include <iostream.h>     // ostream
+
+// print heading to stdout, with some indication of tree level
+ostream &treeOut(int level);
+
+#endif // TREEOUT_H

Added: vendor/elsa/current/elkhound/c.in/c.in0
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in0	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in0	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// c.in0
+// even simpler..
+
+int x;

Added: vendor/elsa/current/elkhound/c.in/c.in1
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// c.in1
+// a simple test of c.gr
+
+int foo ( )
+{
+  return 3 ;
+}
+
+void bar()
+{}
+
+// EOF
+

Added: vendor/elsa/current/elkhound/c.in/c.in10
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in10	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in10	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// possible ambiguity in parameters
+
+int foo ( int ( x ) )
+{ }
+
+
+

Added: vendor/elsa/current/elkhound/c.in/c.in11
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in11	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in11	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+// c.in11
+// playing with initialized globals
+

Added: vendor/elsa/current/elkhound/c.in/c.in12
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in12	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in12	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// TypeId ambiguity
+
+int main()
+{
+  int x;
+
+  // cast to int, or to function returning int?  
+  //x = ( int() )3;           // ruled out by cppstd rules
+
+  //x = ( ( int() )3 )();     // ruled out by my rules
+
+
+  return 0;
+}

Added: vendor/elsa/current/elkhound/c.in/c.in2
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// slightly more complex than c.in1
+
+int y = 4;
+
+int foo (int z)
+{
+  return z + y ;
+}
+
+void bar()
+{
+  int x;
+  
+  x = y - 7;
+  y = foo(x);
+}
+
+
+

Added: vendor/elsa/current/elkhound/c.in/c.in2.c
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in2.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in2.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// possible ambiguity in parameters
+
+typedef int x;
+
+int foo ( int  x  )
+{ }
+
+int takesOneInt(int y) { return 6; }
+
+int bar()
+{
+  int i, j;
+
+  i = foo(4);
+  j = foo(takesOneInt);
+
+  return j;
+}
+
+
+

Added: vendor/elsa/current/elkhound/c.in/c.in3
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,58 @@
+// expressions
+
+typedef struct page { int x; } page;
+
+// interesting: g++ allows both of the following, 
+// but gcc allows neither
+//typedef struct page page;
+//typedef struct page page;
+
+typedef struct pte_t { int y; } pte_t;
+
+typedef struct Mystruct {
+  int a;
+  float b;
+  char c;
+} Mystruct;
+
+void putc(int);
+int get_pte_fast();
+
+int x;
+
+int foo ( )
+{
+  int dest, a, b;
+  int nr;
+  int pmd;
+  //enum E { a,b,c };
+  Mystruct *p;
+  pte_t * page = (pte_t *) get_pte_fast();
+
+  putc(-1);
+  //printf("foo\n");
+  sizeof(x);
+  //return 1 + 2 * 3 ;
+
+  ( dest )  = ( a )  & ( b ) ;     // AMBIGUOUS (no longer!)
+
+  sizeof(dest);
+  //sizeof(bar);
+  sizeof(Mystruct);
+
+  nr = ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long)) ;   // AMBIGUOUS
+
+  // this one is harder because there is a local definition
+  // of 'page' as a variable, and a global definition of it
+  // as a type
+
+  //(( *pmd ).pmd)  = (0x001  | 0x002  | 0x020  | 0x040 )
+  //  + ((unsigned long)( page )- ((unsigned long)(0xC0000000 ) ) ) ;   // AMBIGUOUS
+
+
+  sizeof(*p);
+  sizeof(p);
+
+  return sizeof(Mystruct);
+}
+

Added: vendor/elsa/current/elkhound/c.in/c.in4
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in4	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in4	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,402 @@
+/* -*- c++ -*-
+
+readpass.c
+
+  Author: Tatu Ylonen <ylo at ssh.com>
+
+  Copyright (C) 1995 Tatu Ylonen <ylo at ssh.com>, Espoo, Finland
+  Copyright (C) 1997-2000 SSH Communications Security Corp, Helsinki, Finland
+  All rights reserved.
+
+  Created: Mon Jul 10 22:08:59 1995 ylo
+
+  Functions for reading passphrases and passwords.
+
+*/
+
+
+// sm: stuff I've added to get it through my parser
+typedef void RETSIGTYPE;
+typedef /*bool*/ int Boolean;
+typedef struct FILE {
+  int foo;
+} FILE;
+void tcsetattr(...);
+int fileno(FILE *f);
+FILE *stdin;
+FILE *stdout;
+FILE *stderr;
+int TCSANOW;
+void ioctl(...);
+int TIOCSETP;
+typedef void (*sighandler_t)(int);
+sighandler_t signal(int signal, sighandler_t handler);
+void kill(int pid, int sig);
+int getpid();
+FILE *fopen(...);
+int fprintf(...);
+void fflush(FILE *f);
+int snprintf(...);
+char *getenv(char *);
+typedef void AnyFn(...);
+AnyFn popen, pclose, tcgetattr;
+int TIOCGETP, SIGINT, ECHO, ECHOE,
+    ECHOK, ECHONL;
+int c_lflag, sg_flags;
+int errno;
+void SSH_TRACE(int flag, void *whatever);
+AnyFn strerror, fclose, ssh_xstrdup,
+      memset;
+int isprint(char c);
+int isspace(char c);
+int iscntrl(char c);
+int strlen(char const *s);
+char *fgets(char *s, int size, FILE *stream);
+char *strchr(char *s, char c);
+struct termios {
+  int c_lflag;
+};    
+typedef int size_t;
+size_t read(int fd, void *buf, size_t count);
+int strcmp(char const *s1, char const *s2);
+
+//#include "ssh2includes.h"
+//#include "readpass.h"
+
+//#define SSH_DEBUG_MODULE "SshReadPass"
+
+/* Saved old terminal mode for read_passphrase. */
+//#ifdef USING_TERMIOS
+static struct termios saved_tio  /*thmprv_attr(addrtaken)*/;
+//#endif
+//#ifdef USING_SGTTY
+//static struct sgttyb saved_tio;
+//#endif
+
+/* Old interrupt signal handler for read_passphrase. */
+static RETSIGTYPE (*old_handler)(int sig) = 0/*NULL*/;
+
+/* Interrupt signal handler for read_passphrase. */
+
+RETSIGTYPE ssh_rp_intr_handler(int sig)
+{
+  /* Restore terminal modes. */
+//#ifdef USING_TERMIOS
+  tcsetattr(fileno(stdin), TCSANOW, &saved_tio);
+//#endif
+//#ifdef USING_SGTTY
+  //ioctl(fileno(stdin), TIOCSETP, &saved_tio);
+//#endif
+  /* Restore the old signal handler. */
+  signal(sig, old_handler);
+  /* Resend the signal, with the old handler. */
+  kill(getpid(), sig);
+}
+
+/* Reads a passphrase from /dev/tty with echo turned off.  Returns the
+   passphrase (allocated with ssh_xmalloc).  Returns NULL if EOF is encountered.
+   The passphrase if read from stdin if from_stdin is true (as is the
+   case with ssh-keygen).  */
+
+char *ssh_read_passphrase(const char *prompt, Boolean from_stdin)
+{
+  char buf[1024], *cp;
+  unsigned char quoted_prompt[512];
+  unsigned char const *p;    // sm: swapped order of 'char' and 'const'
+//#ifdef USING_TERMIOS
+  struct termios tio;
+//#endif
+//#ifdef USING_SGTTY
+  //struct sgttyb tio;
+//#endif
+  FILE *f;
+  int i;
+  
+  if (from_stdin)
+    {
+      f = stdin;
+    }
+  else
+    {
+      /* Read the passphrase from /dev/tty to make it possible to ask it even 
+         when stdin has been redirected. */
+      f = fopen("/dev/tty", "r");
+      if (!f)
+        {
+          if (getenv("DISPLAY"))
+            {
+              char command[512];
+              
+              fprintf(stderr,
+                      "Executing ssh-askpass to query the password...\n");
+              fflush(stdout);
+              fflush(stderr);
+              for(p = (unsigned char const *) prompt, i = 0;
+                  i < sizeof(quoted_prompt) - 5 && *p;
+                  i++, p++)
+                {
+                  if (*p == '\'')
+                    {
+                      quoted_prompt[i++] = '\'';
+                      quoted_prompt[i++] = '\\';
+                      quoted_prompt[i++] = '\'';
+                      quoted_prompt[i] = '\'';
+                    }
+                  else if (isprint(*p) || isspace(*p))
+                    quoted_prompt[i] = *p;
+                  else if (iscntrl(*p))
+                    {
+                      quoted_prompt[i++] = '^';
+                      if (*p < ' ')
+                        quoted_prompt[i] = *p + '@';
+                      else
+                        quoted_prompt[i] = '?';
+                    }
+                  else if (*p > 128)
+                    quoted_prompt[i] = *p;
+                }
+              quoted_prompt[i] = '\0';
+  
+              snprintf(command, sizeof(command),
+                       "ssh-askpass '%.400s'", quoted_prompt);
+              
+              f = popen(command, "r");
+              if (f == 0/*NULL*/)
+                {
+                  fprintf(stderr, "Could not query passphrase: '%.200s' failed.\n",
+                          command);
+                  return 0/*NULL*/;
+                }
+              if (!fgets(buf, sizeof(buf), f))
+                {
+                  pclose(f);
+                  fprintf(stderr, "No passphrase supplied.\n");
+                  return 0/*NULL*/;
+                }
+              pclose(f);
+              if (strchr(buf, '\n'))
+                *strchr(buf, '\n') = 0;
+              return ssh_xstrdup(buf);
+            }
+
+          /* No controlling terminal and no DISPLAY.  Nowhere to read. */
+          fprintf(stderr, "You have no controlling tty and no DISPLAY.  Cannot read passphrase.\n");
+          return 0/*NULL*/;
+        }
+    }
+
+  for(p = (unsigned char const *) prompt, i = 0;
+      i < sizeof(quoted_prompt) - 4 && *p; i++, p++)
+    {
+      if (isprint(*p) || isspace(*p))
+        quoted_prompt[i] = *p;
+      else if (iscntrl(*p))
+        {
+          quoted_prompt[i++] = '^';
+          if (*p < ' ')
+            quoted_prompt[i] = *p + '@';
+          else
+            quoted_prompt[i] = '?';
+        }
+      else if (*p > 128)
+        quoted_prompt[i] = *p;
+    }
+  quoted_prompt[i] = '\0';
+  
+  /* Display the prompt (on stderr because stdout might be redirected). */
+  fflush(stdout);
+  fprintf(stderr, "%s", quoted_prompt);
+  fflush(stderr);
+
+  /* Get terminal modes. */
+//#ifdef USING_TERMIOS
+  tcgetattr(fileno(f), &tio);
+//#endif
+//#ifdef USING_SGTTY
+  //ioctl(fileno(f), TIOCGETP, &tio);
+//#endif
+  saved_tio = tio;
+  /* Save signal handler and set the new handler. */
+  old_handler = signal(SIGINT, ssh_rp_intr_handler);
+
+  /* Set new terminal modes disabling all echo. */
+//#ifdef USING_TERMIOS
+  tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+  tcsetattr(fileno(f), TCSANOW, &tio);
+//#endif
+//#ifdef USING_SGTTY
+  //tio.sg_flags &= ~(ECHO);
+  //ioctl(fileno(f), TIOCSETP, &tio);
+//#endif
+  
+  {
+    /* Read the passphrase from the terminal. */
+    int read_bytes = 0, ret = 0;
+    while ((ret = read(fileno(f), &buf[read_bytes], 1)) != 0)
+      {
+        if (ret == -1)
+          {
+            if (errno == 5/*EAGAIN*/ || errno == 6/*EWOULDBLOCK*/ || errno == 7/*EINTR*/)
+              {
+                SSH_TRACE(2, ("got errno %d, system error %s",
+                              errno, strerror(errno)));
+                /* No more data at this time, or interrupted by system
+                   call.*/
+                continue;
+              }
+            else
+              {
+                /* Got some other error. */
+                SSH_TRACE(2, ("read() returned -1, with errno %d, "
+                              "system error message %s.",
+                              errno, strerror(errno)));
+                goto read_error;
+              }
+          }
+
+        read_bytes++;
+        if (buf[read_bytes - 1] == '\n' || buf[read_bytes - 1] == '\r' ||
+            read_bytes + 1>= sizeof(buf))
+          {
+            /* Got newline, error, or buf full. */
+            buf[read_bytes] = '\0';
+            break;            
+          }
+      }
+    if (ret == 0)
+      {
+        SSH_TRACE(2, ("Received EOF."));
+      read_error:
+        /* Got EOF, or error.  Just return NULL. */
+        /* Restore terminal modes. */
+//#ifdef USING_TERMIOS
+        tcsetattr(fileno(f), TCSANOW, &saved_tio);
+//#endif
+//#ifdef USING_SGTTY
+        ioctl(fileno(f), TIOCSETP, &saved_tio);
+//#endif
+        /* Restore the signal handler. */
+        signal(SIGINT, old_handler);
+        /* Print a newline (the prompt probably didn\'t have one). */
+        fprintf(stderr, "\r\n");
+        /* Close the file. */
+        if (f != stdin)
+          fclose(f);
+        return 0/*NULL*/;
+        
+      }
+  }
+
+//#ifdef OLDXXX
+  /* Read the passphrase from the terminal. */
+  if (fgets(buf, sizeof(buf), f) == 0/*NULL*/)
+    {
+      /* Got EOF.  Just return NULL. */
+      /* Restore terminal modes. */
+//#ifdef USING_TERMIOS
+      tcsetattr(fileno(f), TCSANOW, &saved_tio);
+//#endif
+//#ifdef USING_SGTTY
+      //ioctl(fileno(f), TIOCSETP, &saved_tio);
+//#endif
+      /* Restore the signal handler. */
+      signal(SIGINT, old_handler);
+      /* Print a newline (the prompt probably didn\'t have one). */
+      fprintf(stderr, "\r\n");
+      /* Close the file. */
+      if (f != stdin)
+        fclose(f);
+      return 0/*NULL*/;
+    }
+//#endif /* OLDXXX */
+  /* Restore terminal modes. */
+//#ifdef USING_TERMIOS
+  tcsetattr(fileno(f), TCSANOW, &saved_tio);
+//#endif
+//#ifdef USING_SGTTY
+  //ioctl(fileno(f), TIOCSETP, &saved_tio);
+//#endif
+  /* Restore the signal handler. */
+  (void)signal(SIGINT, old_handler);
+  /* Remove newline from the passphrase. */
+  if (strchr(buf, '\n'))
+    *strchr(buf, '\n') = 0;
+  if (strchr(buf, '\r'))
+    *strchr(buf, '\r') = 0;
+  /* Allocate a copy of the passphrase. */
+  cp = ssh_xstrdup(buf);
+  /* Clear the buffer so we don\'t leave copies of the passphrase laying
+     around. */
+  memset(buf, 0, sizeof(buf));
+  /* Print a newline since the prompt probably didn\'t have one. */
+  fprintf(stderr, "\r\n");
+  /* Close the file. */
+  if (f != stdin)
+    fclose(f);
+  return cp;
+}
+
+
+/* Reads a yes/no confirmation from /dev/tty.  Returns TRUE if "yes" is
+   received.  Otherwise returns FALSE (also if EOF is encountered). */
+
+Boolean ssh_read_confirmation(const char *prompt, Boolean from_stdin)
+{
+  char buf[1024], *p;
+  FILE *f;
+  
+  if (from_stdin)
+    {
+      f = stdin;
+    }
+  else
+    {
+      /* Read the passphrase from /dev/tty to make it possible to ask it even 
+         when stdin has been redirected. */
+      f = fopen("/dev/tty", "r");
+      if (!f)
+        {
+          fprintf(stderr, "You have no controlling tty.  Cannot read "
+                  "confirmation.\n");
+          return 0/*FALSE*/;
+        }
+    }
+
+  /* Read the passphrase from the terminal. */
+  do
+    {
+      /* Display the prompt (on stderr because stdout might be redirected). */
+      fflush(stdout);
+      fprintf(stderr, "%s", prompt);
+      fflush(stderr);
+      /* Read line */
+      if (fgets(buf, sizeof(buf), f) == 0/*NULL*/)
+        {
+          /* Got EOF.  Just exit. */
+          /* Print a newline (the prompt probably didn\'t have one). */
+          fprintf(stderr, "\n");
+          fprintf(stderr, "Aborted by user");
+          /* Close the file. */
+          if (f != stdin)
+            fclose(f);
+          return 0/*FALSE*/;
+        }
+      p = buf + strlen(buf) - 1;
+      while (p > buf && isspace(*p))
+        *p-- = '\0';
+      p = buf;
+      while (*p && isspace(*p))
+        p++;
+      if (strcmp(p, "no") == 0)
+        {
+          /* Close the file. */
+          if (f != stdin)
+            fclose(f);
+          return 0/*FALSE*/;
+        }
+    } while (strcmp(p, "yes") != 0);
+  /* Close the file. */
+  if (f != stdin)
+    fclose(f);
+  return 1/*TRUE*/;
+}

Added: vendor/elsa/current/elkhound/c.in/c.in4b
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in4b	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in4b	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,401 @@
+/* -*- c++ -*-
+
+readpass.c
+
+  Author: Tatu Ylonen <ylo at ssh.com>
+
+  Copyright (C) 1995 Tatu Ylonen <ylo at ssh.com>, Espoo, Finland
+  Copyright (C) 1997-2000 SSH Communications Security Corp, Helsinki, Finland
+  All rights reserved.
+
+  Created: Mon Jul 10 22:08:59 1995 ylo
+
+  Functions for reading passphrases and passwords.
+
+*/
+
+
+// sm: stuff I've added to get it through my parser
+typedef void RETSIGTYPE;
+typedef /*bool*/ int Boolean;
+typedef struct FILE {
+  int foo;
+} FILE;
+void tcsetattr(...);
+int fileno(struct FILE *f);
+struct FILE *stdin;
+struct FILE *stdout;
+struct FILE *stderr;
+int TCSANOW;
+void ioctl(...);
+int TIOCSETP;
+//typedef void (*sighandler_t)(int);
+//sighandler_t signal(int signal, sighandler_t handler);
+void kill(int pid, int sig);
+int getpid();
+struct FILE *fopen(...);
+int fprintf(...);
+void fflush(struct FILE *f);
+int snprintf(...);
+char *getenv(char *);
+//typedef void AnyFn(...);
+//AnyFn popen, pclose, tcgetattr;
+int TIOCGETP, SIGINT, ECHO, ECHOE,
+    ECHOK, ECHONL;
+int c_lflag, sg_flags;
+int errno;
+void SSH_TRACE(int flag, void *whatever);
+//AnyFn strerror, fclose, ssh_xstrdup, memset;
+int isprint(char c);
+int isspace(char c);
+int iscntrl(char c);
+int strlen(char const *s);
+char *fgets(char *s, int size, struct FILE *stream);
+char *strchr(char *s, char c);
+struct termios {
+  int c_lflag;
+};    
+typedef int size_t;
+int read(int fd, void *buf, int count);
+int strcmp(char const *s1, char const *s2);
+
+//#include "ssh2includes.h"
+//#include "readpass.h"
+
+//#define SSH_DEBUG_MODULE "SshReadPass"
+
+/* Saved old terminal mode for read_passphrase. */
+//#ifdef USING_TERMIOS
+static struct termios saved_tio  /*thmprv_addr(addrtaken)*/;
+//#endif
+//#ifdef USING_SGTTY
+//static struct sgttyb saved_tio;
+//#endif
+
+/* Old interrupt signal handler for read_passphrase. */
+static void (*old_handler)(int sig) = 0/*NULL*/;
+
+/* Interrupt signal handler for read_passphrase. */
+
+void ssh_rp_intr_handler(int sig)
+{
+  /* Restore terminal modes. */
+//#ifdef USING_TERMIOS
+  tcsetattr(fileno(stdin), TCSANOW, &saved_tio);
+//#endif
+//#ifdef USING_SGTTY
+  //ioctl(fileno(stdin), TIOCSETP, &saved_tio);
+//#endif
+  /* Restore the old signal handler. */
+  signal(sig, old_handler);
+  /* Resend the signal, with the old handler. */
+  kill(getpid(), sig);
+}
+
+/* Reads a passphrase from /dev/tty with echo turned off.  Returns the
+   passphrase (allocated with ssh_xmalloc).  Returns NULL if EOF is encountered.
+   The passphrase if read from stdin if from_stdin is true (as is the
+   case with ssh-keygen).  */
+
+char *ssh_read_passphrase(const char *prompt, int from_stdin)
+{
+  char buf[1024], *cp;
+  unsigned char quoted_prompt[512];
+  unsigned char const *p;    // sm: swapped order of 'char' and 'const'
+//#ifdef USING_TERMIOS
+  struct termios tio;
+//#endif
+//#ifdef USING_SGTTY
+  //struct sgttyb tio;
+//#endif
+  struct FILE *f;
+  int i;
+  
+  if (from_stdin)
+    {
+      f = stdin;
+    }
+  else
+    {
+      /* Read the passphrase from /dev/tty to make it possible to ask it even 
+         when stdin has been redirected. */
+      f = fopen("/dev/tty", "r");
+      if (!f)
+        {
+          if (getenv("DISPLAY"))
+            {
+              char command[512];
+              
+              fprintf(stderr,
+                      "Executing ssh-askpass to query the password...\n");
+              fflush(stdout);
+              fflush(stderr);
+              for(p = (unsigned char const *) prompt, i = 0;
+                  i < sizeof(quoted_prompt) - 5 && *p;
+                  i++, p++)
+                {
+                  if (*p == '\'')
+                    {
+                      quoted_prompt[i++] = '\'';
+                      quoted_prompt[i++] = '\\';
+                      quoted_prompt[i++] = '\'';
+                      quoted_prompt[i] = '\'';
+                    }
+                  else if (isprint(*p) || isspace(*p))
+                    quoted_prompt[i] = *p;
+                  else if (iscntrl(*p))
+                    {
+                      quoted_prompt[i++] = '^';
+                      if (*p < ' ')
+                        quoted_prompt[i] = *p + '@';
+                      else
+                        quoted_prompt[i] = '?';
+                    }
+                  else if (*p > 128)
+                    quoted_prompt[i] = *p;
+                }
+              quoted_prompt[i] = '\0';
+  
+              snprintf(command, sizeof(command),
+                       "ssh-askpass '%.400s'", quoted_prompt);
+              
+              f = popen(command, "r");
+              if (f == 0/*NULL*/)
+                {
+                  fprintf(stderr, "Could not query passphrase: '%.200s' failed.\n",
+                          command);
+                  return 0/*NULL*/;
+                }
+              if (!fgets(buf, sizeof(buf), f))
+                {
+                  pclose(f);
+                  fprintf(stderr, "No passphrase supplied.\n");
+                  return 0/*NULL*/;
+                }
+              pclose(f);
+              if (strchr(buf, '\n'))
+                *strchr(buf, '\n') = 0;
+              return ssh_xstrdup(buf);
+            }
+
+          /* No controlling terminal and no DISPLAY.  Nowhere to read. */
+          fprintf(stderr, "You have no controlling tty and no DISPLAY.  Cannot read passphrase.\n");
+          return 0/*NULL*/;
+        }
+    }
+
+  for(p = (unsigned char const *) prompt, i = 0;
+      i < sizeof(quoted_prompt) - 4 && *p; i++, p++)
+    {
+      if (isprint(*p) || isspace(*p))
+        quoted_prompt[i] = *p;
+      else if (iscntrl(*p))
+        {
+          quoted_prompt[i++] = '^';
+          if (*p < ' ')
+            quoted_prompt[i] = *p + '@';
+          else
+            quoted_prompt[i] = '?';
+        }
+      else if (*p > 128)
+        quoted_prompt[i] = *p;
+    }
+  quoted_prompt[i] = '\0';
+  
+  /* Display the prompt (on stderr because stdout might be redirected). */
+  fflush(stdout);
+  fprintf(stderr, "%s", quoted_prompt);
+  fflush(stderr);
+
+  /* Get terminal modes. */
+//#ifdef USING_TERMIOS
+  tcgetattr(fileno(f), &tio);
+//#endif
+//#ifdef USING_SGTTY
+  //ioctl(fileno(f), TIOCGETP, &tio);
+//#endif
+  saved_tio = tio;
+  /* Save signal handler and set the new handler. */
+  old_handler = signal(SIGINT, ssh_rp_intr_handler);
+
+  /* Set new terminal modes disabling all echo. */
+//#ifdef USING_TERMIOS
+  tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+  tcsetattr(fileno(f), TCSANOW, &tio);
+//#endif
+//#ifdef USING_SGTTY
+  //tio.sg_flags &= ~(ECHO);
+  //ioctl(fileno(f), TIOCSETP, &tio);
+//#endif
+  
+  {
+    /* Read the passphrase from the terminal. */
+    int read_bytes = 0, ret = 0;
+    while ((ret = read(fileno(f), &buf[read_bytes], 1)) != 0)
+      {
+        if (ret == -1)
+          {
+            if (errno == 5/*EAGAIN*/ || errno == 6/*EWOULDBLOCK*/ || errno == 7/*EINTR*/)
+              {
+                SSH_TRACE(2, ("got errno %d, system error %s",
+                              errno, strerror(errno)));
+                /* No more data at this time, or interrupted by system
+                   call.*/
+                continue;
+              }
+            else
+              {
+                /* Got some other error. */
+                SSH_TRACE(2, ("read() returned -1, with errno %d, "
+                              "system error message %s.",
+                              errno, strerror(errno)));
+                goto read_error;
+              }
+          }
+
+        read_bytes++;
+        if (buf[read_bytes - 1] == '\n' || buf[read_bytes - 1] == '\r' ||
+            read_bytes + 1>= sizeof(buf))
+          {
+            /* Got newline, error, or buf full. */
+            buf[read_bytes] = '\0';
+            break;            
+          }
+      }
+    if (ret == 0)
+      {
+        SSH_TRACE(2, ("Received EOF."));
+      read_error:
+        /* Got EOF, or error.  Just return NULL. */
+        /* Restore terminal modes. */
+//#ifdef USING_TERMIOS
+        tcsetattr(fileno(f), TCSANOW, &saved_tio);
+//#endif
+//#ifdef USING_SGTTY
+        ioctl(fileno(f), TIOCSETP, &saved_tio);
+//#endif
+        /* Restore the signal handler. */
+        signal(SIGINT, old_handler);
+        /* Print a newline (the prompt probably didn\'t have one). */
+        fprintf(stderr, "\r\n");
+        /* Close the file. */
+        if (f != stdin)
+          fclose(f);
+        return 0/*NULL*/;
+        
+      }
+  }
+
+//#ifdef OLDXXX
+  /* Read the passphrase from the terminal. */
+  if (fgets(buf, sizeof(buf), f) == 0/*NULL*/)
+    {
+      /* Got EOF.  Just return NULL. */
+      /* Restore terminal modes. */
+//#ifdef USING_TERMIOS
+      tcsetattr(fileno(f), TCSANOW, &saved_tio);
+//#endif
+//#ifdef USING_SGTTY
+      //ioctl(fileno(f), TIOCSETP, &saved_tio);
+//#endif
+      /* Restore the signal handler. */
+      signal(SIGINT, old_handler);
+      /* Print a newline (the prompt probably didn\'t have one). */
+      fprintf(stderr, "\r\n");
+      /* Close the file. */
+      if (f != stdin)
+        fclose(f);
+      return 0/*NULL*/;
+    }
+//#endif /* OLDXXX */
+  /* Restore terminal modes. */
+//#ifdef USING_TERMIOS
+  tcsetattr(fileno(f), TCSANOW, &saved_tio);
+//#endif
+//#ifdef USING_SGTTY
+  //ioctl(fileno(f), TIOCSETP, &saved_tio);
+//#endif
+  /* Restore the signal handler. */
+  (void)signal(SIGINT, old_handler);
+  /* Remove newline from the passphrase. */
+  if (strchr(buf, '\n'))
+    *strchr(buf, '\n') = 0;
+  if (strchr(buf, '\r'))
+    *strchr(buf, '\r') = 0;
+  /* Allocate a copy of the passphrase. */
+  cp = ssh_xstrdup(buf);
+  /* Clear the buffer so we don\'t leave copies of the passphrase laying
+     around. */
+  memset(buf, 0, sizeof(buf));
+  /* Print a newline since the prompt probably didn\'t have one. */
+  fprintf(stderr, "\r\n");
+  /* Close the file. */
+  if (f != stdin)
+    fclose(f);
+  return cp;
+}
+
+
+/* Reads a yes/no confirmation from /dev/tty.  Returns TRUE if "yes" is
+   received.  Otherwise returns FALSE (also if EOF is encountered). */
+
+int ssh_read_confirmation(const char *prompt, int from_stdin)
+{
+  char buf[1024], *p;
+  struct FILE *f;
+  
+  if (from_stdin)
+    {
+      f = stdin;
+    }
+  else
+    {
+      /* Read the passphrase from /dev/tty to make it possible to ask it even 
+         when stdin has been redirected. */
+      f = fopen("/dev/tty", "r");
+      if (!f)
+        {
+          fprintf(stderr, "You have no controlling tty.  Cannot read "
+                  "confirmation.\n");
+          return 0/*FALSE*/;
+        }
+    }
+
+  /* Read the passphrase from the terminal. */
+  do
+    {
+      /* Display the prompt (on stderr because stdout might be redirected). */
+      fflush(stdout);
+      fprintf(stderr, "%s", prompt);
+      fflush(stderr);
+      /* Read line */
+      if (fgets(buf, sizeof(buf), f) == 0/*NULL*/)
+        {
+          /* Got EOF.  Just exit. */
+          /* Print a newline (the prompt probably didn\'t have one). */
+          fprintf(stderr, "\n");
+          fprintf(stderr, "Aborted by user");
+          /* Close the file. */
+          if (f != stdin)
+            fclose(f);
+          return 0/*FALSE*/;
+        }
+      p = buf + strlen(buf) - 1;
+      while (p > buf && isspace(*p))
+        *p-- = '\0';
+      p = buf;
+      while (*p && isspace(*p))
+        p++;
+      if (strcmp(p, "no") == 0)
+        {
+          /* Close the file. */
+          if (f != stdin)
+            fclose(f);
+          return 0/*FALSE*/;
+        }
+    } while (strcmp(p, "yes") != 0);
+  /* Close the file. */
+  if (f != stdin)
+    fclose(f);
+  return 1/*TRUE*/;
+}

Added: vendor/elsa/current/elkhound/c.in/c.in5
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in5	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in5	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// reproducing qpmouse failure
+
+// this typedef should disambiguate casts and fn calls
+typedef unsigned short __u16;
+int ___arch__swab16(int f);
+int __builtin_constant_p(int x);
+
+// this is needed for a similar purpose
+extern __inline__ __const__ __u16 __fswab16(__u16 x)
+{
+ return ___arch__swab16( x ) ;
+}
+
+extern __inline__ __u16 __swab16p(__u16 *x)
+{
+  (__u16)( *( x ) );
+
+  // this line causes the problem
+  return (
+    __builtin_constant_p
+      ((__u16)( *( x ) )) ?
+      ((__u16)( (((__u16)( ( *( x ) ) ) & (__u16)0x00ffU) << 8) | (((__u16)( ( *( x ) ) ) & (__u16)0xff00U) >> 8) ))  :
+      __fswab16(( *( x ) ))
+  )  ;
+}

Added: vendor/elsa/current/elkhound/c.in/c.in6
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in6	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in6	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,94 @@
+// c.in6
+// testcases for the translator: make sure I emit every
+// construct in Cil
+
+int binops()
+{
+  int r,x,y,z;
+
+  r = x + y - z * x / y % z;
+  r = x << y >> z;
+  r = x < y > z <= x >= y;
+  r = x == y != z;
+  r = x & y ^ z | x;
+  r = x && y;     // should do short-circuit!
+  r = z || y;
+
+  return r;
+}
+
+
+int unops(int x)
+{
+  int r;     
+  
+  r = -x;
+  r = !x;
+  r = ~x;
+  
+  return r;
+}
+
+
+void exprs()
+{
+  int x,y,z;
+
+  x = 5;
+  x = (int)y;       // seen as an lval cast
+  x = (int)(y+z);   // seen as an rval cast
+  x = &z;
+}
+
+
+typedef struct S { int m; } S;
+S global_s;
+
+void lvals()
+{
+  int x,y,z,*ip;
+  int a[3];
+  S s, *sp;
+
+  x = y;
+  *ip = z;
+  s.m = z;
+  sp->m = 5;
+  //(char)x = z;      // removed casts as lvals
+  a[1] = y;
+
+  // TODO: handle this more gracefully
+  //(char)(x+y) = z;
+}
+
+
+int twoArgFn(int a, int b);
+
+void insts()
+{
+  int x,y,z;
+  x = y;
+  y = binops();
+  z = unops(x);
+  x = twoArgFn(y,z);
+  { x=1; y=2; }       // interestingly, this doesn't lead to a CilCompound
+  
+  while (x) {
+    y = 3;
+  }
+
+  if (x) { 
+    z = 1;
+  }
+  else {
+    z = 2;
+  }
+  
+mylabel:
+  x = 6;
+  goto mylabel;
+
+  return y;
+}
+
+

Added: vendor/elsa/current/elkhound/c.in/c.in7
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in7	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in7	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,101 @@
+// c.in7
+// testcases for translator: exercise all the
+// translation code in cc.gr
+
+int fn0();
+int fn1(int g);
+int fn2(int g, int h);
+int fn3(int g, int h, int i);
+
+typedef struct S {
+  int m1;
+  int m2;
+} S;
+
+int foo()
+{
+  int a,b,c,x,y,z,arr[4];
+  S s, *sp;
+
+  a = 5;              // Literal and VariableName
+
+  x = arr[1];         // array ref
+  arr[2] = y;
+
+  x = fn0();          // fn call
+  y = fn1(x);
+  z = fn2(x, y);
+
+  a = s.m1;           // field access
+  b = sp->m2;         // deref and field access
+  
+  a = b++;            // postfix ++
+  c = z--;            // postfix --
+  
+  y = ++x;            // prefix --
+  c = --a;            // prefix ++
+  
+  b = sizeof(a);      // sizeof of expr, with built-in type
+  c = sizeof(s);      // sizeof of expr, with user-def type
+
+  b = &s;             // addr-of
+
+  b = sizeof(int);    // sizeof built-in type
+  a = sizeof(S);      // sizeof user-def type
+
+  //(int)c = x;         // cast of lval (removed)
+  b = (int)(x+y);     // cast of expr
+
+  a = b + c;          // binary expr
+  a = x && y;         // short-circuit and
+  a = z || x;         // short-circuit or
+  
+  c = x ? y : z;      // ?: with control flow
+  //c = x ?: z;         // strange crap
+  
+  a = b;              // assignment
+  x += y;             // accumulation assignment
+
+  a = (b , c);        // comma operator (lower prec. than '=' !)
+  
+myLabel: x=y;         // labeled statement
+
+  if (a++) {            // if-then
+    b = c;
+  }
+
+  if (a++) {            // if-then-else
+    b = y;
+  }
+  else {
+    c = z;
+  }
+
+  while (x++) {         // while
+    y = z;
+  }
+
+  do {                  // do-while
+    y = z;
+  } while (x++);
+
+  for (a=0; a<5; a++) { // for
+    y=z;
+  }
+  
+  // C++ only
+  //for (int i=0; i; ) {  // for with decl in initializer slot
+  //  i=7;
+  //} 
+
+  return 6;             // return with arg
+  //return;               // return w/o arg
+
+  goto myLabel;         // goto
+
+  { x=5; y=6; }         // compound
+  {}                    // empty compound
+
+  int j;                // simple decl
+  int k=6;              // initializing decl
+}

Added: vendor/elsa/current/elkhound/c.in/c.in8
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in8	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in8	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// c.in8
+// exercise type printer
+
+void *ptrToVoid;
+void const *ptrToConstVoid;
+
+int anInt;
+int const aConstInt;
+
+float aFloat;
+float volatile aVolatileFloat;
+
+typedef struct List {
+  int x;
+  struct List *next;
+} List;
+List aList;
+List const aConstList;
+
+int arrayOf5Ints[5];
+void *arrayOfPtrs[];
+
+typedef struct Union {
+  int i;
+  float f;
+} Union;
+Union aUnion;
+
+typedef enum Enum { e0, e1, e2, e7=7, e8, e4=4, e5 } Enum;
+Enum e;
+
+int twoArgFn(int x, int y);
+
+
+

Added: vendor/elsa/current/elkhound/c.in/c.in9
===================================================================
--- vendor/elsa/current/elkhound/c.in/c.in9	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/c.in/c.in9	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,51 @@
+// c.in9
+// testing the lval translator
+
+typedef struct S { int f,ar[5]; } S;
+typedef struct T { struct S s; } T;
+
+void foo()
+{
+  S s,sarr[3];
+  T t;
+  int x,y,*p,arr[3];
+  float f;
+
+  // simple varref rewrite
+  x = y;
+
+  // simple deref rewrite
+  *p = y;
+
+
+  // array elt rewrite
+  arr[1] = 4;
+
+  // not simplified!
+  *(arr+1) = 4;
+
+  
+  // unassigned lval cast rewrite
+  f = (float)x;
+
+  // assigned lval cast rewrite
+  //(float)x = f;   // removed this syntax
+
+
+  // field of field
+  x = t.s.f;
+
+  // field of array elt
+  sarr[3].f = y;
+
+  // array elt of field
+  s.ar[3] = y;
+
+  // array elt of array elt
+  sarr[2].ar[1] = 8;
+
+
+  // illegal lval cast to struct
+  y = ((S)x).f;
+
+}

Added: vendor/elsa/current/elkhound/cc2/cc2.gr
===================================================================
--- vendor/elsa/current/elkhound/cc2/cc2.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/cc2/cc2.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1236 @@
+// cc2.gr            see license.txt for copyright and terms of use
+// starting over with a C++ grammar
+// working from ISO/IEC 14882:1998(E)
+
+option useGCDefaults;
+
+verbatim [
+
+#include "ptreenode.h"    // PTreeNode
+
+]
+
+context_class CC2 : public UserActions {
+public:
+  CC2() {}
+};
+
+
+terminals {
+  // grab list generated by lexer
+  include("c/c.tok")
+}
+
+
+// start symbol
+nonterm StartSymbol -> TranslationUnit;
+
+
+// map from my lexer's names into the Standard's names
+nonterm Identifier -> L2_NAME;
+
+nonterm IntegerLiteral -> L2_INT_LITERAL;
+
+nonterm CharacterLiteral -> L2_CHAR_LITERAL;
+
+nonterm FloatingLiteral -> L2_FLOAT_LITERAL;
+
+nonterm StringLiteral -> L2_STRING_LITERAL;
+
+nonterm BooleanLiteral {
+  -> "true";
+  -> "false";
+}
+
+
+// -------------------- A.1 Keywords --------------------
+
+nonterm TypedefName {
+  -> Identifier;
+}
+
+nonterm NamespaceName {
+  -> OriginalNamespaceName;
+  -> NamespaceAlias;
+}
+
+nonterm OriginalNamespaceName {
+  -> Identifier;
+}
+
+nonterm NamespaceAlias {
+  -> Identifier;
+}
+
+nonterm ClassName {
+  -> Identifier;
+  -> TemplateId;
+}
+
+nonterm EnumName {
+  -> Identifier;
+}
+
+nonterm TemplateName {
+  -> Identifier;
+}
+
+
+// -------------------- A.2 Lexical conventions --------------------
+
+// since I assume the use of a conventional lexical analyzer, I don't
+// reproduce all of the rules from the standard here; instead I list
+// the tokens I assume will be exported by the lexer:
+
+//   Identifier
+//   IntegerLiteral
+//   CharacterLiteral
+//   FloatingLiteral
+//   StringLiteral
+//   BooleanLiteral
+//   keywords: "this", "if", ...
+//   operators: "+", "-", ...
+//   punctuators: "(", ")", ";", ...
+
+nonterm Literal {
+  -> IntegerLiteral;
+  -> CharacterLiteral;
+  -> FloatingLiteral;
+  -> StringLiteral;
+  -> BooleanLiteral;
+}
+
+
+// -------------------- A.3 Basic concepts --------------------
+
+nonterm TranslationUnit {
+  -> DeclarationSeqOpt;
+}
+
+
+// -------------------- A.4 Expressions --------------------
+
+nonterm PrimaryExpression {
+  -> Literal;
+  -> "this";
+  -> "(" Expression ")";
+  -> IdExpression;
+}
+
+nonterm IdExpression {
+  -> UnqualifiedId;
+  -> QualifiedId;
+}
+
+nonterm UnqualifiedId {
+  -> Identifier;
+  -> OperatorFunctionId;
+  -> ConversionFunctionId;
+  -> "~" ClassName;
+  -> TemplateId;
+}
+
+nonterm ColonColonOpt {
+  -> empty;
+  -> "::";
+}
+
+nonterm TemplateOpt {
+  -> empty;
+  -> "template";
+}
+
+nonterm QualifiedId {
+  -> ColonColonOpt NestedNameSpecifier TemplateOpt UnqualifiedId;
+  -> "::" Identifier;
+  -> "::" OperatorFunctionId;
+  -> "::" TemplateId;
+}
+
+nonterm NestedNameSpecifierOpt {
+  -> empty;
+  -> NestedNameSpecifier;
+}
+
+nonterm NestedNameSpecifier {
+  -> ClassOrNamespaceName "::" NestedNameSpecifierOpt;
+  -> ClassOrNamespaceName "::" "template" NestedNameSpecifier;
+}
+
+nonterm ClassOrNamespaceName {
+  -> ClassName;
+  -> NamespaceName;
+}                                                
+
+nonterm ExpressionListOpt {
+  -> empty;
+  -> ExpressionList;
+}
+
+nonterm PostfixExpression {
+  fun merge(l,r) [ return l; ]
+
+  -> PrimaryExpression;
+  -> PostfixExpression "[" Expression "]";
+  -> PostfixExpression "(" ExpressionListOpt ")";
+  -> SimpleTypeSpecifier "(" ExpressionListOpt ")";
+  -> "typename" ColonColonOpt NestedNameSpecifier Identifier "(" ExpressionListOpt ")";
+  -> "typename" ColonColonOpt NestedNameSpecifier TemplateOpt TemplateId "(" ExpressionListOpt ")";
+  -> PostfixExpression "." TemplateOpt IdExpression;
+  -> PostfixExpression "->" TemplateOpt IdExpression;
+  -> PostfixExpression "." PseudoDestructorName;
+  -> PostfixExpression "->" PseudoDestructorName;
+  -> PostfixExpression "++";
+  -> PostfixExpression "--";
+  -> "dynamic_cast"     "<" TypeId ">" "(" Expression ")";
+  -> "static_cast"      "<" TypeId ">" "(" Expression ")";
+  -> "reinterpret_cast" "<" TypeId ">" "(" Expression ")";
+  -> "const_cast"       "<" TypeId ">" "(" Expression ")";
+  -> "typeid" "(" Expression ")";
+  -> "typeid" "(" TypeId ")";
+}
+
+nonterm ExpressionList {
+  -> AssignmentExpression;
+  -> ExpressionList "," AssignmentExpression;
+}
+
+nonterm PseudoDestructorName {
+  -> ColonColonOpt NestedNameSpecifierOpt TypeName "::" "~" TypeName;
+  -> ColonColonOpt NestedNameSpecifier "template" TemplateId "::" "~" TypeName;
+  -> ColonColonOpt NestedNameSpecifierOpt "~" TypeName;
+}
+
+nonterm UnaryExpression {
+  fun merge(l,r) [ return l; ]
+
+  -> PostfixExpression;
+  -> "++" CastExpression;
+  -> "--" CastExpression;
+  -> UnaryOperator CastExpression;
+  -> "sizeof" UnaryExpression;
+  -> "sizeof" "(" TypeId ")";
+  -> NewExpression;
+  -> DeleteExpression;
+}
+
+nonterm UnaryOperator {
+  -> "*";
+  -> "&";
+  -> "+";
+  -> "-";
+  -> "!";
+  -> "~";
+}
+  
+nonterm NewPlacementOpt {
+  -> empty;
+  -> NewPlacement;
+}
+
+nonterm NewInitializerOpt {
+  -> empty;
+  -> NewInitializer;
+}
+
+nonterm NewExpression {
+  -> ColonColonOpt "new" NewPlacementOpt NewTypeId NewInitializerOpt;
+  -> ColonColonOpt "new" NewPlacementOpt "(" TypeId ")" NewInitializerOpt;
+}
+
+nonterm NewPlacement {
+  -> "(" ExpressionList ")";
+}                           
+
+nonterm NewDeclaratorOpt {
+  -> empty;
+  -> NewDeclarator;
+}
+
+nonterm NewTypeId {
+  -> TypeSpecifierSeq NewDeclaratorOpt;
+}
+
+nonterm NewDeclarator {
+  -> PtrOperator NewDeclaratorOpt;
+  -> DirectNewDeclarator;
+}
+
+nonterm DirectNewDeclarator {
+  -> "[" Expression "]";
+  -> DirectNewDeclarator "[" ConstantExpression "]";
+}
+
+nonterm NewInitializer {
+  -> "(" ExpressionListOpt ")";
+}
+
+nonterm DeleteExpression {
+  -> ColonColonOpt "delete" CastExpression;
+  -> ColonColonOpt "delete" "[" "]" CastExpression;
+}
+
+nonterm CastExpression {
+  fun merge(l,r) [ return l; ]
+
+  -> UnaryExpression;
+  -> "(" TypeId ")" CastExpression;
+}
+
+nonterm PmExpression {
+  -> CastExpression;
+  -> PmExpression ".*" CastExpression;
+  -> PmExpression "->*" CastExpression;
+}
+
+nonterm MultiplicativeExpression {
+  -> PmExpression;
+  -> MultiplicativeExpression "*" PmExpression;
+  -> MultiplicativeExpression "/" PmExpression;
+  -> MultiplicativeExpression "%" PmExpression;
+}
+
+nonterm AdditiveExpression {
+  fun merge(l,r) [ return l; ]
+
+  -> MultiplicativeExpression;
+  -> AdditiveExpression "+" MultiplicativeExpression;
+  -> AdditiveExpression "-" MultiplicativeExpression;
+}
+
+nonterm ShiftExpression {
+  -> AdditiveExpression;
+  -> ShiftExpression "<<" AdditiveExpression;
+  -> ShiftExpression ">>" AdditiveExpression;
+}
+
+nonterm RelationalExpression {
+  fun merge(l,r) { return l; }
+
+  -> ShiftExpression;
+  -> RelationalExpression "<" ShiftExpression;
+  -> RelationalExpression ">" ShiftExpression;
+  -> RelationalExpression "<=" ShiftExpression;
+  -> RelationalExpression ">=" ShiftExpression;
+}
+
+nonterm EqualityExpression {
+  -> RelationalExpression;
+  -> EqualityExpression "==" RelationalExpression;
+  -> EqualityExpression "!=" RelationalExpression;
+}
+
+nonterm AndExpression {
+  fun merge(l,r) [ return l; ]
+
+  -> EqualityExpression;
+  -> AndExpression "&" EqualityExpression;
+}
+
+nonterm ExclusiveOrExpression {
+  -> AndExpression;
+  -> ExclusiveOrExpression "^" AndExpression;
+}
+
+nonterm InclusiveOrExpression {
+  -> ExclusiveOrExpression;
+  -> InclusiveOrExpression "|" ExclusiveOrExpression;
+}
+
+nonterm LogicalAndExpression {
+  -> InclusiveOrExpression;
+  -> LogicalAndExpression "&&" InclusiveOrExpression;
+}
+
+nonterm LogicalOrExpression {
+  -> LogicalAndExpression;
+  -> LogicalOrExpression "||" LogicalAndExpression;
+}
+
+nonterm ConditionalExpression {
+  -> LogicalOrExpression;
+  -> LogicalOrExpression "?" Expression ":" AssignmentExpression;
+}
+
+nonterm AssignmentExpression {
+  -> ConditionalExpression;
+  -> LogicalOrExpression AssignmentOperator AssignmentExpression;
+  -> ThrowExpression;
+}
+
+nonterm AssignmentOperator {
+  -> "=";
+  -> "*=";
+  -> "/=";
+  -> "%=";
+  -> "+=";
+  -> "-=";
+  -> ">>=";
+  -> "<<=";
+  -> "&=";
+  -> "^=";
+  -> "|=";
+}
+
+nonterm Expression {
+  -> AssignmentExpression;
+  -> Expression "," AssignmentExpression;
+}
+
+nonterm ConstantExpression {
+  -> ConditionalExpression;
+}
+
+
+// -------------------- A.5 Statements --------------------
+
+nonterm Statement {
+  fun merge(l,r) [ return l; ]
+
+  -> LabeledStatement;
+  -> ExpressionStatement;
+  -> CompoundStatement;
+  -> SelectionStatement;
+  -> IterationStatement;
+  -> JumpStatement;
+  -> DeclarationStatement;
+  -> TryBlock;
+}
+
+nonterm LabeledStatement {
+  -> Identifier ":" Statement;
+  -> "case" ConstantExpression ":" Statement;
+  -> "default" ":" Statement;      // note: linux kernel contains "switch (..) { ... default: }" ..
+}
+
+nonterm ExpressionOpt {
+  -> empty;
+  -> Expression;
+}
+
+nonterm ExpressionStatement {
+  -> ExpressionOpt ";";
+}
+
+nonterm StatementSeqOpt {
+  -> empty;
+  -> StatementSeq;
+}
+
+nonterm CompoundStatement {
+  -> "{" StatementSeqOpt "}";
+}
+
+nonterm StatementSeq {
+  -> Statement;
+  -> StatementSeq Statement;
+}
+
+nonterm SelectionStatement {
+  -> "if" "(" Condition ")" Statement;
+  -> "if" "(" Condition ")" Statement "else" Statement;
+  -> "switch" "(" Condition ")" Statement;
+}
+
+nonterm Condition {
+  -> Expression;
+  -> TypeSpecifierSeq Declarator "=" AssignmentExpression;     // ?
+}
+  
+nonterm ConditionOpt {
+  -> empty;
+  -> Condition;
+}
+
+nonterm IterationStatement {
+  -> "while" "(" Condition ")" Statement;
+  -> "do" Statement "while" "(" Expression ")" ";";
+  -> "for" "(" ForInitStatement ConditionOpt ";" ExpressionOpt ")" Statement;
+}
+
+nonterm ForInitStatement {
+  fun merge(l,r) [ return l; ]
+
+  -> ExpressionStatement;
+  -> SimpleDeclaration;
+}
+
+nonterm JumpStatement {
+  -> "break" ";";
+  -> "continue" ";";
+  -> "return" ExpressionOpt ";";
+  -> "goto" Identifier ";";
+}
+
+nonterm DeclarationStatement {
+  -> BlockDeclaration;
+}
+
+
+// -------------------- A.6 Declarations --------------------
+
+nonterm DeclarationSeq {
+  -> Declaration;
+  -> DeclarationSeq Declaration;
+}
+
+nonterm Declaration {
+  -> BlockDeclaration;
+  -> FunctionDefinition;
+  -> TemplateDeclaration;
+  -> ExplicitInstantiation;
+  -> ExplicitSpecialization;
+  -> LinkageSpecification;
+  -> NamespaceDefinition;
+}
+
+nonterm BlockDeclaration {
+  -> SimpleDeclaration;
+  -> AsmDefinition;
+  -> NamespaceAliasDefinition;
+  -> UsingDeclaration;
+  -> UsingDirective;
+}
+
+nonterm DeclSpecifierSeqOpt {
+  -> empty;
+  -> DeclSpecifierSeq;
+}
+
+nonterm InitDeclaratorListOpt {
+  -> empty;
+  -> InitDeclaratorList;
+}
+
+// Q: why is the InitDeclaratorList optional?  "int ;" is not valid
+// A: because we can say "class C { ... };"
+//
+// Q: for that matter, why is the DeclSpecifierSeq optional?  ";" is
+// not a valid declaration (it's a statement)
+// A: the declspecifierseq is missing for constructors
+nonterm SimpleDeclaration {
+  fun merge(l,r) [ return l; ]
+
+  -> DeclSpecifierSeqOpt InitDeclaratorListOpt ";";
+}
+
+nonterm DeclSpecifier {
+  -> StorageClassSpecifier;
+  -> TypeSpecifier;
+  -> FunctionSpecifier;
+  -> "friend";
+  -> "typedef";
+}
+
+nonterm DeclSpecifierSeq {
+  -> DeclSpecifierSeqOpt DeclSpecifier;
+}
+
+nonterm StorageClassSpecifier {
+  -> "auto";
+  -> "register";
+  -> "static";
+  -> "extern";
+  -> "mutable";
+}
+
+nonterm FunctionSpecifier {
+  -> "inline";
+  -> "virtual";
+  -> "explicit";
+}
+
+// repeated in spec
+//nonterm TypedefName {
+//  -> Identifier;
+//} 
+
+nonterm TypeSpecifier {
+  -> SimpleTypeSpecifier;
+  -> ClassSpecifier;
+  -> EnumSpecifier;
+  -> ElaboratedTypeSpecifier;
+  -> CvQualifier;
+}
+
+nonterm SimpleTypeSpecifier {
+  -> ColonColonOpt NestedNameSpecifierOpt TypeName;
+  -> ColonColonOpt NestedNameSpecifier "template" TemplateId;
+  -> "char";
+  -> "wchar_t";
+  -> "bool";
+  -> "short";
+  -> "int";
+  -> "long";
+  -> "signed";
+  -> "unsigned";
+  -> "float";
+  -> "double";
+  -> "void";
+}
+
+nonterm TypeName {
+  fun merge(l,r) [ return l; ]
+
+  -> ClassName;
+  -> EnumName;
+  -> TypedefName;
+}
+
+nonterm ElaboratedTypeSpecifier {
+  -> ClassKey ColonColonOpt NestedNameSpecifierOpt Identifier;
+  -> "enum" ColonColonOpt NestedNameSpecifierOpt Identifier;
+  -> "typename" ColonColonOpt NestedNameSpecifier Identifier;
+  -> "typename" ColonColonOpt NestedNameSpecifier TemplateOpt TemplateId;
+}
+
+// this is repeated in the spec
+//nonterm EnumName {
+//  -> Identifier;
+//}
+
+nonterm IdentifierOpt {
+  -> empty;
+  -> Identifier;
+}
+        
+nonterm EnumeratorListOpt {
+  -> empty;
+  -> EnumeratorList;
+}
+
+nonterm EnumSpecifier {
+  -> "enum" IdentifierOpt "{" EnumeratorListOpt "}";
+}
+
+nonterm EnumeratorList {
+  -> EnumeratorDefinition;
+  -> EnumeratorList "," EnumeratorDefinition;
+}
+
+nonterm EnumeratorDefinition {
+  -> Enumerator;
+  -> Enumerator "=" ConstantExpression;
+}
+
+nonterm Enumerator {
+  -> Identifier;
+}
+
+// repeated in spec
+//nonterm NamespaceName {
+//  -> OriginalNamespaceName;
+//  -> NamespaceAlias;
+//} 
+
+// repeated in spec
+//nonterm OriginalNamespaceName {
+//  -> Identifier;
+//} 
+
+nonterm NamespaceDefinition {
+  -> NamedNamespaceDefinition;
+  -> UnnamedNamespaceDefinition;
+}
+
+nonterm NamedNamespaceDefinition {
+  -> OriginalNamespaceDefinition;
+  -> ExtensionNamespaceDefinition;
+}
+
+nonterm OriginalNamespaceDefinition {
+  -> "namespace" Identifier "{" NamespaceBody "}";
+}
+
+nonterm ExtensionNamespaceDefinition {
+  -> "namespace" OriginalNamespaceName "{" NamespaceBody "}";
+}
+
+nonterm UnnamedNamespaceDefinition {
+  -> "namespace" "{" NamespaceBody "}";
+}
+
+nonterm DeclarationSeqOpt {
+  -> empty;
+  -> DeclarationSeq;
+}
+
+nonterm NamespaceBody {
+  -> DeclarationSeqOpt;
+}
+
+// repeated in spec
+//nonterm NamespaceAlias {
+//  -> Identifier;
+//} 
+
+nonterm NamespaceAliasDefinition {
+  -> "namespace" Identifier "=" QualifiedNamespaceSpecifier ";";
+}
+
+nonterm QualifiedNamespaceSpecifier {
+  -> ColonColonOpt NestedNameSpecifierOpt NamespaceName;
+}
+
+nonterm TypenameOpt {
+  -> empty;
+  -> "typename";
+}
+
+nonterm UsingDeclaration {
+  -> "using" TypenameOpt ColonColonOpt NestedNameSpecifier UnqualifiedId ";";
+  -> "using" "::" UnqualifiedId ";";
+}
+
+nonterm UsingDirective {
+  -> "using" "namespace" ColonColonOpt NestedNameSpecifierOpt NamespaceName ";";
+}
+
+nonterm AsmDefinition {
+  -> "asm" "(" StringLiteral ")" ";";
+}
+
+nonterm LinkageSpecification {
+  -> "extern" StringLiteral "{" DeclarationSeqOpt "}";
+  -> "extern" StringLiteral Declaration;
+}
+
+
+// -------------------- A.7 Declarators --------------------
+
+nonterm InitDeclaratorList {
+  -> InitDeclarator;
+  -> InitDeclaratorList "," InitDeclarator;
+}
+
+nonterm InitializerOpt {
+  -> empty;
+  -> Initializer;
+}
+
+nonterm InitDeclarator {
+  fun merge(l,r) [ return l; ]
+
+  -> Declarator InitializerOpt;
+}
+
+nonterm Declarator {
+  -> DirectDeclarator;
+  -> PtrOperator Declarator;
+}
+
+nonterm CvQualifierSeqOpt {
+  -> empty;
+  -> CvQualifierSeq;
+}
+
+nonterm ExceptionSpecificationOpt {
+  -> empty;
+  -> ExceptionSpecification;
+}
+
+nonterm ConstantExpressionOpt {
+  -> empty;
+  -> ConstantExpression;
+}
+
+nonterm DirectDeclarator {
+  -> DeclaratorId;
+  -> DirectDeclarator "(" ParameterDeclarationClause ")" CvQualifierSeqOpt ExceptionSpecificationOpt;
+  -> DirectDeclarator "[" ConstantExpressionOpt "]";
+  -> "(" Declarator ")";
+}
+
+nonterm PtrOperator {
+  -> "*" CvQualifierSeqOpt;
+  -> "&";
+  -> ColonColonOpt NestedNameSpecifier "*" CvQualifierSeqOpt;     // pointer to member
+}
+
+nonterm CvQualifierSeq {
+  -> CvQualifier CvQualifierSeqOpt;
+}
+
+nonterm CvQualifier {
+  -> "const";
+  -> "volatile";
+}
+
+nonterm DeclaratorId {
+  fun merge(l,r) [ return l; ]
+
+  -> IdExpression;
+  -> ColonColonOpt NestedNameSpecifierOpt TypeName;
+}
+
+nonterm AbstractDeclaratorOpt {
+  -> empty;
+  -> AbstractDeclarator;
+}
+
+nonterm TypeId {
+  -> TypeSpecifierSeq AbstractDeclaratorOpt;
+}
+
+nonterm TypeSpecifierSeqOpt {
+  -> empty;
+  -> TypeSpecifierSeq;
+}
+
+nonterm TypeSpecifierSeq {
+  -> TypeSpecifier TypeSpecifierSeqOpt;
+}
+
+nonterm AbstractDeclarator {
+  -> PtrOperator AbstractDeclaratorOpt;
+  -> DirectAbstractDeclarator;
+}
+     
+nonterm DirectAbstractDeclaratorOpt {
+  -> empty;
+  -> DirectAbstractDeclarator;
+}
+
+nonterm DirectAbstractDeclarator {
+  -> DirectAbstractDeclaratorOpt "(" ParameterDeclarationClause ")" CvQualifierSeqOpt ExceptionSpecificationOpt;
+  -> DirectAbstractDeclaratorOpt "[" ConstantExpressionOpt "]";
+  -> "(" AbstractDeclarator ")";
+}
+
+nonterm ParameterDeclarationListOpt {
+  -> empty;
+  -> ParameterDeclarationList;
+}
+
+nonterm EllipsisOpt {
+  -> empty;
+  -> "...";
+}
+
+nonterm ParameterDeclarationClause {
+  -> ParameterDeclarationListOpt EllipsisOpt;
+  -> ParameterDeclarationList "," "...";
+}
+
+nonterm ParameterDeclarationList {
+  -> ParameterDeclaration;
+  -> ParameterDeclarationList "," ParameterDeclaration;
+}
+
+nonterm ParameterDeclaration {
+  fun merge(l,r) [ return l; ]
+
+  -> DeclSpecifierSeq Declarator;
+  -> DeclSpecifierSeq Declarator "=" AssignmentExpression;
+  -> DeclSpecifierSeq AbstractDeclaratorOpt;
+  -> DeclSpecifierSeq AbstractDeclaratorOpt "=" AssignmentExpression;
+}
+
+nonterm CtorInitializerOpt {
+  -> empty;
+  -> CtorInitializer;
+}
+
+nonterm FunctionDefinition {
+  -> DeclSpecifierSeqOpt Declarator CtorInitializerOpt FunctionBody;
+  -> DeclSpecifierSeqOpt Declarator FunctionTryBlock;
+}
+
+nonterm FunctionBody {
+  -> CompoundStatement;
+}
+
+nonterm Initializer {
+  -> "=" InitializerClause;
+  -> "(" ExpressionList ")";
+}
+
+nonterm CommaOpt {
+  -> empty;
+  -> ",";
+}
+
+nonterm InitializerClause {
+  -> AssignmentExpression;
+  -> "{" InitializerList CommaOpt "}";
+  -> "{" "}";
+}
+
+nonterm InitializerList {
+  -> InitializerClause;
+  -> InitializerList "," InitializerClause;
+}
+
+
+// -------------------- A.8 Classes --------------------
+
+// repeated in spec
+//nonterm ClassName {
+//  -> Identifier;
+//  -> TemplateId;
+//} 
+
+nonterm MemberSpecificationOpt {
+  -> empty;
+  -> MemberSpecification;
+}
+
+nonterm ClassSpecifier {
+  -> ClassHead "{" MemberSpecificationOpt "}";
+}
+
+nonterm BaseClauseOpt {
+  -> empty;
+  -> BaseClause;
+}
+
+nonterm ClassHead {
+  -> ClassKey IdentifierOpt BaseClauseOpt;
+  -> ClassKey NestedNameSpecifier Identifier BaseClauseOpt;
+  -> ClassKey NestedNameSpecifierOpt TemplateId BaseClauseOpt;
+}
+
+nonterm ClassKey {
+  -> "class";
+  -> "struct";
+  -> "union";
+}
+  
+nonterm MemberSpecification {
+  -> MemberDeclaration MemberSpecificationOpt;
+  -> AccessSpecifier ":" MemberSpecificationOpt;
+}
+
+nonterm MemberDeclaratorListOpt {
+  -> empty;
+  -> MemberDeclaratorList;
+}
+  
+nonterm SemicolonOpt {
+  -> empty;
+  -> ";";
+}
+
+nonterm MemberDeclaration {
+  fun merge(l,r) [ return l; ]
+
+  -> DeclSpecifierSeqOpt MemberDeclaratorListOpt ";";
+  -> FunctionDefinition SemicolonOpt;
+  -> ColonColonOpt NestedNameSpecifier TemplateOpt UnqualifiedId ";";
+  -> UsingDeclaration;
+  -> TemplateDeclaration;
+}
+
+nonterm MemberDeclaratorList {
+  -> MemberDeclarator;
+  -> MemberDeclaratorList "," MemberDeclarator;
+}
+
+nonterm PureSpecifierOpt {
+  -> empty;
+  -> PureSpecifier;
+}
+
+nonterm ConstantInitializerOpt {
+  -> empty;
+  -> ConstantInitializer;
+}
+
+nonterm MemberDeclarator {
+  fun merge(l,r) [ return l; ]
+
+  -> Declarator PureSpecifierOpt;           // for when declarator is a function type
+  -> Declarator ConstantInitializerOpt;     // for when it is any other type
+  -> IdentifierOpt ":" ConstantExpression;  // bitfield with optional name
+}
+
+nonterm PureSpecifier {
+  -> "=" IntegerLiteral;         // standard says "0" here but that's not one of my tokens..
+}
+
+nonterm ConstantInitializer{ 
+  -> "=" ConstantExpression;
+}
+
+
+// -------------------- A.9 Derived classes --------------------
+
+nonterm BaseClause {
+  -> ":" BaseSpecifierList;
+}
+
+nonterm BaseSpecifierList {
+  -> BaseSpecifier;
+  -> BaseSpecifierList "," BaseSpecifier;
+}
+ 
+// Q: is there a nonterminal called "virtual"?
+// A: no.  the standard uses the wrong font for "virtual" in the base-specifier rules
+nonterm VirtualOpt {
+  -> empty;
+  -> "virtual";
+}
+
+nonterm AccessSpecifierOpt {
+  -> empty;
+  -> AccessSpecifier;
+}
+
+nonterm BaseSpecifier {
+  -> ColonColonOpt NestedNameSpecifierOpt ClassName;
+  -> "virtual" AccessSpecifierOpt ColonColonOpt NestedNameSpecifierOpt ClassName;
+  -> AccessSpecifier VirtualOpt   ColonColonOpt NestedNameSpecifierOpt ClassName;
+}
+
+nonterm AccessSpecifier {
+  -> "private";
+  -> "protected";
+  -> "public";
+}
+
+
+// -------------------- A.10 Special member functions --------------------
+
+nonterm ConversionFunctionId {
+  -> "operator" ConversionTypeId;
+}
+
+nonterm ConversionDeclaratorOpt {
+  -> empty;
+  -> ConversionDeclarator;
+}
+
+nonterm ConversionTypeId {
+  -> TypeSpecifierSeq ConversionDeclaratorOpt;
+}
+
+nonterm ConversionDeclarator {
+  -> PtrOperator ConversionDeclaratorOpt;
+}
+
+nonterm CtorInitializer {
+  -> ":" MemInitializerList;
+}
+
+// Q: why right recursion?
+nonterm MemInitializerList {
+  -> MemInitializer;
+  -> MemInitializer "," MemInitializerList;
+}                                          
+
+// Q: what is a mem-initializer?
+// A: "member initializer", in constructors after the ":" but before "{"
+nonterm MemInitializer {
+  -> MemInitializerId "(" ExpressionListOpt ")";
+}
+
+nonterm MemInitializerId {
+  fun merge(l,r) { return l; }
+
+  -> ColonColonOpt NestedNameSpecifierOpt ClassName;
+  -> Identifier;
+}
+
+
+// -------------------- A.11 Overloading --------------------
+
+nonterm OperatorFunctionId {
+  -> "operator" Operator;
+}
+
+nonterm Operator {
+  -> "new";
+  -> "delete";
+  -> "new" "[" "]";
+  -> "delete" "[" "]";
+  -> "+";
+  -> "-";
+  -> "*";
+  -> "/";
+  -> "%";
+  -> "^";
+  -> "&";
+  -> "|";
+  -> "~";
+  -> "!";
+  -> "=";
+  -> "<";
+  -> ">";
+  -> "+=";
+  -> "-=";
+  -> "*=";
+  -> "/=";
+  -> "%=";
+  -> "^=";
+  -> "&=";
+  -> "|=";
+  -> "<<";
+  -> ">>";
+  -> ">>=";
+  -> "<<=";
+  -> "==";
+  -> "!=";
+  -> "<=";
+  -> ">=";
+  -> "&&";
+  -> "||";
+  -> "++";
+  -> "--";
+  -> ",";
+  -> "->*";
+  -> "->";
+  -> "(" ")";
+  -> "[" "]";
+}
+
+
+// -------------------- A.12 Templates --------------------
+
+nonterm ExportOpt {
+  -> empty;
+  -> "export";
+}
+
+nonterm TemplateDeclaration {
+  -> ExportOpt "template" "<" TemplateParameterList ">" Declaration;
+}
+
+nonterm TemplateParameterList {
+  -> TemplateParameter;
+  -> TemplateParameterList "," TemplateParameter;
+}
+
+nonterm TemplateParameter {
+  fun merge(l,r) { return l; }
+
+  -> TypeParameter;
+  -> ParameterDeclaration;
+}
+
+nonterm TypeParameter {
+  -> "class" IdentifierOpt;
+  -> "class" IdentifierOpt "=" TypeId;
+  -> "typename" IdentifierOpt;
+  -> "typename" IdentifierOpt "=" TypeId;
+  -> "template" "<" TemplateParameterList ">" "class" IdentifierOpt;
+  -> "template" "<" TemplateParameterList ">" "class" IdentifierOpt "=" IdExpression;
+}
+
+nonterm TemplateArgumentListOpt {
+  -> empty;
+  -> TemplateArgumentList;
+}
+
+nonterm TemplateId {
+  -> TemplateName "<" TemplateArgumentListOpt ">";
+}
+
+// repeated in spec
+//nonterm TemplateName {
+//  -> Identifier;
+//} 
+
+nonterm TemplateArgumentList {
+  -> TemplateArgument;
+  -> TemplateArgumentList "," TemplateArgument;
+}
+
+nonterm TemplateArgument {
+  fun merge(l,r) [ return l; ]
+
+  -> AssignmentExpression;
+  -> TypeId;
+  -> IdExpression;
+}
+
+nonterm ExplicitInstantiation {
+  -> "template" Declaration;
+}
+
+nonterm ExplicitSpecialization {
+  -> "template" "<" ">" Declaration;
+}
+
+
+// -------------------- A.13 Exception handling --------------------
+
+nonterm TryBlock {
+  -> "try" CompoundStatement HandlerSeq;
+}
+
+nonterm FunctionTryBlock {
+  -> "try" CtorInitializerOpt FunctionBody HandlerSeq;
+}
+
+nonterm HandlerSeqOpt {
+  -> empty;
+  -> HandlerSeq;
+}
+
+// Q: why did they choose to use right recursion for this one?  all of
+// the other sequences use left recursion..
+nonterm HandlerSeq {
+  -> Handler HandlerSeqOpt;
+}
+
+nonterm Handler {
+  -> "catch" "(" ExceptionDeclaration ")" CompoundStatement;
+}
+
+nonterm ExceptionDeclaration {
+  -> TypeSpecifierSeq Declarator;
+  -> TypeSpecifierSeq AbstractDeclarator;
+  -> TypeSpecifierSeq;
+  -> "...";
+}
+
+nonterm AssignmentExpressionOpt {
+  -> empty;
+  -> AssignmentExpression;
+}
+
+nonterm ThrowExpression {
+  -> "throw" AssignmentExpressionOpt;
+}
+
+nonterm TypeIdListOpt {
+  -> empty;
+  -> TypeIdList;
+}
+
+nonterm ExceptionSpecification {
+  -> "throw" "(" TypeIdListOpt ")";
+}
+
+nonterm TypeIdList {
+  -> TypeId;
+  -> TypeIdList "," TypeId;
+}
+
+
+// A.14 Preprocessing directives: deferring to separate preprocessor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Added: vendor/elsa/current/elkhound/cc2/cc2main.cc
===================================================================
--- vendor/elsa/current/elkhound/cc2/cc2main.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/cc2/cc2main.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,68 @@
+// cc2main.cc            see license.txt for copyright and terms of use
+// toplevel driver for cc2
+
+#include <iostream.h>     // cout
+#include <stdlib.h>       // exit
+
+#include "trace.h"        // traceAddSys
+#include "parssppt.h"     // ParseTreeAndTokens, treeMain
+#include "cc_lang.h"      // CCLang
+#include "ptreenode.h"    // PTreeNode
+#include "parsetables.h"  // ParseTables
+#include "cc2.gr.gen.h"   // CC2
+
+
+// no bison-parser present, so need to define this
+Lexer2Token const *yylval = NULL;
+
+
+void doit(int argc, char **argv)
+{
+  traceAddSys("progress");
+  //traceAddSys("parse-tree");
+
+  SourceLocManager mgr;
+
+  // parsing language options
+  CCLang lang;
+  lang.ANSI_Cplusplus();
+
+
+  // --------------- parse --------------
+  {
+    SemanticValue treeTop;
+    ParseTreeAndTokens tree(lang, treeTop);
+    UserActions *user = new CC2;
+    ParseTables *tables = user->makeTables();
+    tree.userAct = user;
+    tree.tables = tables;
+    if (!treeMain(tree, argc, argv,
+          "  additional flags for cc2:\n"
+          "    printTree          print tree after parsing (if avail.)\n"
+          "")) {
+      // parse error
+      exit(2);
+    }
+
+    traceProgress(2) << "final parse result: " << treeTop << endl;
+
+    if (treeTop && tracingSys("printTree")) {
+      PTreeNode *node = (PTreeNode*)treeTop;
+      cout << "local ambiguities: " << PTreeNode::alternativeCount << endl;
+      cout << "number of parses: " << node->countTrees() << endl;
+      node->printTree(cout);
+    }
+
+    delete user;         
+    delete tables;
+  }
+
+  traceRemoveAll();
+}
+
+int main(int argc, char **argv)
+{
+  doit(argc, argv);
+
+  return 0;
+}

Added: vendor/elsa/current/elkhound/cc2/license.txt
===================================================================
--- vendor/elsa/current/elkhound/cc2/license.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/cc2/license.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+The software in this directory is
+Copyright (c) 2002, Regents of the University of California
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above 
+      copyright notice, this list of conditions and the following 
+      disclaimer in the documentation and/or other materials provided 
+      with the distribution.
+
+    * Neither the name of the University of California, Berkeley nor 
+      the names of its contributors may be used to endorse or promote 
+      products derived from this software without specific prior 
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: vendor/elsa/current/elkhound/cc2/test.cc
===================================================================
--- vendor/elsa/current/elkhound/cc2/test.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/cc2/test.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// test.cc
+// just a simple C++ test program to see what switches I
+// need to compile it
+
+#include <iostream.h>    // count
+
+// try to pull in something from my parent directory
+#include "rcptr.h"
+
+int main()
+{
+  cout << "test.cc works\n";
+  return 0;
+}

Added: vendor/elsa/current/elkhound/cc2/testprog.cc
===================================================================
--- vendor/elsa/current/elkhound/cc2/testprog.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/cc2/testprog.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// testprog.cc
+// see if I can #include a file in the parent directory
+                         
+// this lives in "..", and happens to not #include anything else
+#include "trivlex.h"
+
+int main()
+{
+  return 0;
+}

Added: vendor/elsa/current/elkhound/cdecl2.gr
===================================================================
--- vendor/elsa/current/elkhound/cdecl2.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/cdecl2.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,187 @@
+// cdecl2.gr            see license.txt for copyright and terms of use
+// demonstration of resolving C ident/type ambiguity
+// cdecl2 solves the problem using token reclassification (cf. cdecl)
+
+verbatim ParseEnv [
+
+#include <iostream.h>      // cout
+#include "trace.h"         // trace
+#include "locstr.h"        // LocString
+#include "strhash.h"       // StringHash
+#include "objlist.h"       // ObjList
+#include "parssppt.h"      // ParseTreeAndTokens
+
+#define D(msg) \
+  trace("cdecl") << msg << endl
+#define R0 return 0
+
+
+// parsing action state
+class ParseEnv : public UserActions {
+public:
+  StringRef intType;              // "int"
+  ObjList<StringHash> types;      // stack of hashes which identify names of types
+
+public:
+  ParseEnv(StringTable &table);
+  ~ParseEnv();
+
+  void enterScope();
+  void leaveScope();
+  void addType(StringRef type);
+  bool isType(StringRef name);
+
+  // declarations for the generated code
+  #include "cdecl2.gen.h"
+};
+
+
+UserActions *makeUserActions(StringTable &table)
+{
+  return new ParseEnv(table);
+}
+
+ParseEnv::ParseEnv(StringTable &table)
+{
+  intType = table.add("int");
+}
+
+ParseEnv::~ParseEnv()
+{}
+
+
+static char const *identity(void *data)
+{
+  return (char const*)data;
+}
+
+void ParseEnv::enterScope()
+{
+  types.prepend(new StringHash(identity));
+}
+
+void ParseEnv::leaveScope()
+{
+  delete types.removeAt(0);
+}
+
+void ParseEnv::addType(StringRef type)
+{
+  StringHash *h = types.first();
+  if (h->get(type)) {
+    cout << "duplicate entry for " << type << " -- will ignore\n";
+  }
+  else {
+    h->add(type, (void*)type);
+  }
+}
+
+bool ParseEnv::isType(StringRef name)
+{
+  if (name == intType) {
+    return true;
+  }
+
+  FOREACH_OBJLIST(StringHash, types, iter) {
+    if (iter.data()->get(name)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+] // end verbatim
+
+
+terminals {
+  // grab the lexer's token list
+  include("cc.tok")
+
+  token[StringRef] L2_NAME {
+    // every time I pull an L2_NAME from the lexer, this code is
+    // run to possibly reclassify the token kind; the semantic
+    // value is passed (and ParseEnv is available as context), but
+    // the same semantic value will be used
+    classify(s) [
+      if (isType(s)) {
+        return L2_TYPE_NAME;
+      }
+      else {
+        return L2_VARIABLE_NAME;
+      }
+    ]
+  }
+
+  token[StringRef] L2_TYPE_NAME;
+  token[StringRef] L2_VARIABLE_NAME;
+}
+
+
+nonterm Start -> Toplevel L2_EOF ;
+
+nonterm Toplevel -> EnterScope Stmts LeaveScope ;
+
+// these are placed at strategic points to get scoping right
+nonterm EnterScope -> empty    [
+  D("entering scope"); 
+  enterScope(); 
+  R0;
+]
+
+nonterm LeaveScope -> empty     [
+  D("exiting scope"); 
+  leaveScope();
+  R0;
+]
+
+nonterm Stmts {
+  -> empty         ;
+  -> Stmts Stmt    ;
+}
+
+nonterm[int] Stmt {
+  -> t:TypeName "(" n:VarName ")" ";"   [    // declaration
+       D("declaration of " << n << ", type " << t); R0;
+     ]
+
+  -> f:VarName "(" a:VarName ")" ";"    [    // function call
+       D("call of " << f << " with arg " << a); R0;
+     ]
+
+  -> Typedef ";" ;
+
+  -> "{" EnterScope Stmts LeaveScope "}" ;    // scope
+}
+
+// this has to be pulled out so its reduction occurs before we
+// finish with the terminating semicolon, so the interaction order
+// is correct (if the token that follows the semicolon is a name,
+// it might be the name in this typedef, so we need to update the
+// environment before attempting to classify it)
+nonterm Typedef
+  -> "typedef" t:TypeName n:Name      [    // typedef: introduce type name
+       D("typedef of " << n << " as type " << t);
+       addType(n);
+       R0;
+     ]
+
+nonterm[StringRef] VarName {
+  -> n:L2_VARIABLE_NAME     [ return n; ]
+}
+
+nonterm[StringRef] TypeName {
+  -> n:L2_TYPE_NAME         [ return n; ]
+
+  // this is a little bit of a hack, but in some sense it's valid
+  // to regard the global strings as another stringtable.. of course,
+  // equality won't work, but I don't need it for the moment
+  -> L2_INT                 [ return intType; ]
+}
+
+// having classified these apart, there are some situations where
+// the name is being defined, so it doesn't matter what kind of
+// thing it might have been before
+nonterm[StringRef] Name {
+  -> n:L2_VARIABLE_NAME     [ return n; ]
+  -> n:L2_TYPE_NAME         [ return n; ]
+}

Added: vendor/elsa/current/elkhound/configure.pl
===================================================================
--- vendor/elsa/current/elkhound/configure.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/configure.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,345 @@
+#!/usr/bin/perl -w
+# configure script for elkhound
+
+use strict 'subs';
+
+# default location of smbase relative to this package
+$SMBASE = "../smbase";
+$req_smcv = 1.03;            # required sm_config version number
+$thisPackage = "elkhound";
+
+# -------------- BEGIN common block ---------------
+# do an initial argument scan to find if smbase is somewhere else
+for (my $i=0; $i < @ARGV; $i++) {
+  my ($d) = ($ARGV[$i] =~ m/-*smbase=(.*)/);
+  if (defined($d)) {
+    $SMBASE = $d;
+  }
+}
+
+# try to load the sm_config module
+eval {
+  push @INC, ($SMBASE);
+  require sm_config;
+};
+if ($@) {
+  die("$@" .     # ends with newline, usually
+      "\n" .
+      "I looked for smbase in \"$SMBASE\".\n" .
+      "\n" .
+      "You can explicitly specify the location of smbase with the -smbase=<dir>\n" .
+      "command-line argument.\n");
+}
+
+# check version number
+$smcv = get_sm_config_version();
+if ($smcv < $req_smcv) {
+  die("This package requires version $req_smcv of sm_config, but found\n" .
+      "only version $smcv.\n");
+}
+# -------------- END common block ---------------
+
+
+# defaults
+%flags = (
+  "loc" => 1,
+
+  "eef" => 0,
+  "gcs" => 0,
+  "gcsc" => 0,
+  "crs" => 0,
+
+  "subconfigure" => 1
+);
+$AST = "../ast";
+
+# arguments to pass to sub-configures
+ at c_args = ();
+ at arith_args = ();
+
+
+# copy from %flags to individual global variables
+sub copyFlagsToGlobals {
+  $loc = $flags{loc};
+
+  $eef = $flags{eef};
+  $gcs = $flags{gcs};
+  $gcsc = $flags{gcsc};
+  $crs = $flags{crs};
+
+  $subconfigure = $flags{subconfigure};
+
+  # test consistency of configuration
+  if ($gcs && !$eef) {
+    die "GCS requires EEF\n";
+  }
+  if ($gcsc && !$gcs) {
+    die "GCSC requires GCS\n";
+  }
+}
+copyFlagsToGlobals();
+
+
+sub usage {
+  standardUsage();
+
+  print(<<"EOF");
+package options:
+  -prof              enable profiling
+  -devel             add options useful while developing
+  -loc[=0/1]:        enable/disable source location tracking [enabled]
+  -action:           enable use of "-tr action" to see parser actions
+  -compression[=0/1]:  enable/disable all table compression options [disabled]
+    -eef[=0/1]         enable/disable EEF compression [disabled]
+    -gcs[=0/1]         enable/disable GCS compression [disabled]
+    -gcsc[=0/1]        enable/disable GCS column compression [disabled]
+    -crs[=0/1]         enable/disable CRS compression [disabled]
+  -fastest:          turn off all Elkhound features that are not present
+                     in Bison, for the purpose of performance comparison
+                     (note that Elsa will not work in this mode)
+  -nosub:            do not invoke subdirectory configure scripts
+  -ast=<dir>:        specify where the ast library is [$AST]
+EOF
+}
+
+
+# -------------- BEGIN common block 2 -------------
+# global variables holding information about the current command-line
+# option being processed
+$option = "";
+$value = "";
+
+# process command-line arguments
+foreach $optionAndValue (@ARGV) {
+  # ignore leading '-' characters, and split at first '=' (if any)
+  ($option, $value) =
+    ($optionAndValue =~ m/^-*([^-][^=]*)=?(.*)$/);
+                      #      option     = value
+
+  my $arg = $option;
+
+  if (handleStandardOption()) {
+    # handled by sm_config.pm
+  }
+  # -------------- END common block 2 -------------
+
+  elsif ($arg eq "prof") {
+    push @CCFLAGS, "-pg";
+    push @c_args, $arg;
+    push @arith_args, $arg;
+  }
+
+  elsif ($arg eq "devel") {
+    push @CCFLAGS, "-Werror";
+    push @c_args, $arg;
+    push @arith_args, $arg;
+  }
+
+  elsif ($arg eq "loc") {
+    $flags{loc} = getBoolArg();
+  }
+
+  elsif ($arg eq "action") {
+    push @CCFLAGS, "-DACTION_TRACE=1";
+  }
+
+  elsif ($arg eq "fastest") {
+    # the idea is I can say
+    #   $ ./configure -fastest
+    #   $ make clean; make
+    #   $ ./perf -tests c -iters 5
+    # to verify that I'm still within 3% of Bison (at least
+    # when compiled with gcc-2.95.3)
+    $flags{loc} = 0;
+    $flags{debug} = 0;
+    push @CCFLAGS,
+      ("-DUSE_RECLASSIFY=0",        # no token reclassification
+       "-DUSE_KEEP=0",              # don't call keep() functions
+       "-DNDEBUG_NO_ASSERTIONS",    # disable all xassert() calls
+       "-DDO_ACCOUNTING=0",         # don't count stack nodes, etc.
+       "-DENABLE_YIELD_COUNT=0");   # don't check for yield-then-merge at runtime
+    push @c_args, "-DUSE_RECLASSIFY=0";
+  }
+
+  elsif ($arg eq "nosub") {
+    $flags{subconfigure} = 0;
+  }
+
+  elsif ($arg eq "ast") {
+    $AST = getOptArg();
+    if ($AST !~ m|^/|) {
+      push @c_args, "-ast=../$AST";
+      push @arith_args, "-ast=../../$AST";
+    }
+    else {
+      push @c_args, "-ast=$AST";
+      push @arith_args, "-ast=$AST";
+    }
+  }
+
+  elsif ($arg =~ "compression|eef|gcs|gcsc|crs") {
+    my $value = getBoolArg();
+
+    if ($arg eq "compression") {
+      $flags{eef} = $value;
+      $flags{gcs} = $value;
+      $flags{gcsc} = $value;
+      $flags{crs} = $value;
+    }
+    else {
+      $flags{$arg} = $value;
+    }
+  }
+
+  else {
+    die "unknown option: $arg\n";
+  }
+}
+
+copyFlagsToGlobals();
+finishedOptionProcessing();
+
+# summarize compression flags
+ at compflags = ();
+for $k (keys %flags) {
+  if ($k eq "eef" || $k eq "gcs" || $k eq "gcsc" || $k eq "crs") {
+    if ($flags{$k}) {
+      push @compflags, $k;
+    }
+  }
+}
+if (@compflags) {
+  $compflags = join(',', @compflags);
+}
+else {
+  $compflags = "<none>";
+}
+
+
+
+# ------------------ needed components ---------------
+test_smbase_presence();
+
+test_CXX_compiler();
+
+# does the compiler want me to pass "-I."?  unfortunately, some versions
+# of gcc-3 will emit an annoying warning if I pass "-I." when I don't need to
+print("checking whether compiler needs \"-I.\"... ");
+$cmd = "$CXX -c @CCFLAGS cc2/testprog.cc";
+if (0!=system("$cmd >/dev/null 2>&1")) {
+  # failed without "-I.", so try adding it
+  $cmd = "$CXX -c -I. @CCFLAGS cc2/testprog.cc";
+  if (0!=system("$cmd >/dev/null 2>&1")) {
+    my $wd = `pwd`;
+    chomp($wd);
+    die "\n" .
+        "I was unable to compile a simple test program.  I tried:\n" .
+        "  cd $wd\n" .
+        "  $cmd\n" .
+        "Try it yourself to see the error message.  This needs be fixed\n" .
+        "before Elkhound will compile.\n";
+  }
+
+  # adding "-I." fixed the problem
+  print("yes\n");
+  push @CCFLAGS, "-I.";
+}
+else {
+  print("no\n");
+}
+
+
+# ast
+if (! -f "$AST/asthelp.h") {
+  die "I cannot find asthelp.h in `$AST'.\n" .
+      "The ast library is required for elkhound.\n" .
+      "If it's in a different location, use the -ast=<dir> option.\n";
+}
+
+
+$PERL = get_PERL_variable();
+
+
+# ------------------ config.summary -----------------
+$summary = getStandardConfigSummary();
+
+$summary .= <<"OUTER_EOF";
+cat <<EOF
+  loc:         $loc
+  compression: $compflags
+EOF
+OUTER_EOF
+
+writeConfigSummary($summary);
+
+
+# ------------------- config.status ------------------
+writeConfigStatus("PERL" => "$PERL",
+                  "AST" => "$AST");
+
+# extend config.status
+open(OUT, ">>config.status") or die("could not append to config.status: $!\n");
+print OUT (<<"OUTER_EOF");
+
+cat >glrconfig.h.tmp <<EOF
+// glrconfig.h
+// do not edit; generated by ./configure
+
+EOF
+
+sed -e "s|\@GLR_SOURCELOC\@|$loc|g" \\
+    -e "s|\@eef\@|$eef|g" \\
+    -e "s|\@gcs\@|$gcs|g" \\
+    -e "s|\@gcsc\@|$gcsc|g" \\
+    -e "s|\@crs\@|$crs|g" \\
+  <glrconfig.h.in >>glrconfig.h.tmp
+
+# see if the new glrconfig.h differs from the old; if not, then
+# leave the old, so 'make' won't think something needs to be rebuilt
+if diff glrconfig.h glrconfig.h.tmp >/dev/null 2>&1; then
+  # leave it
+  echo "glrconfig.h is unchanged"
+else
+  echo "creating glrconfig.h ..."
+
+  # overwrite it, and make it read-only
+  mv -f glrconfig.h.tmp glrconfig.h
+  chmod a-w glrconfig.h
+fi
+
+
+OUTER_EOF
+
+close(OUT) or die;
+chmod 0755, "config.status";
+
+
+# ----------------- final actions -----------------
+# invoke sub-configures
+if ($subconfigure) {
+  chdir("c") or die;
+  my $tmp = join(' ', ("./configure", @c_args));
+  print("Invoking $tmp in 'c' directory..\n");
+  run("./configure", @c_args);
+  chdir("..") or die;
+
+  chdir("examples/arith") or die;
+  $tmp = join(' ', ("./configure", @arith_args));
+  print("Invoking $tmp in 'examples/arith' directory..\n");
+  run("./configure", @arith_args);
+  chdir("../..") or die;
+}
+
+# run the output file generator
+run("./config.status");
+
+print("\nYou can now run make, usually called 'make' or 'gmake'.\n");
+
+
+exit(0);
+
+
+# silence warnings
+pretendUsed($thisPackage);
+
+# EOF


Property changes on: vendor/elsa/current/elkhound/configure.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/cyctimer.cc
===================================================================
--- vendor/elsa/current/elkhound/cyctimer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/cyctimer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,70 @@
+// cyctimer.cc            see license.txt for copyright and terms of use
+// code for cyctimer.h
+
+#include "cyctimer.h"    // this module
+#include "cycles.h"      // getCycles_ll
+#include "nonport.h"     // getMilliseconds
+
+#include <stdio.h>       // sprintf
+
+
+CycleTimer::CycleTimer()
+{
+  // I make the cycle timer the inner of the two, since presumably
+  // it's more precise, so shouldn't measure the time taken to issue
+  // the getMilliseconds() call (which might involve a system call
+  // on some systems)
+  startMilliseconds = getMilliseconds();
+  startCycles = getCycles_ll();
+}
+
+
+string CycleTimer::elapsed() const
+{
+  unsigned long long cycles = getCycles_ll() - startCycles;
+  unsigned long ms = getMilliseconds() - startMilliseconds;
+
+  // I print the cycles with an underscore separating the millions
+  // from the rest because it's easier to read that way (and because
+  // on a 1GHz machine, like mine, it's where the decimal point goes
+  // when interpreting it as milliseconds)
+  char buf[80];
+  sprintf(buf, "%lu ms, %llu_%06llu cycles",
+               ms, cycles/1000000, cycles%1000000);
+
+  return string(buf);     // makes a copy
+}
+
+
+// --------------------- test code ----------------
+#ifdef TEST_CYCTIMER
+
+#include <unistd.h>    // sleep
+
+int main()
+{
+  {
+    CycleTimer timer;
+    string s = timer.elapsed();
+    printf("short time: %s\n", s.pcharc());
+  }
+
+  {
+    CycleTimer timer;
+    sleep(1);
+    string s = timer.elapsed();
+    printf("one second: %s\n", s.pcharc());
+  }
+  
+  {
+    CycleTimer timer;
+    sleep(2);
+    string s = timer.elapsed();
+    printf("two seconds: %s\n", s.pcharc());
+  }
+
+  return 0;
+}
+
+
+#endif // TEST_CYCTIMER

Added: vendor/elsa/current/elkhound/cyctimer.h
===================================================================
--- vendor/elsa/current/elkhound/cyctimer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/cyctimer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// cyctimer.h            see license.txt for copyright and terms of use
+// simple cycles/milliseconds timer
+
+#ifndef CYCTIMER_H
+#define CYCTIMER_H
+
+#include "str.h"           // string
+
+class CycleTimer {
+public:
+  unsigned long long startCycles;
+  unsigned long startMilliseconds;
+  
+public:
+  CycleTimer();            // starts timer
+  string elapsed() const;  // formats elapsed time as "NN ms, NN_NNNNNN cycles"
+};
+
+#endif // CYCTIMER_H

Added: vendor/elsa/current/elkhound/emitcode.cc
===================================================================
--- vendor/elsa/current/elkhound/emitcode.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/emitcode.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,109 @@
+// emitcode.cc            see license.txt for copyright and terms of use
+// code for emitcode.h
+
+#include "emitcode.h"      // this module
+#include "syserr.h"        // xsyserror
+#include "srcloc.h"        // SourceLoc
+#include "trace.h"         // tracingSys
+#include <string.h>        // memcpy
+
+EmitCode::EmitCode(rostring f)
+  : stringBuilder(),
+    os(f.c_str()),
+    fname(f),
+    line(1)
+{
+  if (!os) {
+    xsyserror("open", fname);
+  }
+}
+
+EmitCode::~EmitCode()
+{
+  flush();
+}
+
+
+int EmitCode::getLine()
+{
+  flush();
+  return line;
+}
+
+
+void EmitCode::flush()
+{
+  // count newlines
+  char const *p = c_str();
+  while (*p) {
+    if (*p == '\n') {
+      line++;
+    }
+    p++;
+  }
+
+  #if 0
+    // this is the original code
+    os << *this;
+  #else
+    // 2005-06-28: There is a bug in the cygwin implementation of
+    // ofstream::operator<< that causes a stack overflow segfault
+    // when writing strings longer than about 2MB.  So, I will
+    // manually break up the string into little chunks to write it.
+
+    // how long is the string?
+    int len = p - c_str();
+
+    enum { SZ = 0x1000 };       // write in 4k chunks
+    p = c_str();
+
+    while (len >= SZ) {
+      char buf[SZ+1];
+      memcpy(buf, p, SZ);
+      buf[SZ] = 0;
+
+      os << buf;
+
+      p += SZ;
+      len -= SZ;
+    }
+
+    os << p;
+  #endif
+
+  setlength(0);
+}
+
+
+char const *hashLine()
+{                   
+  if (tracingSys("nolines")) {
+    // emit with comment to disable its effect
+    return "// #line ";
+  }
+  else {
+    return "#line "; 
+  }
+}
+
+
+// note that #line must be preceeded by a newline
+string lineDirective(SourceLoc loc)
+{
+  char const *fname;
+  int line, col;
+  sourceLocManager->decodeLineCol(loc, fname, line, col);
+
+  return stringc << hashLine() << line << " \"" << fname << "\"\n";
+}
+
+stringBuilder &restoreLine(stringBuilder &sb)
+{
+  // little hack..
+  EmitCode &os = (EmitCode&)sb;
+
+  // +1 because we specify what line will be *next*
+  int line = os.getLine()+1;
+  return os << hashLine() << line
+            << " \"" << os.getFname() << "\"\n";
+}

Added: vendor/elsa/current/elkhound/emitcode.h
===================================================================
--- vendor/elsa/current/elkhound/emitcode.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/emitcode.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// emitcode.h            see license.txt for copyright and terms of use
+// track state of emitted code so I can emit #line too
+
+#ifndef EMITCODE_H
+#define EMITCODE_H
+
+#include "str.h"          // stringBuffer
+#include "srcloc.h"       // SourceLoc
+#include "ofstreamts.h"   // ofstreamTS
+
+class EmitCode : public stringBuilder {
+private:     // data
+  ofstreamTS os;       // stream to write to
+  string fname;        // filename for emitting #line
+  int line;            // current line number
+
+public:      // funcs
+  EmitCode(rostring fname);
+  ~EmitCode();
+
+  string const &getFname() const { return fname; }
+
+  // get current line number; flushes internally
+  int getLine();
+
+  // flush data in stringBuffer to 'os'
+  void flush();
+};
+
+
+// return a #line directive for the given location
+string lineDirective(SourceLoc loc);
+
+// emit a #line directive to restore reporting to the
+// EmitCode file itself (the 'sb' argument must be an EmitFile object)
+stringBuilder &restoreLine(stringBuilder &sb);
+
+
+#endif // EMITCODE_H

Added: vendor/elsa/current/elkhound/examples/arith/arith.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/arith/arith.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/arith/arith.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,108 @@
+// arith.cc
+// driver program for arithmetic evaluator
+
+#include "arith.h"     // this module
+#include "glr.h"       // GLR parser
+#include "ptreenode.h" // PTreeNode
+#include "ptreeact.h"  // ParseTreeLexer, ParseTreeActions
+#include "trace.h"     // traceAddSys
+
+#include <assert.h>    // assert
+
+
+// ------------------ ArithLexer ------------------
+/*static*/ void ArithLexer::nextToken(ArithLexer *ths)
+{
+  // call underlying lexer; it will set 'sval' if necessary
+  ths->type = yylex();
+}
+
+LexerInterface::NextTokenFunc ArithLexer::getTokenFunc() const
+{
+  return (NextTokenFunc)&ArithLexer::nextToken;
+}
+
+  
+char const *toString(ArithTokenCodes code)
+{
+  char const * const names[] = {
+    "EOF",
+    "number",
+    "+",
+    "-",
+    "*",
+    "/",
+    "(",
+    ")",
+  };
+
+  assert((unsigned)code < sizeof(names) / sizeof(names[0]));
+  return names[code];
+}
+
+string ArithLexer::tokenDesc() const
+{
+  if (type == TOK_NUMBER) {
+    return stringc << "number(" << (int)sval << ")";
+  }
+  else {
+    return toString((ArithTokenCodes)type);
+  }
+}
+
+string ArithLexer::tokenKindDesc(int kind) const
+{
+  return toString((ArithTokenCodes)kind);
+}
+
+
+// --------------------- main ----------------------
+ArithLexer lexer;
+
+int main(int argc)
+{
+  // initialize lexer by grabbing first token
+  lexer.nextToken(&lexer);
+
+  // create parser; actions and tables not dealloc'd but who cares
+  Arith *arith = new Arith;
+  ParseTables *tables = arith->makeTables();
+
+  // uncomment this to get bison-like shift/reduce reports
+  //traceAddSys("parse");
+  
+  // get tracing info from environment variable TRACE
+  traceAddFromEnvVar();
+
+  if (argc == 1) {
+    // start parsing
+    GLR glr(arith, tables);
+    SemanticValue result;
+    if (!glr.glrParse(lexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print result
+    printf("result: %d\n", (int)result);
+  }
+
+  else {
+    // make it print a parse tree instead of evaluating the expression
+    ParseTreeLexer ptlexer(&lexer, arith);
+    ParseTreeActions ptact(arith, tables);
+
+    GLR glr(&ptact, tables);
+    SemanticValue result;
+    if (!glr.glrParse(ptlexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print the tree
+    PTreeNode *ptn = (PTreeNode*)result;
+    ptn->printTree(cout, PTreeNode::PF_EXPAND);
+  }
+
+  return 0;
+}

Added: vendor/elsa/current/elkhound/examples/arith/arith.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/arith/arith.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/arith/arith.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,119 @@
+// arith.gr
+// parser for a very simple language of arithmetic expressions
+
+// since this example is intended to be the user's first encounter
+// with Elkhound syntax, it includes comments that explain syntax
+// (whereas other examples typically won't)
+
+
+// "context_class" is a required section that tells the parser
+// generator which class the generated action functions should be
+// members of.  All context classes implement the UserActions
+// interface, so they inherit it.  Syntactically, the body is a
+// C++ class definition.
+context_class Arith : public UserActions {
+public:
+  // there's nothing to put in the context for this example
+};
+
+
+// syntax: The second section is a list of tokens (terminals) that the
+// lexer will yield.  The primary purpose is simply to give
+// human-readable names to the numeric codes the lexer will actually
+// use.  
+//
+// Optionally, you can associate quoted aliases, which can help to
+// make the grammar more readable.  For example, with an alias a rule
+// like
+//   E -> E TOK_PLUS E
+// can be rewritten as
+//   E -> E "+" E
+//
+// Don't be confused by the syntax: Elkhound does *not* include a
+// lexer component, and there is no necessary connection between the
+// alias you choose to give and the actual token spellings the lexer
+// might recognize.  (Obviously, for readability's sake, they should
+// correspond anyway.)
+//
+// The intent is this list will be generated automatically from some
+// other specification.  For example, the C grammar cc.gr uses the
+// list printed by the 'lexer2' module when compiled as a stand-alone
+// program.  Here, for simplicity, I'll just type it by hand the same
+// as is written in the ArithTokenCodes enumeration in arith.h.
+terminals {
+  // there's always an explicit EOF token
+  0 : TOK_EOF;
+  1 : TOK_NUMBER;              // no alias
+  2 : TOK_PLUS     "+";        // alias is "+" (including quotes)
+  3 : TOK_MINUS    "-";
+  4 : TOK_TIMES    "*";
+  5 : TOK_DIVIDE   "/";
+  6 : TOK_LPAREN   "(";
+  7 : TOK_RPAREN   ")";
+  
+  // syntax: Some terminals have useful semantic values, and those
+  // are declared here.
+  token(int) TOK_NUMBER;       // numbers have associated int-typed values
+
+  // syntax: Precedence and associativity come next.  Precedence levels
+  // are specified by explicit integers, instead of by their relative
+  // order, to make it possible for grammar extension modules to insert
+  // new tokens anywhere in the precedence ladder.
+  precedence {
+    // high precedence
+    left 20 "*" "/";
+    left 10 "+" "-";
+    // low precedence
+  }
+}
+
+
+// syntax: The third and final section is a sequence of nonterminal
+// ('nonterm') definitions.  The first nonterminal is always the start
+// symbol of the grammar.
+//
+// syntax: Nonterminal definitions can optionally include a semantic
+// value type in square brackets, then the nonterminal's name, then
+// an open-brace, productions, and finally a close-brace.
+//
+// Note: In the current implementation, semantic values are internally
+// stored in an 'unsigned long'-sized variable (32 or 64 bits,
+// typically), so the type you put here should usually be either an
+// int (long int is ok), an enum or bool, or a pointer.  The parser
+// generator will insert the appropriate casts to hide the type of the
+// underlying representation, but it cannot accomodate types that are
+// wider than that representation.  [TODO: Move this explanation to
+// someplace more global, like a user manual, and refer the user to
+// that explanation.]
+nonterm(int) Exp {
+  // syntax: Productons start with "->", then the list of right-hand
+  // side (RHS) symbols, then reduction action code.  The RHS symbols
+  // must be given tags (e.g. "e") if the action code wants to refer
+  // to their value.  The action code may be omitted, in which case
+  // it defaults to the equivalent of "return 0;".
+  //
+  // Looking at this first rule, we see that an Exp nonterminal (the
+  // block we're in) can be rewritten as a sequence of three symbols:
+  // an Exp nonterminal, a "+" token (a.k.a. TOK_PLUS), and another
+  // Exp nonterminal.  When the two Exp nonterminals are matched,
+  // their rules will yield semantic values.  To allow this rule to
+  // use those values, we give them names: e1 and e2.  Then in the
+  // action rule (enclosed in square brackets), the names 'e1' and
+  // 'e2' refer to those semantic values.  The action code will be
+  // compiled in a context where the semantic value names have the
+  // type that you associated with the nonterminal (in square brackets
+  // after the keyword "nonterm").
+  -> e1:Exp "+" e2:Exp        { return e1 + e2; }
+
+  -> e1:Exp "-" e2:Exp        [ return e1 - e2; ]
+  -> e1:Exp "*" e2:Exp        [ return e1 * e2; ]
+  -> e1:Exp "/" e2:Exp        [ return e1 / e2; ]
+  -> n:TOK_NUMBER             [ return n; ]
+  -> p:ParenthesizedExp       [ return p; ]
+}
+
+// I've separated this rule out into its own nonterminal just to
+// show an example of having more than one nonterminal in a grammar.
+nonterm[int] ParenthesizedExp {
+  -> "(" e:Exp ")"            [ return e; ]
+}

Added: vendor/elsa/current/elkhound/examples/arith/arith.h
===================================================================
--- vendor/elsa/current/elkhound/examples/arith/arith.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/arith/arith.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+// arith.h
+// declarations shared across the arith evaluator
+
+#ifndef ARITH_H
+#define ARITH_H
+
+#include "lexerint.h"        // LexerInterface
+#include "arith.gr.gen.h"    // Arith, the parser context class
+
+class ParseTables;           // parsetables.h
+class UserActions;           // useract.h
+
+
+
+// interface to the parser generator's output;
+// defined in arith.gr -> arith.gr.gen.cc
+UserActions *makeUserActions();
+ParseTables *make_Arith_tables();
+
+// interface to the lexer
+int yylex();                        // defined in arith.lex -> arithyy.cc
+
+
+// token codes
+enum ArithTokenCodes {
+  TOK_EOF    =0,
+  TOK_NUMBER =1,
+  TOK_PLUS   =2,
+  TOK_MINUS  =3,
+  TOK_TIMES  =4,
+  TOK_DIVIDE =5,
+  TOK_LPAREN =6,
+  TOK_RPAREN =7,
+};
+
+char const *toString(ArithTokenCodes code);
+
+
+// lexer interface object
+class ArithLexer : public LexerInterface {
+public:
+  static void nextToken(ArithLexer *ths);
+
+  // LexerInterface functions
+  virtual NextTokenFunc getTokenFunc() const;
+  virtual string tokenDesc() const;
+  virtual string tokenKindDesc(int kind) const;
+};
+
+// there will be only one
+extern ArithLexer lexer;
+
+
+
+#endif // ARITH_H

Added: vendor/elsa/current/elkhound/examples/arith/arith.lex
===================================================================
--- vendor/elsa/current/elkhound/examples/arith/arith.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/arith/arith.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+/* arith.lex
+ * lexical analyzer for arithmetic language */
+
+/* flex options */
+%option noyywrap
+%option nounput
+
+
+/* C++ declarations */
+  #include "arith.h"       // lexer, ArithTokenCodes
+
+
+/* token definitions */
+%%
+
+[0-9]+      {
+  lexer.sval = (SemanticValue)atoi(yytext);
+  return TOK_NUMBER;
+}
+
+  /* operators, punctuators */
+"+"         { return TOK_PLUS; }
+"-"         { return TOK_MINUS; }
+"*"         { return TOK_TIMES; }
+"/"         { return TOK_DIVIDE; }
+"("         { return TOK_LPAREN; }
+")"         { return TOK_RPAREN; }
+
+[ \t\n]     {
+  /* whitespace; ignore */
+}
+
+"#.*\n"     {
+  /* comment; ignore */
+}
+
+.           {
+  printf("illegal character: %c\n", yytext[0]);
+  /* but continue anyway */
+}

Added: vendor/elsa/current/elkhound/examples/arith/arithyy.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/arith/arithyy.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/arith/arithyy.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1572 @@
+#line 2 "arithyy.cc"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define yywrap() 1
+#define YY_SKIP_YYWRAP
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 11
+#define YY_END_OF_BUFFER 12
+static yyconst short int yy_accept[20] =
+    {   0,
+        0,    0,   12,   10,    8,    8,   10,    6,    7,    4,
+        2,    3,    5,    1,    0,    1,    0,    9,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    1,    4,    1,    1,    1,    1,    5,
+        6,    7,    8,    1,    9,   10,   11,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[13] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1
+    } ;
+
+static yyconst short int yy_base[20] =
+    {   0,
+        0,    0,   18,   19,   19,   19,    7,   19,   19,   19,
+       19,   19,   19,    4,    8,    2,   10,   19,   19
+    } ;
+
+static yyconst short int yy_def[20] =
+    {   0,
+       19,    1,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,    0
+    } ;
+
+static yyconst short int yy_nxt[32] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,   11,   12,    4,
+       13,   14,   18,   16,   17,   16,   15,   19,    3,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19
+    } ;
+
+static yyconst short int yy_chk[32] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,   17,   16,   15,   14,    7,    3,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "arith.lex"
+#define INITIAL 0
+/* arith.lex
+ * lexical analyzer for arithmetic language */
+/* flex options */
+#define YY_NO_UNPUT 1
+/* C++ declarations */
+#include "arith.h"       // lexer, ArithTokenCodes
+/* token definitions */
+#line 384 "arithyy.cc"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 14 "arith.lex"
+
+
+#line 538 "arithyy.cc"
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 20 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 19 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 16 "arith.lex"
+{
+  lexer.sval = (SemanticValue)atoi(yytext);
+  return TOK_NUMBER;
+}
+	YY_BREAK
+/* operators, punctuators */
+case 2:
+YY_RULE_SETUP
+#line 22 "arith.lex"
+{ return TOK_PLUS; }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 23 "arith.lex"
+{ return TOK_MINUS; }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 24 "arith.lex"
+{ return TOK_TIMES; }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 25 "arith.lex"
+{ return TOK_DIVIDE; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 26 "arith.lex"
+{ return TOK_LPAREN; }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 27 "arith.lex"
+{ return TOK_RPAREN; }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 29 "arith.lex"
+{
+  /* whitespace; ignore */
+}
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 33 "arith.lex"
+{
+  /* comment; ignore */
+}
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 37 "arith.lex"
+{
+  printf("illegal character: %c\n", yytext[0]);
+  /* but continue anyway */
+}
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 41 "arith.lex"
+ECHO;
+	YY_BREAK
+#line 687 "arithyy.cc"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 20 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 20 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 19);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+#endif	/* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+
+	return c;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b );
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+	{
+	int len;
+	for ( len = 0; yy_str[len]; ++len )
+		;
+
+	return yy_scan_bytes( yy_str, len );
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+	{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc( n );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < len; ++i )
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+	{
+	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 41 "arith.lex"

Added: vendor/elsa/current/elkhound/examples/arith/configure.pl
===================================================================
--- vendor/elsa/current/elkhound/examples/arith/configure.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/arith/configure.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,142 @@
+#!/usr/bin/perl -w
+# configure script for C parser
+
+use strict 'subs';
+
+# default location of smbase relative to this package
+$SMBASE = "../../../smbase";
+$req_smcv = 1.03;            # required sm_config version number
+$thisPackage = "elkhound/examples/arith";
+
+# -------------- BEGIN common block ---------------
+# do an initial argument scan to find if smbase is somewhere else
+for (my $i=0; $i < @ARGV; $i++) {
+  my ($d) = ($ARGV[$i] =~ m/-*smbase=(.*)/);
+  if (defined($d)) {
+    $SMBASE = $d;
+  }
+}
+
+# try to load the sm_config module
+eval {
+  push @INC, ($SMBASE);
+  require sm_config;
+};
+if ($@) {
+  die("$@" .     # ends with newline, usually
+      "\n" .
+      "I looked for smbase in \"$SMBASE\".\n" .
+      "\n" .
+      "You can explicitly specify the location of smbase with the -smbase=<dir>\n" .
+      "command-line argument.\n");
+}
+
+# check version number
+$smcv = get_sm_config_version();
+if ($smcv < $req_smcv) {
+  die("This package requires version $req_smcv of sm_config, but found\n" .
+      "only version $smcv.\n");
+}
+# -------------- END common block ---------------
+
+
+# defaults
+$AST = "../../../ast";
+$ELKHOUND = "../..";
+
+
+sub usage {
+  standardUsage();
+
+  print(<<"EOF");
+package options:
+  -ast=<dir>:        specify where the ast system is [$AST]
+  -elkhound=<dir>:   specify where the elkhound system is [$ELKHOUND]
+EOF
+}
+
+
+# -------------- BEGIN common block 2 -------------
+# global variables holding information about the current command-line
+# option being processed
+$option = "";
+$value = "";
+
+# process command-line arguments
+foreach $optionAndValue (@ARGV) {
+  # ignore leading '-' characters, and split at first '=' (if any)
+  ($option, $value) =
+    ($optionAndValue =~ m/^-*([^-][^=]*)=?(.*)$/);
+                      #      option     = value
+
+  my $arg = $option;
+
+  if (handleStandardOption()) {
+    # handled by sm_config.pm
+  }
+  # -------------- END common block 2 -------------
+
+  elsif ($arg eq "ast") {
+    $AST = $tmp;
+  }
+  elsif ($arg eq "elkhound") {
+    $ELKHOUND = $tmp;
+  }
+
+  else {
+    die "unknown option: $arg\n";
+  }
+}
+
+finishedOptionProcessing();
+
+
+# ------------------ check for needed components ----------------
+test_smbase_presence();
+
+test_CXX_compiler();
+
+# ast
+if (! -f "$AST/asthelp.h") {
+  die "I cannot find asthelp.h in `$AST'.\n" .
+      "The ast system is required for elsa.\n" .
+      "If it's in a different location, use the -ast=<dir> option.\n";
+}
+
+# elkhound
+if (! -f "$ELKHOUND/glr.h") {
+  die "I cannot find glr.h in `$ELKHOUND'.\n" .
+      "The elkhound system is required for elsa.\n" .
+      "If it's in a different location, use the -elkhound=<dir> option.\n";
+}
+
+
+# ------------------ config.summary -----------------
+$summary = getStandardConfigSummary();
+
+$summary .= <<"OUTER_EOF";
+cat <<EOF
+  AST:         $AST
+  ELKHOUND:    $ELKHOUND
+EOF
+OUTER_EOF
+
+writeConfigSummary($summary);
+
+
+# ------------------- config.status ------------------
+writeConfigStatus("AST" => "$AST",
+                  "ELKHOUND" => "$ELKHOUND");
+
+
+# ----------------- final actions -----------------
+# run the output file generator
+run("./config.status");
+
+print("\nYou can now run make, usually called 'make' or 'gmake'.\n");
+
+exit(0);
+
+
+# silence warnings
+pretendUsed($thisPackage);


Property changes on: vendor/elsa/current/elkhound/examples/arith/configure.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/examples/asu419.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/asu419.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/asu419.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// asu419.gr
+// [ASU] grammar 4.19, p.222: demonstrating LR sets-of-items construction
+
+verbatim Asu419 []
+
+terminals {
+  0 : plus "+";
+  1 : times "*";
+  2 : lparen "(";
+  3 : rparen ")";
+  4 : id "id";
+  5 : eof "$";
+}
+
+nonterm[int] Start -> E "$"      [ return 0; ]
+
+nonterm[int] E {
+  -> E "+" T      [ return 0; ]
+  -> T            [ return 0; ]
+}
+
+nonterm[int] T {
+  -> T "*" F      [ return 0; ]
+  -> F            [ return 0; ]
+}
+
+nonterm[int] F {
+  -> "(" E ")"    [ return 0; ]
+  -> id           [ return 0; ]
+}
+

Added: vendor/elsa/current/elkhound/examples/cc_eeb.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/cc_eeb.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/cc_eeb.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,282 @@
+// cc_eeb.cc
+// *** DO NOT EDIT BY HAND ***
+// automatically generated by gramanl, from cc_eeb.gr
+
+// GLR source location information is enabled
+
+#include "cc_eeb.h"     // EEB
+#include "parsetables.h" // ParseTables
+#include "srcloc.h"      // SourceLoc
+
+#include <assert.h>      // assert
+#include <iostream.h>    // cout
+#include <stdlib.h>      // abort
+
+static char const *termNames[] = {
+  "TOK_EOF",  // 0
+  "TOK_PLUS",  // 1
+  "TOK_B",  // 2
+};
+
+string EEB::terminalDescription(int termId, SemanticValue sval)
+{
+  return stringc << termNames[termId]
+                 << "(" << (sval % 100000) << ")";
+}
+
+
+static char const *nontermNames[] = {
+  "empty",  // 0
+  "__EarlyStartSymbol",  // 1
+  "E",  // 2
+};
+
+string EEB::nonterminalDescription(int nontermId, SemanticValue sval)
+{
+  return stringc << nontermNames[nontermId]
+                 << "(" << (sval % 100000) << ")";
+}
+
+
+char const *EEB::terminalName(int termId)
+{
+  return termNames[termId];
+}
+
+char const *EEB::nonterminalName(int nontermId)
+{
+  return nontermNames[nontermId];
+}
+
+// ------------------- actions ------------------
+// [0] __EarlyStartSymbol[Node*] -> top:E TOK_EOF
+inline Node* EEB::action0___EarlyStartSymbol(SourceLoc loc, Node* top)
+#line 507 "grampar.cc"
+{ return top;  }
+#line 57 "cc_eeb.cc"
+
+// [1] E[Node*] -> e1:E + e2:E
+inline Node* EEB::action1_E(SourceLoc loc, Node* e1, Node* e2)
+#line 18 "cc_eeb.gr"
+{ return new PlusNode(e1, e2);  }
+#line 63 "cc_eeb.cc"
+
+// [2] E[Node*] -> b:b
+inline Node* EEB::action2_E(SourceLoc loc, int b)
+#line 19 "cc_eeb.gr"
+{ return new LeafNode(b);  }
+#line 69 "cc_eeb.cc"
+
+
+/*static*/ SemanticValue EEB::doReductionAction(
+  EEB *ths,
+  int productionId, SemanticValue const *semanticValues,
+  SourceLoc loc)
+{
+  switch (productionId) {
+    case 0:
+      return (SemanticValue)(ths->action0___EarlyStartSymbol(loc, (Node*)(semanticValues[0])));
+    case 1:
+      return (SemanticValue)(ths->action1_E(loc, (Node*)(semanticValues[0]), (Node*)(semanticValues[2])));
+    case 2:
+      return (SemanticValue)(ths->action2_E(loc, (int)(semanticValues[0])));
+    default:
+      assert(!"invalid production code");
+      return (SemanticValue)0;   // silence warning
+  }
+}
+
+UserActions::ReductionActionFunc EEB::getReductionAction()
+{
+  return (ReductionActionFunc)&EEB::doReductionAction;
+}
+
+
+// ---------------- dup/del/merge/keep nonterminals ---------------
+
+inline Node* EEB::dup_E(Node* n) 
+#line 14 "cc_eeb.gr"
+{ n->incRefCt();  }
+#line 101 "cc_eeb.cc"
+
+inline void EEB::del_E(Node* n) 
+#line 15 "cc_eeb.gr"
+{ n->delRefCt();  }
+#line 106 "cc_eeb.cc"
+
+inline Node* EEB::merge_E(Node* a, Node* b) 
+#line 16 "cc_eeb.gr"
+{ return pickLeftAssocTree(a,b);  }
+#line 111 "cc_eeb.cc"
+
+SemanticValue EEB::duplicateNontermValue(int nontermId, SemanticValue sval)
+{
+  switch (nontermId) {
+    case 2:
+      return (SemanticValue)dup_E((Node*)sval);
+    default:
+      return (SemanticValue)0;
+  }
+}
+
+void EEB::deallocateNontermValue(int nontermId, SemanticValue sval)
+{
+  switch (nontermId) {
+    case 2:
+      del_E((Node*)sval);
+      return;
+    default:
+      cout << "WARNING: there is no action to deallocate nonterm "
+           << nontermNames[nontermId] << endl;
+  }
+}
+
+SemanticValue EEB::mergeAlternativeParses(int nontermId, SemanticValue left,
+                                           SemanticValue right,  SourceLoc loc)
+{
+  switch (nontermId) {
+    case 2:
+      return (SemanticValue)merge_E((Node*)left, (Node*)right);
+    default:
+      cout << toString(loc) 
+           << ": WARNING: there is no action to merge nonterm "
+           << nontermNames[nontermId] << endl;
+      return left;
+  }
+}
+
+bool EEB::keepNontermValue(int nontermId, SemanticValue sval)
+{
+  switch (nontermId) {
+    default:
+      return true;
+  }
+}
+
+
+// ---------------- dup/del/classify terminals ---------------
+SemanticValue EEB::duplicateTerminalValue(int termId, SemanticValue sval)
+{
+  switch (termId) {
+    default:
+      return (SemanticValue)0;
+  }
+}
+
+void EEB::deallocateTerminalValue(int termId, SemanticValue sval)
+{
+  switch (termId) {
+    default:
+      cout << "WARNING: there is no action to deallocate terminal "
+           << termNames[termId] << endl;
+  }
+}
+
+/*static*/ int EEB::reclassifyToken(EEB *ths, int oldTokenType, SemanticValue sval)
+{
+  switch (oldTokenType) {
+    default:
+      return oldTokenType;
+  }
+}
+
+UserActions::ReclassifyFunc EEB::getReclassifier()
+{
+  return (ReclassifyFunc)&EEB::reclassifyToken;
+}
+
+
+// this makes a ParseTables from some literal data;
+// the code is written by ParseTables::emitConstructionCode()
+// in parsetables.cc
+class EEB_ParseTables : public ParseTables {
+public:
+  EEB_ParseTables();
+};
+
+EEB_ParseTables::EEB_ParseTables()
+  : ParseTables(false /*owning*/)
+{
+  numTerms = 3;
+  numNonterms = 3;
+  numStates = 6;
+  numProds = 3;
+  actionCols = 3;
+  actionRows = 6;
+  gotoCols = 3;
+  gotoRows = 6;
+  ambigTableSize = 3;
+  startState = (StateId)0;
+  finalProductionIndex = 0;
+  bigProductionListSize = 0;
+  errorBitsRowSize = 4;
+  uniqueErrorRows = 0;
+
+  static ActionEntry const actionTable_static[18] = {
+    /*0*/ 0, 0, 4, 
+    /*1*/ 0, 0, 0, 
+    /*2*/ 0, 0, 4, 
+    /*3*/ -3, -3, 0, 
+    /*4*/ 2, 3, 0, 
+    /*5*/ -2, 7, 0, 
+  };
+  actionTable = const_cast<ActionEntry*>(actionTable_static);
+
+  static GotoEntry const gotoTable_static[18] = {
+    /*0*/ 65535, 65535, 4, 
+    /*1*/ 65535, 65535, 65535, 
+    /*2*/ 65535, 65535, 5, 
+    /*3*/ 65535, 65535, 65535, 
+    /*4*/ 65535, 65535, 65535, 
+    /*5*/ 65535, 65535, 65535, 
+  };
+  gotoTable = const_cast<GotoEntry*>(gotoTable_static);
+
+  static ParseTables::ProdInfo const prodInfo_static[3] = {
+    /*0*/ {2,1}, {3,2}, {1,2}, 
+  };
+  prodInfo = const_cast<ParseTables::ProdInfo*>(prodInfo_static);
+
+  static SymbolId const stateSymbol_static[6] = {
+    /*0*/ 0, 1, 2, 3, -3, -3, 
+  };
+  stateSymbol = const_cast<SymbolId*>(stateSymbol_static);
+
+  static ActionEntry const ambigTable_static[3] = {
+    /*0*/ 2, 3, -2, 
+  };
+  ambigTable = const_cast<ActionEntry*>(ambigTable_static);
+
+  static NtIndex const nontermOrder_static[3] = {
+    /*0*/ 2, 1, 0, 
+  };
+  nontermOrder = const_cast<NtIndex*>(nontermOrder_static);
+
+  ErrorBitsEntry *errorBits_static = NULL;
+  errorBits = const_cast<ErrorBitsEntry*>(errorBits_static);
+
+  errorBitsPointers = NULL;
+
+  TermIndex *actionIndexMap_static = NULL;
+  actionIndexMap = const_cast<TermIndex*>(actionIndexMap_static);
+
+  actionRowPointers = NULL;
+
+  NtIndex *gotoIndexMap_static = NULL;
+  gotoIndexMap = const_cast<NtIndex*>(gotoIndexMap_static);
+
+  gotoRowPointers = NULL;
+
+  firstWithTerminal = NULL;
+  firstWithNonterminal = NULL;
+  bigProductionList = NULL;
+  productionsForState = NULL;
+  ambigStateTable = NULL;
+}
+
+
+ParseTables *EEB::makeTables()
+{
+  return new EEB_ParseTables;
+}
+

Added: vendor/elsa/current/elkhound/examples/cc_eeb.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/cc_eeb.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/cc_eeb.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// cc_eeb.gr
+// EEb example from CC04 submission
+
+context_class EEB : public UserActions {};
+
+terminals {
+  0: TOK_EOF;
+  1: TOK_PLUS "+";
+  2: TOK_B "b";
+  token(int) TOK_B;      // "b" sval is an int
+}
+
+nonterm(Node*) E {
+  fun dup(n)     { n->incRefCt(); }
+  fun del(n)     { n->delRefCt(); }
+  fun merge(a,b) { return pickLeftAssocTree(a,b); }
+
+  -> e1:E "+" e2:E       { return new PlusNode(e1, e2); }
+  -> b:"b"               { return new LeafNode(b); }
+}

Added: vendor/elsa/current/elkhound/examples/cc_eeb.h
===================================================================
--- vendor/elsa/current/elkhound/examples/cc_eeb.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/cc_eeb.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// cc_eeb.h
+// *** DO NOT EDIT BY HAND ***
+// automatically generated by elkhound, from cc_eeb.gr
+
+#ifndef CC_EEB_H
+#define CC_EEB_H
+
+#include "useract.h"     // UserActions
+
+
+// parser context class
+class 
+#line 4 "cc_eeb.gr"
+ EEB : public UserActions {
+#line 16 "cc_eeb.h"
+
+
+private:
+  USER_ACTION_FUNCTIONS      // see useract.h
+
+  // declare the actual action function
+  static SemanticValue doReductionAction(
+    EEB *ths,
+    int productionId, SemanticValue const *semanticValues,
+  SourceLoc loc);
+
+  // declare the classifier function
+  static int reclassifyToken(
+    EEB *ths,
+    int oldTokenType, SemanticValue sval);
+
+  Node* action0___EarlyStartSymbol(SourceLoc loc, Node* top);
+  Node* action1_E(SourceLoc loc, Node* e1, Node* e2);
+  Node* action2_E(SourceLoc loc, int b);
+  inline Node* dup_E(Node* n) ;
+  inline void del_E(Node* n) ;
+  inline Node* merge_E(Node* a, Node* b) ;
+
+// the function which makes the parse tables
+public:
+  virtual ParseTables *makeTables();
+};
+
+#endif // CC_EEB_H

Added: vendor/elsa/current/elkhound/examples/cdecl/cdecl.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/cdecl/cdecl.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/cdecl/cdecl.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,192 @@
+// cdecl.gr
+// demonstration of resolving C ident/type ambiguity
+// cdecl solves it using reduction cancellation (cf. cdecl2)
+
+verbatim [
+
+#include <iostream.h>      // cout
+#include "trace.h"         // trace
+#include "locstr.h"        // LocString
+#include "strhash.h"       // StringHash
+#include "objlist.h"       // ObjList
+#include "parssppt.h"      // ParseTreeAndTokens
+
+#define D(msg) \
+  trace("cdecl") << msg << endl
+#define R0 return 0
+
+]
+
+// parsing action state
+context_class ParseEnv : public UserActions {
+public:
+  StringRef intType;              // "int"
+  ObjList<StringHash> types;      // stack of hashes which identify names of types
+
+public:
+  ParseEnv(StringTable &table);
+  ~ParseEnv();
+
+  void enterScope();
+  void leaveScope();
+  void addType(StringRef type);
+  bool isType(StringRef name);
+};
+
+
+impl_verbatim [
+
+// bit of a hack..
+ParseTables *tables;
+
+class CCLang;
+UserActions *makeUserActions(StringTable &table, CCLang &lang)
+{
+  ParseEnv *ret = new ParseEnv(table);
+  tables = ret->makeTables();
+  return ret;
+}
+
+ParseTables *make_ParseEnv_tables();
+ParseTables *makeParseTables()
+{
+  return tables;
+}
+
+
+ParseEnv::ParseEnv(StringTable &table)
+{
+  intType = table.add("int");
+}
+
+ParseEnv::~ParseEnv()
+{}
+
+
+static char const *identity(void *data)
+{
+  return (char const*)data;
+}
+
+void ParseEnv::enterScope()
+{
+  types.prepend(new StringHash(identity));
+}
+
+void ParseEnv::leaveScope()
+{
+  delete types.removeAt(0);
+}
+
+void ParseEnv::addType(StringRef type)
+{
+  StringHash *h = types.first();
+  if (h->get(type)) {
+    cout << "duplicate entry for " << type << " -- will ignore\n";
+  }
+  else {
+    h->add(type, (void*)type);
+  }
+}
+
+bool ParseEnv::isType(StringRef name)
+{
+  if (name == intType) {
+    return true;
+  }
+
+  FOREACH_OBJLIST(StringHash, types, iter) {
+    if (iter.data()->get(name)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+#if 0
+void doit(int argc, char **argv)
+{
+  traceAddSys("progress");
+  //traceAddSys("parse-tree");
+
+  SemanticValue treeTop;
+  ParseTreeAndTokens tree(treeTop);
+  ParseEnv env(tree);
+  treeMain(tree, argc, argv);
+
+  cout << "final parse result: " << treeTop << endl;
+}
+
+int main(int argc, char **argv)
+{
+  doit(argc, argv);
+
+  //malloc_stats();
+
+  return 0;
+}
+#endif // 0
+
+] // end impl_verbatim
+
+
+terminals {
+  // grab the lexer's token list
+  include("../../c/c.tok")
+
+  token[StringRef] L2_NAME {
+    fun dup(s) [ return s; ]
+    fun del()  []
+  }
+}
+
+
+nonterm[int] Start -> Stmts  [
+  D("exiting scope");
+  leaveScope();
+  R0;
+]
+
+nonterm[int] Stmts {
+  -> empty         [ D("entering scope"); enterScope(); R0; ]
+  -> Stmts Stmt    [ R0; ]
+}
+
+nonterm[int] Stmt {
+  -> t:TypeName "(" n:VarName ")" ";"   [    // declaration
+       D("declaration of " << n << ", type " << t); R0;
+     ]
+
+  -> f:VarName "(" a:VarName ")" ";"    [    // function call
+       D("call of " << f << " with arg " << a); R0;
+     ]
+
+  -> "typedef" t:TypeName n:L2_NAME ";" [    // typedef: introduce type name
+       D("typedef of " << n << " as type " << t);
+       addType(n);
+       R0;
+     ]
+
+  -> "{" Stmts "}"                      [    // scope
+       D("exiting scope"); leaveScope(); R0;
+     ]
+}
+
+nonterm[StringRef] VarName {
+  fun keep(n)      [ return !isType(n); ]
+
+  -> n:L2_NAME     [ return n; ]
+}
+
+nonterm[StringRef] TypeName {
+  fun keep(n)      [ return isType(n); ]
+
+  -> n:L2_NAME     [ return n; ]
+
+  // this is a little bit of a hack, but in some sense it's valid
+  // to regard the global strings as another stringtable.. of course,
+  // equality won't work, but I don't need it for the moment
+  -> L2_INT        [ return intType; ]
+}
+

Added: vendor/elsa/current/elkhound/examples/cexp/cexp3.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/cexp/cexp3.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/cexp/cexp3.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,87 @@
+// cexp3.gr
+// another go at C expressions, with user-supplied actions
+
+verbatim {
+  #include <iostream.h>            // cout
+  #include "cexp3ast.ast.gen.h"    // Exp
+  #include "trace.h"               // trace
+  #include "useract.h"             // UserActions
+
+  #define D(msg) \
+    trace("exptree") << msg << endl
+}
+
+context_class Cexp3 : public UserActions {
+};
+
+impl_verbatim {
+  class CCLang;
+  UserActions *makeUserActions(StringTable &, CCLang &)
+  {
+    return new Cexp3;
+  }
+
+  ParseTables *make_Cexp3_tables();
+  ParseTables *makeParseTables()
+  {
+    return (new Cexp3 /*leaked..*/)->makeTables();
+  }
+}
+
+/*
+  // this says that anyplace below where I say "[int]", the dup
+  // and del functions should be as specified
+  typemap [int] {
+    dup(i) {}
+    del(i) {}
+    // no merge provided, it should never be needed
+  }
+
+  typemap [Exp*] {
+    dup(p) { return p->deepCopy(); }
+    del(p) { delete p; }
+    merge(p1, p2) { return Exp::mergeAlts(p1, p2); }
+  }
+*/
+
+terminals {
+  // grab the lexer's token list
+  include("../../c/c.tok")
+
+  // annotate some with semantic types
+  token[int] L2_INT_LITERAL {
+    fun dup(i) [ return i; ]
+    fun del()  []
+    // no merge provided, it should never be needed
+  }
+  
+  // precedence and associativity
+  // I mark with 'PREC' lines to be removed to yield a version
+  // which disambiguates using 'merge'
+  precedence {
+    // high precedence
+    left 20 "*";                  // PREC
+    left 10 "+";                  // PREC
+    // low precedence
+  }
+}
+
+nonterm[int] Start {
+  -> e:Exp             [ int ret = e->eval();
+                         cout << "reduced Start: " << ret << endl;
+                         e->decRefCt();
+                         return ret;]
+}
+
+nonterm[Exp*] Exp {
+  fun dup(p) [ D("dup " << p); p->incRefCt(); return p; ]
+  fun del(p) [ D("del " << p); p->decRefCt(); ]
+  fun merge(p1, p2) [ D("merge " << p1 << " and " << p2);
+                      return Exp::mergeAlts(p1, p2); ]
+
+  -> i:L2_INT_LITERAL  [ D("literal: " << i);
+                         return new E_int(i); ]
+  -> e1:Exp "+" e2:Exp [ return new E_op('+', e1, e2); ]
+  -> e1:Exp "*" e2:Exp [ return new E_op('*', e1, e2); ]
+}
+

Added: vendor/elsa/current/elkhound/examples/cexp/cexp3ast.ast
===================================================================
--- vendor/elsa/current/elkhound/examples/cexp/cexp3ast.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/cexp/cexp3ast.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,52 @@
+// cexp3ast.ast
+// simple expression AST
+
+verbatim {
+  inline string toString(Exp const *e) {
+    return stringc << (void*)e;
+  }
+}
+
+class Exp {
+  // reference count
+  private int refCt;
+  public void incRefCt();
+  public void decRefCt();      // deletes when it hits 0
+  
+  // whoever creates this object initially is its first owner,
+  // hence the refct starts at 1
+  ctor { refCt=0; incRefCt(); };
+
+  // number of nodes in this subtree, including myself
+  public(func) virtual int numNodes() const = 0;
+
+  // evaluate the arithmetic value of the subtree
+  public(func) virtual int eval() const = 0;
+
+  // merge alternative interpretations
+  public static Exp *mergeAlts(Exp *p1, Exp *p2);
+
+  // expression containing simply a literal integer
+  -> E_int(int i) {
+    public int numNodes() const
+      { return 1; };
+    public int eval() const
+      { return i; };
+  }
+
+  // 'op' can be either '+' or '*' 
+  // the explicit pointer notation means "serf"
+  -> E_op(char op, Exp *left, Exp *right) {
+    dtor {
+      left->decRefCt();
+      right->decRefCt();
+    };
+    public int numNodes() const
+      { return 1 + left->numNodes() + right->numNodes(); };
+    public int eval() const {
+      int L = left->eval();
+      int R = right->eval();
+      return op=='+'? L+R : L*R;
+    };
+  }
+}

Added: vendor/elsa/current/elkhound/examples/cexp/cexp3mrg.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/cexp/cexp3mrg.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/cexp/cexp3mrg.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,69 @@
+// cexp3mrg.cc
+// code to merge alternatives for cexp3ast.ast
+
+#include "cexp3ast.ast.gen.h"    // Exp
+#include "xassert.h"             // xfailure
+#include "trace.h"               // trace
+
+
+void Exp::incRefCt()
+{
+  refCt++;
+  trace("refct") << "incremented refct of " << this << " to " << refCt << endl;
+}
+
+void Exp::decRefCt()
+{
+  xassert(refCt > 0);
+  --refCt;
+  trace("refct") << "decremented refct of " << this << " to " << refCt << endl;
+  if (refCt == 0) {
+    delete this;
+  }
+}
+
+
+// this code is used to select between two competing interpretations
+// for the same sequence of ground terminals
+STATICDEF Exp *Exp::mergeAlts(Exp *_p1, Exp *_p2)
+{
+  E_op *p1 = _p1->ifE_op();
+  E_op *p2 = _p2->ifE_op();
+                    
+  // the only way conflict can occur is between E_op expressions
+  xassert(p1 && p2);
+
+  // look at the operators
+  if (p1->op != p2->op) {
+    // they are different; keep the one with '+' at the
+    // top, as this is the lower-precedence operator
+    if (p1->op == '+') {
+      p2->decRefCt();
+      return p1;
+    }
+    else {
+      p1->decRefCt();
+      return p2;
+    }
+  }
+
+  // same operators; decide using associativity:
+  // for left associativity, we want the left subtree to be larger
+  int nodes1 = p1->left->numNodes();
+  int nodes2 = p2->left->numNodes();
+  if (nodes1 != nodes2) {
+    if (nodes1 > nodes2) {
+      p2->decRefCt();
+      return p1;
+    }
+    else {
+      p1->decRefCt();
+      return p2;
+    }
+  }
+
+  // it should never be possible for two competing interpretations
+  // to have the same operators and the same tree sizes
+  xfailure("competing trees are too similar");
+  return NULL;    // silence warning
+}

Added: vendor/elsa/current/elkhound/examples/crash1.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/crash1.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/crash1.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// crash1.gr
+// an example from Jeremy Condit that caused Elkhound to crash
+
+context_class Context : public UserActions {};
+
+terminals {
+    0 : T;
+    token T { fun del(s) {} }
+}
+
+nonterm foo {}

Added: vendor/elsa/current/elkhound/examples/gcom/eval.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/eval.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/eval.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,173 @@
+// eval.cc
+// implementation of the 'eval' methods declared in gcom.ast
+
+#include "eval.h"        // this module
+#include "ast.h"         // AST declarations
+
+#include <stdlib.h>      // exit
+#include <assert.h>      // assert
+#include <stdio.h>       // printf
+
+
+// ------------------- Binding -----------------
+Binding::~Binding()
+{}
+
+
+// --------------------- Env -------------------
+static char const *bindToName(Binding *b)
+{
+  return b->name.c_str();
+}
+
+Env::Env()
+  : map(bindToName)
+{}
+
+Env::~Env()
+{}
+
+
+int Env::get(char const *x)
+{
+  Binding *b = map.get(x);
+  if (!b) {
+    return 0;     // unset variables default to 0 value
+  }
+  else {
+    return b->value;
+  }
+}
+
+void Env::set(char const *x, int val)
+{
+  Binding *b = map.get(x);
+  if (!b) {
+    // add new binding
+    map.add(x, new Binding(x, val));
+  }
+  else {
+    b->value = val;
+  }
+}
+
+
+// -------------------- AExp -------------------
+int A_lit::eval(Env &env)
+{
+  return n;
+}
+
+int A_var::eval(Env &env)
+{
+  return env.get(x.c_str());
+}
+
+int A_bin::eval(Env &env)
+{
+  switch (op) {
+    default:       assert(!"bad code");
+    case AO_PLUS:  return a1->eval(env) + a2->eval(env);
+    case AO_MINUS: return a1->eval(env) - a2->eval(env);
+    case AO_TIMES: return a1->eval(env) * a2->eval(env);
+  }
+}
+
+
+// -------------------- BExp -------------------
+bool B_lit::eval(Env &env)
+{
+  return b;
+}
+
+bool B_pred::eval(Env &env)
+{
+  switch (op) {
+    default:       assert(!"bad code");
+    case BP_EQUAL: return a1->eval(env) == a2->eval(env);
+    case BP_LESS:  return a1->eval(env) < a2->eval(env);
+  }
+}
+
+bool B_not::eval(Env &env)
+{
+  return !b->eval(env);
+}
+
+bool B_bin::eval(Env &env)
+{
+  switch (op) {
+    default:       assert(!"bad code");
+    case BO_AND: return b1->eval(env) && b2->eval(env);
+    case BO_OR:  return b1->eval(env) && b2->eval(env);
+  }
+}
+
+
+// -------------------- Stmt -------------------
+void S_skip::eval(Env &env)
+{}
+
+void S_abort::eval(Env &env)
+{
+  printf("abort command executed\n");
+  exit(0);
+}
+
+void S_print::eval(Env &env)
+{
+  printf("%s is %d\n", x.c_str(), env.get(x.c_str()));
+}
+
+void S_assign::eval(Env &env)
+{
+  env.set(x.c_str(), a->eval(env));
+}
+
+void S_seq::eval(Env &env)
+{
+  s1->eval(env);
+  s2->eval(env);
+}
+
+void S_if::eval(Env &env)
+{
+  if (!g->eval(env)) {
+    printf("'if' command had no enabled alternatives; aborting\n");
+    exit(0);
+  }
+}
+
+void S_do::eval(Env &env)
+{
+  while (g->eval(env))
+    {}
+}
+
+
+// -------------------- GCom -------------------
+bool G_stmt::eval(Env &env)
+{ 
+  if (b->eval(env)) {
+    s->eval(env);
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+bool G_seq::eval(Env &env)
+{
+  // The usual semantics for guarded commands say that if both guards
+  // are true, then we can execute either one.  Here, I'm going to
+  // always execute the *first* one with an enabled guard; that
+  // behavior is allowed, but not required.  I leave it as an exercise
+  // to modify this code so that the executions it models will cover a
+  // larger fraction of the state space reachable under the
+  // traditional semantics.
+  
+  if (g1->eval(env)) { return true; }
+  if (g2->eval(env)) { return true; }
+  return false;
+}

Added: vendor/elsa/current/elkhound/examples/gcom/eval.h
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/eval.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/eval.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// eval.h
+// evaluation environment for gcom
+
+#ifndef EVAL_H
+#define EVAL_H
+
+#include "strhash.h"      // TStringHash
+#include "str.h"          // string
+
+class Binding {
+public:
+  string name;
+  int value;
+  
+public:
+  Binding(char const *n, int v)
+    : name(n),
+      value(v)
+  {}
+  ~Binding();
+};
+
+class Env {
+private:
+  // map: name -> value
+  TStringHash<Binding> map;
+
+public:
+  Env();
+  ~Env();
+
+  int get(char const *x);
+  void set(char const *x, int val);
+};
+
+#endif // ENV_H

Added: vendor/elsa/current/elkhound/examples/gcom/gcom.ast
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/gcom.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/gcom.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,67 @@
+// gcom.ast
+// AST for guarded command language
+
+verbatim {
+  class Env;       // eval.h
+
+  // binary arithmetic operators
+  enum AOp {
+    AO_PLUS,
+    AO_MINUS,
+    AO_TIMES
+  };
+
+  // binary boolean predicates over arithmetic expressions
+  enum BPred {
+    BP_EQUAL,
+    BP_LESS
+  };
+
+  // binary boolean operators
+  enum BOp {
+    BO_AND,
+    BO_OR
+  };
+}
+
+
+// arithmetic expressions
+class AExp {
+  pure_virtual int eval(Env &env);
+
+  -> A_lit(int n);
+  -> A_var(string x);
+  -> A_bin(AExp a1, AOp op, AExp a2);
+}
+
+// boolean expressions
+class BExp {
+  pure_virtual bool eval(Env &env);
+
+  -> B_lit(bool b);
+  -> B_pred(AExp a1, BPred op, AExp a2);
+  -> B_not(BExp b);
+  -> B_bin(BExp b1, BOp op, BExp b2);
+}
+
+// statements
+class Stmt {
+  pure_virtual void eval(Env &env);
+
+  -> S_skip();
+  -> S_abort();
+  -> S_print(string x);
+  -> S_assign(string x, AExp a);
+  -> S_seq(Stmt s1, Stmt s2);
+  -> S_if(GCom g);
+  -> S_do(GCom g);
+}
+
+// guarded commands
+class GCom {                       
+  // returns true if it finds an enabled alternative, false o.w.
+  pure_virtual bool eval(Env &env);
+
+  -> G_stmt(BExp b, Stmt s);
+  -> G_seq(GCom g1, GCom g2);
+}

Added: vendor/elsa/current/elkhound/examples/gcom/gcom.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/gcom.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/gcom.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,89 @@
+// gcom.gr
+// parser for guarded command example language
+
+verbatim {
+  #include "str.h"        // stringf
+  #include "ast.h"        // AST declarations
+
+  #include <stdlib.h>     // getenv, atoi, putenv
+  #include <stdio.h>      // printf
+}
+
+// the parser context class is useful in large examples;
+// an empty one will suffice here
+context_class GComContext : public UserActions {
+public:
+  // given a lexer-allocated string, make a 'string', and
+  // deallocate the lexer-created copy
+  static inline string copyAndFree(char *x)
+  {
+    string ret(x);
+    delete x;
+    return ret;
+  }
+};
+
+// pull in the tokens generated from lexer.h
+terminals {
+  include("tokens.tok")
+
+  // declare token sval types
+  token(int) TOK_LITERAL;
+  token(char*) TOK_IDENTIFIER;
+
+  precedence {           
+    // high precedence
+    left  60 "*";
+    left  50 "+" "-";
+    left  40 "!";        // ! has higher precedence than /\ and \/
+    left  30 TOK_AND;    // /\ has higher precedence than \/
+    left  20 TOK_OR;
+    left  10 ";" "#";    // precedence is irrelvant
+    // low precedence
+  }
+}
+
+
+// now the grammar; the first symbol is the start symbol
+nonterm(Stmt*) Start {
+  -> s:Stmt                       { return s; }
+}
+
+
+nonterm(AExp*) AExp {
+  -> n:TOK_LITERAL                { return new A_lit(n); }
+  -> x:TOK_IDENTIFIER             { return new A_var(copyAndFree(x)); }
+  -> a1:AExp "+" a2:AExp          { return new A_bin(a1, AO_PLUS, a2); }
+  -> a1:AExp "-" a2:AExp          { return new A_bin(a1, AO_MINUS, a2); }
+  -> a1:AExp "*" a2:AExp          { return new A_bin(a1, AO_TIMES, a2); }
+  -> "(" a:AExp ")"               { return a; }
+}
+
+
+nonterm(BExp*) BExp {
+  -> "true"                       { return new B_lit(true); }
+  -> "false"                      { return new B_lit(false); }
+  -> a1:AExp "=" a2:AExp          { return new B_pred(a1, BP_EQUAL, a2); }
+  -> a1:AExp "<" a2:AExp          { return new B_pred(a1, BP_LESS, a2); }
+  -> "!" b:BExp                   { return new B_not(b); }
+  -> b1:BExp TOK_AND b2:BExp      { return new B_bin(b1, BO_AND, b2); }
+  -> b1:BExp TOK_OR  b2:BExp      { return new B_bin(b1, BO_OR, b2); }
+  -> "(" b:BExp ")"               { return b; }
+}
+
+
+nonterm(Stmt*) Stmt {
+  -> "skip"                       { return new S_skip; }
+  -> "abort"                      { return new S_abort; }
+  -> "print" x:TOK_IDENTIFIER     { return new S_print(copyAndFree(x)); }
+  -> x:TOK_IDENTIFIER ":=" a:AExp { return new S_assign(copyAndFree(x), a); }
+  -> s1:Stmt ";" s2:Stmt          { return new S_seq(s1, s2); }
+  -> "if" g:GCom "fi"             { return new S_if(g); }
+  -> "do" g:GCom "od"             { return new S_do(g); }
+}
+
+
+nonterm(GCom*) GCom {
+  -> b:BExp "->" s:Stmt           { return new G_stmt(b, s); }
+  -> g1:GCom "#" g2:GCom          { return new G_seq(g1, g2); }
+}

Added: vendor/elsa/current/elkhound/examples/gcom/in1
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2 @@
+x := 5;
+print x

Added: vendor/elsa/current/elkhound/examples/gcom/in2
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+x := 0;
+do x < 10 ->
+  print x;
+  x := x + 1
+od;
+print x

Added: vendor/elsa/current/elkhound/examples/gcom/in3
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/in3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/in3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+x := 152;
+y := 104;
+do !(x = y) ->
+  print x;
+  print y;
+  if x < y -> y := y - x #
+     y < x -> x := x - y fi
+od;
+print x
+
+

Added: vendor/elsa/current/elkhound/examples/gcom/lexer.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/lexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/lexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,209 @@
+// lexer.cc
+// code for lexer.h
+
+#include "lexer.h"       // this module
+
+#include <stdio.h>       // getchar, ungetc
+#include <ctype.h>       // isspace, isalpha, isalnum
+#include <string.h>      // strchr, strdup, strcmp
+#include <stdlib.h>      // abort
+#include <assert.h>      // assert
+
+// simple hand-written lexer; could also be done using (e.g.) flex
+void Lexer::nextToken(LexerInterface *lex)
+{
+  // avoid accidental use of another token's sval
+  lex->sval = (SemanticValue)0;
+
+  int ch = getchar();
+
+  // skip whitespace
+  while (isspace(ch)) {
+    ch = getchar();
+  }
+
+  // end of file?
+  if (ch == EOF) {
+    lex->type = TOK_EOF;
+    return;
+  }
+
+  // simple one-character tokens
+  switch (ch) {
+    case '+': lex->type = TOK_PLUS; return;
+    case '*': lex->type = TOK_TIMES; return;
+    case '(': lex->type = TOK_LPAREN; return;
+    case ')': lex->type = TOK_RPAREN; return;
+
+    case '-':
+      // TOK_MINUS or TOK_ARROW?
+      ch = getchar();
+      if (ch == '>') {
+        lex->type = TOK_ARROW;
+      }
+      else {
+        lex->type = TOK_MINUS;
+        ungetc(ch, stdin);
+      }
+      return;
+
+    case '=': lex->type = TOK_EQUAL; return;
+    case '<': lex->type = TOK_LESS; return;
+    case '!': lex->type = TOK_NOT; return;
+    case ';': lex->type = TOK_SEMI; return;
+    case '#': lex->type = TOK_FATBAR; return;
+
+    case '/':
+      ch = getchar();
+      if (ch != '\\') fail("'/' must be followed by '\\'");
+      lex->type = TOK_AND; 
+      return;
+
+    case '\\':
+      ch = getchar();
+      if (ch != '/') fail("'\\' must be followed by '/'");
+      lex->type = TOK_OR;
+      return;
+
+    case ':':
+      ch = getchar();
+      if (ch != '=') fail("':' must be followed by '='");
+      lex->type = TOK_ASSIGN;
+      return;
+  }
+  
+  // integer literal
+  if (isdigit(ch)) {
+    int value = 0;
+    while (isdigit(ch)) {
+      value = value*10 + ch-'0';
+      ch = getchar();
+    }
+    ungetc(ch, stdin);      // put back the nondigit
+
+    // semantic value is the integer value of the literal
+    lex->sval = (SemanticValue)value;
+
+    lex->type = TOK_LITERAL;
+    return;
+  }
+
+  // identifier or keyword
+  if (isalpha(ch)) {        // must start with letter
+    char buf[80];
+    int i=0;
+    while (isalnum(ch)) {   // but allow digits later on
+      buf[i++] = (char)ch;
+      if (i==80) {
+        fail("identifier is too long\n");
+      }
+      ch = getchar();
+    }
+    buf[i]=0;
+    ungetc(ch, stdin);
+
+    // keyword?  (not a very efficient way to do this ...)
+    if (0==strcmp(buf, "true"))  { lex->type = TOK_TRUE; return; }
+    if (0==strcmp(buf, "false")) { lex->type = TOK_FALSE; return; }
+    if (0==strcmp(buf, "skip"))  { lex->type = TOK_SKIP; return; }
+    if (0==strcmp(buf, "abort")) { lex->type = TOK_ABORT; return; }
+    if (0==strcmp(buf, "print")) { lex->type = TOK_PRINT; return; }
+    if (0==strcmp(buf, "if"))    { lex->type = TOK_IF; return; }
+    if (0==strcmp(buf, "fi"))    { lex->type = TOK_FI; return; }
+    if (0==strcmp(buf, "do"))    { lex->type = TOK_DO; return; }
+    if (0==strcmp(buf, "od"))    { lex->type = TOK_OD; return; }
+
+    // semantic value is a pointer to an allocated string; it
+    // is simply leaked (never deallocated) for this example
+    lex->sval = (SemanticValue)strdup(buf);
+
+    lex->type = TOK_IDENTIFIER;
+    return;
+  }
+
+  fprintf(stderr, "illegal character: %c\n", ch);
+  abort();
+}
+
+void Lexer::fail(char const *msg)
+{
+  fprintf(stderr, "%s\n", msg);
+  abort();
+}
+
+
+string Lexer::tokenDesc() const
+{
+  switch (type) {
+    // for two kinds of tokens, interpret their semantic value
+    case TOK_LITERAL:      return stringf("%d", (int)sval);
+    case TOK_IDENTIFIER:   return stringf("id(%s)", (char*)sval);
+
+    // otherwise, just return the token kind description
+    default:               return tokenKindDesc(type);
+  }
+}
+
+
+string Lexer::tokenKindDesc(int kind) const
+{
+  switch (kind) {
+    case TOK_EOF:          return "EOF";
+    case TOK_LITERAL:      return "lit";
+    case TOK_IDENTIFIER:   return "id";
+    default: {
+      static char const * const map[] = {
+        "+",
+        "-",
+        "*",
+        "(",
+        ")",
+
+        "true",
+        "false",
+        "=",
+        "<",
+        "!",
+        "/\\",
+        "\\/",
+
+        "skip",
+        "abort",
+        "print",
+        ":=",
+        ";",
+        "if",
+        "fi",
+        "do",
+        "od",
+
+        "->",
+        "#"
+      };
+      kind -= TOK_PLUS;
+      assert((unsigned)kind < (sizeof(map)/sizeof(map[0])));
+      return map[kind];
+    }
+  }
+}
+
+
+#ifdef TEST_LEXER
+int main()
+{
+  Lexer lexer;
+  for (;;) {
+    lexer.getTokenFunc()(&lexer);    // first call yields a function pointer
+    
+    // print the returned token
+    string desc = lexer.tokenDesc();
+    printf("%s\n", desc.c_str());
+
+    if (lexer.type == TOK_EOF) {
+      break;
+    }
+  }
+  
+  return 0;
+}
+#endif // TEST_LEXER

Added: vendor/elsa/current/elkhound/examples/gcom/lexer.h
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/lexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/lexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,66 @@
+// lexer.h
+// lexer for the guarded-command example language
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "lexerint.h"      // LexerInterface
+
+// token codes (must agree with the parser)
+enum TokenCode {
+  TOK_EOF         = 0,     // end of file
+  
+  // minimal set of tokens for AExp
+  TOK_LITERAL,             // integer literal
+  TOK_IDENTIFIER,          // identifier like "x"
+  TOK_PLUS,                // "+"
+  TOK_MINUS,               // "-"
+  TOK_TIMES,               // "*"
+  TOK_LPAREN,              // "("
+  TOK_RPAREN,              // ")"
+
+  // for BExp
+  TOK_TRUE,                // "true"
+  TOK_FALSE,               // "false"
+  TOK_EQUAL,               // "="
+  TOK_LESS,                // "<"
+  TOK_NOT,                 // "!"
+  TOK_AND,                 // elkhound doesn't like quoted backslashes
+  TOK_OR,
+
+  // for Stmt
+  TOK_SKIP,                // "skip"
+  TOK_ABORT,               // "abort"
+  TOK_PRINT,               // "print"
+  TOK_ASSIGN,              // ":="
+  TOK_SEMI,                // ";"
+  TOK_IF,                  // "if"
+  TOK_FI,                  // "fi"
+  TOK_DO,                  // "do"
+  TOK_OD,                  // "od"
+  
+  // for GCom
+  TOK_ARROW,               // "->"
+  TOK_FATBAR,              // "#"
+};
+
+
+// read characters from stdin, yield tokens for the parser
+class Lexer : public LexerInterface {
+private:
+  static void fail(char const *msg);
+
+public:
+  // function that retrieves the next token from
+  // the input stream
+  static void nextToken(LexerInterface *lex);
+  virtual NextTokenFunc getTokenFunc() const
+    { return &Lexer::nextToken; }
+
+  // debugging assistance functions
+  string tokenDesc() const;
+  string tokenKindDesc(int kind) const;
+};
+
+
+#endif // LEXER_H

Added: vendor/elsa/current/elkhound/examples/gcom/parser.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom/parser.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom/parser.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,80 @@
+// parser.cc
+// driver program for guarded command example
+
+#include "lexer.h"     // Lexer
+#include "gcom.h"      // GCom
+#include "glr.h"       // GLR
+#include "ptreenode.h" // PTreeNode
+#include "ptreeact.h"  // ParseTreeLexer, ParseTreeActions
+#include "ast.h"       // Stmt, etc.
+#include "eval.h"      // Env
+
+#include <string.h>    // strcmp
+
+
+int main(int argc, char *argv[])
+{
+  // use "-tree" command-line arg to print the tree
+  bool printTree = argc==2 && 0==strcmp(argv[1], "-tree");
+  bool printAST  = argc==2 && 0==strcmp(argv[1], "-ast");
+
+  // create and initialize the lexer
+  Lexer lexer;
+  lexer.nextToken(&lexer);
+
+  // create the parser context object
+  GComContext gcom;
+
+  if (printTree) {
+    // wrap the lexer and actions with versions that make a parse tree
+    ParseTreeLexer ptlexer(&lexer, &gcom);
+    ParseTreeActions ptact(&gcom, gcom.makeTables());
+
+    // initialize the parser
+    GLR glr(&ptact, ptact.getTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(ptlexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print the tree
+    PTreeNode *ptn = (PTreeNode*)result;
+    ptn->printTree(cout, PTreeNode::PF_EXPAND);
+  }
+
+  else {
+    // initialize the parser
+    GLR glr(&gcom, gcom.makeTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(lexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // result is an AST node
+    Stmt *top = (Stmt*)result;
+    
+    if (printAST) {
+      top->debugPrint(cout, 0);
+    }
+
+    // evaluate
+    printf("evaluating...\n");
+    Env env;
+    top->eval(env);
+    printf("program terminated normally\n");
+               
+    // recursively deallocate the tree
+    delete top;
+  }
+
+  return 0;
+}
+
+
+

Added: vendor/elsa/current/elkhound/examples/gcom1/gcom.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom1/gcom.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom1/gcom.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// gcom.gr
+// parser for guarded command example language
+
+// the parser context class is useful in large examples;
+// an empty one will suffice here
+context_class GCom : public UserActions {
+public:
+  // empty for now
+};
+
+// pull in the tokens generated from lexer.h
+terminals {
+  include("tokens.tok")
+}
+
+// now the grammar
+
+nonterm AExp {
+  -> TOK_LITERAL;
+  -> TOK_IDENTIFIER;
+  -> AExp "+" AExp;
+  -> AExp "-" AExp;
+  -> AExp "*" AExp;
+  -> "(" AExp ")";
+}
+

Added: vendor/elsa/current/elkhound/examples/gcom1/lexer.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom1/lexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom1/lexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,125 @@
+// lexer.cc
+// code for lexer.h
+
+#include "lexer.h"       // this module
+
+#include <stdio.h>       // getchar, ungetc
+#include <ctype.h>       // isspace
+#include <string.h>      // strchr, strdup
+#include <stdlib.h>      // abort
+
+// simple hand-written lexer; could also be done using (e.g.) flex
+void Lexer::nextToken(LexerInterface *lex)
+{
+  int ch = getchar();
+
+  // skip whitespace
+  while (isspace(ch)) {
+    ch = getchar();
+  }
+
+  // end of file?
+  if (ch == EOF) {
+    lex->type = TOK_EOF;
+    return;
+  }
+
+  // simple one-character tokens
+  switch (ch) {
+    case '+': lex->type = TOK_PLUS; return;
+    case '-': lex->type = TOK_PLUS; return;
+    case '*': lex->type = TOK_TIMES; return;
+    case '(': lex->type = TOK_LPAREN; return;
+    case ')': lex->type = TOK_RPAREN; return;
+  }
+  
+  // integer literal
+  if (isdigit(ch)) {
+    int value = 0;
+    while (isdigit(ch)) {
+      value = value*10 + ch-'0';
+      ch = getchar();
+    }
+    ungetc(ch, stdin);      // put back the nondigit
+
+    // semantic value is the integer value of the literal
+    lex->sval = (SemanticValue)value;
+
+    lex->type = TOK_LITERAL;
+    return;
+  }
+
+  // identifier
+  if (isalpha(ch)) {        // must start with letter
+    char buf[80];
+    int i=0;
+    while (isalnum(ch)) {   // but allow digits later on
+      buf[i++] = (char)ch;
+      if (i==80) {
+        fprintf(stderr, "identifier is too long\n");
+        abort();
+      }
+      ch = getchar();
+    }
+    buf[i]=0;
+    ungetc(ch, stdin);
+
+    // semantic value is a pointer to an allocated string; it
+    // is simply leaked (never deallocated) for this example
+    lex->sval = (SemanticValue)strdup(buf);
+
+    lex->type = TOK_IDENTIFIER;
+    return;
+  }
+
+  fprintf(stderr, "illegal character: %c\n", ch);
+  abort();
+}
+
+
+string Lexer::tokenDesc() const
+{
+  switch (type) {
+    // for two kinds of tokens, interpret their semantic value
+    case TOK_LITERAL:      return stringf("%d", (int)sval);
+    case TOK_IDENTIFIER:   return string((char*)sval);
+    
+    // otherwise, just return the token kind description
+    default:               return tokenKindDesc(type);
+  }
+}
+
+
+string Lexer::tokenKindDesc(int kind) const
+{
+  switch (kind) {
+    case TOK_EOF:          return "EOF";
+    case TOK_LITERAL:      return "lit";
+    case TOK_IDENTIFIER:   return "id";
+    default: {
+      static char const map[] = "+-*()";
+      return substring(&map[kind-TOK_PLUS], 1);
+    }
+  }
+}
+
+
+#ifdef TEST_LEXER
+int main()
+{
+  Lexer lexer;
+  for (;;) {
+    lexer.getTokenFunc()(&lexer);    // first call yields a function pointer
+    
+    // print the returned token
+    string desc = lexer.tokenDesc();
+    printf("%s\n", desc.c_str());
+
+    if (lexer.type == TOK_EOF) {
+      break;
+    }
+  }
+  
+  return 0;
+}
+#endif // TEST_LEXER

Added: vendor/elsa/current/elkhound/examples/gcom1/lexer.h
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom1/lexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom1/lexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// lexer.h
+// lexer for the guarded-command example language
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "lexerint.h"      // LexerInterface
+
+// token codes (must agree with the parser)
+enum TokenCode {
+  TOK_EOF         = 0,     // end of file
+  TOK_LITERAL,             // integer literal
+  TOK_IDENTIFIER,          // identifier like "x"
+  TOK_PLUS,                // "+"
+  TOK_MINUS,               // "-"
+  TOK_TIMES,               // "*"
+  TOK_LPAREN,              // "("
+  TOK_RPAREN,              // ")"
+};
+
+
+// read characters from stdin, yield tokens for the parser
+class Lexer : public LexerInterface {
+public:
+  // function that retrieves the next token from
+  // the input stream
+  static void nextToken(LexerInterface *lex);
+  virtual NextTokenFunc getTokenFunc() const
+    { return &Lexer::nextToken; }
+
+  // debugging assistance functions
+  string tokenDesc() const;
+  string tokenKindDesc(int kind) const;
+};
+
+
+#endif // LEXER_H

Added: vendor/elsa/current/elkhound/examples/gcom1/parser.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom1/parser.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom1/parser.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// parser.cc
+// driver program for guarded command example
+
+#include "lexer.h"     // Lexer
+#include "gcom.h"      // GCom
+#include "glr.h"       // GLR
+
+
+int main()
+{
+  // create and initialize the lexer
+  Lexer lexer;
+  lexer.nextToken(&lexer);
+
+  // create the parser context object
+  GCom gcom;
+
+  // initialize the parser
+  GLR glr(&gcom, gcom.makeTables());
+
+  // parse the input
+  SemanticValue result;
+  if (!glr.glrParse(lexer, result)) {
+    printf("parse error\n");
+    return 2;
+  }
+  
+  // print result
+  printf("result: %d\n", (int)result);
+  
+  return 0;
+}
+
+
+

Added: vendor/elsa/current/elkhound/examples/gcom2/parser.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom2/parser.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom2/parser.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,64 @@
+// parser.cc
+// driver program for guarded command example
+
+#include "lexer.h"     // Lexer
+#include "gcom.h"      // GCom
+#include "glr.h"       // GLR
+#include "ptreenode.h" // PTreeNode
+#include "ptreeact.h"  // ParseTreeLexer, ParseTreeActions
+
+#include <string.h>    // strcmp
+
+
+int main(int argc, char *argv[])
+{
+  // use "-tree" command-line arg to print the tree
+  bool printTree = argc==2 && 0==strcmp(argv[1], "-tree");
+
+  // create and initialize the lexer
+  Lexer lexer;
+  lexer.nextToken(&lexer);
+
+  // create the parser context object
+  GCom gcom;
+
+  if (printTree) {
+    // wrap the lexer and actions with versions that make a parse tree
+    ParseTreeLexer ptlexer(&lexer, &gcom);
+    ParseTreeActions ptact(&gcom, gcom.makeTables());
+
+    // initialize the parser
+    GLR glr(&ptact, ptact.getTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(ptlexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print the tree
+    PTreeNode *ptn = (PTreeNode*)result;
+    ptn->printTree(cout, PTreeNode::PF_EXPAND);
+  }
+  
+  else {
+    // initialize the parser
+    GLR glr(&gcom, gcom.makeTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(lexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print result
+    printf("result: %d\n", (int)result);
+  }
+
+  return 0;
+}
+
+
+

Added: vendor/elsa/current/elkhound/examples/gcom3/gcom.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom3/gcom.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom3/gcom.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// gcom.gr
+// parser for guarded command example language
+
+// the parser context class is useful in large examples;
+// an empty one will suffice here
+context_class GCom : public UserActions {
+public:
+  // empty for now
+};
+
+// pull in the tokens generated from lexer.h
+terminals {
+  include("tokens.tok")
+
+  precedence {
+    left  20 "*";        // high precedence, left associative
+    left  10 "+" "-";    // low precedence, left associative
+  }
+}
+
+// now the grammar
+
+nonterm AExp {
+  -> TOK_LITERAL;
+  -> TOK_IDENTIFIER;
+  -> AExp "+" AExp;
+  -> AExp "-" AExp;
+  -> AExp "*" AExp;
+  -> "(" AExp ")";
+}
+

Added: vendor/elsa/current/elkhound/examples/gcom4/gcom.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom4/gcom.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom4/gcom.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// gcom.gr
+// parser for guarded command example language
+
+verbatim {
+  #include <stdlib.h>     // getenv, atoi
+}
+
+// the parser context class is useful in large examples;
+// an empty one will suffice here
+context_class GCom : public UserActions {
+public:
+  // empty for now
+};
+
+// pull in the tokens generated from lexer.h
+terminals {
+  include("tokens.tok")
+
+  // declare token sval types
+  token(int) TOK_LITERAL;
+  token(char*) TOK_IDENTIFIER;
+
+  precedence {
+    left  20 "*";        // high precedence, left associative
+    left  10 "+" "-";    // low precedence, left associative
+  }
+}
+
+// now the grammar
+
+nonterm(int) AExp {
+  -> n:TOK_LITERAL         { return n; }
+  -> a1:AExp "+" a2:AExp   { return a1 + a2; }
+  -> a1:AExp "-" a2:AExp   { return a1 - a2; }
+  -> a1:AExp "*" a2:AExp   { return a1 * a2; }
+  -> "(" a:AExp ")"        { return a; }
+  
+  // interpret identifiers using environment variables; it's
+  // a bit of a hack, and we'll do something better later
+  -> x:TOK_IDENTIFIER {
+       char const *envp = getenv(x);
+       if (envp) {
+         return atoi(envp);
+       }
+       else {
+         return 0;      // not defined, call it 0
+       }
+     }
+}
+

Added: vendor/elsa/current/elkhound/examples/gcom4/lexer.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom4/lexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom4/lexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,125 @@
+// lexer.cc
+// code for lexer.h
+
+#include "lexer.h"       // this module
+
+#include <stdio.h>       // getchar, ungetc
+#include <ctype.h>       // isspace
+#include <string.h>      // strchr, strdup
+#include <stdlib.h>      // abort
+
+// simple hand-written lexer; could also be done using (e.g.) flex
+void Lexer::nextToken(LexerInterface *lex)
+{
+  int ch = getchar();
+
+  // skip whitespace
+  while (isspace(ch)) {
+    ch = getchar();
+  }
+
+  // end of file?
+  if (ch == EOF) {
+    lex->type = TOK_EOF;
+    return;
+  }
+
+  // simple one-character tokens
+  switch (ch) {
+    case '+': lex->type = TOK_PLUS; return;
+    case '-': lex->type = TOK_PLUS; return;
+    case '*': lex->type = TOK_TIMES; return;
+    case '(': lex->type = TOK_LPAREN; return;
+    case ')': lex->type = TOK_RPAREN; return;
+  }
+  
+  // integer literal
+  if (isdigit(ch)) {
+    int value = 0;
+    while (isdigit(ch)) {
+      value = value*10 + ch-'0';
+      ch = getchar();
+    }
+    ungetc(ch, stdin);      // put back the nondigit
+
+    // semantic value is the integer value of the literal
+    lex->sval = (SemanticValue)value;
+
+    lex->type = TOK_LITERAL;
+    return;
+  }
+
+  // identifier
+  if (isalpha(ch)) {        // must start with letter
+    char buf[80];
+    int i=0;
+    while (isalnum(ch)) {   // but allow digits later on
+      buf[i++] = (char)ch;
+      if (i==80) {
+        fprintf(stderr, "identifier is too long\n");
+        abort();
+      }
+      ch = getchar();
+    }
+    buf[i]=0;
+    ungetc(ch, stdin);
+
+    // semantic value is a pointer to an allocated string; it
+    // is simply leaked (never deallocated) for this example
+    lex->sval = (SemanticValue)strdup(buf);
+
+    lex->type = TOK_IDENTIFIER;
+    return;
+  }
+
+  fprintf(stderr, "illegal character: %c\n", ch);
+  abort();
+}
+
+
+string Lexer::tokenDesc() const
+{
+  switch (type) {
+    // for two kinds of tokens, interpret their semantic value
+    case TOK_LITERAL:      return stringf("%d", (int)sval);
+    case TOK_IDENTIFIER:   return string((char*)sval);
+    
+    // otherwise, just return the token kind description
+    default:               return tokenKindDesc(type);
+  }
+}
+
+
+string Lexer::tokenKindDesc(int kind) const
+{
+  switch (kind) {
+    case TOK_EOF:          return "EOF";
+    case TOK_LITERAL:      return "lit";
+    case TOK_IDENTIFIER:   return "id";
+    default: {
+      static char const map[] = "+-*()";
+      return substring(&map[kind-TOK_PLUS], 1);
+    }
+  }
+}
+
+
+#ifdef TEST_LEXER
+int main()
+{
+  Lexer lexer;
+  for (;;) {
+    lexer.getTokenFunc()(&lexer);    // first call yields a function pointer
+    
+    // print the returned token
+    string desc = lexer.tokenDesc();
+    printf("%s\n", desc.c_str());
+
+    if (lexer.type == TOK_EOF) {
+      break;
+    }
+  }
+  
+  return 0;
+}
+#endif // TEST_LEXER

Added: vendor/elsa/current/elkhound/examples/gcom4/lexer.h
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom4/lexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom4/lexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// lexer.h
+// lexer for the guarded-command example language
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "lexerint.h"      // LexerInterface
+
+// token codes (must agree with the parser)
+enum TokenCode {
+  TOK_EOF         = 0,     // end of file
+  TOK_LITERAL,             // integer literal
+  TOK_IDENTIFIER,          // identifier like "x"
+  TOK_PLUS,                // "+"
+  TOK_MINUS,               // "-"
+  TOK_TIMES,               // "*"
+  TOK_LPAREN,              // "("
+  TOK_RPAREN,              // ")"
+};
+
+
+// read characters from stdin, yield tokens for the parser
+class Lexer : public LexerInterface {
+public:
+  // function that retrieves the next token from
+  // the input stream
+  static void nextToken(LexerInterface *lex);
+  virtual NextTokenFunc getTokenFunc() const
+    { return &Lexer::nextToken; }
+
+  // debugging assistance functions
+  string tokenDesc() const;
+  string tokenKindDesc(int kind) const;
+};
+
+
+#endif // LEXER_H

Added: vendor/elsa/current/elkhound/examples/gcom4/parser.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom4/parser.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom4/parser.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,64 @@
+// parser.cc
+// driver program for guarded command example
+
+#include "lexer.h"     // Lexer
+#include "gcom.h"      // GCom
+#include "glr.h"       // GLR
+#include "ptreenode.h" // PTreeNode
+#include "ptreeact.h"  // ParseTreeLexer, ParseTreeActions
+
+#include <string.h>    // strcmp
+
+
+int main(int argc, char *argv[])
+{
+  // use "-tree" command-line arg to print the tree
+  bool printTree = argc==2 && 0==strcmp(argv[1], "-tree");
+
+  // create and initialize the lexer
+  Lexer lexer;
+  lexer.nextToken(&lexer);
+
+  // create the parser context object
+  GCom gcom;
+
+  if (printTree) {
+    // wrap the lexer and actions with versions that make a parse tree
+    ParseTreeLexer ptlexer(&lexer, &gcom);
+    ParseTreeActions ptact(&gcom, gcom.makeTables());
+
+    // initialize the parser
+    GLR glr(&ptact, ptact.getTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(ptlexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print the tree
+    PTreeNode *ptn = (PTreeNode*)result;
+    ptn->printTree(cout, PTreeNode::PF_EXPAND);
+  }
+  
+  else {
+    // initialize the parser
+    GLR glr(&gcom, gcom.makeTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(lexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print result
+    printf("result: %d\n", (int)result);
+  }
+
+  return 0;
+}
+
+
+

Added: vendor/elsa/current/elkhound/examples/gcom5/gcom.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom5/gcom.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom5/gcom.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,133 @@
+// gcom.gr
+// parser for guarded command example language
+
+verbatim {
+  #include "str.h"        // stringf
+  #include <stdlib.h>     // getenv, atoi, putenv
+  #include <stdio.h>      // printf
+  #include <string.h>     // strdup
+}
+
+// the parser context class is useful in large examples;
+// an empty one will suffice here
+context_class GCom : public UserActions {
+public:
+  // empty for now
+};
+
+// pull in the tokens generated from lexer.h
+terminals {
+  include("tokens.tok")
+
+  // declare token sval types
+  token(int) TOK_LITERAL;
+  token(char*) TOK_IDENTIFIER;
+
+  precedence {           
+    // high precedence
+    left  60 "*";
+    left  50 "+" "-";
+    left  40 "!";        // ! has higher precedence than /\ and \/
+    left  30 TOK_AND;    // /\ has higher precedence than \/
+    left  20 TOK_OR;
+    left  10 ";" "#";    // precedence is irrelvant
+    // low precedence
+  }
+}
+
+
+// now the grammar; the first symbol is the start symbol
+nonterm Start {
+  -> Stmt;
+}
+
+
+nonterm(int) AExp {
+  -> n:TOK_LITERAL         { return n; }
+  -> a1:AExp "+" a2:AExp   { return a1 + a2; }
+  -> a1:AExp "-" a2:AExp   { return a1 - a2; }
+  -> a1:AExp "*" a2:AExp   { return a1 * a2; }
+  -> "(" a:AExp ")"        { return a; }
+
+  // interpret identifiers using environment variables; it's
+  // a bit of a hack, and we'll do something better later
+  -> x:TOK_IDENTIFIER {
+       char const *envp = getenv(x);
+       if (envp) {
+         return atoi(envp);
+       }
+       else {
+         return 0;      // not defined, call it 0
+       }
+     }
+}
+        
+
+nonterm(bool) BExp {
+  -> "true"                     { return true; }
+  -> "false"                    { return false; }
+  -> a1:AExp "=" a2:AExp        { return a1 == a2; }
+  -> a1:AExp "<" a2:AExp        { return a1 < a2; }
+  -> "!" b:BExp                 { return !b; }
+  -> b1:BExp TOK_AND b2:BExp    { return b1 && b2; }
+  -> b1:BExp TOK_OR  b2:BExp    { return b1 || b2; }
+  -> "(" b:BExp ")"             { return b; }
+}
+
+           
+nonterm Stmt {
+  -> "skip" {
+       // no-op
+     }
+
+  -> "abort" {
+       printf("abort command executed\n");
+       exit(0);
+     }
+
+  -> "print" x:TOK_IDENTIFIER {
+       char const *envp = getenv(x);
+       printf("%s is %d\n", x, envp? atoi(envp) : 0);
+     }
+
+  -> x:TOK_IDENTIFIER ":=" a:AExp {
+       // like above, use the environment variables
+       putenv(strdup(stringf("%s=%d", x, a).c_str()));
+     }
+
+  -> Stmt ";" Stmt {
+       // sequencing is automatic
+     }
+
+  -> "if" g:GCom "fi" {
+       if (!g) {
+         printf("'if' command had no enabled alternatives; aborting\n");
+         exit(0);
+       }
+     }
+
+  -> "do" GCom "od" {
+       // There's no way to get the parser to loop; that's not its job.
+       // For now, we'll just treat it like an 'if' that doesn't mind
+       // when no alternative is enabled.  Later, we'll build a tree
+       // and do this right.
+     }
+}
+
+                  
+// a guarded command returns true if it found an enabled guard, and
+// false otherwise
+nonterm(bool) GCom {
+  -> b:BExp "->" Stmt {
+       // Like for 'do', there is no way to tell the parser not to
+       // parse part of its input, so the statement will be executed
+       // regardless of the value of 'b'.  Again, this will be fixed
+       // in a later version of this example.  For now, we can at
+       // least indicate whether the guard succeeded.
+       return b;
+     }
+     
+  -> g1:GCom "#" g2:GCom {
+       return g1 || g2;
+     }
+}

Added: vendor/elsa/current/elkhound/examples/gcom5/lexer.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom5/lexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom5/lexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,209 @@
+// lexer.cc
+// code for lexer.h
+
+#include "lexer.h"       // this module
+
+#include <stdio.h>       // getchar, ungetc
+#include <ctype.h>       // isspace, isalpha, isalnum
+#include <string.h>      // strchr, strdup, strcmp
+#include <stdlib.h>      // abort
+#include <assert.h>      // assert
+
+// simple hand-written lexer; could also be done using (e.g.) flex
+void Lexer::nextToken(LexerInterface *lex)
+{
+  // avoid accidental use of another token's sval
+  lex->sval = (SemanticValue)0;
+
+  int ch = getchar();
+
+  // skip whitespace
+  while (isspace(ch)) {
+    ch = getchar();
+  }
+
+  // end of file?
+  if (ch == EOF) {
+    lex->type = TOK_EOF;
+    return;
+  }
+
+  // simple one-character tokens
+  switch (ch) {
+    case '+': lex->type = TOK_PLUS; return;
+    case '*': lex->type = TOK_TIMES; return;
+    case '(': lex->type = TOK_LPAREN; return;
+    case ')': lex->type = TOK_RPAREN; return;
+
+    case '-':
+      // TOK_MINUS or TOK_ARROW?
+      ch = getchar();
+      if (ch == '>') {
+        lex->type = TOK_ARROW;
+      }
+      else {
+        lex->type = TOK_MINUS;
+        ungetc(ch, stdin);
+      }
+      return;
+
+    case '=': lex->type = TOK_EQUAL; return;
+    case '<': lex->type = TOK_LESS; return;
+    case '!': lex->type = TOK_NOT; return;
+    case ';': lex->type = TOK_SEMI; return;
+    case '#': lex->type = TOK_FATBAR; return;
+
+    case '/':
+      ch = getchar();
+      if (ch != '\\') fail("'/' must be followed by '\\'");
+      lex->type = TOK_AND; 
+      return;
+
+    case '\\':
+      ch = getchar();
+      if (ch != '/') fail("'\\' must be followed by '/'");
+      lex->type = TOK_OR;
+      return;
+
+    case ':':
+      ch = getchar();
+      if (ch != '=') fail("':' must be followed by '='");
+      lex->type = TOK_ASSIGN;
+      return;
+  }
+  
+  // integer literal
+  if (isdigit(ch)) {
+    int value = 0;
+    while (isdigit(ch)) {
+      value = value*10 + ch-'0';
+      ch = getchar();
+    }
+    ungetc(ch, stdin);      // put back the nondigit
+
+    // semantic value is the integer value of the literal
+    lex->sval = (SemanticValue)value;
+
+    lex->type = TOK_LITERAL;
+    return;
+  }
+
+  // identifier or keyword
+  if (isalpha(ch)) {        // must start with letter
+    char buf[80];
+    int i=0;
+    while (isalnum(ch)) {   // but allow digits later on
+      buf[i++] = (char)ch;
+      if (i==80) {
+        fail("identifier is too long\n");
+      }
+      ch = getchar();
+    }
+    buf[i]=0;
+    ungetc(ch, stdin);
+
+    // keyword?  (not a very efficient way to do this ...)
+    if (0==strcmp(buf, "true"))  { lex->type = TOK_TRUE; return; }
+    if (0==strcmp(buf, "false")) { lex->type = TOK_FALSE; return; }
+    if (0==strcmp(buf, "skip"))  { lex->type = TOK_SKIP; return; }
+    if (0==strcmp(buf, "abort")) { lex->type = TOK_ABORT; return; }
+    if (0==strcmp(buf, "print")) { lex->type = TOK_PRINT; return; }
+    if (0==strcmp(buf, "if"))    { lex->type = TOK_IF; return; }
+    if (0==strcmp(buf, "fi"))    { lex->type = TOK_FI; return; }
+    if (0==strcmp(buf, "do"))    { lex->type = TOK_DO; return; }
+    if (0==strcmp(buf, "od"))    { lex->type = TOK_OD; return; }
+
+    // semantic value is a pointer to an allocated string; it
+    // is simply leaked (never deallocated) for this example
+    lex->sval = (SemanticValue)strdup(buf);
+
+    lex->type = TOK_IDENTIFIER;
+    return;
+  }
+
+  fprintf(stderr, "illegal character: %c\n", ch);
+  abort();
+}
+
+void Lexer::fail(char const *msg)
+{
+  fprintf(stderr, "%s\n", msg);
+  abort();
+}
+
+
+string Lexer::tokenDesc() const
+{
+  switch (type) {
+    // for two kinds of tokens, interpret their semantic value
+    case TOK_LITERAL:      return stringf("%d", (int)sval);
+    case TOK_IDENTIFIER:   return stringf("id(%s)", (char*)sval);
+
+    // otherwise, just return the token kind description
+    default:               return tokenKindDesc(type);
+  }
+}
+
+
+string Lexer::tokenKindDesc(int kind) const
+{
+  switch (kind) {
+    case TOK_EOF:          return "EOF";
+    case TOK_LITERAL:      return "lit";
+    case TOK_IDENTIFIER:   return "id";
+    default: {
+      static char const * const map[] = {
+        "+",
+        "-",
+        "*",
+        "(",
+        ")",
+
+        "true",
+        "false",
+        "=",
+        "<",
+        "!",
+        "/\\",
+        "\\/",
+
+        "skip",
+        "abort",
+        "print",
+        ":=",
+        ";",
+        "if",
+        "fi",
+        "do",
+        "od",
+
+        "->",
+        "#"
+      };
+      kind -= TOK_PLUS;
+      assert((unsigned)kind < (sizeof(map)/sizeof(map[0])));
+      return map[kind];
+    }
+  }
+}
+
+
+#ifdef TEST_LEXER
+int main()
+{
+  Lexer lexer;
+  for (;;) {
+    lexer.getTokenFunc()(&lexer);    // first call yields a function pointer
+    
+    // print the returned token
+    string desc = lexer.tokenDesc();
+    printf("%s\n", desc.c_str());
+
+    if (lexer.type == TOK_EOF) {
+      break;
+    }
+  }
+  
+  return 0;
+}
+#endif // TEST_LEXER

Added: vendor/elsa/current/elkhound/examples/gcom5/lexer.h
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom5/lexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom5/lexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,66 @@
+// lexer.h
+// lexer for the guarded-command example language
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "lexerint.h"      // LexerInterface
+
+// token codes (must agree with the parser)
+enum TokenCode {
+  TOK_EOF         = 0,     // end of file
+  
+  // minimal set of tokens for AExp
+  TOK_LITERAL,             // integer literal
+  TOK_IDENTIFIER,          // identifier like "x"
+  TOK_PLUS,                // "+"
+  TOK_MINUS,               // "-"
+  TOK_TIMES,               // "*"
+  TOK_LPAREN,              // "("
+  TOK_RPAREN,              // ")"
+
+  // for BExp
+  TOK_TRUE,                // "true"
+  TOK_FALSE,               // "false"
+  TOK_EQUAL,               // "="
+  TOK_LESS,                // "<"
+  TOK_NOT,                 // "!"
+  TOK_AND,                 // elkhound doesn't like quoted backslashes
+  TOK_OR,
+
+  // for Stmt
+  TOK_SKIP,                // "skip"
+  TOK_ABORT,               // "abort"
+  TOK_PRINT,               // "print"
+  TOK_ASSIGN,              // ":="
+  TOK_SEMI,                // ";"
+  TOK_IF,                  // "if"
+  TOK_FI,                  // "fi"
+  TOK_DO,                  // "do"
+  TOK_OD,                  // "od"
+  
+  // for GCom
+  TOK_ARROW,               // "->"
+  TOK_FATBAR,              // "#"
+};
+
+
+// read characters from stdin, yield tokens for the parser
+class Lexer : public LexerInterface {
+private:
+  static void fail(char const *msg);
+
+public:
+  // function that retrieves the next token from
+  // the input stream
+  static void nextToken(LexerInterface *lex);
+  virtual NextTokenFunc getTokenFunc() const
+    { return &Lexer::nextToken; }
+
+  // debugging assistance functions
+  string tokenDesc() const;
+  string tokenKindDesc(int kind) const;
+};
+
+
+#endif // LEXER_H

Added: vendor/elsa/current/elkhound/examples/gcom5/parser.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom5/parser.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom5/parser.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,64 @@
+// parser.cc
+// driver program for guarded command example
+
+#include "lexer.h"     // Lexer
+#include "gcom.h"      // GCom
+#include "glr.h"       // GLR
+#include "ptreenode.h" // PTreeNode
+#include "ptreeact.h"  // ParseTreeLexer, ParseTreeActions
+
+#include <string.h>    // strcmp
+
+
+int main(int argc, char *argv[])
+{
+  // use "-tree" command-line arg to print the tree
+  bool printTree = argc==2 && 0==strcmp(argv[1], "-tree");
+
+  // create and initialize the lexer
+  Lexer lexer;
+  lexer.nextToken(&lexer);
+
+  // create the parser context object
+  GCom gcom;
+
+  if (printTree) {
+    // wrap the lexer and actions with versions that make a parse tree
+    ParseTreeLexer ptlexer(&lexer, &gcom);
+    ParseTreeActions ptact(&gcom, gcom.makeTables());
+
+    // initialize the parser
+    GLR glr(&ptact, ptact.getTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(ptlexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print the tree
+    PTreeNode *ptn = (PTreeNode*)result;
+    ptn->printTree(cout, PTreeNode::PF_EXPAND);
+  }
+  
+  else {
+    // initialize the parser
+    GLR glr(&gcom, gcom.makeTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(lexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print result
+    printf("result: %d\n", (int)result);
+  }
+
+  return 0;
+}
+
+
+

Added: vendor/elsa/current/elkhound/examples/gcom7/eval.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom7/eval.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom7/eval.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,178 @@
+// eval.cc
+// implementation of the 'eval' methods declared in gcom.ast
+
+#include "eval.h"        // this module
+#include "ast.h"         // AST declarations
+
+#include <stdlib.h>      // exit
+#include <assert.h>      // assert
+#include <stdio.h>       // printf
+
+
+// ------------------- Binding -----------------
+Binding::~Binding()
+{}
+
+
+// --------------------- Env -------------------
+static char const *bindToName(Binding *b)
+{
+  return b->name.c_str();
+}
+
+Env::Env()
+  : map(bindToName)
+{}
+
+Env::~Env()
+{}
+
+
+int Env::get(char const *x)
+{
+  Binding *b = map.get(x);
+  if (!b) {
+    return 0;     // unset variables default to 0 value
+  }
+  else {
+    return b->value;
+  }
+}
+
+void Env::set(char const *x, int val)
+{
+  Binding *b = map.get(x);
+  if (!b) {
+    // add new binding
+    map.add(x, new Binding(x, val));
+  }
+  else {
+    b->value = val;
+  }
+}
+
+
+// -------------------- AExp -------------------
+int A_lit::eval(Env &env)
+{
+  return n;
+}
+
+int A_var::eval(Env &env)
+{
+  return env.get(x.c_str());
+}
+
+int A_bin::eval(Env &env)
+{
+  switch (op) {
+    default:       assert(!"bad code");
+    case AO_PLUS:  return a1->eval(env) + a2->eval(env);
+    case AO_MINUS: return a1->eval(env) - a2->eval(env);
+    case AO_TIMES: return a1->eval(env) * a2->eval(env);
+  }
+}
+
+int A_group::eval(Env &env)
+{
+  return a->eval(env);
+}
+
+
+// -------------------- BExp -------------------
+bool B_lit::eval(Env &env)
+{
+  return b;
+}
+
+bool B_pred::eval(Env &env)
+{
+  switch (op) {
+    default:       assert(!"bad code");
+    case BP_EQUAL: return a1->eval(env) == a2->eval(env);
+    case BP_LESS:  return a1->eval(env) < a2->eval(env);
+  }
+}
+
+bool B_not::eval(Env &env)
+{
+  return !b->eval(env);
+}
+
+bool B_bin::eval(Env &env)
+{
+  switch (op) {
+    default:       assert(!"bad code");
+    case BO_AND: return b1->eval(env) && b2->eval(env);
+    case BO_OR:  return b1->eval(env) && b2->eval(env);
+  }
+}
+
+
+// -------------------- Stmt -------------------
+void S_skip::eval(Env &env)
+{}
+
+void S_abort::eval(Env &env)
+{
+  printf("abort command executed\n");
+  exit(0);
+}
+
+void S_print::eval(Env &env)
+{
+  printf("%s is %d\n", x.c_str(), env.get(x.c_str()));
+}
+
+void S_assign::eval(Env &env)
+{
+  env.set(x.c_str(), a->eval(env));
+}
+
+void S_seq::eval(Env &env)
+{
+  s1->eval(env);
+  s2->eval(env);
+}
+
+void S_if::eval(Env &env)
+{
+  if (!g->eval(env)) {
+    printf("'if' command had no enabled alternatives; aborting\n");
+    exit(0);
+  }
+}
+
+void S_do::eval(Env &env)
+{
+  while (g->eval(env))
+    {}
+}
+
+
+// -------------------- GCom -------------------
+bool G_stmt::eval(Env &env)
+{ 
+  if (b->eval(env)) {
+    s->eval(env);
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+bool G_seq::eval(Env &env)
+{
+  // The usual semantics for guarded commands say that if both guards
+  // are true, then we can execute either one.  Here, I'm going to
+  // always execute the *first* one with an enabled guard; that
+  // behavior is allowed, but not required.  I leave it as an exercise
+  // to modify this code so that the executions it models will cover a
+  // larger fraction of the state space reachable under the
+  // traditional semantics.
+  
+  if (g1->eval(env)) { return true; }
+  if (g2->eval(env)) { return true; }
+  return false;
+}

Added: vendor/elsa/current/elkhound/examples/gcom7/eval.h
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom7/eval.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom7/eval.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// eval.h
+// evaluation environment for gcom
+
+#ifndef EVAL_H
+#define EVAL_H
+
+#include "strhash.h"      // TStringHash
+#include "str.h"          // string
+
+class Binding {
+public:
+  string name;
+  int value;
+  
+public:
+  Binding(char const *n, int v)
+    : name(n),
+      value(v)
+  {}
+  ~Binding();
+};
+
+class Env {
+private:
+  // map: name -> value
+  TStringHash<Binding> map;
+
+public:
+  Env();
+  ~Env();
+
+  int get(char const *x);
+  void set(char const *x, int val);
+};
+
+#endif // ENV_H

Added: vendor/elsa/current/elkhound/examples/gcom7/gcom.ast
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom7/gcom.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom7/gcom.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,68 @@
+// gcom.ast
+// AST for guarded command language
+
+verbatim {
+  class Env;       // eval.h
+
+  // binary arithmetic operators
+  enum AOp {
+    AO_PLUS,
+    AO_MINUS,
+    AO_TIMES
+  };
+
+  // binary boolean predicates over arithmetic expressions
+  enum BPred {
+    BP_EQUAL,
+    BP_LESS
+  };
+
+  // binary boolean operators
+  enum BOp {
+    BO_AND,
+    BO_OR
+  };
+}
+
+
+// arithmetic expressions
+class AExp {
+  pure_virtual int eval(Env &env);
+
+  -> A_lit(int n);
+  -> A_var(string x);
+  -> A_bin(AExp a1, AOp op, AExp a2);
+  -> A_group(AExp a);
+}
+
+// boolean expressions
+class BExp {
+  pure_virtual bool eval(Env &env);
+
+  -> B_lit(bool b);
+  -> B_pred(AExp a1, BPred op, AExp a2);
+  -> B_not(BExp b);
+  -> B_bin(BExp b1, BOp op, BExp b2);
+}
+
+// statements
+class Stmt {
+  pure_virtual void eval(Env &env);
+
+  -> S_skip();
+  -> S_abort();
+  -> S_print(string x);
+  -> S_assign(string x, AExp a);
+  -> S_seq(Stmt s1, Stmt s2);
+  -> S_if(GCom g);
+  -> S_do(GCom g);
+}
+
+// guarded commands
+class GCom {                       
+  // returns true if it finds an enabled alternative, false o.w.
+  pure_virtual bool eval(Env &env);
+
+  -> G_stmt(BExp b, Stmt s);
+  -> G_seq(GCom g1, GCom g2);
+}

Added: vendor/elsa/current/elkhound/examples/gcom7/gcom.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom7/gcom.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom7/gcom.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,130 @@
+// gcom.gr
+// parser for guarded command example language
+
+verbatim {
+  #include "str.h"        // stringf
+  #include "ast.h"        // AST declarations
+
+  #include <stdlib.h>     // getenv, atoi, putenv
+  #include <stdio.h>      // printf
+}
+
+// the parser context class is useful in large examples;
+// an empty one will suffice here
+context_class GComContext : public UserActions {
+public:
+  // given a lexer-allocated string, make a 'string', and
+  // deallocate the lexer-created copy
+  static inline string copyAndFree(char *x)
+  {
+    string ret(x);
+    delete x;
+    return ret;
+  }
+  
+  // for run-time precedence/associativity
+  static int precedence(AExp *a)
+  {
+    if (!a->isA_bin())       { return 20; }      // unary
+
+    A_bin *ab = a->asA_bin();
+    if (ab->op == AO_TIMES)  { return 10; }      // *
+    else                     { return 0;  }      // +,-
+  }
+};
+
+// pull in the tokens generated from lexer.h
+terminals {
+  include("tokens.tok")
+
+  // declare token sval types
+  token(int) TOK_LITERAL {
+    fun dup(n) { return n; }     // nothing special to do for ints
+    fun del(n) {}
+  }
+  token(char*) TOK_IDENTIFIER {
+    fun dup(x) { return strdup(x); }     // make a copy
+    fun del(x) { free(x); }              // delete a copy
+  }
+
+  precedence {           
+    // high precedence
+    //left  60 "*";
+    //left  50 "+" "-";
+    left  40 "!";        // ! has higher precedence than /\ and \/
+    left  30 TOK_AND;    // /\ has higher precedence than \/
+    left  20 TOK_OR;
+    left  10 ";" "#";    // precedence is irrelvant
+    // low precedence
+  }
+}
+
+
+// now the grammar; the first symbol is the start symbol
+nonterm(Stmt*) Start {
+  -> s:Stmt                       { return s; }
+}
+
+
+nonterm(AExp*) AExp {
+  fun dup(a) { return a->clone(); }     // deep copy
+  fun del(a) { delete a; }              // deep delete
+
+  // implemented precedence/associativity at run time
+  fun merge(a1,a2) {
+    if (precedence(a1) < precedence(a2))
+      { delete a2; return a1; }         // lowest precedence goes on top
+    if (precedence(a1) > precedence(a2))
+      { delete a1; return a2; }
+
+    // equal precedence, must be binary operators
+    A_bin *ab1 = a1->asA_bin();         // cast to A_bin*
+    A_bin *ab2 = a2->asA_bin();
+
+    // same precedence; associates to the left; that means
+    // that the RHS must use a higher-precedence operator
+    if (precedence(ab1) < precedence(ab1->a2))
+      { delete ab2; return ab1; }       // high-prec exp on right
+    if (precedence(ab2) < precedence(ab2->a2))
+      { delete ab1; return ab2; }       // high-prec exp on right
+
+    printf("failed to disambiguate!\n");
+    delete ab2; return ab1;             // pick arbitrarily
+  }
+  
+  -> n:TOK_LITERAL                { return new A_lit(n); }
+  -> x:TOK_IDENTIFIER             { return new A_var(copyAndFree(x)); }
+  -> a1:AExp "+" a2:AExp          { return new A_bin(a1, AO_PLUS, a2); }
+  -> a1:AExp "-" a2:AExp          { return new A_bin(a1, AO_MINUS, a2); }
+  -> a1:AExp "*" a2:AExp          { return new A_bin(a1, AO_TIMES, a2); }
+  -> "(" a:AExp ")"               { return new A_group(a); }
+}
+
+
+nonterm(BExp*) BExp {
+  -> "true"                       { return new B_lit(true); }
+  -> "false"                      { return new B_lit(false); }
+  -> a1:AExp "=" a2:AExp          { return new B_pred(a1, BP_EQUAL, a2); }
+  -> a1:AExp "<" a2:AExp          { return new B_pred(a1, BP_LESS, a2); }
+  -> "!" b:BExp                   { return new B_not(b); }
+  -> b1:BExp TOK_AND b2:BExp      { return new B_bin(b1, BO_AND, b2); }
+  -> b1:BExp TOK_OR  b2:BExp      { return new B_bin(b1, BO_OR, b2); }
+  -> "(" b:BExp ")"               { return b; }
+}
+
+
+nonterm(Stmt*) Stmt {
+  -> "skip"                       { return new S_skip; }
+  -> "abort"                      { return new S_abort; }
+  -> "print" x:TOK_IDENTIFIER     { return new S_print(copyAndFree(x)); }
+  -> x:TOK_IDENTIFIER ":=" a:AExp { return new S_assign(copyAndFree(x), a); }
+  -> s1:Stmt ";" s2:Stmt          { return new S_seq(s1, s2); }
+  -> "if" g:GCom "fi"             { return new S_if(g); }
+  -> "do" g:GCom "od"             { return new S_do(g); }
+}
+
+
+nonterm(GCom*) GCom {
+  -> b:BExp "->" s:Stmt           { return new G_stmt(b, s); }
+  -> g1:GCom "#" g2:GCom          { return new G_seq(g1, g2); }
+}

Added: vendor/elsa/current/elkhound/examples/gcom7/lexer.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom7/lexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom7/lexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,209 @@
+// lexer.cc
+// code for lexer.h
+
+#include "lexer.h"       // this module
+
+#include <stdio.h>       // getchar, ungetc
+#include <ctype.h>       // isspace, isalpha, isalnum
+#include <string.h>      // strchr, strdup, strcmp
+#include <stdlib.h>      // abort
+#include <assert.h>      // assert
+
+// simple hand-written lexer; could also be done using (e.g.) flex
+void Lexer::nextToken(LexerInterface *lex)
+{
+  // avoid accidental use of another token's sval
+  lex->sval = (SemanticValue)0;
+
+  int ch = getchar();
+
+  // skip whitespace
+  while (isspace(ch)) {
+    ch = getchar();
+  }
+
+  // end of file?
+  if (ch == EOF) {
+    lex->type = TOK_EOF;
+    return;
+  }
+
+  // simple one-character tokens
+  switch (ch) {
+    case '+': lex->type = TOK_PLUS; return;
+    case '*': lex->type = TOK_TIMES; return;
+    case '(': lex->type = TOK_LPAREN; return;
+    case ')': lex->type = TOK_RPAREN; return;
+
+    case '-':
+      // TOK_MINUS or TOK_ARROW?
+      ch = getchar();
+      if (ch == '>') {
+        lex->type = TOK_ARROW;
+      }
+      else {
+        lex->type = TOK_MINUS;
+        ungetc(ch, stdin);
+      }
+      return;
+
+    case '=': lex->type = TOK_EQUAL; return;
+    case '<': lex->type = TOK_LESS; return;
+    case '!': lex->type = TOK_NOT; return;
+    case ';': lex->type = TOK_SEMI; return;
+    case '#': lex->type = TOK_FATBAR; return;
+
+    case '/':
+      ch = getchar();
+      if (ch != '\\') fail("'/' must be followed by '\\'");
+      lex->type = TOK_AND; 
+      return;
+
+    case '\\':
+      ch = getchar();
+      if (ch != '/') fail("'\\' must be followed by '/'");
+      lex->type = TOK_OR;
+      return;
+
+    case ':':
+      ch = getchar();
+      if (ch != '=') fail("':' must be followed by '='");
+      lex->type = TOK_ASSIGN;
+      return;
+  }
+  
+  // integer literal
+  if (isdigit(ch)) {
+    int value = 0;
+    while (isdigit(ch)) {
+      value = value*10 + ch-'0';
+      ch = getchar();
+    }
+    ungetc(ch, stdin);      // put back the nondigit
+
+    // semantic value is the integer value of the literal
+    lex->sval = (SemanticValue)value;
+
+    lex->type = TOK_LITERAL;
+    return;
+  }
+
+  // identifier or keyword
+  if (isalpha(ch)) {        // must start with letter
+    char buf[80];
+    int i=0;
+    while (isalnum(ch)) {   // but allow digits later on
+      buf[i++] = (char)ch;
+      if (i==80) {
+        fail("identifier is too long\n");
+      }
+      ch = getchar();
+    }
+    buf[i]=0;
+    ungetc(ch, stdin);
+
+    // keyword?  (not a very efficient way to do this ...)
+    if (0==strcmp(buf, "true"))  { lex->type = TOK_TRUE; return; }
+    if (0==strcmp(buf, "false")) { lex->type = TOK_FALSE; return; }
+    if (0==strcmp(buf, "skip"))  { lex->type = TOK_SKIP; return; }
+    if (0==strcmp(buf, "abort")) { lex->type = TOK_ABORT; return; }
+    if (0==strcmp(buf, "print")) { lex->type = TOK_PRINT; return; }
+    if (0==strcmp(buf, "if"))    { lex->type = TOK_IF; return; }
+    if (0==strcmp(buf, "fi"))    { lex->type = TOK_FI; return; }
+    if (0==strcmp(buf, "do"))    { lex->type = TOK_DO; return; }
+    if (0==strcmp(buf, "od"))    { lex->type = TOK_OD; return; }
+
+    // semantic value is a pointer to an allocated string; it
+    // is simply leaked (never deallocated) for this example
+    lex->sval = (SemanticValue)strdup(buf);
+
+    lex->type = TOK_IDENTIFIER;
+    return;
+  }
+
+  fprintf(stderr, "illegal character: %c\n", ch);
+  abort();
+}
+
+void Lexer::fail(char const *msg)
+{
+  fprintf(stderr, "%s\n", msg);
+  abort();
+}
+
+
+string Lexer::tokenDesc() const
+{
+  switch (type) {
+    // for two kinds of tokens, interpret their semantic value
+    case TOK_LITERAL:      return stringf("%d", (int)sval);
+    case TOK_IDENTIFIER:   return stringf("id(%s)", (char*)sval);
+
+    // otherwise, just return the token kind description
+    default:               return tokenKindDesc(type);
+  }
+}
+
+
+string Lexer::tokenKindDesc(int kind) const
+{
+  switch (kind) {
+    case TOK_EOF:          return "EOF";
+    case TOK_LITERAL:      return "lit";
+    case TOK_IDENTIFIER:   return "id";
+    default: {
+      static char const * const map[] = {
+        "+",
+        "-",
+        "*",
+        "(",
+        ")",
+
+        "true",
+        "false",
+        "=",
+        "<",
+        "!",
+        "/\\",
+        "\\/",
+
+        "skip",
+        "abort",
+        "print",
+        ":=",
+        ";",
+        "if",
+        "fi",
+        "do",
+        "od",
+
+        "->",
+        "#"
+      };
+      kind -= TOK_PLUS;
+      assert((unsigned)kind < (sizeof(map)/sizeof(map[0])));
+      return map[kind];
+    }
+  }
+}
+
+
+#ifdef TEST_LEXER
+int main()
+{
+  Lexer lexer;
+  for (;;) {
+    lexer.getTokenFunc()(&lexer);    // first call yields a function pointer
+    
+    // print the returned token
+    string desc = lexer.tokenDesc();
+    printf("%s\n", desc.c_str());
+
+    if (lexer.type == TOK_EOF) {
+      break;
+    }
+  }
+  
+  return 0;
+}
+#endif // TEST_LEXER

Added: vendor/elsa/current/elkhound/examples/gcom7/lexer.h
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom7/lexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom7/lexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,66 @@
+// lexer.h
+// lexer for the guarded-command example language
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "lexerint.h"      // LexerInterface
+
+// token codes (must agree with the parser)
+enum TokenCode {
+  TOK_EOF         = 0,     // end of file
+  
+  // minimal set of tokens for AExp
+  TOK_LITERAL,             // integer literal
+  TOK_IDENTIFIER,          // identifier like "x"
+  TOK_PLUS,                // "+"
+  TOK_MINUS,               // "-"
+  TOK_TIMES,               // "*"
+  TOK_LPAREN,              // "("
+  TOK_RPAREN,              // ")"
+
+  // for BExp
+  TOK_TRUE,                // "true"
+  TOK_FALSE,               // "false"
+  TOK_EQUAL,               // "="
+  TOK_LESS,                // "<"
+  TOK_NOT,                 // "!"
+  TOK_AND,                 // elkhound doesn't like quoted backslashes
+  TOK_OR,
+
+  // for Stmt
+  TOK_SKIP,                // "skip"
+  TOK_ABORT,               // "abort"
+  TOK_PRINT,               // "print"
+  TOK_ASSIGN,              // ":="
+  TOK_SEMI,                // ";"
+  TOK_IF,                  // "if"
+  TOK_FI,                  // "fi"
+  TOK_DO,                  // "do"
+  TOK_OD,                  // "od"
+  
+  // for GCom
+  TOK_ARROW,               // "->"
+  TOK_FATBAR,              // "#"
+};
+
+
+// read characters from stdin, yield tokens for the parser
+class Lexer : public LexerInterface {
+private:
+  static void fail(char const *msg);
+
+public:
+  // function that retrieves the next token from
+  // the input stream
+  static void nextToken(LexerInterface *lex);
+  virtual NextTokenFunc getTokenFunc() const
+    { return &Lexer::nextToken; }
+
+  // debugging assistance functions
+  string tokenDesc() const;
+  string tokenKindDesc(int kind) const;
+};
+
+
+#endif // LEXER_H

Added: vendor/elsa/current/elkhound/examples/gcom7/parser.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/gcom7/parser.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/gcom7/parser.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,80 @@
+// parser.cc
+// driver program for guarded command example
+
+#include "lexer.h"     // Lexer
+#include "gcom.h"      // GCom
+#include "glr.h"       // GLR
+#include "ptreenode.h" // PTreeNode
+#include "ptreeact.h"  // ParseTreeLexer, ParseTreeActions
+#include "ast.h"       // Stmt, etc.
+#include "eval.h"      // Env
+
+#include <string.h>    // strcmp
+
+
+int main(int argc, char *argv[])
+{
+  // use "-tree" command-line arg to print the tree
+  bool printTree = argc==2 && 0==strcmp(argv[1], "-tree");
+  bool printAST  = argc==2 && 0==strcmp(argv[1], "-ast");
+
+  // create and initialize the lexer
+  Lexer lexer;
+  lexer.nextToken(&lexer);
+
+  // create the parser context object
+  GComContext gcom;
+
+  if (printTree) {
+    // wrap the lexer and actions with versions that make a parse tree
+    ParseTreeLexer ptlexer(&lexer, &gcom);
+    ParseTreeActions ptact(&gcom, gcom.makeTables());
+
+    // initialize the parser
+    GLR glr(&ptact, ptact.getTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(ptlexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print the tree
+    PTreeNode *ptn = (PTreeNode*)result;
+    ptn->printTree(cout, PTreeNode::PF_EXPAND);
+  }
+
+  else {
+    // initialize the parser
+    GLR glr(&gcom, gcom.makeTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(lexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // result is an AST node
+    Stmt *top = (Stmt*)result;
+    
+    if (printAST) {
+      top->debugPrint(cout, 0);
+    }
+
+    // evaluate
+    printf("evaluating...\n");
+    Env env;
+    top->eval(env);
+    printf("program terminated normally\n");
+               
+    // recursively deallocate the tree
+    delete top;
+  }
+
+  return 0;
+}
+
+
+

Added: vendor/elsa/current/elkhound/examples/scannerless/main.cc
===================================================================
--- vendor/elsa/current/elkhound/examples/scannerless/main.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/scannerless/main.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,103 @@
+// main.cc
+// driver program for scannerless example
+
+#include "sless.h"     // Scannerless
+#include "glr.h"       // GLR
+#include "lexerint.h"  // LexerInterface
+#include "strutil.h"   // quoted
+#include "ptreenode.h" // PTreeNode
+#include "ptreeact.h"  // ParseTreeLexer, ParseTreeActions
+
+#include <stdio.h>     // getchar
+#include <iostream.h>  // cout
+#include <string.h>    // strcmp
+
+
+class Lexer : public LexerInterface {
+public:
+  // function that retrieves the next token from
+  // the input stream
+  static void nextToken(LexerInterface *lex);
+  virtual NextTokenFunc getTokenFunc() const
+    { return &Lexer::nextToken; }
+
+  // debugging assistance functions
+  string tokenDesc() const;
+  string tokenKindDesc(int kind) const;
+};
+
+void Lexer::nextToken(LexerInterface *lex)
+{
+  int ch = getchar();
+
+  if (ch == EOF) {
+    lex->type = 0 /*eof*/;
+  }
+  else {
+    lex->type = ch;
+  }
+}
+
+string Lexer::tokenDesc() const
+{
+  return tokenKindDesc(type);
+}
+
+string Lexer::tokenKindDesc(int kind) const
+{
+  string k = quoted(stringc << (char)kind);
+  return stringf("%s (%d)", k.c_str(), kind);
+}
+
+
+int main(int argc, char *argv[])
+{
+  // use "-tree" command-line arg to print the tree
+  bool printTree = argc==2 && 0==strcmp(argv[1], "-tree");
+
+  // create and initialize the lexer
+  Lexer lexer;
+  lexer.nextToken(&lexer);
+
+  // create the parser context object
+  Scannerless sless;
+
+  if (printTree) {
+    // wrap the lexer and actions with versions that make a parse tree
+    ParseTreeLexer ptlexer(&lexer, &sless);
+    ParseTreeActions ptact(&sless, sless.makeTables());
+
+    // initialize the parser
+    GLR glr(&ptact, ptact.getTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(ptlexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print the tree
+    PTreeNode *ptn = (PTreeNode*)result;
+    ptn->printTree(cout, PTreeNode::PF_EXPAND);
+  }
+  
+  else {
+    // initialize the parser
+    GLR glr(&sless, sless.makeTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(lexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    printf("ok\n");
+  }
+
+  return 0;
+}
+
+
+// EOF

Added: vendor/elsa/current/elkhound/examples/scannerless/sless.gr
===================================================================
--- vendor/elsa/current/elkhound/examples/scannerless/sless.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/examples/scannerless/sless.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,56 @@
+// sless.gr
+// example of scannerless operation in Elkhound
+
+context_class Scannerless : public UserActions {
+public:
+};
+
+terminals {
+   0: CHAR_EOF;
+  10: CHAR_NEWLINE;
+  32: CHAR_SPACE;
+  40: CHAR_LPAREN      "(";
+  41: CHAR_RPAREN      ")";
+  97: CHAR_A           "a";
+ 102: CHAR_F           "f";
+ 105: CHAR_I           "i";
+}
+
+nonterm Start {
+  -> WS Prog;
+}
+
+nonterm Prog {
+  -> empty;
+  -> Prog IDENT;
+  -> Prog IF Prog FI;
+  -> Prog LPAREN Prog RPAREN;
+}
+
+nonterm Ident {
+  fun maximal() {}          // use maximal munch disambiguation
+  -> "f";
+  -> "i";
+  -> "f" Ident;
+  -> "i" Ident;
+  subsets If, Fi;           // prefer keywords to identifiers
+}
+
+// keywords
+nonterm If -> "i" "f";
+nonterm Fi -> "f" "i";
+
+// tokens, with whitespace following
+nonterm IDENT -> Ident WS;
+nonterm IF -> If WS;
+nonterm FI -> Fi WS;
+nonterm LPAREN -> "(" WS;
+nonterm RPAREN -> ")" WS;
+
+// whitespace
+nonterm WS {
+  -> empty;
+  -> CHAR_SPACE WS;
+  -> CHAR_NEWLINE WS;
+}
+

Added: vendor/elsa/current/elkhound/extradep.mk
===================================================================
--- vendor/elsa/current/elkhound/extradep.mk	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/extradep.mk	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+glr.o: glrconfig.h
+gramexpl.o: glrconfig.h
+gramlex.yy.o: grampar.codes.h
+grampar.o: gramast.ast.gen.h
+grampar.o: grampar.tab.h
+grampar.tab.o: gramast.ast.gen.h
+trivlex.o: glrconfig.h
+useract.o: glrconfig.h
+cc2/cc2.gr.gen.o: glrconfig.h
+cc2/cc2main.o: glrconfig.h
+cc2/cc2main.o: cc2/cc2.gr.gen.h

Added: vendor/elsa/current/elkhound/faq.html
===================================================================
--- vendor/elsa/current/elkhound/faq.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/faq.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,170 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elkhound FAQ</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175% }
+    a.toc:link { text-decoration: none }
+    a.toc:visited { text-decoration: none }
+  </style>
+</HEAD>
+
+<body>
+
+<center>
+<p class="title"><b>Elkhound Frequently Asked Questions</b></p>
+</center>
+
+<p>
+This page has answers to questions that I've received and think
+might be useful generally.
+
+<h1>Contents</h1>
+                          
+<p>
+<!-- BEGIN CONTENTS -->
+<!-- automatically generated by insert-html-toc; do not edit the TOC directly -->
+<ul>
+  <li><a class="toc" href="#reductions">1. Reduction Actions</a>
+  <ul>
+    <li><a class="toc" href="#execute_pruned_reductions">1.1 Does Elkhound ever run action routines on parses that are not part of a complete parse tree?</a>
+    <li><a class="toc" href="#pruned_reduction_exception">1.2 What if a reduction has a side effect?</a>
+  </ul>
+  <li><a class="toc" href="#starting_parser">2. Starting the Parser</a>
+  <ul>
+    <li><a class="toc" href="#other_start_symbols">2.1 How do I start parsing from a symbol other than the start symbol?</a>
+  </ul>
+</ul>
+<!-- END CONTENTS -->
+
+<a name="reductions"></a>
+<h1>1. Reduction Actions</h1>
+
+<a name="execute_pruned_reductions"></a>
+<h2>1.1 Does Elkhound ever run action routines on parses that are not part of a complete parse tree?</h2>
+<!-- originally from Carl Eastlund -->
+
+<p>
+Yes, it does.  The question of whether a given reduction can be part of a
+complete parse tree can, in general, only be answered by seeing all of the
+input.  So the two choices are to reduce as you go, which is what Elkhound
+does, or to build a parse tree/forest and then run all reductions after
+parsing is complete.  Elkhound does not do the latter because building a parse
+tree slows parsing by a large (~10) constant factor.
+
+<p>
+In certain circumstances, Elkhound can determine that an action corresponds
+to a parse that is going to fail before processing of the current token
+is finished (see <a href="glr.cc">glr.cc</a>, <tt>GLR::canMakeProgress()</tt>).
+In such cases, the action is preempted, but this is just a quick hack that
+can slightly improve performance.
+
+<p>
+Therefore, unless the grammar is LALR(1) (i.e., there are no
+conflicts), you must assume that any reduction action might be part of
+a parse that will fail.  If the reduction action has effects that need
+to be undone, you can put the undo actions in <tt>del()</tt> methods.
+
+<a name="pruned_reduction_exception"></a>
+<h2>1.2 What if a reduction has a side effect?</h2>
+<!-- originally from Carl Eastlund -->
+
+<p>
+Original question:
+<blockquote>
+  We have a scenario where an action routine is run on part of an
+  expression - this part is legal on its own, but the subdivision is
+  illegal.  The problem is that the action routine raises an exception
+  due to context-sensitive invariants.
+</blockquote>
+
+<p>
+This is an instance of a more general problem: actions that have side
+effects.  Elkhound will call the <tt>del</tt> function corresponding to
+reductions that are performed and then discarded, but if the action had a
+side effect then undoing it in <tt>del</tt> can be very difficult.  Therefore you
+have to be careful about using side effects.  Throwing an exception is
+essentially an extreme form of side effect from Elkhound's point of view.
+
+<p>
+Probably the easiest solution is to delay the activity that leads to
+throwing the exception.  The reduction action can build a record of the
+reduction, but then postpone further processing until another pass, after
+parsing is complete.  As long as this doesn't happen too often, you won't
+incur the cost of a complete parse tree.
+
+<p>
+Another possibility is to examine the parse tables and see if a grammar
+modification can eliminate the nondeterminism that leads to the parse
+split.  This of course requires detailed understanding of how the parsing
+algorithm works; it is probably only worth it if performance is crucial.
+
+
+<a name="starting_parser"></a>
+<h1>2. Starting the Parser</h1>
+
+<a name="other_start_symbols"></a>
+<h2>2.1 How do I start parsing from a symbol other than the start symbol?</h2>
+<!-- originally from Bill McCloskey, also asked by Carl Eastlund -->
+
+<p>
+Sometimes people want to use a single Elkhound specification, but have
+it start parsing with different symbols in different situations.
+Eventually I'd like to build in a feature to do this automatically,
+but in the meantime there is a trick that will work.
+
+<p>
+Suppose you have an Elkhound grammar with several nonterminals
+you want to be able to use as start symbols:
+<pre>
+  nonterm(Foo*) Foo { -&gt; A B C {/*...*/} /*...*/ }
+  nonterm(Bar*) Bar { /*...*/ }
+  nonterm(Baz*) Baz { /*...*/ }
+</pre>
+
+<p>
+You can create a wrapper nonterminal, which (when put first in the
+grammar file) Elkhound will regard as the "real" start symbol, and
+give it rules whose first symbol is a special token that selects the
+start symbol:
+<pre>
+  nonterm(void*) WrapperStart {
+    -&gt; TOK_SELECT_FOO f:Foo { return f; }
+    -&gt; TOK_SELECT_BAR b:Bar { return b; }
+    -&gt; TOK_SELECT_BAZ b:Baz { return b; }
+  }
+</pre>
+
+<p>
+Now, these special tokens (e.g. <tt>TOK_SELECT_FOO</tt>) are declared
+like ordinary tokens but have the property that they are never yielded
+by the lexer.  Instead, you manually provide them as the first token
+when initializing the parser.  This is done instead of the usual
+"priming step"; the parser engine will read the first real token once
+it drops into its normal parsing loop:
+<pre>
+  Lexer lexer;                   // your implementation of LexerInterface
+  lexer.type = TOK_SELECT_FOO;   // you pick what to provide here
+  SemanticValue treeTop;
+  glr.glrParse(lexer, treeTop);
+  Foo *foo = (Foo*)treeTop;      // then interpret the result accordingly
+</pre>
+
+<p>
+Above, I've used <tt>void*</tt> for convenience.  If you're bothered
+by the lack of type safety, or using the OCaml version, you can use
+some kind of tagged union type.  The union only has to carry the
+final parse result from the WrapperStart symbol out to the caller,
+so it is short lived and irrelevant to performance.
+
+
+
+
+</body>
+</html>

Added: vendor/elsa/current/elkhound/ffollow.gr
===================================================================
--- vendor/elsa/current/elkhound/ffollow.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ffollow.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// ffollow.gr            see license.txt for copyright and terms of use
+// grammar 4.11 of [ASU] (p.189), designed to show First and Follow
+
+terminals {
+  0 : eof "$";
+  1 : plus "+";
+  2 : star "*";
+  3 : lparen "(";
+  4 : rparen ")";
+  5 : id "id";
+}
+
+context_class Context : public UserActions {};
+
+nonterm S  ->  E /*"$"*/ ;
+nonterm E  ->  T Ep ;
+nonterm Ep{->  "+" T Ep;  -> empty; }
+nonterm T  ->  F Tp ;
+nonterm Tp{->  "*" F Tp;  -> empty; }
+nonterm F {->  "(" E ")"; -> "id"; }

Added: vendor/elsa/current/elkhound/ffollow_ext.gr
===================================================================
--- vendor/elsa/current/elkhound/ffollow_ext.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ffollow_ext.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,47 @@
+// ffollow_ext.gr
+// extension to ffollow.gr, just to test new replace/delete keywords
+
+// ---- correct ----
+
+nonterm Ep {
+  // new production
+  -> "+" "+";
+
+  // delete a production
+  delete -> "+" T Ep;
+
+  // replace a production
+  replace -> empty { return 1; }
+}
+
+nonterm T {
+  // delete and then new
+  delete -> F Tp;
+  -> F Tp;
+}
+
+
+// ---- incorrect ----
+nonterm Tp {
+  // try to make new, but it already exists in base
+  //ERROR(1): -> "*" F Tp;
+  
+  // delete nonexistent
+  //ERROR(3): delete -> "*" "*" "*";
+
+  // replace nonexistent
+  //ERROR(4): replace -> "*" "*" "*" "*";
+}
+
+nonterm Ep {
+  // try to make new, but already exists above
+  //ERROR(2): -> "+" "+";
+}
+
+nonterm F {
+  // try to replace and then new
+  //ERROR(5): replace -> "(" E ")";
+  //ERROR(5): -> "(" E ")";
+}
+
+

Added: vendor/elsa/current/elkhound/find-extra-deps
===================================================================
--- vendor/elsa/current/elkhound/find-extra-deps	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/find-extra-deps	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,138 @@
+#!/usr/bin/perl -w
+# see usage string for description
+
+use strict 'subs';
+
+if (@ARGV == 0) {
+  print(<<"EOF");
+usage: $0 file1.d [file2.d [...]]
+
+Given a bunch of .d files after compilation is complete, this script
+yields dependencies where the dependee is *not* checked into CVS.
+This is then the dependencies which need to appear explicitly in
+Makefile.in.
+EOF
+  exit(0);
+}
+
+
+for my $fname (@ARGV) {
+  # open the file
+  open(IN, "<$fname") or die("cannot open $fname: $!\n");
+
+  # dependency target is listed first
+  my $line = <IN>;
+  if (!defined($line)) {
+    # empty file, skip it
+  }
+  else {
+    my ($target) = ($line =~ m/^([^:]+):/);
+    die if (!$target);
+
+    # now search for the command-less, prerequisite-less rules
+    # where the dependees are listed
+    while (defined($line = <IN>)) {
+      my ($dependee) = ($line =~ m/^([^:]+):$/);
+      if (!defined($dependee)) {
+        # line is not of right form
+        next;
+      }
+
+      if ($dependee =~ m,^\.\./,) {
+        # it begins with "../", suggesting the file is in another
+        # repository; I'll just assume cross-repository dependencies
+        # don't need to influence the build order of the current
+        # directory
+        next;
+      }
+
+      # is this file checked into CVS?
+      if (isCheckedIn($dependee)) {
+        # no need to include this in the Makefile since the file
+        # will always exist
+        next;
+      }
+      
+      # is the dependee something the Makefile would already
+      # know about?  for example, we don't need to explicitly
+      # say that grampar.tab.o depends on grampar.tab.cc, because
+      # the pattern rule which makes the former already includes
+      # the dependency on the latter
+      if (isPattern($target, ".o", $dependee, ".cc") ||
+          isPattern($target, ".ast.gen.o", $dependee, ".ast.gen.h") ||
+          isPattern($target, ".gr.gen.o", $dependee, ".gr.gen.h")) {
+        # Makefile already knows
+        next;
+      }
+
+      print("$target: $dependee\n");
+    }
+  }
+
+  close(IN) or die;
+}
+
+exit(0);
+
+
+# check whether a given file is checked in, by looking for it
+# in the CVS/Entries file
+sub isCheckedIn {
+  my ($fname) = @_;
+
+  # split into directory and file
+  my ($dir, $file) = ($fname =~ m|^(.*)/([^/]+)$|);
+  if (!defined($file)) {
+    $dir = ".";
+    $file = $fname;
+  }
+
+  # debugging
+  #print("dir: $dir\n");
+  #print("file: $file\n");
+
+  # open the Entries file
+  if (!open(ENTRIES, "<$dir/CVS/Entries")) {
+    # the Entries file doesn't exist, so the file in question
+    # is not checked in to CVS
+    return 0;
+  }
+
+  # look for the file in question among the lines of Entries
+  my $line;
+  while (defined($line = <ENTRIES>)) {
+    if ($line =~ m|^/$file/|) {
+      # found the file, it's checked in
+      close(ENTRIES) or die;
+      return 1;
+    }
+  }
+  
+  close(ENTRIES) or die;
+  
+  # didn't find the file, it's not checked in
+  return 0;
+}
+
+
+# check whether a target and dependee are related by being
+# the same base with two given extensions
+sub isPattern {
+  my ($name1, $ext1, $name2, $ext2) = @_;
+
+  # separate $name1 into a prefix and a suffix
+  my $name1len = length($name1);
+  my $ext1len = length($ext1);
+  if ($name1len < $ext1len) {
+    return 0;
+  }
+  my ($prefix1) = substr($name1, 0, $name1len - $ext1len);
+  #print("prefix1: $prefix1\n");
+
+  # we have a match if the suffix matches $ext1, and if $name2
+  # is exactly the concatenation of $prefix1 and $ext2
+  return ($name1 eq "$prefix1$ext1") &&
+         ($name2 eq "$prefix1$ext2");
+}
+
+


Property changes on: vendor/elsa/current/elkhound/find-extra-deps
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/flatutil.h
===================================================================
--- vendor/elsa/current/elkhound/flatutil.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/flatutil.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,363 @@
+// flatutil.h            see license.txt for copyright and terms of use
+// flatten helpers
+
+#ifndef FLATUTIL_H
+#define FLATUTIL_H
+
+#include "flatten.h"     // Flatten
+#include "objlist.h"     // ObjList
+#include "sobjlist.h"    // SObjList
+
+
+// ------------- xfer of owners -----------------
+template <class T>
+void xferOwnerPtr(Flatten &flat, T *&ptr)
+{
+  if (flat.reading()) {
+    // construct a new, empty object
+    ptr = new T(flat);
+  }
+
+  // read/write it
+  ptr->xfer(flat);
+
+  // note it so we can have serfs to it
+  flat.noteOwner(ptr);
+}
+
+
+template <class T>
+void xferNullableOwnerPtr(Flatten &flat, T *&ptr)
+{
+  bool present = false;     // initial value not used
+  if (flat.reading()) {
+    flat.xferBool(present);
+  }
+  else {
+    present = (ptr != NULL);
+  }
+
+  if (present) {
+    xferOwnerPtr(flat, ptr);
+  }
+}
+
+
+template <class T>
+void xferOwnerPtr_readObj(Flatten &flat, T *&ptr)
+{
+  if (flat.reading()) {
+    // construct a new object, *and* read it from file
+    ptr = T::readObj(flat);
+  }
+  else {
+    // write it
+    ptr->xfer(flat);
+  }
+
+  // note it so we can have serfs to it
+  flat.noteOwner(ptr);
+}
+
+
+template <class T>
+void xferObjList(Flatten &flat, ObjList <T> &list)
+{
+  if (flat.writing()) {
+    flat.writeInt(list.count());
+
+    MUTATE_EACH_OBJLIST(T, list, iter) {
+      iter.data()->xfer(flat);
+      flat.noteOwner(iter.data());
+    }
+  }
+  else {
+    int listLen = flat.readInt();
+
+    ObjListMutator<T> mut(list);
+    while (listLen--) {
+      // construct a new, empty object
+      T *obj = new T(flat);
+
+      // read it
+      obj->xfer(flat);
+      flat.noteOwner(obj);
+
+      // add it to the list
+      mut.append(obj);
+    }
+  }
+}
+
+
+// for things like AExprNode which have a readObj
+// static method .. it's possible to merge this with
+// the above code, but I'm not sure that's a good idea yet
+template <class T>
+void xferObjList_readObj(Flatten &flat, ObjList <T> &list)
+{
+  if (flat.writing()) {
+    flat.writeInt(list.count());
+
+    MUTATE_EACH_OBJLIST(T, list, iter) {
+      iter.data()->xfer(flat);
+      flat.noteOwner(iter.data());
+    }
+  }
+  else {
+    int listLen = flat.readInt();
+
+    ObjListMutator<T> mut(list);
+    while (listLen--) {
+      // construct a new object, *and* read its
+      // contents from the file
+      T *obj = T::readObj(flat);
+      flat.noteOwner(obj);
+
+      // add it to the list
+      mut.append(obj);
+    }
+  }
+}
+
+
+// ------------- xfer of serfs -----------------
+// xfer a list of serf pointers to objects, each object
+// could be in one of several owner lists
+template <class T>
+void xferSObjList_multi(Flatten &flat, SObjList<T> &list,
+                        ObjList<T> **masterLists, int numMasters)
+{
+  // be sure the same number of master lists are used at
+  // read and write time
+  flat.checkpoint(numMasters);
+
+  if (flat.writing()) {
+    flat.writeInt(list.count());
+
+    SMUTATE_EACH_OBJLIST(T, list, iter) {
+      // determine which master list it's in
+      int master;
+      for (master = 0; master<numMasters; master++) {
+        int index = masterLists[master]->indexOf(iter.data());
+        if (index != -1) {
+          // we found it -- encode the list and its index
+          if (numMasters > 1) {
+            flat.writeInt(master);    // only do this if multiple masters
+          }
+          flat.writeInt(index);
+          break;
+        }
+      }
+
+      if (master == numMasters) {
+        // failed to find the master list
+        xfailure("xferSObjList_multi: obj not in any of the lists");
+      }
+    }
+  }
+
+  else {
+    int listLen = flat.readInt();
+
+    SObjListMutator<T> mut(list);
+    while (listLen--) {
+      int master = 0;               // assume just 1 master
+      if (numMasters > 1) {
+        master = flat.readInt();    // then refine
+      }
+
+      mut.append(masterLists[master]->nth(flat.readInt()));
+    }
+  }
+}
+
+
+// xfer a list of serf pointers to objects owner by 'masterList'
+template <class T>
+void xferSObjList(Flatten &flat, SObjList<T> &list, ObjList<T> &masterList)
+{
+  ObjList<T> *ptr = &masterList;
+  xferSObjList_multi(flat, list, &ptr, 1 /*numMasters*/);
+}
+
+
+// xfer a pointer which points to something in a master list
+template <class T>
+void xferSerfPtrToList(Flatten &flat, T *&ptr, ObjList<T> &masterList)
+{
+  if (flat.writing()) {
+    flat.writeInt(masterList.indexOfF(ptr));
+  }
+  else {
+    ptr = masterList.nth(flat.readInt());
+  }
+}
+
+
+template <class T>
+void xferNullableSerfPtrToList(Flatten &flat, T *&ptr, ObjList<T> &masterList)
+{
+  if (flat.writing()) {
+    flat.writeInt(masterList.indexOf(ptr));
+  }
+  else {
+    int index = flat.readInt();
+    if (index >= 0) {
+      ptr = masterList.nth(index);
+    }
+    else {
+      ptr = NULL;
+    }
+  }
+}
+
+                  
+template <class T>
+void computedValue(Flatten &flat, T &variable, T value)
+{
+  if (flat.writing()) {
+    // check it
+    xassert(variable == value);
+  }
+  else {
+    // set it
+    variable = value;
+  }
+}
+
+
+// void* implementation
+//#define Leaf void
+//#define Root void
+//#define FirstLevel void
+template <class Root, class FirstLevel, class Leaf>
+void xferSerfPtr_twoLevelAccess(
+  Flatten &flat,
+  Leaf *&leaf,
+  Root *root,
+  FirstLevel* (*getNthFirst)(Root *r, int n),
+  Leaf* (*getNthLeaf)(FirstLevel *f, int n))
+{
+  if (flat.writing()) {
+    // determine both indices
+    for (int index1=0; ; index1++) {
+      // get a first-level obj
+      FirstLevel *first = getNthFirst(root, index1);
+      if (!first) {
+        // exhausted first-level objs
+        xfailure("xferSerfPtr_twoLevelAccess: couldn't find obj to xfer");
+      }
+
+      // look for the leaf inside it
+      for (int index2=0; ; index2++) {
+        Leaf *second = getNthLeaf(first, index2);
+        if (second == leaf) {
+          // found it; encode both indices
+          flat.writeInt(index1);
+          flat.writeInt(index2);
+          return;
+        }
+        if (second == NULL) {
+          // exhausted this subtree
+          break;
+        }
+      } // end of iter over leaves
+    } // end of iter over first-lvl objs
+  }
+
+  else /*reading*/ {
+    // read both indicies
+    int index1 = flat.readInt();
+    int index2 = flat.readInt();
+
+    // follow the access path
+    FirstLevel *first = getNthFirst(root, index1);
+    formatAssert(first != NULL);
+    Leaf *second = getNthLeaf(first, index2);
+    formatAssert(second != NULL);
+
+    // found it
+    leaf = second;
+  }
+}
+//#undef Leaf
+//#undef Root
+//#undef FirstLevel
+
+
+#if 0
+typedef void *accessFunc_void(void *parent, int childNum);
+
+// typesafe interface
+template <class Root, class FirstLevel, class Leaf>
+inline void xferSerfPtr_twoLevelAccess(
+  Flatten &flat,
+  Leaf *&leaf,
+  Root *root,
+  FirstLevel* (*getNthFirst)(Root *r, int n),
+  Leaf* (*getNthLeaf)(FirstLevel *f, int n))
+{
+  xferSerfPtr_twoLevelAccess(
+    flat,
+    (void*&)leaf,
+    (void*)root,
+    (accessFunc_void)getNthFirst,
+    (accessFunc_void)getNthLeaf);
+}
+#endif // 0
+
+
+template <class Root, class FirstLevel, class Leaf>
+void xferSObjList_twoLevelAccess(
+  Flatten &flat,
+  SObjList<Leaf> &serfList,
+  Root *root,
+  FirstLevel* (*getNthFirst)(Root *r, int n),
+  Leaf* (*getNthLeaf)(FirstLevel *f, int n))
+{
+  if (flat.writing()) {
+    // length of list
+    flat.writeInt(serfList.count());
+
+    // iterate over list
+    SMUTATE_EACH_OBJLIST(Leaf, serfList, iter) {
+      // write the obj
+      Leaf *leaf = iter.data();
+      xferSerfPtr_twoLevelAccess(
+        flat, leaf, root,
+        getNthFirst, getNthLeaf);
+    }
+  }
+  else {
+    int length = flat.readInt();
+
+    SObjListMutator<Leaf> mut(serfList);
+    while (length--) {
+      // read the obj
+      Leaf *leaf;
+      xferSerfPtr_twoLevelAccess(
+        flat, leaf, root,
+        getNthFirst, getNthLeaf);
+
+      // store it in the list
+      mut.append(leaf);
+    }
+  }
+}
+
+
+template <class T>
+void xferSerfPtr(Flatten &flat, T *&serfPtr)
+{
+  flat.xferSerf((void*&)serfPtr, false /*nullable*/);
+}
+
+template <class T>
+void xferNullableSerfPtr(Flatten &flat, T *&serfPtr)
+{
+  flat.xferSerf((void*&)serfPtr, true /*nullable*/);
+}
+
+
+#endif // FLATUTIL_H

Added: vendor/elsa/current/elkhound/forbid.gr
===================================================================
--- vendor/elsa/current/elkhound/forbid.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/forbid.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// forbid.gr
+// demonstrate 'forbid' feature
+
+// the 'forbid' directive should ensure this
+option shift_reduce_conflicts 0;
+
+option unreachable_terminals 96;
+
+context_class Forbid : public UserActions {
+public:
+};
+
+terminals {
+   0: CHAR_EOF;
+  97: CHAR_A           "a";    // plays role of identifier
+  98: CHAR_B           "b";    // plays role of "::" qualifier
+}
+
+nonterm Start {
+  // like a declaration "int x", only both the type and
+  // the declarator are possibly-qualified identifiers
+  -> TopA TopA ;
+}
+
+nonterm TopA {
+  // might be global-scope qualified
+  -> "b" A ;
+  -> A ;
+}
+
+nonterm A {
+  // might have intermediate qualification
+  
+  // by forbidding this reduction when "b" is in the lookahead, we
+  // force any available b's to be consumed as early as possible
+  -> "a"          forbid_next("b") ;
+
+  -> "a" "b" A ;
+}

Added: vendor/elsa/current/elkhound/genml.cc
===================================================================
--- vendor/elsa/current/elkhound/genml.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/genml.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,875 @@
+// genml.cc            see license.txt for copyright and terms of use
+// code for genml.h
+// first half based on 'emitActionCode' and friends from gramanl.cc
+// second half based on 'emitConstructionCode' from parsetables.cc
+
+#include "genml.h"       // this module
+#include "gramanl.h"     // GrammarAnalysis
+#include "emitcode.h"    // EmitCode
+#include "parsetables.h" // ParseTables
+#include "exc.h"         // XOpen
+#include "strutil.h"     // replace
+
+
+// NOTE: The as following code is largely copied from elsewhere,
+// including comments, the comments may be in some places not
+// perfectly in correspondence with the code.
+
+
+
+// prototypes for this section; some of them accept Grammar simply
+// because that's all they need; there's no problem upgrading them
+// to GrammarAnalysis
+void emitMLDescriptions(GrammarAnalysis const &g, EmitCode &out);
+void emitMLActionCode(GrammarAnalysis const &g, rostring mliFname,
+                      rostring mlFname, rostring srcFname);
+void emitMLUserCode(EmitCode &out, LocString const &code, bool braces = true);
+void emitMLActions(Grammar const &g, EmitCode &out, EmitCode &dcl);
+void emitMLDupDelMerge(GrammarAnalysis const &g, EmitCode &out, EmitCode &dcl);
+void emitMLFuncDecl(Grammar const &g, EmitCode &out, EmitCode &dcl,
+                    char const *rettype, char const *params);
+void emitMLDDMInlines(Grammar const &g, EmitCode &out, EmitCode &dcl,
+                      Symbol const &sym);
+void emitMLSwitchCode(Grammar const &g, EmitCode &out,
+                      rostring signature, char const *switchVar,
+                      ObjList<Symbol> const &syms, int whichFunc,
+                      char const *templateCode, char const *actUpon);
+
+
+// ------------- first half: action emission ----------------
+#if 0   // not needed
+// yield the name of the inline function for this production; naming
+// design motivated by desire to make debugging easier
+string actionFuncName(Production const &prod)
+{
+  return stringc << "action" << prod.prodIndex
+                 << "_" << prod.left->name;
+}                    
+#endif // 0
+
+
+// emit the user's action code to a file
+void emitMLActionCode(GrammarAnalysis const &g, rostring mliFname,
+                      rostring mlFname, rostring srcFname)
+{
+  EmitCode dcl(mliFname);
+  if (!dcl) {
+    throw_XOpen(mliFname);
+  }
+
+  // prologue
+  dcl << "(* " << mliFname << " *)\n"
+      << "(* *** DO NOT EDIT BY HAND *** *)\n"
+      << "(* automatically generated by elkhound, from " << srcFname << " *)\n"
+      << "\n"
+      ;
+
+  // insert the stand-alone verbatim sections
+  {FOREACH_OBJLIST(LocString, g.verbatim, iter) {
+    emitMLUserCode(dcl, *(iter.data()), false /*braces*/);
+  }}
+
+  #if 0    // not implemented
+  // insert each of the context class definitions; the last one
+  // is the one whose name is 'g.actionClassName' and into which
+  // the action functions are inserted as methods
+  {
+    int ct=0;
+    FOREACH_OBJLIST(LocString, g.actionClasses, iter) {
+      if (ct++ > 0) {
+        // end the previous class; the following body will open
+        // another one, and the brace following the action list
+        // will close the last one
+        dcl << "};\n";
+      }
+
+      dcl << "\n"
+          << "// parser context class\n"
+          << "class ";
+      emitUserCode(dcl, *(iter.data()), false /*braces*/);
+  }}                         
+
+  // we end the context class with declarations of the action functions
+  dcl << "\n"
+      << "private:\n"
+      << "  USER_ACTION_FUNCTIONS      // see useract.h\n"
+      << "\n"
+      << "  // declare the actual action function\n"
+      << "  static SemanticValue doReductionAction(\n"
+      << "    " << g.actionClassName << " *ths,\n"
+      << "    int productionId, SemanticValue const *semanticValues"
+         SOURCELOC( << ",\n  SourceLoc loc" )
+      << ");\n"
+      << "\n"
+      << "  // declare the classifier function\n"
+      << "  static int reclassifyToken(\n"
+      << "    " << g.actionClassName << " *ths,\n"
+      << "    int oldTokenType, SemanticValue sval);\n"
+      << "\n"
+      ;
+  #endif // 0
+
+  // all that goes into the interface is the name of the
+  // tUserActions and tParseTables objects
+  dcl << "val " << g.actionClassName << "ParseTables: Parsetables.tParseTables\n";
+  dcl << "val " << g.actionClassName << "UserActions: Useract.tUserActions\n";
+
+  EmitCode out(mlFname);
+  if (!out) {
+    throw_XOpen(mlFname);
+  }
+
+  out << "(* " << mlFname << " *)\n";
+  out << "(* *** DO NOT EDIT BY HAND *** *)\n";
+  out << "(* automatically generated by gramanl, from " << srcFname << " *)\n";
+  out << "\n"
+      << "open Useract      (* tSemanticValue *)\n"
+      << "open Parsetables  (* tParseTables *)\n"
+      << "\n"
+      << "\n"
+      ;
+  
+  // stand-alone verbatim sections go into .ml file *also*
+  {FOREACH_OBJLIST(LocString, g.verbatim, iter) {
+    emitMLUserCode(out, *(iter.data()), false /*braces*/);
+  }}
+
+  #if 0   // not implemented and/or not needed
+    #ifdef NO_GLR_SOURCELOC
+      // we need to make sure the USER_ACTION_FUNCTIONS use
+      // the declarations consistent with how we're printing
+      // the definitions
+      out << "#ifndef NO_GLR_SOURCELOC\n";
+      out << "  #define NO_GLR_SOURCELOC\n";
+      out << "#endif\n";
+    #else
+      out << "// GLR source location information is enabled\n";
+    #endif
+    out << "\n";
+    out << "#include \"" << hFname << "\"     // " << g.actionClassName << "\n";
+    out << "#include \"parsetables.h\" // ParseTables\n";
+    out << "#include \"srcloc.h\"      // SourceLoc\n";
+    out << "\n";
+    out << "#include <assert.h>      // assert\n";
+    out << "#include <iostream.h>    // cout\n";
+    out << "#include <stdlib.h>      // abort\n";
+    out << "\n";
+
+    NOSOURCELOC(
+      out << "// parser-originated location information is disabled by\n"
+          << "// NO_GLR_SOURCELOC; any rule which refers to 'loc' will get this one\n"
+          << "static SourceLoc loc = SL_UNKNOWN;\n"
+          << "\n\n";
+    )
+  #endif // 0
+
+  emitMLDescriptions(g, out);
+  // 'emitMLDescriptions' prints two newlines itself..
+
+  // impl_verbatim sections
+  //
+  // 2005-06-23: Moved these to near the top of the file so that
+  // the actions can refer to them.  This is especially important
+  // in OCaml since you can't forward-declare in OCaml (!).
+  FOREACH_OBJLIST(LocString, g.implVerbatim, iter) {
+    emitMLUserCode(out, *(iter.data()), false /*braces*/);
+  }
+
+  emitMLActions(g, out, dcl);
+  out << "\n";
+  out << "\n";
+
+  emitMLDupDelMerge(g, out, dcl);
+  out << "\n";
+  out << "\n";
+
+  // wrap all the action stuff up as a struct
+  out << "let " << g.actionClassName << "UserActions = {\n";
+  #define COPY(name) \
+    out << "  " #name " = " #name "Func;\n";
+  COPY(reductionAction)
+  COPY(duplicateTerminalValue)
+  COPY(duplicateNontermValue)
+  COPY(deallocateTerminalValue)
+  COPY(deallocateNontermValue)
+  COPY(mergeAlternativeParses)
+  COPY(keepNontermValue)
+  COPY(terminalDescription)
+  COPY(nonterminalDescription)
+  COPY(terminalName)
+  COPY(nonterminalName)
+  #undef COPY
+  out << "}\n"
+      << "\n"
+      << "\n"
+      ;
+
+  g.tables->finishTables();
+  g.tables->emitMLConstructionCode(out, string(g.actionClassName), "makeTables");
+
+  #if 0   // not implemented
+    // I put this last in the context class, and make it public
+    dcl << "\n"
+        << "// the function which makes the parse tables\n"
+        << "public:\n"
+        << "  virtual ParseTables *makeTables();\n"
+        << "};\n"
+        << "\n"
+        << "#endif // " << latchName << "\n"
+        ;
+  #endif // 0
+}
+
+
+void emitMLUserCode(EmitCode &out, LocString const &code, bool braces)
+{
+  out << "\n";
+  if (false/*TODO:fix*/ && code.validLoc()) {
+    out << lineDirective(code.loc);
+  }
+
+  // 7/27/03: swapped so that braces are inside the line directive
+  if (braces) {
+    out << "(";
+  }
+
+  out << code;
+
+  // the final brace is on the same line so errors reported at the
+  // last brace go to user code
+  if (braces) {
+    out << " )";
+  }
+
+  if (false/*TODO:fix*/ && code.validLoc()) {
+    out << "\n" << restoreLine;
+  }
+  else {
+    out << "\n";
+  }
+}
+
+
+// bit of a hack: map "void" to "SemanticValue" so that the compiler
+// won't mind when I try to declare parameters of that type
+static char const *notVoid(char const *type)
+{
+  if (0==strcmp(type, "void")) {     // ML: Q: should this now be "unit"?
+    return "tSemanticValue";
+  }
+  else {
+    return type;
+  }
+}
+
+
+// yield the given type, but if it's NULL, then yield
+// something to use instead
+static char const *typeString(char const *type, LocString const &tag)
+{
+  if (!type) {
+    cout << tag.locString() << ": Production tag \"" << tag
+         << "\" on a symbol with no type.\n";
+    return "__error_no_type__";     // will make compiler complain
+  }
+  else {
+    return notVoid(type);
+  }
+}
+
+
+void emitMLDescriptions(GrammarAnalysis const &g, EmitCode &out)
+{
+  // emit a map of terminal ids to their names
+  {
+    out << "let termNamesArray: string array = [|\n";
+    for (int code=0; code < g.numTerminals(); code++) {
+      Terminal const *t = g.getTerminal(code);
+      if (!t) {
+        // no terminal for that code
+        out << "  \"(no terminal)\";  (* " << code << " *)\n";
+      }
+      else {
+        out << "  \"" << t->name << "\";  (* " << code << " *)\n";
+      }
+    }
+    out << "  \"\"   (* dummy final value for ';' separation *)\n"
+        << "|]\n"
+        << "\n";
+  }
+
+  // emit a function to describe terminals; at some point I'd like to
+  // extend my grammar format to allow the user to supply
+  // token-specific description functions, but for now I will just
+  // use the information easily available the synthesize one;
+  // I print "sval % 100000" so I get a 5-digit number, which is
+  // easy for me to compare for equality without adding much clutter
+  //
+  // ML: I could do something like this using Obj, but I'd rather
+  // not abuse that interface unnecessarily.
+  out << "let terminalDescriptionFunc (termId:int) (sval:tSemanticValue) : string =\n"
+      << "begin\n"
+      << "  termNamesArray.(termId)\n"
+      << "end\n"
+      << "\n"
+      << "\n"
+      ;
+
+  // emit a map of nonterminal ids to their names
+  {
+    out << "let nontermNamesArray: string array = [|\n";
+    for (int code=0; code < g.numNonterminals(); code++) {
+      Nonterminal const *nt = g.getNonterminal(code);
+      if (!nt) {
+        // no nonterminal for that code
+        out << "  \"(no nonterminal)\";  (* " << code << " *)\n";
+      }
+      else {
+        out << "  \"" << nt->name << "\";  (* " << code << " *)\n";
+      }
+    }
+    out << "  \"\"   (* dummy final value for ';' separation *)\n"
+        << "|]\n"
+        << "\n";
+  }
+
+  // and a function to describe nonterminals also
+  out << "let nonterminalDescriptionFunc (nontermId:int) (sval:tSemanticValue)\n"
+      << "  : string =\n"
+      << "begin\n"
+      << "  nontermNamesArray.(nontermId)\n"
+      << "end\n"
+      << "\n"
+      << "\n"
+      ;
+
+  // emit functions to get access to the static maps
+  out << "let terminalNameFunc (termId:int) : string =\n"
+      << "begin\n"
+      << "  termNamesArray.(termId)\n"
+      << "end\n"
+      << "\n"
+      << "let nonterminalNameFunc (nontermId:int) : string =\n"
+      << "begin\n"
+      << "  nontermNamesArray.(nontermId)\n"
+      << "end\n"
+      << "\n"
+      << "\n"
+      ;
+}
+
+
+void emitMLActions(Grammar const &g, EmitCode &out, EmitCode &dcl)
+{
+  out << "(* ------------------- actions ------------------ *)\n"
+      << "let reductionActionArray : (tSemanticValue array -> tSemanticValue) array = [|\n"
+      << "\n"
+      ;
+
+  // iterate over productions, emitting action function closures
+  {FOREACH_OBJLIST(Production, g.productions, iter) {
+    Production const &prod = *(iter.data());
+
+    // there's no syntax for a typeless nonterminal, so this shouldn't
+    // be triggerable by the user
+    xassert(prod.left->type);
+
+    // put the production in comments above the defn
+    out << "(* " << prod.toString() << " *)\n";
+
+    out << "(fun svals ->\n";
+
+    // iterate over RHS elements, emitting bindings for each with a tag
+    int index=-1;
+    FOREACH_OBJLIST(Production::RHSElt, prod.right, rhsIter) {
+      Production::RHSElt const &elt = *(rhsIter.data());
+      index++;
+      if (elt.tag.length() == 0) continue;
+
+      // example:
+      //   let e1 = (Obj.obj svals.(0) : int) in
+      out << "  let " << elt.tag << " = (Obj.obj svals.(" << index << ") : "
+          << typeString(elt.sym->type, elt.tag) << ") in\n";
+    }
+    
+    // give a name to the yielded value so we can ensure it conforms to
+    // the declared type
+    out << "  let __result: " << prod.left->type << " =";
+
+    // now insert the user's code, to execute in this environment of
+    // properly-typed semantic values
+    emitMLUserCode(out, prod.action, true /*braces*/);
+
+    out << "  in (Obj.repr __result)\n"     // cast to tSemanticValue
+        << ");\n"
+        << "\n"
+        ;
+  }}
+
+  // finish the array; one dummy element for ';' separation
+  out << "(fun _ -> (failwith \"bad production index\"))   (* no ; *)"
+      << "\n"
+      << "|]\n"
+      << "\n"  
+      ;
+
+  // main action function; uses the array emitted above
+  out << "let reductionActionFunc (productionId:int) (svals: tSemanticValue array)\n"
+      << "  : tSemanticValue =\n"
+      << "begin\n"
+      << "  (reductionActionArray.(productionId) svals)\n"
+      << "end\n"
+      << "\n"
+      ;
+
+
+  #if 0  // shouldn't be needed
+  if (0==strcmp(prod.left->type, "void")) {
+    // cute hack: turn the expression into a comma expression, with
+    // the value returned being 0
+    out << ", 0";
+  }
+  #endif // 0
+}
+
+
+void emitMLDupDelMerge(GrammarAnalysis const &g, EmitCode &out, EmitCode &dcl)
+{
+  out << "(* ---------------- dup/del/merge/keep nonterminals --------------- *)\n"
+      << "\n";
+
+  // emit inlines for dup/del/merge of nonterminals
+  FOREACH_OBJLIST(Nonterminal, g.nonterminals, ntIter) {
+    emitMLDDMInlines(g, out, dcl, *(ntIter.data()));
+  }
+
+  // emit dup-nonterm
+  emitMLSwitchCode(g, out,
+    "let duplicateNontermValueFunc (nontermId:int) (sval:tSemanticValue) : tSemanticValue",
+    "nontermId",
+    (ObjList<Symbol> const&)g.nonterminals,
+    0 /*dupCode*/,
+    "      (Obj.repr (dup_$symName ((Obj.obj sval) : $symType)))\n",
+    NULL);
+
+  // emit del-nonterm
+  emitMLSwitchCode(g, out,
+    "let deallocateNontermValueFunc (nontermId:int) (sval:tSemanticValue) : unit",
+    "nontermId",
+    (ObjList<Symbol> const&)g.nonterminals,
+    1 /*delCode*/,
+    "      (del_$symName ((Obj.obj sval) : $symType));\n",
+    "deallocate nonterm");
+
+  // emit merge-nonterm
+  emitMLSwitchCode(g, out,
+    "let mergeAlternativeParsesFunc (nontermId:int) (left:tSemanticValue)\n"
+    "                               (right:tSemanticValue) : tSemanticValue",
+    // SOURCELOC?
+    "nontermId",
+    (ObjList<Symbol> const&)g.nonterminals,
+    2 /*mergeCode*/,
+    "      (Obj.repr (merge_$symName ((Obj.obj left) : $symType) ((Obj.obj right) : $symType)))\n",
+    "merge nonterm");
+
+  // emit keep-nonterm
+  emitMLSwitchCode(g, out,
+    "let keepNontermValueFunc (nontermId:int) (sval:tSemanticValue) : bool",
+    "nontermId",
+    (ObjList<Symbol> const&)g.nonterminals,
+    3 /*keepCode*/,
+    "      (keep_$symName ((Obj.obj sval) : $symType))\n",
+    NULL);
+
+
+  out << "\n";
+  out << "(* ---------------- dup/del/classify terminals --------------- *)";
+  // emit inlines for dup/del of terminals
+  FOREACH_OBJLIST(Terminal, g.terminals, termIter) {
+    emitMLDDMInlines(g, out, dcl, *(termIter.data()));
+  }
+
+  // emit dup-term
+  emitMLSwitchCode(g, out,
+    "let duplicateTerminalValueFunc (termId:int) (sval:tSemanticValue) : tSemanticValue",
+    "termId",
+    (ObjList<Symbol> const&)g.terminals,
+    0 /*dupCode*/,
+    "      (Obj.repr (dup_$symName ((Obj.obj sval) : $symType)))\n",
+    NULL);
+
+  // emit del-term
+  emitMLSwitchCode(g, out,
+    "let deallocateTerminalValueFunc (termId:int) (sval:tSemanticValue) : unit",
+    "termId",
+    (ObjList<Symbol> const&)g.terminals,
+    1 /*delCode*/,
+    "      (del_$symName ((Obj.obj sval) : $symType));\n",
+    "deallocate terminal");
+
+  // emit classify-term
+  emitMLSwitchCode(g, out,
+    "let reclassifyTokenFunc (oldTokenType:int) (sval:tSemanticValue) : int",
+    "oldTokenType",
+    (ObjList<Symbol> const&)g.terminals,
+    4 /*classifyCode*/,
+    "      (classify_$symName ((Obj.obj sval) : $symType))\n",
+    NULL);
+}
+
+
+// emit both the function decl for the .h file, and the beginning of
+// the function definition for the .cc file
+void emitMLFuncDecl(Grammar const &g, EmitCode &out, EmitCode &dcl,
+                    char const *rettype, char const *params)
+{
+  out << "(*inline*) let " << params << ": " << rettype << " =";
+}
+
+
+void emitMLDDMInlines(Grammar const &g, EmitCode &out, EmitCode &dcl,
+                      Symbol const &sym)
+{
+  Terminal const *term = sym.ifTerminalC();
+  Nonterminal const *nonterm = sym.ifNonterminalC();
+
+  if (sym.dupCode) {
+    emitMLFuncDecl(g, out, dcl, sym.type,
+      stringc << "dup_" << sym.name
+              << " (" << sym.dupParam << ": " << sym.type << ") ");
+    emitMLUserCode(out, sym.dupCode);
+    out << "\n";
+  }
+
+  if (sym.delCode) {
+    emitMLFuncDecl(g, out, dcl, "unit",
+      stringc << "del_" << sym.name
+              << " (" << (sym.delParam? sym.delParam : "_")
+              << ": " << sym.type << ") ");
+    emitMLUserCode(out, sym.delCode);
+    out << "\n";
+  }
+
+  if (nonterm && nonterm->mergeCode) {
+    emitMLFuncDecl(g, out, dcl, notVoid(sym.type),
+      stringc << "merge_" << sym.name
+              << " (" << nonterm->mergeParam1 << ": " << notVoid(sym.type) << ") "
+              << " (" << nonterm->mergeParam2 << ": " << notVoid(sym.type) << ") ");
+    emitMLUserCode(out, nonterm->mergeCode);
+    out << "\n";
+  }
+
+  if (nonterm && nonterm->keepCode) {
+    emitMLFuncDecl(g, out, dcl, "bool",
+      stringc << "keep_" << sym.name
+              << " (" << nonterm->keepParam << ": " << sym.type << ") ");
+    emitMLUserCode(out, nonterm->keepCode);
+    out << "\n";
+  }
+
+  if (term && term->classifyCode) {
+    emitMLFuncDecl(g, out, dcl, "int",
+      stringc << "classify_" << sym.name
+              << " (" << term->classifyParam << ": " << sym.type << ") ");
+    emitMLUserCode(out, term->classifyCode);
+    out << "\n";
+  }
+}
+
+void emitMLSwitchCode(Grammar const &g, EmitCode &out,
+                      rostring signature, char const *switchVar,
+                      ObjList<Symbol> const &syms, int whichFunc,
+                      char const *templateCode, char const *actUpon)
+{
+  out << replace(signature, "$acn", string(g.actionClassName)) << " =\n"
+         "begin\n"
+         "  match " << switchVar << " with\n"
+         ;
+
+  FOREACH_OBJLIST(Symbol, syms, symIter) {
+    Symbol const &sym = *(symIter.data());
+
+    if (whichFunc==0 && sym.dupCode ||
+        whichFunc==1 && sym.delCode ||
+        whichFunc==2 && sym.asNonterminalC().mergeCode ||
+        whichFunc==3 && sym.asNonterminalC().keepCode ||
+        whichFunc==4 && sym.asTerminalC().classifyCode) {
+      out << "  | " << sym.getTermOrNontermIndex() << " -> (\n";
+      out << replace(replace(templateCode,
+               "$symName", string(sym.name)),
+               "$symType", notVoid(sym.type));
+      out << "    )\n";
+    }
+  }
+
+  out << "  | _ -> (\n";
+  switch (whichFunc) {
+    default:
+      xfailure("bad func code");
+
+    // in ML it's not such a good idea to yield cNULL_SVAL, since the
+    // runtime engine might get more confused than a C program
+    // with a NULL pointer.. so always do the gc-defaults thing
+
+    case 0:    // unspecified dup
+      out << "      sval\n";
+      break;
+
+    case 1:    // unspecified del
+      // ignore del
+      out << "      ()\n";
+      break;
+
+    case 2:    // unspecified merge: warn, but then use left (arbitrarily)
+      out << "      (Printf.printf \"WARNING: no action to merge nonterm %s\\n\"\n"
+          << "                     nontermNamesArray.(" << switchVar << "));\n"
+          << "      (flush stdout);\n"
+          << "      left\n"
+          ;
+      break;
+
+    case 3:    // unspecified keep: keep it
+      out << "      true\n";
+      break;
+
+    case 4:    // unspecified classifier: identity map
+      out << "      oldTokenType\n";
+      break;
+  }
+
+  out << "    )\n"
+         "end\n"
+         "\n";
+}
+
+
+// ----------------- second half: table emission ------------------
+// create literal tables
+template <class EltType>
+void emitMLTable(EmitCode &out, EltType const *table, int size, int rowLength,
+                 char const *tableName)
+{
+  if (!table || !size) {
+    out << "  " << tableName << " = [| |];      (* 0 elements *)\n"
+        << "\n"
+        ;
+    return;
+  }
+
+  bool printHex = false;
+  #if 0   // not needed?
+                  0==strcmp(typeName, "ErrorBitsEntry") ||
+                  (ENABLE_CRS_COMPRESSION && 0==strcmp(typeName, "ActionEntry")) ||
+                  (ENABLE_CRS_COMPRESSION && 0==strcmp(typeName, "GotoEntry")) ;
+  bool needCast = 0==strcmp(typeName, "StateId");
+  #endif // 0
+
+  if (size * sizeof(*table) > 50) {    // suppress small ones
+    //out << "  // storage size: " << size * sizeof(*table) << " bytes\n";
+    if (size % rowLength == 0) {
+      out << "  (* rows: " << (size/rowLength) << "  cols: " << rowLength << " *)\n";
+    }
+  }
+
+  int rowNumWidth = stringf("%d", size / rowLength /*round down*/).length();
+
+  out << "  " << tableName << " = [|           (* " << size << " elements *)";
+  int row = 0;
+  for (int i=0; i<size; i++) {
+    if (i % rowLength == 0) {    // one row per state
+      out << stringf("\n    (*%*d*) ", rowNumWidth, row++);
+    }
+
+    #if 0
+    if (needCast) {
+      out << "(" << typeName << ")";           // ML: not used
+    }    
+    #endif // 0
+
+    if (printHex) {
+      out << stringf("0x%02X", table[i]);    // ML: not used
+    }
+    else if (sizeof(table[i]) == 1) {
+      // little bit of a hack to make sure 'unsigned char' gets
+      // printed as an int; the casts are necessary because this
+      // code gets compiled even when EltType is ProdInfo
+      out << (int)(*((unsigned char*)(table+i)));
+    }
+    else {
+      // print the other int-sized things, or ProdInfo using
+      // the overloaded '<<' below
+      out << table[i];
+    }
+
+    if (i != size-1) {
+      out << "; ";
+    }
+  }
+  out << "\n"
+      << "  |];\n"
+      << "\n"
+      ;
+}
+
+#if 0   // not used
+// used to emit the elements of the prodInfo table
+stringBuilder& operator<< (stringBuilder &sb, ParseTables::ProdInfo const &info)
+{
+  sb << "{" << (int)info.rhsLen << "," << (int)info.lhsIndex << "}";
+  return sb;
+}
+
+
+// like 'emitTable', but also set a local called 'tableName'
+template <class EltType>
+void emitMLTable2(EmitCode &out, EltType const *table, int size, int rowLength,
+                  char const *typeName, char const *tableName)
+{
+  string tempName = stringc << tableName << "_static";
+  emitMLTable(out, table, size, rowLength, typeName, tempName);
+  out << "  " << tableName << " = const_cast<" << typeName << "*>("
+      << tempName << ");\n\n";
+}
+
+
+template <class EltType>
+void emitMLOffsetTable(EmitCode &out, EltType **table, EltType *base, int size,
+                       char const *typeName, char const *tableName, char const *baseName)
+{
+  if (!table) {
+    out << "  " << tableName << " = NULL;\n\n";
+    return;
+  }
+
+  // make the pointers persist by storing a table of offsets
+  Array<int> offsets(size);
+  bool allUnassigned = true;
+  for (int i=0; i < size; i++) {
+    if (table[i]) {
+      offsets[i] = table[i] - base;
+      allUnassigned = false;
+    }
+    else {
+      offsets[i] = UNASSIGNED;    // codes for a NULL entry
+    }
+  }
+
+  if (allUnassigned) {
+    // for example, an LALR(1) grammar has no ambiguous entries in its tables
+    size = 0;
+  }
+
+  if (size > 0) {
+    out << "  " << tableName << " = new " << typeName << " [" << size << "];\n";
+
+    emitTable(out, (int*)offsets, size, 16, "int", stringc << tableName << "_offsets");
+
+    // at run time, interpret the offsets table
+    out << "  for (int i=0; i < " << size << "; i++) {\n"
+        << "    int ofs = " << tableName << "_offsets[i];\n"
+        << "    if (ofs >= 0) {\n"
+        << "      " << tableName << "[i] = " << baseName << " + ofs;\n"
+        << "    }\n"
+        << "    else {\n"
+        << "      " << tableName << "[i] = NULL;\n"
+        << "    }\n"
+        << "  }\n\n";
+  }
+  else {
+    out << "  // offset table is empty\n"
+        << "  " << tableName << " = NULL;\n\n";
+  }
+}
+
+
+// for debugging
+template <class EltType>
+void printMLTable(EltType const *table, int size, int rowLength,
+                  char const *typeName, char const *tableName)
+{
+  // disabled for now since I don't need it anymore, and it adds
+  // a link dependency on emitcode.cc ...
+  #if 0
+  {
+    EmitCode out("printTable.tmp");
+    emitTable(out, table, size, rowLength, typeName, tableName);
+  }
+
+  system("cat printTable.tmp; rm printTable.tmp");
+  #endif // 0
+}
+#endif // 0
+
+
+// emit code for a function which, when compiled and executed, will
+// construct this same table (except the constructed table won't own
+// the table data, since it will point to static program data)
+void ParseTables::emitMLConstructionCode
+  (EmitCode &out, rostring className, rostring funcName)
+{
+  // must have already called 'finishTables'
+  xassert(!temp);
+
+  out << "(* a literal tParseTables;\n"
+      << " * the code is written by ParseTables::emitConstructionCode()\n"
+      << " * in " << __FILE__ << " *)\n"
+      << "let " << className << "ParseTables:tParseTables = {\n";
+      ;
+
+  #define SET_VAR(var) \
+    out << "  " #var " = " << var << ";\n";
+
+  SET_VAR(numTerms);
+  SET_VAR(numNonterms);
+  SET_VAR(numProds);
+  out << "\n";
+
+  SET_VAR(numStates);
+  out << "\n";
+
+  SET_VAR(actionCols);
+  emitMLTable(out, actionTable, actionTableSize(),
+              actionCols, "actionTable");
+
+  SET_VAR(gotoCols);
+  emitMLTable(out, gotoTable, gotoTableSize(),
+              gotoCols, "gotoTable");
+
+  // break the prodInfo into two arrays
+  {
+    Array<int> rhsLen(numProds);
+    Array<int> lhsIndex(numProds);
+
+    for (int i=0; i < numProds; i++) {
+      rhsLen[i] = prodInfo[i].rhsLen;
+      lhsIndex[i] = prodInfo[i].lhsIndex;
+    }
+
+    emitMLTable(out, rhsLen.operator int const *(), numProds,
+                16 /*columns; arbitrary*/, "prodInfo_rhsLen");
+    emitMLTable(out, lhsIndex.operator int const *(), numProds,
+                16 /*columns; arbitrary*/, "prodInfo_lhsIndex");
+  }
+
+  emitMLTable(out, stateSymbol, numStates,
+              16, "stateSymbol");
+              
+  SET_VAR(ambigTableSize);
+  emitMLTable(out, ambigTable, ambigTableSize,
+              16, "ambigTable");
+              
+  emitMLTable(out, nontermOrder, nontermOrderSize(),
+              16, "nontermOrder");
+
+  SET_VAR(startState);                                              
+  
+  // no semicolon for last one
+  out << "  finalProductionIndex = " << finalProductionIndex << "\n";
+  
+  out << "}\n"
+      << "\n"
+      ;
+}
+
+
+// EOF

Added: vendor/elsa/current/elkhound/genml.h
===================================================================
--- vendor/elsa/current/elkhound/genml.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/genml.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// genml.h            see license.txt for copyright and terms of use
+// extension to gramanl module that generates ML instead of C
+
+#ifndef GENML_H
+#define GENML_H
+
+#include "str.h"      // rostring
+
+class GrammarAnalysis;
+
+// entry point
+void emitMLActionCode(GrammarAnalysis const &g, rostring mliFname,
+                      rostring mlFname, rostring srcFname);
+
+#endif // GENML_H

Added: vendor/elsa/current/elkhound/glr.cc
===================================================================
--- vendor/elsa/current/elkhound/glr.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/glr.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2496 @@
+// glr.cc            see license.txt for copyright and terms of use
+// code for glr.h
+
+/* Implementation Notes
+ *
+ * A design point: [GLR] uses more 'global's than I do.  My criteria
+ * here is that something should be global (stored in class GLR) if
+ * it has meaning between processing of tokens.  If something is only
+ * used during the processing of a single token, then I make it a
+ * parameter where necessary.
+ *
+ * Update: I've decided to make 'currentToken' and 'parserWorklist'
+ * global because they are needed deep inside of 'glrShiftNonterminal',
+ * though they are not needed by the intervening levels, and their
+ * presence in the argument lists would therefore only clutter them.
+ *
+ * (OLD) It should be clear that many factors contribute to this
+ * implementation being slow, and I'm going to refrain from any
+ * optimization for a bit.
+ *
+ * UPDATE (3/29/02): I'm now trying to optimize it.  The starting
+ * implementation is 300x slower than bison.  Ideal goal is 3x, but
+ * more realistic is 10x.
+ *
+ * UPDATE (8/24/02): It's very fast now; within 3% of Bison for
+ * deterministic grammars, and 5x when I disable the mini-LR core.
+ *
+ * Description of the various lists in play here:
+ *
+ *   topmostParsers
+ *   --------------
+ *   The active parsers are at the frontier of the parse tree
+ *   space.  It *never* contains more than one stack node with
+ *   a given parse state; I call this the unique-state property
+ *   (USP).  If we're about to add a stack node with the same
+ *   state as an existing node, we merge them (if it's a shift,
+ *   we add another leftAdjState; if it's a reduction, we add a
+ *   rule node *and* another leftAdjState).
+ *
+ *   Before a token is processed, topmostParsers contains those
+ *   parsers that successfully shifted the previous token.  This
+ *   list is then walked to make the initial reduction worklist.
+ *
+ *   Before the shifts are processed, the topmostParsers list is
+ *   cleared.  As each shift is processed, the resulting parser is
+ *   added to topmostParsers (modulo USP).
+ *
+ *   [GLR] calls this "active-parsers"
+ *
+ * 
+ * Discussion of path re-examination, called do-limited-reductions by
+ * [GLR]:
+ *
+ * After thinking about this for some time, I have reached the conclusion
+ * that the only way to handle the problem is to separate the collection
+ * of paths from the iteration over them.
+ *
+ * Here are several alternative schemes, and the reasons they don't
+ * work:
+ *
+ *   1. [GLR]'s approach of limiting re-examination to those involving
+ *      the new link
+ *
+ *      This fails because it does not prevent re-examined paths
+ *      from appearing in the normal iteration also.
+ *
+ *   2. Modify [GLR] so the new link can't be used after the re-examination
+ *      is complete
+ *
+ *      Then if *another* new link is added, paths involving both new
+ *      links wouldn't be processed.
+ *
+ *   3. Further schemes involving controlling which re-examination stage can
+ *      use which links
+ *
+ *      Difficult to reason about, unclear a correct scheme exists, short
+ *      of the full-blown path-listing approach I'm going to take.
+ *
+ *   4. My first "fix" which assumes there is never more than one path to
+ *      a given parser
+ *
+ *      This is WRONG.  There can be more than one path, even as all such
+ *      paths are labeled the same (namely, with the RHS symbols).  Consider
+ *      grammar "E -> x | E + E" parsing "x+x+x": both toplevel parses use
+ *      the "E -> E + E" rule, and both arrive at the root parser
+ *
+ * So, the solution I will implement is to collect all paths into a list
+ * before processing any of them.  During path re-examination, I also will
+ * collect paths into a list, this time only those that involve the new
+ * link.
+ *
+ * This scheme is clearly correct, since path collection cannot be disrupted
+ * by the process of adding links, and when links are added, exactly the new
+ * paths are collected and processed.  It's easy to see that every path is
+ * considered exactly once.
+ *
+ *
+ * MAJOR UPDATE (12/06/02):  I've replaced the state worklist (SWL) core
+ * used in all previous GLR implementations with a reduction worklist (RWL)
+ * core.  This core is just as fast, but can be implemented to always
+ * avoid the yield-then-merge problem for acyclic grammars.
+ *
+ *
+ * Below, parse-tree building activity is marked "TREEBUILD".
+ */
+
+
+#include "glr.h"         // this module
+#include "strtokp.h"     // StrtokParse
+#include "syserr.h"      // xsyserror
+#include "trace.h"       // tracing system
+#include "strutil.h"     // replace
+#include "lexerint.h"    // LexerInterface
+#include "test.h"        // PVAL
+#include "cyctimer.h"    // CycleTimer
+#include "sobjlist.h"    // SObjList
+#include "owner.h"       // Owner
+
+#include <stdio.h>       // FILE
+#include <stdlib.h>      // getenv
+
+// ACTION(..) is code to execute for action trace diagnostics, i.e. "-tr action"
+#ifndef ACTION_TRACE
+  #define ACTION_TRACE 0
+#endif
+#if ACTION_TRACE
+  #define ACTION(stmt) stmt
+  #define TRSACTION(stuff) if (tracingSys("action")) { cout << stuff << endl; }
+#else
+  #define ACTION(stmt)
+  #define TRSACTION(stuff)
+#endif
+
+// TRSPARSE(stuff) traces <stuff> during debugging with -tr parse
+#if !defined(NDEBUG)
+  #define IF_NDEBUG(stuff)
+  #define TRSPARSE(stuff) if (trParse) { trsParse << stuff << endl; }
+  #define TRSPARSE_DECL(stuff) stuff
+#else
+  #define IF_NDEBUG(stuff) stuff
+  #define TRSPARSE(stuff)
+  #define TRSPARSE_DECL(stuff)
+#endif
+
+// whether to use the ordinary LR core in addition to the GLR core
+#ifndef USE_MINI_LR
+  #define USE_MINI_LR 1
+#endif
+
+// these disable features of mini-LR for performance testing
+#ifndef USE_ACTIONS
+  #define USE_ACTIONS 1
+#endif
+#ifndef USE_RECLASSIFY
+  #define USE_RECLASSIFY 1
+#endif
+#ifndef USE_KEEP
+  #define USE_KEEP 1
+#endif
+
+// enables tracking of some statistics useful for debugging and profiling
+#ifndef DO_ACCOUNTING
+  #define DO_ACCOUNTING 1
+#endif
+#if DO_ACCOUNTING
+  #define ACCOUNTING(stuff) stuff
+#else
+  #define ACCOUNTING(stuff)
+#endif
+
+// unroll the inner loop; approx. 3% performance improvement
+// update: right now, it actually *costs* about 8%..
+#ifndef USE_UNROLLED_REDUCE
+  #define USE_UNROLLED_REDUCE 0
+#endif
+
+// some things we track..
+int parserMerges = 0;
+int computeDepthIters = 0;
+int totalExtracts = 0;
+int multipleDelayedExtracts = 0;
+
+// can turn this on to experiment.. but right now it
+// actually makes things slower.. (!)
+//#define USE_PARSER_INDEX
+
+
+// Note on inlining generally: Inlining functions is a very important
+// way to improve performance, in inner loops.  However it's easy to
+// guess wrong about where and what to inline.  So generally I mark
+// things as inline whenver the profiler (gprof) reports:
+//   - it's showing up in gprof as a function call (i.e. not already
+//     being inlined)
+//   - the function that calls it takes significant time
+//   - the call itself takes significant time
+// All this is obvious, but is worth saying, since otherwise the
+// tendency is to inline everything, which is a mistake because it
+// makes the system as a whole slower (by wasting space in the I-cache)
+// without leaving a clear indicator of who is to blame (it's very
+// hard to profile for over-aggressive inlining).
+
+
+// the transition to array-based implementations requires I specify
+// initial sizes
+enum {
+  // this one does *not* grow as needed (at least not in the mini-LR core)
+  MAX_RHSLEN = 30,
+
+  // ----------
+  // the settings below here are for initial sizes of growable arrays,
+  // and it should be ok in terms of correctness to set them all to 1,
+  // which may be a useful thing during debugging to verify
+
+  // this one grows as needed
+  TYPICAL_MAX_REDUCTION_PATHS = 5,
+
+  // this is the length to make arrays which hold rhsLen many items
+  // typically, but are growable
+  INITIAL_RHSLEN_SIZE = 10,
+};
+
+
+// ------------- front ends to user code ---------------
+// given a symbol id (terminal or nonterminal), and its associated
+// semantic value, yield a description string
+string symbolDescription(SymbolId sym, UserActions *user, 
+                         SemanticValue sval)
+{
+  if (symIsTerm(sym)) {
+    return user->terminalDescription(symAsTerm(sym), sval);
+  }
+  else {
+    return user->nonterminalDescription(symAsNonterm(sym), sval);
+  }
+}
+
+SemanticValue GLR::duplicateSemanticValue(SymbolId sym, SemanticValue sval)
+{
+  xassert(sym != 0);
+  
+  // 6/23/04: Why did I do this?  Some kind of optimization?  It should
+  // at least be documented... and probably removed altogether.
+  if (!sval) return sval;
+
+  SemanticValue ret;
+  if (symIsTerm(sym)) {
+    ret = userAct->duplicateTerminalValue(symAsTerm(sym), sval);
+  }
+  else {
+    ret = userAct->duplicateNontermValue(symAsNonterm(sym), sval);
+  }
+
+  TRSACTION("  " << symbolDescription(sym, userAct, ret) <<
+            " is DUP of " <<
+            symbolDescription(sym, userAct, sval));
+
+  return ret;
+}
+
+void deallocateSemanticValue(SymbolId sym, UserActions *user,
+                             SemanticValue sval)
+{
+  xassert(sym != 0);
+  TRSACTION("  DEL " << symbolDescription(sym, user, sval));
+
+  if (!sval) return;
+
+  if (symIsTerm(sym)) {
+    return user->deallocateTerminalValue(symAsTerm(sym), sval);
+  }
+  else {
+    return user->deallocateNontermValue(symAsNonterm(sym), sval);
+  }
+}
+
+void GLR::deallocateSemanticValue(SymbolId sym, SemanticValue sval)
+{
+  ::deallocateSemanticValue(sym, userAct, sval);
+}
+
+
+// ------------------ SiblingLink ------------------
+inline SiblingLink::SiblingLink(StackNode *s, SemanticValue sv
+                                SOURCELOCARG( SourceLoc L ) )
+  : sib(s), sval(sv)
+    SOURCELOCARG( loc(L) )
+{
+  YIELD_COUNT( yieldCount = 0; )
+}
+
+SiblingLink::~SiblingLink()
+{}
+
+
+// ----------------------- StackNode -----------------------
+int StackNode::numStackNodesAllocd=0;
+int StackNode::maxStackNodesAllocd=0;
+
+
+StackNode::StackNode()
+  : state(STATE_INVALID),
+    leftSiblings(),
+    firstSib(NULL, NULL_SVAL  SOURCELOCARG( SL_UNKNOWN ) ),
+    referenceCount(0),
+    determinDepth(0),
+    glr(NULL)
+{
+  // the interesting stuff happens in init()
+}
+
+StackNode::~StackNode()
+{
+  // the interesting stuff happens in deinit()
+}
+
+
+inline void StackNode::init(StateId st, GLR *g)
+{
+  state = st;
+  xassertdb(leftSiblings.isEmpty());
+  xassertdb(hasZeroSiblings());
+  referenceCount = 0;
+  determinDepth = 1;    // 0 siblings now, so this node is unambiguous
+  glr = g;
+
+  #if DO_ACCOUNTING
+    INC_HIGH_WATER(numStackNodesAllocd, maxStackNodesAllocd);
+    //TRACE("nodes", "(!!!) init stack node: num=" << numStackNodesAllocd
+    //            << ", max=" << maxStackNodesAllocd);
+  #endif
+}
+
+inline void StackNode::decrementAllocCounter()
+{
+  #if DO_ACCOUNTING
+    numStackNodesAllocd--;
+    //TRACE("nodes", "(...) deinit stack node: num=" << numStackNodesAllocd
+    //            << ", max=" << maxStackNodesAllocd);
+  #endif
+}
+
+inline void StackNode::deinit()
+{
+  decrementAllocCounter();
+
+  if (!unwinding()) {
+    xassert(numStackNodesAllocd >= 0);
+    xassert(referenceCount == 0);
+  }
+
+  deallocSemanticValues();
+
+  // this is pulled out of 'deallocSemanticValues' since dSV gets
+  // called from the mini-LR parser, which sets this to NULL itself
+  // (and circumvents the refct decrement)
+  firstSib.sib = NULL;
+}
+
+inline SymbolId StackNode::getSymbolC() const
+{
+  xassertdb((unsigned)state < (unsigned)(glr->tables->getNumStates()));
+  return glr->tables->getStateSymbol(state);
+}
+
+
+
+void StackNode::deallocSemanticValues()
+{
+  // explicitly deallocate siblings, so I can deallocate their
+  // semantic values if necessary (this requires knowing the
+  // associated symbol, which the SiblingLinks don't know)
+  if (firstSib.sib != NULL) {
+    deallocateSemanticValue(getSymbolC(), glr->userAct, firstSib.sval);
+  }
+
+  while (leftSiblings.isNotEmpty()) {
+    Owner<SiblingLink> sib(leftSiblings.removeAt(0));
+    deallocateSemanticValue(getSymbolC(), glr->userAct, sib->sval);
+  }
+}
+
+
+// add the very first sibling
+inline void StackNode
+  ::addFirstSiblingLink_noRefCt(StackNode *leftSib, SemanticValue sval
+                                SOURCELOCARG( SourceLoc loc ) )
+{
+  xassertdb(hasZeroSiblings());
+
+  // my depth will be my new sibling's depth, plus 1
+  determinDepth = leftSib->determinDepth + 1;
+
+  // we don't have any siblings yet; use embedded
+  // don't update reference count of 'leftSib', instead caller must do so
+  //firstSib.sib = leftSib;
+  xassertdb(firstSib.sib == NULL);      // otherwise we'd miss a decRefCt
+  firstSib.sib.setWithoutUpdateRefct(leftSib);
+
+  firstSib.sval = sval;
+
+  // initialize some other fields
+  SOURCELOC( firstSib.loc = loc; )
+  YIELD_COUNT( firstSib.yieldCount = 0; )
+}
+
+
+// add a new sibling by creating a new link
+inline SiblingLink *StackNode::
+  addSiblingLink(StackNode *leftSib, SemanticValue sval
+                 SOURCELOCARG( SourceLoc loc ) )
+{
+  if (hasZeroSiblings()) {
+    addFirstSiblingLink_noRefCt(leftSib, sval  SOURCELOCARG( loc ) );
+
+    // manually increment leftSib's refct
+    leftSib->incRefCt();
+
+    // sibling link pointers are used to control the reduction
+    // process in certain corner cases; an interior pointer
+    // should work fine
+    return &firstSib;
+  }
+  else {
+    // as best I can tell, x86 static branch prediction is simply
+    // "conditional forward branches are assumed not taken", hence
+    // the uncommon case belongs in the 'else' branch
+    return addAdditionalSiblingLink(leftSib, sval  SOURCELOCARG( loc ) );
+  }
+}
+
+
+// pulled out of 'addSiblingLink' so I can inline addSiblingLink
+// without excessive object code bloat; the branch represented by
+// the code in this function is much less common
+SiblingLink *StackNode::
+  addAdditionalSiblingLink(StackNode *leftSib, SemanticValue sval
+                           SOURCELOCARG( SourceLoc loc ) )
+{
+  // there's currently at least one sibling, and now we're adding another;
+  // right now, no other stack node should point at this one (if it does,
+  // most likely will catch that when we use the stale info)
+  determinDepth = 0;
+
+  SiblingLink *link = new SiblingLink(leftSib, sval  SOURCELOCARG( loc ) );
+  leftSiblings.prepend(link);   // dsw: don't append; it becomes quadratic!
+  return link;
+}
+
+
+// inlined for the GLR part; mini-LR doesn't use this directly;
+// gcc will inline the first level, even though it's recursive,
+// and the effect is significant (~10%) for GLR-only parser
+inline void StackNode::decRefCt()
+{
+  xassert(referenceCount > 0);
+  
+  //printf("decrementing node %d to %d\n", state, referenceCount-1);
+
+  if (--referenceCount == 0) {
+    glr->stackNodePool->dealloc(this);
+  }
+}
+
+
+SiblingLink const *StackNode::getUniqueLinkC() const
+{
+  xassert(hasOneSibling());
+  return &firstSib;
+}
+
+
+SiblingLink *StackNode::getLinkTo(StackNode *another)
+{
+  // check first..
+  if (firstSib.sib == another) {
+    return &firstSib;
+  }
+
+  // check rest
+  MUTATE_EACH_OBJLIST(SiblingLink, leftSiblings, sibIter) {
+    SiblingLink *candidate = sibIter.data();
+    if (candidate->sib == another) {
+      return candidate;
+    }
+  }
+  return NULL;
+}
+
+
+STATICDEF void StackNode::printAllocStats()
+{
+  cout << "stack nodes: " << numStackNodesAllocd
+       << ", max stack nodes: " << maxStackNodesAllocd
+       << endl;
+}
+
+
+int StackNode::computeDeterminDepth() const
+{
+  if (hasZeroSiblings()) {
+    return 1;
+  }
+  else if (hasOneSibling()) {
+    // it must be equal to sibling's, plus one
+    return firstSib.sib->determinDepth + 1;
+  }
+  else {
+    xassert(hasMultipleSiblings());
+    return 0;
+  }
+}
+
+
+// I sprinkle calls to this here and there; in NDEBUG mode
+// they'll all disappear
+inline void StackNode::checkLocalInvariants() const
+{
+  xassertdb(computeDeterminDepth() == determinDepth);
+}
+
+
+// ------------- stack node list ops ----------------
+void decParserList(ArrayStack<StackNode*> &list)
+{
+  for (int i=0; i < list.length(); i++) {
+    list[i]->decRefCt();
+  }
+}
+
+void incParserList(ArrayStack<StackNode*> &list)
+{
+  for (int i=0; i < list.length(); i++) {
+    list[i]->incRefCt();
+  }
+}
+
+// candidate for adding to ArrayStack.. but I'm hesitant for some reason
+bool parserListContains(ArrayStack<StackNode*> &list, StackNode *node)
+{
+  for (int i=0; i < list.length(); i++) {
+    if (list[i] == node) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// ------------------------- GLR ---------------------------
+GLR::GLR(UserActions *user, ParseTables *t)
+  : userAct(user),
+    tables(t),
+    lexerPtr(NULL),
+    topmostParsers(),
+    parserIndex(NULL),
+    toPass(MAX_RHSLEN),
+    prevTopmost(),
+    stackNodePool(NULL),
+    pathQueue(t),
+    noisyFailedParse(true),
+    trParse(tracingSys("parse")),
+    trsParse(trace("parse") << "parse tracing enabled\n"),
+    detShift(0),
+    detReduce(0),
+    nondetShift(0),
+    nondetReduce(0),
+    yieldThenMergeCt(0)
+  // some fields (re-)initialized by 'clearAllStackNodes'
+{
+  // originally I had this inside glrParse() itself, but that
+  // made it 25% slower!  gcc register allocator again!
+  if (tracingSys("glrConfig")) {
+    printConfig();
+  }
+
+  // the ordinary GLR core doesn't have this limitation because
+  // it uses a growable array
+  #if USE_MINI_LR
+    // make sure none of the productions have right-hand sides
+    // that are too long; I think it's worth doing an iteration
+    // here since going over the limit would be really hard to
+    // debug, and this ctor is of course outside the main
+    // parsing loop
+    for (int i=0; i < tables->getNumProds(); i++) {
+      if (tables->getProdInfo(i).rhsLen > MAX_RHSLEN) {
+        printf("Production %d contains %d right-hand side symbols,\n"
+               "but the GLR core has been compiled with a limit of %d.\n"
+               "Please adjust MAX_RHSLEN and recompile the GLR core.\n",
+               i, tables->getProdInfo(i).rhsLen, MAX_RHSLEN);
+        xfailure("cannot continue");
+      }
+    }
+  #endif // USE_MINI_LR
+
+  // check that the parse tables' compression (if any) is the same
+  // as this core expects
+  configCheck("EEF compression", ENABLE_EEF_COMPRESSION, tables->eef_enabled());
+  configCheck("GCS compression", ENABLE_GCS_COMPRESSION, tables->gcs_enabled());
+  configCheck("GCS column compression", ENABLE_GCS_COLUMN_COMPRESSION, tables->gcsc_enabled());
+  configCheck("CRS compression", ENABLE_CRS_COMPRESSION, tables->crs_enabled());
+}
+
+void GLR::configCheck(char const *option, bool core, bool table)
+{
+  if (core != table) {
+    xfailure(stringc
+      << "The GLR parser core was compiled with " << option
+      << (core? " enabled" : " disabled")
+      << ", but the parse tables generated by Elkhound have it "
+      << (table? "enabled" : "disabled"));
+  }
+}
+
+GLR::~GLR()
+{
+  if (parserIndex) {
+    delete[] parserIndex;
+  }
+
+  // NOTE: must not delete 'tables' until after the 'decParserList'
+  // calls above, because they refer to the tables!
+}
+
+
+void GLR::clearAllStackNodes()
+{
+  // the stack nodes themselves are now reference counted, so they
+  // should already be cleared if we're between parses (modulo
+  // creation of cycles, which I currently just ignore and allow to
+  // leak..)
+}
+
+
+// print compile-time configuration; this is useful for making
+// sure a given binary has been compiled the way you think
+void GLR::printConfig() const
+{
+  printf("GLR configuration follows.  Settings marked with an\n"
+         "asterisk (*) are the higher-performance settings.\n");
+
+  printf("  source location information: \t\t\t%s\n",
+         SOURCELOC(1+)0? "enabled" : "disabled *");
+
+  printf("  stack node columns: \t\t\t\t%s\n",
+         NODE_COLUMN(1+)0? "enabled" : "disabled *");
+
+  printf("  semantic value yield count: \t\t\t%s\n",
+         YIELD_COUNT(1+)0? "enabled" : "disabled *");
+
+  printf("  ACTION_TRACE (for debugging): \t\t%s\n",
+         ACTION(1+)0? "enabled" : "disabled *");
+
+  printf("  NDEBUG: \t\t\t\t\t%s\n",
+         IF_NDEBUG(1+)0? "set      *" : "not set");
+
+  printf("  xassert-style assertions: \t\t\t%s\n",
+         #ifdef NDEBUG_NO_ASSERTIONS
+           "disabled *"
+         #else
+           "enabled"
+         #endif
+         );
+
+  printf("  user actions: \t\t\t\t%s\n",
+         USE_ACTIONS? "respected" : "ignored  *");
+
+  printf("  token reclassification: \t\t\t%s\n",
+         USE_RECLASSIFY? "enabled" : "disabled *");
+
+  printf("  reduction cancellation: \t\t\t%s\n",
+         USE_KEEP? "enabled" : "disabled *");
+
+  printf("  mini-LR parser core: \t\t\t\t%s\n",
+         USE_MINI_LR? "enabled  *" : "disabled");
+
+  printf("  allocated-node and parse action accounting: \t%s\n",
+         ACCOUNTING(1+)0? "enabled" : "disabled *");
+
+  printf("  unrolled reduce loop: \t\t\t%s\n",
+         USE_UNROLLED_REDUCE? "enabled  *" : "disabled");
+
+  printf("  parser index: \t\t\t\t%s\n",
+         #ifdef USE_PARSER_INDEX
+           "enabled"
+         #else
+           "disabled *"
+         #endif
+         );
+
+  // checking __OPTIMIZE__ is misleading if preprocessing is entirely
+  // divorced from compilation proper, but I still think this printout
+  // is useful; also, gcc does not provide a way to tell what level of
+  // optimization was applied (as far as I know)
+  printf("  C++ compiler's optimizer: \t\t\t%s\n",
+         #ifdef __OPTIMIZE__
+           "enabled  *"
+         #else
+           "disabled"
+         #endif
+         );
+
+  // at the moment, disabling compression makes it fastest
+  printf("  Error Entry Factoring (EEF): \t\t\t%s\n",
+         ENABLE_EEF_COMPRESSION? "enabled" : "disabled *");
+  printf("  Graph Coloring Scheme (GCS): \t\t\t%s\n",
+         ENABLE_GCS_COMPRESSION? "enabled" : "disabled *");
+  printf("  GCS for columns (GCSC): \t\t\t%s\n",
+         ENABLE_GCS_COLUMN_COMPRESSION? "enabled" : "disabled *");
+  printf("  Code Reduction Scheme (CRS): \t\t\t%s\n",
+         ENABLE_CRS_COMPRESSION? "enabled" : "disabled *");
+}
+
+
+// used to extract the svals from the nodes just under the
+// start symbol reduction
+SemanticValue GLR::grabTopSval(StackNode *node)
+{
+  SiblingLink *sib = node->getUniqueLink();
+  SemanticValue ret = sib->sval;
+  sib->sval = duplicateSemanticValue(node->getSymbolC(), sib->sval);
+
+  TRSACTION("dup'd " << ret << " for top sval, yielded " << sib->sval);
+
+  return ret;
+}
+
+
+// This macro has been pulled out so I can have even finer control
+// over the allocation process from the mini-LR core.
+//   dest: variable into which the pointer to the new node will be put
+//   state: DFA state for this node
+//   glr: pointer to the associated GLR object
+//   pool: node pool from which to allocate
+#define MAKE_STACK_NODE(dest, state, glr, pool)              \
+  dest = (pool).alloc();                                     \
+  dest->init(state, glr);                                    \
+  NODE_COLUMN( dest->column = (glr)->globalNodeColumn; )
+
+// more-friendly inline version, for use outside mini-LR
+inline StackNode *GLR::makeStackNode(StateId state)
+{
+  StackNode *sn;
+  MAKE_STACK_NODE(sn, state, this, *stackNodePool);
+  return sn;
+}
+
+
+// add a new parser to the 'topmostParsers' list, maintaing
+// related invariants
+inline void GLR::addTopmostParser(StackNode *parser)
+{
+  parser->checkLocalInvariants();
+
+  topmostParsers.push(parser);
+  parser->incRefCt();
+
+  // I implemented this index, and then discovered it made no difference
+  // (actually, slight degradation) in performance; so for now it will
+  // be an optional design choice, off by default
+  #ifdef USE_PARSER_INDEX
+    // fill in the state id index; if the assertion here ever fails, it
+    // means there are more than 255 active parsers; either the grammer
+    // is highly ambiguous by mistake, or else ParserIndexEntry needs to
+    // be re-typedef'd to something bigger than 'char'
+    int index = topmostParsers.length()-1;   // index just used
+    xassert(index < INDEX_NO_PARSER);
+
+    xassert(parserIndex[parser->state] == INDEX_NO_PARSER);
+    parserIndex[parser->state] = index;
+  #endif // USE_PARSER_INDEX
+}
+
+
+void GLR::buildParserIndex()
+{
+  if (parserIndex) {
+    delete[] parserIndex;
+  }
+  parserIndex = new ParserIndexEntry[tables->getNumStates()];
+  {
+    for (int i=0; i < tables->getNumStates(); i++) {
+      parserIndex[i] = INDEX_NO_PARSER;
+    }
+  }
+}
+
+
+bool GLR::glrParse(LexerInterface &lexer, SemanticValue &treeTop)
+{
+  #if !ACTION_TRACE
+    // tell the user why "-tr action" doesn't do anything, if 
+    // they specified that
+    trace("action") << "warning: ACTION_TRACE is currently disabled by a\n";
+    trace("action") << "compile-time switch, so you won't see parser actions.\n";
+  #endif
+                 
+  #ifdef NDEBUG
+    trace("parse") << "warning: Because NDEBUG was specified when elkhound was\n";
+    trace("parse") << "         compiled, the 'parse' tracing flag does nothing.\n";
+  #endif
+
+  // get ready..
+  traceProgress(2) << "parsing...\n";
+  clearAllStackNodes();
+
+  // this should be reset to NULL on all exit paths..
+  lexerPtr = &lexer;
+
+  // build the parser index (I do this regardless of whether I'm going
+  // to use it, because up here it makes no performance difference,
+  // and I'd like as little code as possible being #ifdef'd)
+  buildParserIndex();
+
+  // call the inner parser core, which is a static member function
+  bool ret;
+  {
+    //CycleTimer timer;
+    ret = innerGlrParse(*this, lexer, treeTop);
+    //traceProgress() << "done parsing (" << timer.elapsed() << ")\n";
+  }
+
+  // prevent dangling references, clear any stack node pointers
+  stackNodePool = NULL;
+  topmostParsers.empty();
+  prevTopmost.empty();
+
+  if (!ret) {
+    lexerPtr = NULL;
+    return ret;
+  }
+
+  // sm: I like to always see these statistics, but dsw doesn't,
+  // so I'll just set ELKHOUND_DEBUG in my .bashrc
+  if (getenv("ELKHOUND_DEBUG")) {
+    #if DO_ACCOUNTING
+      StackNode::printAllocStats();
+      cout << "detShift=" << detShift
+           << ", detReduce=" << detReduce
+           << ", nondetShift=" << nondetShift
+           << ", nondetReduce=" << nondetReduce
+           << endl;
+      //PVAL(parserMerges);
+      PVAL(computeDepthIters);
+      
+      PVAL(yieldThenMergeCt);
+      PVAL(totalExtracts);
+      PVAL(multipleDelayedExtracts);
+    #endif
+  }
+
+  lexerPtr = NULL;
+  return ret;
+}
+
+
+// old note: this function's complexity and/or size is *right* at the
+// limit of what gcc-2.95.3 is capable of optimizing well; I've already
+// pulled quite a bit of functionality into separate functions to try
+// to reduce the register pressure, but it's still near the limit;
+// if you do something to cross a pressure threshold, performance drops
+// 25% so watch out!
+//
+// This function is the core of the parser, and its performance is
+// critical to the end-to-end performance of the whole system.  It is
+// a static member so the accesses to 'glr' (aka 'this') will be
+// visible.
+STATICDEF bool GLR
+  ::innerGlrParse(GLR &glr, LexerInterface &lexer, SemanticValue &treeTop)
+{
+  #ifndef NDEBUG
+    bool doDumpGSS = tracingSys("dumpGSS");
+  #endif
+
+  // pull a bunch of things out of 'glr' so they'll be accessible from
+  // the stack frame instead of having to indirect into the 'glr' object
+  UserActions *userAct = glr.userAct;
+  ParseTables *tables = glr.tables;
+  #if USE_MINI_LR
+    ArrayStack<StackNode*> &topmostParsers = glr.topmostParsers;
+  #endif
+
+  // lexer token function
+  LexerInterface::NextTokenFunc nextToken = lexer.getTokenFunc();
+
+  #if USE_RECLASSIFY
+  // reclassifier
+  UserActions::ReclassifyFunc reclassifyToken =
+    userAct->getReclassifier();
+  #endif
+
+  // the stack node pool is a local variable of this function for
+  // fastest access by the mini-LR core; other parts of the algorihthm
+  // can access it using a pointer stored in the GLR class (caller
+  // nullifies this pointer afterward to prevent dangling references)
+  ObjectPool<StackNode> stackNodePool(30);
+  glr.stackNodePool = &stackNodePool;
+
+  // create an initial ParseTop with grammar-initial-state,
+  // set active-parsers to contain just this
+  NODE_COLUMN( glr.globalNodeColumn = 0; )
+  {
+    StackNode *first = glr.makeStackNode(tables->startState);
+    glr.addTopmostParser(first);
+  }
+
+  #if USE_MINI_LR
+    // reduction action function
+    UserActions::ReductionActionFunc reductionAction =
+      userAct->getReductionAction();
+
+    // this is *not* a reference to the 'glr' member because it
+    // doesn't need to be shared with the rest of the algorithm (it's
+    // only used in the Mini-LR core), and by having it directly on
+    // the stack another indirection is saved
+    //
+    // new approach: let's try embedding this directly into the stack
+    // (this saves 10% in end-to-end performance!)
+    //GrowArray<SemanticValue> toPass(TYPICAL_MAX_RHSLEN);
+    SemanticValue toPass[MAX_RHSLEN];
+  #endif
+                   
+  // count # of times we use mini LR
+  ACCOUNTING( int localDetShift=0; int localDetReduce=0; )
+
+  // for each input symbol
+  #ifndef NDEBUG
+    int tokenNumber = 0;
+
+    // some debugging streams so the TRSPARSE etc. macros work
+    bool trParse       = glr.trParse;
+    ostream &trsParse  = glr.trsParse;
+  #endif
+  for (;;) {
+    // debugging
+    TRSPARSE(
+           "------- "
+        << "processing token " << lexer.tokenDesc()
+        << ", " << glr.topmostParsers.length() << " active parsers"
+        << " -------"
+    )
+    TRSPARSE("Stack:" << glr.stackSummary())
+
+    #ifndef NDEBUG
+      if (doDumpGSS) {
+        glr.dumpGSS(tokenNumber);
+      }
+    #endif
+
+    // get token type, possibly using token reclassification
+    #if USE_RECLASSIFY
+      lexer.type = reclassifyToken(userAct, lexer.type, lexer.sval);
+    #else     // this is what bccgr does
+      //if (lexer.type == 1 /*L2_NAME*/) {
+      //  lexer.type = 3 /*L2_VARIABLE_NAME*/;
+      //} 
+    #endif
+
+    // alternate debugging; print after reclassification
+    TRSACTION("lookahead token: " << lexer.tokenDesc() <<
+              " aka " << userAct->terminalDescription(lexer.type, lexer.sval));
+
+  #if USE_MINI_LR
+    // try to cache a few values in locals (this didn't help any..)
+    //ActionEntry const * const actionTable = this->tables->actionTable;
+    //int const numTerms = this->tables->numTerms;
+
+  tryDeterministic:
+    // --------------------- mini-LR parser -------------------------
+    // optimization: if there's only one active parser, and the
+    // action is unambiguous, and it doesn't involve traversing
+    // parts of the stack which are nondeterministic, then do the
+    // parse action the way an ordinary LR parser would
+    //
+    // please note:  The code in this section is cobbled together
+    // from various other GLR functions.  Everything here appears in
+    // at least one other place, so modifications will usually have
+    // to be done in both places.
+    //
+    // This code is the core of the parsing algorithm, so it's a bit
+    // hairy for its performance optimizations.
+    if (topmostParsers.length() == 1) {
+      StackNode *parser = topmostParsers[0];
+      xassertdb(parser->referenceCount==1);     // 'topmostParsers[0]' is referrer
+      
+      #if ENABLE_EEF_COMPRESSION
+        if (tables->actionEntryIsError(parser->state, lexer.type)) {
+          return false;    // parse error
+        }
+      #endif
+
+      ActionEntry action =
+        tables->getActionEntry_noError(parser->state, lexer.type);
+
+      // I decode reductions before shifts because:
+      //   - they are 4x more common in my C grammar
+      //   - decoding a reduction is one less integer comparison
+      // however I can only measure ~1% performance difference
+      if (tables->isReduceAction(action)) {
+        ACCOUNTING( localDetReduce++; )
+        int prodIndex = tables->decodeReduce(action, parser->state);
+        ParseTables::ProdInfo const &prodInfo = tables->getProdInfo(prodIndex);
+        int rhsLen = prodInfo.rhsLen;
+        if (rhsLen <= parser->determinDepth) {
+          // can reduce unambiguously
+
+          // I need to hide this declaration when debugging is off and
+          // optimizer and -Werror are on, because it provokes a warning
+          TRSPARSE_DECL( int startStateId = parser->state; )
+          
+          // if we're tracing actions, I'm going to build a string 
+          // that describes all of the RHS symbols
+          ACTION( 
+            string rhsDescription("");
+            if (rhsLen == 0) {
+              // print something anyway
+              rhsDescription = " empty";
+            }
+          )
+
+          // record location of left edge; defaults to no location
+          // (used for epsilon rules)
+          // update: use location of lookahead token instead, for epsilons
+          SOURCELOC( SourceLoc leftEdge = lexer.loc; )
+
+          //toPass.ensureIndexDoubler(rhsLen-1);
+          xassertdb(rhsLen <= MAX_RHSLEN);
+
+          // we will manually string the stack nodes together onto
+          // the free list in 'stackNodePool', and 'prev' will point
+          // to the head of the current list; at the end, we'll
+          // install the final value of 'prev' back into
+          // 'stackNodePool' as the new head of the list
+          StackNode *prev = stackNodePool.private_getHead();
+
+          #if USE_UNROLLED_REDUCE
+            // What follows is unrollings of the loop below,
+            // labeled "loop for arbitrary rhsLen".  Read that loop
+            // before the unrollings here, since I omit the comments
+            // here.  In general, this program should be correct
+            // whether USE_UNROLLED_REDUCE is set or not.
+            //
+            // To produce the unrolled versions, simply copy all of the
+            // noncomment lines from the general loop, and replace the
+            // occurrence of 'i' with the value of one less than the 'case'
+            // label number.
+            switch ((unsigned)rhsLen) {    // gcc produces slightly better code if I cast to unsigned first
+              case 1: {
+                SiblingLink &sib = parser->firstSib;
+                toPass[0] = sib.sval;
+                ACTION( rhsDescription =
+                  stringc << " "
+                          << symbolDescription(parser->getSymbolC(), userAct, sib.sval)
+                          << rhsDescription; )
+                SOURCELOC(
+                  if (sib.validLoc()) {
+                    leftEdge = sib.loc;
+                  }
+                )
+                parser->nextInFreeList = prev;
+                prev = parser;
+                parser = sib.sib;
+                xassertdb(parser->referenceCount==1);
+                xassertdb(prev->referenceCount==1);
+                prev->decrementAllocCounter();
+                prev->firstSib.sib.setWithoutUpdateRefct(NULL);
+                xassertdb(parser->referenceCount==1);
+                // drop through into next case
+              }
+
+              case 0:
+                // nothing to do
+                goto afterGeneralLoop;
+            }
+          #endif // USE_UNROLLED_REDUCE
+
+          // ------ loop for arbitrary rhsLen ------
+          // pop off 'rhsLen' stack nodes, collecting as many semantic
+          // values into 'toPass'
+          // NOTE: this loop is the innermost inner loop of the entire
+          // parser engine -- even *one* branch inside the loop body
+          // costs about 30% end-to-end performance loss!
+          for (int i = rhsLen-1; i >= 0; i--) {
+            // grab 'parser's only sibling link
+            //SiblingLink *sib = parser->getUniqueLink();
+            SiblingLink &sib = parser->firstSib;
+
+            // Store its semantic value it into array that will be
+            // passed to user's routine.  Note that there is no need to
+            // dup() this value, since it will never be passed to
+            // another action routine (avoiding that overhead is
+            // another advantage to the LR mode).
+            toPass[i] = sib.sval;
+
+            // when tracing actions, continue building rhs desc
+            ACTION( rhsDescription = 
+              stringc << " "
+                      << symbolDescription(parser->getSymbolC(), userAct, sib.sval)
+                      << rhsDescription; )
+
+            // not necessary:
+            //   sib.sval = NULL;                  // link no longer owns the value
+            // this assignment isn't necessary because the usual treatment
+            // of NULL is to ignore it, and I manually ignore *any* value
+            // in the inline-expanded code below
+
+            // if it has a valid source location, grab it
+            SOURCELOC(
+              if (sib.validLoc()) {
+                leftEdge = sib.loc;
+              }
+            )
+
+            // pop 'parser' and move to the next one
+            parser->nextInFreeList = prev;
+            prev = parser;
+            parser = sib.sib;
+
+            // don't actually increment, since I now no longer actually decrement
+            // cancelled(1) effect: parser->incRefCt();    // so 'parser' survives deallocation of 'sib'
+            // cancelled(1) observable: xassertdb(parser->referenceCount==1);       // 'sib' and the fake one
+
+            // so now it's just the one
+            xassertdb(parser->referenceCount==1);     // just 'sib'
+
+            xassertdb(prev->referenceCount==1);
+            // expand "prev->decRefCt();"             // deinit 'prev', dealloc 'sib'
+            {
+              // I don't actually decrement the reference count on 'prev'
+              // because it will be reset to 0 anyway when it is inited
+              // the next time it is used
+              //prev->referenceCount = 0;
+
+              // adjust the global count of stack nodes
+              prev->decrementAllocCounter();
+
+              // I previously had a test for "prev->firstSib.sval != NULL",
+              // but that can't happen because I set it to NULL above!
+              // (as the alias sib.sval)
+              // update: now I don't even set it to NULL because the code here
+              // has been changed to ignore *any* value
+              //if (prev->firstSib.sval != NULL) {
+              //  cout << "I GOT THE ANALYSIS WRONG!\n";
+              //}
+
+              // cancelled(1) effect: parser->decRefCt();
+              prev->firstSib.sib.setWithoutUpdateRefct(NULL);
+
+              // possible optimization: I could eliminiate
+              // "prev->firstSib.sib=NULL" if I consistently modified all
+              // creation of stack nodes to treat sib as a dead value:
+              // right after creation I would make sure the new
+              // sibling value *overwrites* sib, and no attempt is
+              // made to decrement a refct on the dead value
+
+              // this is obviated by the manual construction of the
+              // free list links (nestInFreeList) above
+              //stackNodePool.deallocNoDeinit(prev);
+            }
+
+            xassertdb(parser->referenceCount==1);     // fake refct only
+          } // end of general rhsLen loop
+
+        #if USE_UNROLLED_REDUCE    // suppress the warning when not using it..
+        afterGeneralLoop:
+        #endif
+          // having now manually strung the deallocated stack nodes together
+          // on the free list, I need to make the node pool's head point at them
+          stackNodePool.private_setHead(prev);
+
+          // call the user's action function (TREEBUILD)
+          SemanticValue sval =
+          #if USE_ACTIONS
+            reductionAction(userAct, prodIndex, toPass /*.getArray()*/
+                            SOURCELOCARG( leftEdge ) );
+          #else
+            NULL;
+          #endif
+
+          // now, push a new state; essentially, shift prodInfo.lhsIndex.
+          // do "glrShiftNonterminal(parser, prodInfo.lhsIndex, sval, leftEdge);",
+          // except avoid interacting with the worklists
+
+          // this is like a shift -- we need to know where to go; the
+          // 'goto' table has this information
+          StateId newState = tables->decodeGoto(
+            tables->getGotoEntry(parser->state, prodInfo.lhsIndex),
+            prodInfo.lhsIndex);
+
+          // debugging
+          TRSPARSE("state " << startStateId <<
+                   ", (unambig) reduce by " << prodIndex <<
+                   " (len=" << rhsLen <<
+                   "), back to " << parser->state <<
+                   " then out to " << newState);
+
+          // 'parser' has refct 1, reflecting the local variable only
+          xassertdb(parser->referenceCount==1);
+
+          // push new state
+          StackNode *newNode;
+          MAKE_STACK_NODE(newNode, newState, &glr, stackNodePool)
+
+          newNode->addFirstSiblingLink_noRefCt(
+            parser, sval  SOURCELOCARG( leftEdge ) );
+          // cancelled(3) effect: parser->incRefCt();
+
+          // cancelled(3) effect: xassertdb(parser->referenceCount==2);
+          // expand:
+          //   "parser->decRefCt();"                 // local variable "parser" about to go out of scope
+          {
+            // cancelled(3) effect: parser->referenceCount = 1;
+          }
+          xassertdb(parser->referenceCount==1);
+
+          // replace whatever is in 'topmostParsers[0]' with 'newNode'
+          topmostParsers[0] = newNode;
+          newNode->incRefCt();
+          xassertdb(newNode->referenceCount == 1);   // topmostParsers[0] is referrer
+
+          // emit some trace output
+          TRSACTION("  " << 
+                    symbolDescription(newNode->getSymbolC(), userAct, sval) <<
+                    " ->" << rhsDescription);
+
+          #if USE_KEEP
+            // see if the user wants to keep this reduction
+            if (!userAct->keepNontermValue(prodInfo.lhsIndex, sval)) {
+              ACTION( string lhsDesc =
+                        userAct->nonterminalDescription(prodInfo.lhsIndex, sval); )
+              TRSACTION("    CANCELLED " << lhsDesc);
+              glr.printParseErrorMessage(newNode->state);
+              ACCOUNTING(
+                glr.detShift += localDetShift;
+                glr.detReduce += localDetReduce;
+              )
+              
+              // TODO: I'm pretty sure I'm not properly cleaning
+              // up all of my state here..
+              return false;
+            }
+          #endif // USE_KEEP
+
+          // after all this, we haven't shifted any tokens, so the token
+          // context remains; let's go back and try to keep acting
+          // determinstically (if at some point we can't be deterministic,
+          // then we drop into full GLR, which always ends by shifting)
+          goto tryDeterministic;
+        }
+      }
+
+      else if (tables->isShiftAction(action)) {
+        ACCOUNTING( localDetShift++; )
+
+        // can shift unambiguously
+        StateId newState = tables->decodeShift(action, lexer.type);
+
+        TRSPARSE("state " << parser->state <<
+                 ", (unambig) shift token " << lexer.tokenDesc() <<
+                 ", to state " << newState);
+
+        NODE_COLUMN( glr.globalNodeColumn++; )
+
+        StackNode *rightSibling;
+        MAKE_STACK_NODE(rightSibling, newState, &glr, stackNodePool);
+
+        rightSibling->addFirstSiblingLink_noRefCt(
+          parser, lexer.sval  SOURCELOCARG( lexer.loc ) );
+        // cancelled(2) effect: parser->incRefCt();
+
+        // replace 'parser' with 'rightSibling' in the topmostParsers list
+        topmostParsers[0] = rightSibling;
+        // cancelled(2) effect: xassertdb(parser->referenceCount==2);         // rightSibling & topmostParsers[0]
+        // expand "parser->decRefCt();"
+        {
+          // cancelled(2) effect: parser->referenceCount = 1;
+        }
+        xassertdb(parser->referenceCount==1);         // rightSibling
+
+        xassertdb(rightSibling->referenceCount==0);   // just created
+        // expand "rightSibling->incRefCt();"
+        {
+          rightSibling->referenceCount = 1;
+        }
+        xassertdb(rightSibling->referenceCount==1);   // topmostParsers[0] refers to it
+
+        // get next token
+        goto getNextToken;
+      }
+
+      else {
+        // error or ambig; not deterministic
+      }
+    }
+    // ------------------ end of mini-LR parser ------------------
+  #endif // USE_MINI_LR
+
+    // if we get here, we're dropping into the nondeterministic GLR
+    // algorithm in its full glory
+    if (!glr.nondeterministicParseToken()) {
+      return false;
+    }
+
+  #if USE_MINI_LR    // silence a warning when it's not enabled
+  getNextToken:
+  #endif
+    // was that the last token?
+    if (lexer.type == 0) {
+      break;
+    }
+
+    // get the next token
+    nextToken(&lexer);
+    #ifndef NDEBUG
+      tokenNumber++;
+    #endif
+  }
+
+  // push stats into main object
+  ACCOUNTING(
+    glr.detShift += localDetShift;
+    glr.detReduce += localDetReduce;
+  )
+
+  // end of parse; note that this function must be called *before*
+  // the stackNodePool is deallocated
+  return glr.cleanupAfterParse(treeTop);
+}
+
+
+// diagnostic/debugging function: yield sequence of
+// states represented by 'parser'; in the case of
+// ambiguity, just show one...
+string stackTraceString(StackNode *parser)
+{
+  // hmm.. what to do about cyclic stacks?
+  return string("need to think about this some more..");
+}
+
+
+// return false if caller should return false; pulled out of
+// glrParse to reduce register pressure (but didn't help as
+// far as I can tell!)
+bool GLR::nondeterministicParseToken()
+{
+  //cout << "not deterministic\n";
+
+  // ([GLR] called the code from here to the end of
+  // the loop 'parseword')
+
+  // work through the worklist
+  StateId lastToDie = STATE_INVALID;
+
+  // do all reduction explicitly first, then all shifts by
+  // re-iterating over topmost parsers
+  int i;
+  for (i=0; i < topmostParsers.length(); i++) {
+    StackNode *parser = topmostParsers[i];
+
+    ActionEntry action =
+      tables->getActionEntry(parser->state, lexerPtr->type);
+    int actions = rwlEnqueueReductions(parser, action, NULL /*sibLink*/);
+
+    if (actions == 0) {
+      TRSPARSE("parser in state " << parser->state << " died");
+      lastToDie = parser->state;
+    }
+  }
+
+  // now that the reductions for all the existing topmost states
+  // have been enqueued, process that worklist
+  rwlProcessWorklist();
+
+  // finally, do all the shifts that the topmost states can do
+  rwlShiftTerminals();
+
+
+  // if all active parsers have died, there was an error
+  if (topmostParsers.isEmpty()) {
+    printParseErrorMessage(lastToDie);
+    return false;
+  }
+  else {
+    return true;
+  }
+}
+
+
+// pulled out of glrParse() to reduce register pressure
+void GLR::printParseErrorMessage(StateId lastToDie)
+{
+  if (!noisyFailedParse) {
+    return;
+  }
+
+  // print which tokens could have allowed progress; this isn't
+  // perfect because I'm only printing this for one state, but in the
+  // nondeterministic algorithm there might have been more than one
+  // state that could have made progress..
+  if (lastToDie != STATE_INVALID) {
+    cout << "In state " << lastToDie << ", I expected one of these tokens:\n";
+    cout << "  ";
+    for (int i=0; i < tables->getNumTerms(); i++) {
+      ActionEntry act = tables->getActionEntry(lastToDie, i);
+      if (!tables->isErrorAction(act)) {
+        //cout << "  [" << i << "] " << lexerPtr->tokenKindDesc(i) << "\n";
+        cout << lexerPtr->tokenKindDesc(i) << ", ";
+      }
+    }
+    cout << "\n";
+  }
+  else {                                                                          
+    // this happens because I lose the dead-parser info while processing
+    // the reduction worklist; to implement this I'd need to remember each
+    // state that died while processing the worklist; for now I'll just let
+    // it be, and only have the right info sometimes
+    cout << "(expected-token info not available due to nondeterministic mode)\n";
+  }
+
+  // failure caused by unprimed lexer?
+  if (lexerPtr->type == 0 && 
+      lexerPtr->sval == (SemanticValue)LexerInterface::DEFAULT_UNPRIMED_SVAL) {
+    cout << "It looks like you forgot to prime the lexer before calling the parser.\n";
+  }
+
+  cout << toString(lexerPtr->loc)
+       << ": Parse error (state " << lastToDie << ") at "
+       << lexerPtr->tokenDesc()
+       << endl;
+
+  // removing this for now since keeping it would mean putting
+  // sample inputs and left contexts for all states into the
+  // parse tables
+  #if 0
+  if (lastToDie == STATE_INVALID) {
+    // I'm not entirely confident it has to be nonnull..
+    cout << "what the?  lastToDie is STATE_INVALID??\n";
+  }
+  else {
+    // print out the context of that parser
+    cout << "last parser (state " << lastToDie << ") to die had:\n"
+         << "  sample input: "
+         << sampleInput(getItemSet(lastToDie)) << "\n"
+         << "  left context: "
+         << leftContextString(getItemSet(lastToDie)) << "\n";
+  }
+  #endif // 0
+}
+
+
+SemanticValue GLR::doReductionAction(
+  int productionId, SemanticValue const *svals
+  SOURCELOCARG( SourceLoc loc ) )
+{
+  // get the function pointer and invoke it; possible optimization
+  // is to cache the function pointer in the GLR object
+  return (userAct->getReductionAction())(userAct, productionId, svals  SOURCELOCARG(loc));
+}
+
+
+// pulled from glrParse() to reduce register pressure
+bool GLR::cleanupAfterParse(SemanticValue &treeTop)
+{
+  trsParse << "Parse succeeded!\n";
+
+
+  // finish the parse by reducing to start symbol
+  if (topmostParsers.length() != 1) {
+    cout << "parsing finished with more than one active parser!\n";
+    return false;
+  }
+  StackNode *last = topmostParsers.top();
+
+  // pull out the semantic values; this assumes the start symbol
+  // always looks like "Start -> Something EOF"; it also assumes
+  // the top of the tree is unambiguous
+  SemanticValue arr[2];
+  StackNode *nextToLast = last->getUniqueLink()->sib;
+  arr[0] = grabTopSval(nextToLast);   // Something's sval
+  arr[1] = grabTopSval(last);         // eof's sval
+
+  // reduce
+  TRSACTION("handing toplevel sval " << arr[0] <<
+            " and " << arr[1] <<
+            " to top start's reducer");
+  treeTop = doReductionAction(
+              //getItemSet(last->state)->getFirstReduction()->prodIndex,
+              tables->finalProductionIndex,
+              arr
+              SOURCELOCARG( last->getUniqueLinkC()->loc ) );
+
+  // why do this song-and-dance here, instead of letting the normal
+  // parser engine do the final reduction?  because the GLR algorithm
+  // always finishes its iterations with a shift, and it's not trivial
+  // to add a special exception for the case of the reduce which
+  // finishes the parse
+
+  // these also must be done before the pool goes away..
+  decParserList(topmostParsers);
+
+  return true;
+}
+
+
+// this used to be code in glrParse(), but its presense disturbs gcc's
+// register allocator to the tune of a 33% performance hit!  so I've
+// pulled it in hopes the allocator will be happier now
+void GLR::pullFromTopmostParsers(StackNode *parser)
+{
+  int last = topmostParsers.length()-1;
+  for (int i=0; i <= last; i++) {
+    if (topmostParsers[i] == parser) {
+      // remove it; if it's not last in the list, swap it with
+      // the last one to maintain contiguity
+      if (i < last) {
+        topmostParsers[i] = topmostParsers[last];
+        // (no need to actually copy 'i' into 'last')
+      }
+      topmostParsers.pop();     // removes a reference to 'parser'
+      parser->decRefCt();       // so decrement reference count
+      break;
+    }
+  }
+}
+
+
+// return true if the given parser can either shift or reduce.  NOTE:
+// this isn't really sufficient for its intended purpose, since I
+// don't check to see whether *further* actions after a reduce are
+// possible; moreover, checking that could be very expensive, since
+// there may be many paths along which to consider reducing, and many
+// paths from that reduced node forward..
+bool GLR::canMakeProgress(StackNode *parser)
+{
+  ActionEntry entry =
+    tables->getActionEntry(parser->state, lexerPtr->type);
+
+  return tables->isShiftAction(entry) ||
+         tables->isReduceAction(entry) ||
+         !tables->isErrorAction(entry);
+}
+
+
+// if an active parser is at 'state', return it; otherwise
+// return NULL
+StackNode *GLR::findTopmostParser(StateId state)
+{
+  #ifdef USE_PARSER_INDEX
+    int index = parserIndex[state];
+    if (index != INDEX_NO_PARSER) {
+      return topmostParsers[index];
+    }
+    else {
+      return NULL;
+    }
+  #else
+    for (int i=0; i < topmostParsers.length(); i++) {
+      StackNode *node = topmostParsers[i];
+      if (node->state == state) {
+        return node;
+      }
+    }
+    return NULL;
+  #endif
+}
+
+
+// print the graph-structured stack to a file, named according
+// to the current token number, in a format suitable for a
+// graph visualization tool of some sort
+void GLR::dumpGSS(int tokenNumber) const
+{
+  FILE *dest = fopen(stringc << "gss." << tokenNumber << ".g", "w");
+
+  // list of nodes we've already printed, to avoid printing any
+  // node more than once
+  SObjList<StackNode> printed;
+
+  // list of nodes to print; might intersect 'printed', in which case
+  // such nodes should be discarded; initially contains all the active
+  // parsers (tops of stacks)
+  SObjList<StackNode> queue;
+  for (int i=0; i < topmostParsers.length(); i++) {
+    queue.append(topmostParsers[i]);
+  }
+
+  // keep printing nodes while there are still some to print
+  while (queue.isNotEmpty()) {
+    StackNode *node = queue.removeFirst();
+    if (printed.contains(node)) {
+      continue;
+    }
+    printed.append(node);
+
+    // only edges actually get printed (since the node names
+    // encode all the important information); so iterate over
+    // the sibling links now; while iterating, add the discovered
+    // nodes to the queue so we'll print them too
+    if (node->firstSib.sib != NULL) {
+      dumpGSSEdge(dest, node, node->firstSib.sib);
+      queue.append(node->firstSib.sib);
+
+      FOREACH_OBJLIST(SiblingLink, node->leftSiblings, iter) {
+        dumpGSSEdge(dest, node, iter.data()->sib);
+        queue.append(const_cast<StackNode*>( iter.data()->sib.getC() ));
+      }
+    }
+  }
+
+  fclose(dest);
+}
+
+
+void GLR::dumpGSSEdge(FILE *dest, StackNode const *src,
+                                  StackNode const *target) const
+{
+  fprintf(dest, "e %d_%p_%d %d_%p_%d\n",
+                0 NODE_COLUMN( + src->column ), src, src->state,
+                0 NODE_COLUMN( + target->column ), target, target->state);
+}
+
+
+// alternative to above: stack info in a single string
+string GLR::stackSummary() const
+{
+  stringBuilder sb;
+
+  // list of nodes we've already printed, to avoid printing any
+  // node more than once
+  SObjList<StackNode const> printed;
+
+  for (int i=0; i < topmostParsers.length(); i++) {
+    sb << " (" << i << ": ";
+    innerStackSummary(sb, printed, topmostParsers[i]);
+    sb << ")";
+  }
+
+  return sb;
+}
+
+void GLR::nodeSummary(stringBuilder &sb, StackNode const *node) const
+{
+  sb << node->state << "[" << node->referenceCount << "]";
+}
+
+void GLR::innerStackSummary(stringBuilder &sb, SObjList<StackNode const> &printed,
+                            StackNode const *node) const
+{
+  if (printed.contains(node)) {
+    sb << "(rep:";
+    nodeSummary(sb, node);
+    sb << ")";
+    return;
+  }
+
+  nodeSummary(sb, node);
+  printed.append(node);
+
+  if (!node->firstSib.sib) {
+    return;   // no siblings
+  }
+
+  sb << "-";
+
+  if (node->leftSiblings.isEmpty()) {
+    // one sibling
+    innerStackSummary(sb, printed, node->firstSib.sib);
+  }
+  else {
+    // multiple siblings
+    sb << "(";
+    innerStackSummary(sb, printed, node->firstSib.sib);
+
+    FOREACH_OBJLIST(SiblingLink, node->leftSiblings, iter) {
+      sb << "|";
+      innerStackSummary(sb, printed, iter.data()->sib);
+    }
+    sb << ")";
+  }
+}
+
+
+#if 0
+SemanticValue GLR::getParseResult()
+{
+  // the final topmost parser is the one that shifted the
+  // end-of-stream marker, so we want its left sibling, since that
+  // will be the reduction(s) to the start symbol
+  SemanticValue sv =
+    topmostParsers.first()->                    // parser that shifted end-of-stream
+      leftSiblings.first()->sib->              // parser that shifted start symbol
+      leftSiblings.first()->                   // sibling link with start symbol
+      sval;                                    // start symbol tree node
+
+  return sv;
+}    
+#endif // 0
+
+
+// -------------- reduction worklist (RWL) algorithm --------------
+// This algorithm is an attempt to avoid the problem where a semantic
+// value is yielded to a reduction action, but then merged with
+// another semantic value, such that the original one yielded is now
+// stale.  It's described in more detail in the tech report.
+
+ReductionPathQueue::Path::Path()
+  : startStateId(STATE_INVALID),
+    prodIndex(-1),
+    startColumn(-1),
+    leftEdgeNode(NULL),
+    sibLinks(INITIAL_RHSLEN_SIZE),
+    symbols(INITIAL_RHSLEN_SIZE)
+{
+  next = NULL;
+}
+
+ReductionPathQueue::Path::~Path()
+{}
+
+
+void ReductionPathQueue::Path::init(StateId ssi, int pi, int rhsLen)
+{
+  startStateId = ssi;
+  prodIndex = pi;
+
+  sibLinks.ensureIndexDoubler(rhsLen);
+  symbols.ensureIndexDoubler(rhsLen);
+}
+
+
+ReductionPathQueue::ReductionPathQueue(ParseTables *t)
+  : top(NULL),
+    pathPool(30),    // arbitrary initial pool size
+    tables(t)
+{}
+
+ReductionPathQueue::~ReductionPathQueue()
+{
+  // 'pathPool' will automatically array-deallocate all of the
+  // paths, which will themselves then delete their internal
+  // 'sibLinks' and 'symbols' arrays
+}
+
+
+ReductionPathQueue::Path *ReductionPathQueue::newPath(
+  StateId startStateId, int prodIndex, int rhsLen)
+{
+  Path *p = pathPool.alloc();
+  p->init(startStateId, prodIndex, rhsLen);
+  return p;
+}
+
+
+void ReductionPathQueue::insertPathCopy(Path const *src, StackNode *leftEdge)
+{
+  ParseTables::ProdInfo const &prodInfo = tables->getProdInfo(src->prodIndex);
+
+  // make a new node
+  Path *p = pathPool.alloc();
+  p->init(src->startStateId, src->prodIndex, prodInfo.rhsLen);
+
+  // fill in left edge info
+  p->leftEdgeNode = leftEdge;
+  p->startColumn = leftEdge->column;
+
+  // copy the path info
+  for (int i = prodInfo.rhsLen-1; i>=0; i--) {
+    p->sibLinks[i] = src->sibLinks[i];
+    p->symbols[i] = src->symbols[i];
+  }
+
+  // find the proper place to insert it
+  if (!top || goesBefore(p, top)) {
+    // prepend
+    p->next = top;
+    top = p;
+  }
+  else {
+    // search
+    Path *prev = top;
+    while (prev->next && !goesBefore(p, prev->next)) {
+      prev = prev->next;
+    }
+
+    // insert
+    p->next = prev->next;
+    prev->next = p;
+  }
+}
+
+bool ReductionPathQueue::goesBefore(Path const *p1, Path const *p2) const
+{
+  if (p1->startColumn > p2->startColumn) {
+    // 'p1' spans fewer tokens, so it goes first
+    return true;
+  }
+  else if (p2->startColumn > p1->startColumn) {
+    // same logic
+    return false;
+  }
+  else {
+    // equal start columns, so compare ids of nonterminals
+    // to which we're reducing in each case
+    NtIndex p1NtIndex = tables->getProdInfo(p1->prodIndex).lhsIndex;
+    NtIndex p2NtIndex = tables->getProdInfo(p2->prodIndex).lhsIndex;
+
+    // consult total order on nonterminals
+    int ord1 = tables->getNontermOrdinal(p1NtIndex);
+    int ord2 = tables->getNontermOrdinal(p2NtIndex);
+
+    return ord1 < ord2;
+  }
+}
+
+
+inline ReductionPathQueue::Path *ReductionPathQueue::dequeue()
+{
+  Path *ret = top;
+  top = top->next;
+  return ret;
+}
+
+
+void ReductionPathQueue::deletePath(Path *p)
+{
+  pathPool.dealloc(p);
+}
+
+
+// process the reduction worklist
+void GLR::rwlProcessWorklist()
+{
+  // location of this token
+  SOURCELOC( SourceLoc tokenLoc = lexerPtr->loc; )
+
+  while (pathQueue.isNotEmpty()) {
+    // process the enabled reductions in priority order
+    ReductionPathQueue::Path *path = pathQueue.dequeue();
+
+    // info about the production
+    ParseTables::ProdInfo const &prodInfo = tables->getProdInfo(path->prodIndex);
+    int rhsLen = prodInfo.rhsLen;
+
+    TRSPARSE("state " << path->startStateId <<
+             ", reducing by production " << path->prodIndex <<
+             " (rhsLen=" << rhsLen <<
+             "), back to state " << path->leftEdgeNode->state);
+
+    ACCOUNTING( nondetReduce++; )
+
+    // record location of left edge; initially is location of
+    // the lookahead token
+    SOURCELOC( SourceLoc leftEdge = tokenLoc; )
+
+    // build description of rhs for tracing
+    ACTION(
+      string rhsDescription("");
+      if (rhsLen == 0) {
+        // print something anyway
+        rhsDescription = " empty";
+      }
+    )
+
+    // before calling the user, duplicate any needed values; this loop
+    // goes from right to left backwards so that 'leftEdge' is
+    // computed properly
+    toPass.ensureIndexDoubler(rhsLen-1);
+    for (int i=rhsLen-1; i >= 0; i--) {
+      SiblingLink *sib = path->sibLinks[i];
+
+      // we're about to yield sib's 'sval' to the reduction action
+      toPass[i] = sib->sval;
+
+      // continue building rhs desc
+      ACTION( rhsDescription =
+        stringc << symbolDescription(path->symbols[i], userAct, sib->sval)
+                << " "
+                << rhsDescription;
+      )
+
+      // left edge?  or, have all previous tokens failed to yield
+      // information?
+      SOURCELOC(
+        if (sib->loc != SL_UNKNOWN) {     
+          leftEdge = sib->loc;
+        }
+      )
+
+      // we inform the user, and the user responds with a value
+      // to be kept in this sibling link *instead* of the passed
+      // value; if this link yields a value in the future, it will
+      // be this replacement
+      sib->sval = duplicateSemanticValue(path->symbols[i], sib->sval);
+
+      YIELD_COUNT( sib->yieldCount++; )
+    }
+
+    // we've popped the required number of symbols; call the
+    // user's code to synthesize a semantic value by combining them
+    // (TREEBUILD)
+    SemanticValue sval =
+      doReductionAction(path->prodIndex, toPass.getArray()
+                        SOURCELOCARG( leftEdge ) );
+
+    // emit tracing diagnostics for this reduction
+    ACTION( string lhsDesc =
+              userAct->nonterminalDescription(prodInfo.lhsIndex, sval); )
+    TRSACTION("  " << lhsDesc << " ->" << rhsDescription);
+
+    // see if the user wants to keep this reduction
+    if (USE_KEEP &&
+        !userAct->keepNontermValue(prodInfo.lhsIndex, sval)) {
+      TRSACTION("    CANCELLED " << lhsDesc);
+    }
+    else {
+      // shift the nonterminal with its reduced semantic value
+      SiblingLink *newLink =
+        rwlShiftNonterminal(path->leftEdgeNode, prodInfo.lhsIndex,
+                            sval  SOURCELOCARG( leftEdge ) );
+
+      if (newLink) {
+        // for each 'finished' parser ...
+        for (int i=0; i < topmostParsers.length(); i++) {
+          StackNode *parser = topmostParsers[i];
+
+          // ... do any reduce actions that are now enabled by the new link
+          ActionEntry action =
+            tables->getActionEntry(parser->state, lexerPtr->type);
+          rwlEnqueueReductions(parser, action, newLink);
+        }
+      }
+    }
+
+    pathQueue.deletePath(path);
+  }
+}
+
+
+// shift reduction onto 'leftSibling' parser, 'lhsIndex' says which
+// nonterminal is being shifted; 'sval' is the semantic value of this
+// subtree, and 'loc' is the location of the left edge; return value
+// is the newly added link, if one was added between existing nodes
+// ([GLR] calls this function 'reducer')
+//
+// exactly one of three possible things happens:
+//   - we make a new stack node
+//   - we add a new link between existing stack nodes
+//   - we merge two semantic values onto an existing link
+SiblingLink *GLR::rwlShiftNonterminal(StackNode *leftSibling, int lhsIndex,
+                                      SemanticValue /*owner*/ sval
+                                      SOURCELOCARG( SourceLoc loc ) )
+{
+  // this is like a shift -- we need to know where to go; the
+  // 'goto' table has this information
+  StateId rightSiblingState = tables->decodeGoto(
+    tables->getGotoEntry(leftSibling->state, lhsIndex), lhsIndex);
+
+  // debugging
+  TRSPARSE("state " << leftSibling->state <<
+           ", shift nonterm " << lhsIndex <<
+           ", to state " << rightSiblingState);
+
+  // is there already an active parser with this state?
+  StackNode *rightSibling = findTopmostParser(rightSiblingState);
+  if (rightSibling) {
+    // does it already have a sibling link to 'leftSibling'?
+    SiblingLink *sibLink = rightSibling->getLinkTo(leftSibling);
+    if (sibLink) {
+      // we already have a sibling link, so we don't need to add one
+
+      // +--------------------------------------------------+
+      // | it is here that we are bringing the tops of two  |
+      // | alternative parses together (TREEBUILD)          |
+      // +--------------------------------------------------+
+
+      // sometimes we are trying to merge dead trees--if the
+      // 'rightSibling' cannot make progress at all, it would be much
+      // better to just drop this alternative than demand the user
+      // merge trees when there is not necessarily any ambiguity
+      if (!canMakeProgress(rightSibling)) {
+        // both trees are dead; deallocate one (the other alternative
+        // will be dropped later, when 'rightSibling' is considered
+        // for action in the usual way)
+        TRSPARSE("avoided a merge by noticing the state was dead");
+        deallocateSemanticValue(rightSibling->getSymbolC(), sval);
+        return NULL;
+      }
+
+      // remember previous value, for yield count warning
+      YIELD_COUNT(SemanticValue old2 = sibLink->sval);
+
+      // remember descriptions of the values before they are merged
+      ACTION(
+        string leftDesc = userAct->nonterminalDescription(lhsIndex, sibLink->sval);
+        string rightDesc = userAct->nonterminalDescription(lhsIndex, sval);
+      )
+
+      // call the user's code to merge, and replace what we have
+      // now with the merged version
+      sibLink->sval =
+        userAct->mergeAlternativeParses(lhsIndex, sibLink->sval, sval  SOURCELOCARG( loc ) );
+
+      // emit tracing diagnostics for the merge
+      TRSACTION("  " <<
+                userAct->nonterminalDescription(lhsIndex, sibLink->sval) <<
+                " is MERGE of " << leftDesc << " and " << rightDesc);
+
+      YIELD_COUNT(
+        if (sibLink->yieldCount > 0) {
+          // yield-then-merge (YTM) happened
+          yieldThenMergeCt++;
+          SOURCELOC( trace("ytm") << "at " << toString(loc) << endl; )
+
+          // if merging yielded a new semantic value, then we most likely
+          // have a problem; if it yielded the *same* value, then most
+          // likely the user has implemented the 'ambiguity' link soln,
+          // so we're ok
+          if (old2 != sibLink->sval) {
+            cout << "warning: incomplete parse forest: " << (void*)old2
+                 << " has already been yielded, but it now has been "
+                 << "merged with " << (void*)sval << " to make "
+                 << (void*)(sibLink->sval) << " (lhsIndex="
+                 << lhsIndex << ")" << endl;
+          }
+        }
+      )
+
+      // ok, done
+      return NULL;
+
+      // and since we didn't add a link, there is no potential for new
+      // paths
+    }
+
+    // we get here if there is no suitable sibling link already
+    // existing; so add the link (and keep the ptr for loop below)
+    sibLink = rightSibling->addSiblingLink(leftSibling, sval  SOURCELOCARG( loc ) );
+
+    // adding a new sibling link may have introduced additional
+    // opportunties to do reductions from parsers we thought
+    // we were finished with.
+    //
+    // what's more, it's not just the parser ('rightSibling') we
+    // added the link to -- if rightSibling's itemSet contains 'A ->
+    // alpha . B beta' and B ->* empty (so A's itemSet also has 'B
+    // -> .'), then we reduced it (if lookahead ok), so
+    // 'rightSibling' now has another left sibling with 'A -> alpha
+    // B . beta'.  We need to let this sibling re-try its reductions
+    // also.
+    //
+    // so, the strategy is to let all 'finished' parsers re-try
+    // reductions, and process those that actually use the just-
+    // added link
+
+    // TODO: I think this code path is unusual; confirm by measurement
+    // update: it's taken maybe 1 in 10 times through this function..
+    parserMerges++;
+
+    // we don't have to recompute if nothing else points at
+    // 'rightSibling'; the refct is always at least 1 because we found
+    // it on the "active parsers" worklist
+    if (rightSibling->referenceCount > 1) {
+      // since we added a new link *all* determinDepths might
+      // be compromised; iterating more than once should be very
+      // rare (and this code path should already be unusual)
+      int changes=1, iters=0;
+      while (changes) {
+        changes = 0;
+        for (int i=0; i < topmostParsers.length(); i++) {
+          StackNode *parser = topmostParsers[i];
+          int newDepth = parser->computeDeterminDepth();
+          if (newDepth != parser->determinDepth) {
+            changes++;
+            parser->determinDepth = newDepth;
+          }
+        }
+        iters++;
+        xassert(iters < 1000);    // protect against infinite loop
+        computeDepthIters++;
+      }
+    }
+
+    // inform the caller that a new sibling link was added
+    return sibLink;
+  }
+
+  else {
+    // no, there is not already an active parser with this
+    // state.  we must create one; it will become the right
+    // sibling of 'leftSibling'
+    rightSibling = makeStackNode(rightSiblingState);
+
+    // add the sibling link (and keep ptr for tree stuff)
+    rightSibling->addSiblingLink(leftSibling, sval  SOURCELOCARG( loc ) );
+
+    // since this is a new parser top, it needs to become a
+    // member of the frontier
+    addTopmostParser(rightSibling);
+
+    // here, rather than adding something to the parser worklist,
+    // we'll directly expand its reduction paths and add them
+    // to the reduction worklist
+    ActionEntry action =
+      tables->getActionEntry(rightSibling->state, lexerPtr->type);
+    rwlEnqueueReductions(rightSibling, action, NULL /*sibLink*/);
+
+    // no need for the elaborate re-checking above, since we
+    // just created rightSibling, so no new opportunities
+    // for reduction could have arisen
+    return NULL;
+  }
+}
+
+
+// find and enqueue all the reductions that 'parser' can do; 'action'
+// is the parser's action code; we only consider reductions that use
+// 'mustUseLink', if that is not NULL
+//
+// This function will enqueue reduction paths, ordered first by the
+// number of terminals spanned and second by the nonterminal
+// derivability relation on the nonterminal to which the path reduces
+// (if A ->+ B then we will reduce to B before reducing to A, if
+// terminal spans are equal).
+//
+// this function returns the # of actions the parser can take, as
+// part of a rather weak error reporting scheme..
+int GLR::rwlEnqueueReductions(StackNode *parser, ActionEntry action,
+                              SiblingLink *mustUseLink)
+{
+  parser->checkLocalInvariants();
+
+  if (tables->isShiftAction(action)) {
+    // do nothing, we're only interested in reductions
+    return 1;
+  }
+  else if (tables->isReduceAction(action)) {
+    // reduce
+    int prodIndex = tables->decodeReduce(action, parser->state);
+
+    // get information about the production we'll use
+    ParseTables::ProdInfo const &info = tables->getProdInfo(prodIndex);
+    int rhsLen = info.rhsLen;
+    xassert(rhsLen >= 0);    // paranoia before using this to control recursion
+
+    // initialize a prototype Path which will monitor our progress
+    // though the enumeration of all paths
+    ReductionPathQueue::Path *proto =
+      pathQueue.newPath(parser->state, prodIndex, rhsLen);
+
+    // kick off the recursion
+    rwlRecursiveEnqueue(proto, rhsLen, parser, mustUseLink);
+
+    // deallocate the prototype
+    pathQueue.deletePath(proto);
+
+    return 1;
+  }
+  else if (tables->isErrorAction(action)) {
+    // the parser dies, we don't do anything
+    return 0;
+  }
+  else {
+    // ambiguous; check for reductions
+    ActionEntry *entry = tables->decodeAmbigAction(action, parser->state);
+    for (int i=0; i<entry[0]; i++) {
+      rwlEnqueueReductions(parser, entry[i+1], mustUseLink);
+    }
+
+    return entry[0];
+  }
+}
+
+
+// arguments have same meanings as in 'rwlRecursiveEnqueue'
+inline void GLR::rwlCollectPathLink(
+  ReductionPathQueue::Path *proto, int popsRemaining,
+  StackNode *currentNode, SiblingLink *mustUseLink, SiblingLink *linkToAdd)
+{
+  proto->sibLinks[popsRemaining] = linkToAdd;
+  proto->symbols[popsRemaining] = currentNode->getSymbolC();
+
+  if (linkToAdd == mustUseLink) {
+    rwlRecursiveEnqueue(proto, popsRemaining, linkToAdd->sib,
+                        NULL /*mustUseLink*/);
+  }
+  else {
+    rwlRecursiveEnqueue(proto, popsRemaining, linkToAdd->sib,
+                        mustUseLink);
+  }
+}
+
+// recursive depth-first enumeration of paths
+void GLR::rwlRecursiveEnqueue(
+  ReductionPathQueue::Path *proto,  // prototype path, with path so far
+  int popsRemaining,                // # of links yet to traverse to find a full path
+  StackNode *currentNode,           // node we're at in the path
+  SiblingLink *mustUseLink)         // link the path must use (if non-NULL)
+{
+  if (popsRemaining == 0) {
+    // we found path of required length
+
+    // if we have failed to use the required link, ignore this path
+    if (mustUseLink != NULL) {
+      return;
+    }
+
+    // the prototype path is the one we want; copy it, fill in
+    // the 'startColumn', and insert it into the queue
+    pathQueue.insertPathCopy(proto, currentNode);
+  }
+
+  else {
+    // explore 'currentNode's siblings
+    rwlCollectPathLink(proto, popsRemaining-1, currentNode, mustUseLink,
+                       &(currentNode->firstSib));
+
+    // test before dropping into the loop, since profiler reported
+    // some time spent calling VoidListMutator::reset ..
+    if (currentNode->leftSiblings.isNotEmpty()) {
+      FOREACH_OBJLIST_NC(SiblingLink, currentNode->leftSiblings, sibling) {
+        rwlCollectPathLink(proto, popsRemaining-1, currentNode, mustUseLink,
+                           sibling.data());
+      }
+    }
+  }
+}
+
+
+// final phase in processing of a token: all topmost parsers
+// shift the current token, if they can
+void GLR::rwlShiftTerminals()
+{
+  NODE_COLUMN( globalNodeColumn++; )
+
+  // move all the parsers from 'topmostParsers' into 'prevTopmost'
+  xassert(prevTopmost.isEmpty());
+  prevTopmost.swapWith(topmostParsers);
+  xassert(topmostParsers.isEmpty());
+
+  // to solve the multi-yield problem for tokens, I'll remember
+  // the previously-created sibling link (if any), and dup the
+  // sval in that link as needed
+  SiblingLink *prev = NULL;
+
+  // foreach node in prevTopmost
+  while (prevTopmost.isNotEmpty()) {                
+    // take the node from 'prevTopmost'; the refcount includes both
+    // 'leftSibling' and 'prevTopmost', and then we decrement the
+    // count to reflect that only 'leftSibling' has it
+    RCPtr<StackNode> leftSibling(prevTopmost.pop());
+    xassertdb(leftSibling->referenceCount >= 2);
+    leftSibling->decRefCt();
+
+    // where can this shift, if anyplace?
+    ActionEntry action =
+      tables->getActionEntry(leftSibling->state, lexerPtr->type);
+      
+    // we'll set this if we find a valid shift dest
+    StateId newState = STATE_INVALID;
+
+    // consult action table, looking only for shifts
+    if (tables->isShiftAction(action)) {
+      // unambiguous shift
+      newState = tables->decodeShift(action, lexerPtr->type);
+    }
+    else if (tables->isReduceAction(action) ||
+             tables->isErrorAction(action)) {
+      // reduce or error
+      continue;
+    }
+    else {
+      // nondeterministic; get actions
+      ActionEntry *entry = tables->decodeAmbigAction(action, leftSibling->state);
+
+      // do each one
+      for (int i=0; i<entry[0]; i++) {
+        action = entry[i+1];
+        if (tables->isShiftAction(action)) {
+          // a shift was among the conflicted actions
+          newState = tables->decodeShift(action, lexerPtr->type);
+          break;
+        }
+      }
+
+      // did we find a shift?
+      if (newState == STATE_INVALID) {
+        continue;    // no
+      }
+    }
+
+    // found a shift to perform
+    ACCOUNTING( nondetShift++; )
+
+    // debugging
+    TRSPARSE("state " << leftSibling->state <<
+             ", shift token " << lexerPtr->tokenDesc() <<
+             ", to state " << newState);
+
+    // if there's already a parser with this state
+    StackNode *rightSibling = findTopmostParser(newState);
+    if (rightSibling != NULL) {
+      // no need to create the node
+    }
+
+    else {
+      // must make a new stack node
+      rightSibling = makeStackNode(newState);
+
+      // and add it to the active parsers
+      addTopmostParser(rightSibling);
+    }
+
+    SemanticValue sval = lexerPtr->sval;
+    if (prev) {
+      // the 'sval' we just grabbed has already been claimed by
+      // 'prev->sval'; get a fresh one by duplicating the latter
+      sval = userAct->duplicateTerminalValue(lexerPtr->type, prev->sval);
+      
+      TRSACTION("  " << userAct->terminalDescription(lexerPtr->type, sval) <<
+                " is (@lexer) DUP of " <<
+                userAct->terminalDescription(lexerPtr->type, prev->sval));
+    }
+
+    // either way, add the sibling link now
+    //TRSACTION("grabbed token sval " << lexerPtr->sval);
+    prev = rightSibling->addSiblingLink(leftSibling, sval
+                                        SOURCELOCARG( lexerPtr->loc ) );
+
+    // adding this sibling link cannot violate the determinDepth
+    // invariant of some other node, because all of the nodes created
+    // or added-to during shifting do not have anything pointing at
+    // them, so in particular nothing points to 'rightSibling'; a simple
+    // check of this is to check the reference count and verify it is 1,
+    // the 1 being for the 'topmostParsers' list it is on
+    xassert(rightSibling->referenceCount == 1);
+  }
+}
+
+
+// ------------------ stuff for outputting raw graphs ------------------
+#if 0   // disabled for now
+// name for graphs (can't have any spaces in the name)
+string stackNodeName(StackNode const *sn)
+{
+  Symbol const *s = sn->getSymbolC();
+  char const *symName = (s? s->name.pcharc() : "(null)");
+  return stringb(sn->stackNodeId
+              << ":col="  << sn->tokenColumn
+              << ",st=" << sn->state->id
+              << ",sym=" << symName);
+}
+
+// name for rules; 'rn' is the 'ruleNo'-th rule in 'sn'
+// (again, no spaces allowed)
+string reductionName(StackNode const *sn, int ruleNo, Reduction const *red)
+{
+  return stringb(sn->stackNodeId << "/" << ruleNo << ":"
+              << replace(red->production->toString(), " ", "_"));
+}                                                            
+
+
+// this prints the graph in my java graph applet format, where
+// nodes lines look like
+//   n <name> <optional-desc>
+// and edges look like
+//   e <from> <to>
+// unfortunately, the graph applet needs a bit of work before it
+// is worthwhile to use this routinely (though it's great for
+// quickly verifying a single (small) parse)
+//
+// however, it's worth noting that the text output is not entirely
+// unreadable...
+void GLR::writeParseGraph(char const *fname) const
+{
+  FILE *out = fopen(stringb("graphs/" << fname), "w");
+  if (!out) {
+    xsyserror("fopen", stringb("opening file `graphs/" << fname << "'"));
+  }
+
+  // header info
+  fprintf(out, "# parse graph file: %s\n", fname);
+  fprintf(out, "# automatically generated\n"
+               "\n");
+
+  #if 0    // can't do anymore because allStackNodes is gone ...
+  // for each stack node
+  FOREACH_OBJLIST(StackNode, allStackNodes, stackNodeIter) {
+    StackNode const *stackNode = stackNodeIter.data();
+    string myName = stackNodeName(stackNode);
+
+    // visual delimiter
+    fputs(stringb("\n# ------ node: " << myName << " ------\n"), out);
+
+    // write info for the node itself
+    fputs(stringb("n " << myName << "\n\n"), out);
+
+    // for all sibling links
+    int ruleNo=0;
+    FOREACH_OBJLIST(SiblingLink, stackNode->leftSiblings, sibIter) {
+      SiblingLink const *link = sibIter.data();
+
+      // write the sibling link
+      fputs(stringb("e " << myName << " "
+                         << stackNodeName(link->sib) << "\n"), out);
+
+      // ideally, we'd attach the reduction nodes directly to the
+      // sibling edge.  however, since I haven't developed the
+      // graph applet far enough for that, I'll instead attach it
+      // to the stack node directly..
+
+      if (link->treeNode->isNonterm()) {
+        // for each reduction node
+        FOREACH_OBJLIST(Reduction, link->treeNode->asNonterm().reductions,
+                        redIter) {
+          Reduction const *red = redIter.data();
+          ruleNo++;
+
+          string ruleName = reductionName(stackNode, ruleNo, red);
+
+          // write info for the rule node
+          fputs(stringb("n " << ruleName << "\n"), out);
+
+          // put the link from the stack node to the rule node
+          fputs(stringb("e " << myName << " " << ruleName << "\n"), out);
+
+          // write all child links
+          // ACK!  until my graph format is better, this is almost impossible
+          #if 0
+          SFOREACH_OBJLIST(StackNode, rule->children, child) {
+            fputs(stringb("e " << ruleName << " "
+                               << stackNodeName(child.data()) << "\n"), out);
+          }
+          #endif // 0
+
+          // blank line for visual separation
+          fputs("\n", out);
+        } // for each reduction
+      } // if is nonterminal
+    } // for each sibling
+  } // for each stack node
+  #endif // 0
+
+  // done
+  if (fclose(out) != 0) {
+    xsyserror("fclose");
+  }
+}
+#endif // 0
+
+
+// --------------------- testing ------------------------
+// read an entire file into a single string
+// currenty is *not* pipe-friendly because it must seek
+// (candidate for adding to 'str' module)
+string readFileIntoString(char const *fname)
+{
+  return readStringFromFile(fname);
+                                   
+  #if 0   // old
+  // open file
+  FILE *fp = fopen(fname, "r");
+  if (!fp) {
+    xsyserror("fopen", stringb("opening `" << fname << "' for reading"));
+  }
+
+  // determine file's length
+  if (fseek(fp, 0, SEEK_END) < 0) {
+    xsyserror("fseek");
+  }
+  int len = (int)ftell(fp);      // conceivably problematic cast..
+  if (len < 0) {
+    xsyserror("ftell");
+  }
+  if (fseek(fp, 0, SEEK_SET) < 0) {
+    xsyserror("fseek");
+  }
+
+  // allocate a sufficiently large buffer
+  string ret(len);
+
+  // read the file into that buffer
+  if (fread(ret.pchar(), 1, len, fp) < (size_t)len) {
+    xsyserror("fread");
+  }
+
+  // close file
+  if (fclose(fp) < 0) {
+    xsyserror("fclose");
+  }
+
+  // return the new string
+  return ret;
+  #endif // 0
+}
+
+
+// EOF

Added: vendor/elsa/current/elkhound/glr.h
===================================================================
--- vendor/elsa/current/elkhound/glr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/glr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,460 @@
+// glr.h            see license.txt for copyright and terms of use
+// GLR parsing algorithm
+
+/*
+ * Author: Scott McPeak, April 2000
+ *
+ * The fundamental concept in Generalized LR (GLR) parsing
+ * is to permit (at least local) ambiguity by "forking" the
+ * parse stack.  If the input is actually unambiguous, then
+ * all but one of the forked parsers will, at some point,
+ * fail to shift a symbol, and die.  If the input is truly
+ * ambiguous, forked parsers rejoin at some point, and the
+ * parse tree becomes a parse DAG, representing all possible
+ * parses.  (In fact, since cyclic grammars are supported,
+ * which can have an infinite number of parse trees for
+ * some inputs, we may end up with a cyclic parse *graph*.)
+ *
+ * In the larger scheme of things, this level of support for
+ * ambiguity is useful because it lets us use simpler and
+ * more intuitive grammars, more sophisticated disambiguation
+ * techniques, and parsing in the presence of incomplete
+ * or incorrect information (e.g. in an editor).
+ *
+ * The downside is that parsing is slower, and whatever tool
+ * processes the parse graph needs to have ways of dealing
+ * with the multiple parse interpretations.
+ *
+ * references:
+ *
+ *   [GLR]  J. Rekers.  Parser Generation for Interactive
+ *          Environments.  PhD thesis, University of
+ *          Amsterdam, 1992.  Available by ftp from
+ *          ftp://ftp.cwi.nl/pub/gipe/reports/Rek92.ps.Z .
+ *          [Contains a good description of the Generalized
+ *          LR (GLR) algorithm.]
+ */
+
+#ifndef GLR_H
+#define GLR_H
+
+#include "glrconfig.h"     // SOURCELOC
+#include "parsetables.h"   // StateId
+#include "rcptr.h"         // RCPtr
+#include "useract.h"       // UserActions, SemanticValue
+#include "objpool.h"       // ObjectPool, GrowArray
+#include "objlist.h"       // ObjList
+#include "srcloc.h"        // SourceLoc
+#include "sobjlist.h"      // SObjList
+
+#include <stdio.h>         // FILE
+#include <iostream.h>      // ostream
+
+
+// fwds from other files
+class LexerInterface;      // lexerint.h
+
+// forward decls for things declared below
+class StackNode;           // unit of parse state
+class SiblingLink;         // connections between stack nodes
+class PendingShift;        // for postponing shifts.. may remove
+class GLR;                 // main class for GLR parsing
+
+
+// a pointer from a stacknode to one 'below' it (in the LR
+// parse stack sense); also has a link to the parse graph
+// we're constructing
+class SiblingLink {
+public:
+  // the stack node being pointed-at; it was created eariler
+  // than the one doing the pointing
+  RCPtr<StackNode> sib;
+
+  // this is the semantic value associated with this link
+  // (parse tree nodes are *not* associated with stack nodes --
+  // that's now it was originally, but I figured out the hard
+  // way that's wrong (more info in compiler.notes.txt));
+  // this is an *owner* pointer
+  SemanticValue sval;
+
+  // the source location of the left edge of the subtree rooted
+  // at this stack node; this is in essence part of the semantic
+  // value, but automatically propagated by the parser
+  SOURCELOC( SourceLoc loc; )
+
+  // number of times this 'sval' has been yielded; this is used
+  // to track cases where we yield a value and then merge it
+  // (which means the induced parse forest is incomplete)
+  YIELD_COUNT( int yieldCount; )
+
+  // if you add additional fields, they need to be inited in the
+  // constructor *and* in StackNode::addFirstSiblingLink_noRefCt
+
+public:
+  SiblingLink(StackNode *s, SemanticValue sv
+              SOURCELOCARG( SourceLoc L ) );
+  ~SiblingLink();
+  
+  #if GLR_SOURCELOC
+    bool validLoc() const { return loc != SL_UNKNOWN; }
+  #else
+    bool validLoc() const { return false; }
+  #endif
+};
+
+
+// the GLR parse state is primarily made up of a graph of these
+// nodes, which play a role analogous to the stack nodes of a
+// normal LR parser; GLR nodes form a graph instead of a linear
+// stack because choice points (real or potential ambiguities)
+// are represented as multiple left-siblings
+class StackNode {
+public:
+  // the LR state the parser is in when this node is at the
+  // top ("at the top" means that nothing, besides perhaps itself,
+  // is pointing to it)
+  //ItemSet const * const state;                 // (serf)
+  StateId state;       // now it is an id
+
+  // each leftSibling points to a stack node in one possible LR stack.
+  // if there is more than one, it means two or more LR stacks have
+  // been joined at this point.  this is the parse-time representation
+  // of ambiguity (actually, unambiguous grammars or inputs do
+  // sometimes lead to multiple siblings)
+  ObjList<SiblingLink> leftSiblings;           // this is a set
+
+  // the *first* sibling is simply embedded directly into the
+  // stack node, to avoid list overhead in the common case of
+  // only one sibling; when firstSib.sib==NULL, there are no
+  // siblings
+  SiblingLink firstSib;
+
+  // number of sibling links pointing at 'this', plus the number
+  // of worklists on which 'this' appears (some liberty is taken
+  // in the mini-LR parser, but it is carefully documented there)
+  int referenceCount;
+
+  // how many stack nodes can I pop before hitting a nondeterminism?
+  // if this node itself has >1 sibling link, determinDepth==0; if
+  // this node has 1 sibling, but that sibling has >1 sibling, then
+  // determinDepth==1, and so on; if this node has 0 siblings, then
+  // determinDepth==1
+  int determinDepth;
+
+  union {
+    // somewhat nonideal: I need access to the 'userActions' to
+    // deallocate semantic values when refCt hits zero, and I need
+    // to map states to state-symbols for the same reason.
+    // update: now I'm also using this to support pool-based
+    // deallocation in decRefCt()
+    GLR *glr;
+
+    // this is used by the ObjectPool which handles allocation of
+    // StackNodes
+    StackNode *nextInFreeList;
+  };
+
+  // ordinal position of the token that was being processed
+  // when this stack node was created; this information is useful
+  // for laying out the nodes when visualizing the GSS, but is
+  // not used by the parsing algorithm itself
+  NODE_COLUMN( int column; )
+
+  // count and high-water for stack nodes
+  static int numStackNodesAllocd;
+  static int maxStackNodesAllocd;
+                           
+  
+private:    // funcs
+  SiblingLink *
+    addAdditionalSiblingLink(StackNode *leftSib, SemanticValue sval
+                             SOURCELOCARG( SourceLoc loc ) );
+
+public:     // funcs
+  StackNode();
+  ~StackNode();
+
+  // ctor/dtor from point of view of the object pool user
+  void init(StateId state, GLR *glr);
+  void deinit();
+
+  // internal workings of 'deinit', exposed for performance reasons
+  inline void decrementAllocCounter();
+  void deallocSemanticValues();
+
+  // add a new link with the given tree node; return the link
+  SiblingLink *addSiblingLink(StackNode *leftSib, SemanticValue sval
+                              SOURCELOCARG( SourceLoc loc ) );
+                                
+  // specialized version for performance-critical sections
+  inline void
+    addFirstSiblingLink_noRefCt(StackNode *leftSib, SemanticValue sval
+                                SOURCELOCARG( SourceLoc loc ) );
+
+  // return the symbol represented by this stack node;  it's
+  // the symbol shifted or reduced-to to get to this state
+  // (this used to be a data member, but there are at least
+  // two ways to compute it, so there's no need to store it)
+  SymbolId getSymbolC() const;
+
+  // reference count stuff
+  void incRefCt() { referenceCount++; }
+  void decRefCt();
+
+  // sibling count queries (each one answerable in constant time)
+  bool hasZeroSiblings() const { return firstSib.sib==NULL; }
+  bool hasOneSibling() const { return firstSib.sib!=NULL && leftSiblings.isEmpty(); }
+  bool hasMultipleSiblings() const { return leftSiblings.isNotEmpty(); }
+
+  // when you expect there's only one sibling link, get it this way
+  SiblingLink const *getUniqueLinkC() const;
+  SiblingLink *getUniqueLink() { return const_cast<SiblingLink*>(getUniqueLinkC()); }
+
+  // retrieve pointer to the sibling link to a given node, or NULL if none
+  SiblingLink *getLinkTo(StackNode *another);
+
+  // recompute my determinDepth based on siblings, 
+  // but don't actually change the state
+  int computeDeterminDepth() const;
+
+  // debugging
+  static void printAllocStats();
+  void checkLocalInvariants() const;
+};
+
+
+// this is a priority queue of stack node paths that are candidates to
+// reduce, maintained such that we can select paths in an order which
+// will avoid yield-then-merge
+class ReductionPathQueue {
+public:       // types
+  // a single path in the stack
+  class Path {
+  public:     // data
+    // ---- right edge info ----
+    // the rightmost state's id; we're reducing in this state
+    StateId startStateId;
+
+    // id of the production with which we're reducing
+    int prodIndex;
+
+    // ---- left edge info ----
+    // the token column (ordinal position of a token in the token
+    // stream) of the leftmost stack node; the smaller the
+    // startColumn, the more tokens this reduction spans
+    int startColumn;
+
+    // stack node at the left edge; our reduction will push a new
+    // stack node on top of this one
+    StackNode *leftEdgeNode;
+
+    // ---- path in between ----
+    // array of sibling links, naming the path; 'sibLink[0]' is the
+    // leftmost link; array length is given by the rhsLen of
+    // prodIndex's production
+    GrowArray<SiblingLink*> sibLinks;    // (array of serfs)
+
+    // corresponding array of symbol ids so we know how to interpret
+    // the semantic values in the links
+    GrowArray<SymbolId> symbols;
+
+    union {
+      // link between nodes for construction of a linked list,
+      // kept in sorted order
+      Path *next;
+
+      // link for free list in the object pool
+      Path *nextInFreeList;
+    };
+
+  public:     // funcs
+    Path();
+    ~Path();
+
+    void init(StateId startStateId, int prodIndex, int rhsLen);
+    void deinit() {}
+  };
+
+private:      // data
+  // head of the list
+  Path *top;
+
+  // allocation pool of Path objects
+  ObjectPool<Path> pathPool;
+
+  // parse tables, so we can decode prodIndex and also compare
+  // production ids for sorting purposes
+  ParseTables *tables;
+       
+private:      // funcs
+  bool goesBefore(Path const *p1, Path const *p2) const;
+
+public:       // funcs
+  ReductionPathQueue(ParseTables *t);
+  ~ReductionPathQueue();
+
+  // get another Path object, inited with these values
+  Path *newPath(StateId startStateId, int prodIndex, int rhsLen);
+
+  // make a copy of the prototype 'src', fill in its left-edge
+  // fields using 'leftEdge', and insert it into sorted order
+  // in the queue
+  void insertPathCopy(Path const *src, StackNode *leftEdge);
+                       
+  // true if there are no more paths
+  bool isEmpty() const { return top == NULL; }
+  bool isNotEmpty() const { return !isEmpty(); }
+
+  // remove the next path to reduce from the list, and return it
+  Path *dequeue();
+
+  // mark a path as not being used, so it will be recycled into the pool
+  void deletePath(Path *p);
+};
+
+
+// each GLR object is a parser for a specific grammar, but can be
+// used to parse multiple token streams
+class GLR {
+public:
+  // ---- grammar-wide data ----
+  // user-specified actions
+  UserActions *userAct;                     // (serf)
+
+  // parse tables derived from the grammar
+  ParseTables *tables;                      // (serf)
+
+  // ---- parser state between tokens ----
+  // I keep a pointer to this so I can ask for token descriptions
+  // inside some of the helper functions
+  LexerInterface *lexerPtr;                 // (serf)
+
+  // Every node in this set is (the top of) a parser that might
+  // ultimately succeed to parse the input, or might reach a
+  // point where it cannot proceed, and therefore dies.  (See
+  // comments at top of glr.cc for more details.)
+  ArrayStack<StackNode*> topmostParsers;     // (refct list)
+
+  // index: StateId -> index in 'topmostParsers' of unique parser
+  // with that state, or INDEX_NO_PARSER if none has that state
+  typedef unsigned char ParserIndexEntry;
+  enum { INDEX_NO_PARSER = 255 };
+  ParserIndexEntry *parserIndex;            // (owner)
+
+  // this is for assigning unique ids to stack nodes
+  int nextStackNodeId;
+  enum { initialStackNodeId = 1 };
+
+  // ---- parser state during each token ----
+  // I used to have fields:
+  //   int currentTokenType;
+  //   SemanticValue currentTokenValue;
+  //   SourceLoc currentTokenLoc;
+  // but these have been now replaced by, respectively,
+  //   lexerPtr->type
+  //   lexerPtr->sval
+  //   lexerPtr->loc
+
+  // ---- scratch space re-used at token-level (or finer) granularity ----
+  // to be regarded as a local variable of GLR::rwlProcessWorklist
+  GrowArray<SemanticValue> toPass;
+
+  // persistent array that I swap with 'topmostParsers' during
+  // 'rwlShiftTerminals' to avoid extra copying or allocation;
+  // this should be regarded as variable local to that function
+  ArrayStack<StackNode*> prevTopmost;        // (refct list)
+
+  // ---- allocation pools ----
+  // this is a pointer to the same-named local variable in innerGlrParse
+  ObjectPool<StackNode> *stackNodePool;
+                               
+  // pool and list for the RWL implementation
+  ReductionPathQueue pathQueue;
+
+  // ---- user options ----
+  // when true, failed parses are accompanied by some rudimentary
+  // diagnosis; when false, failed parses are silent (default: true)
+  bool noisyFailedParse;
+
+  // ---- debugging trace ----
+  // these are computed during GLR::GLR since the profiler reports
+  // there is significant expense to computing the debug strings
+  // (that are then usually not printed)
+  bool trParse;                             // tracingSys("parse")
+  ostream &trsParse;                        // trace("parse")
+
+  // track column for new nodes
+  NODE_COLUMN( int globalNodeColumn; )
+
+  // statistics on parser actions
+  int detShift, detReduce, nondetShift, nondetReduce;
+  
+  // count of # of times yield-then-merge happens
+  int yieldThenMergeCt;
+
+private:    // funcs
+  // comments in glr.cc
+  SemanticValue duplicateSemanticValue(SymbolId sym, SemanticValue sval);
+  void deallocateSemanticValue(SymbolId sym, SemanticValue sval);
+  SemanticValue grabTopSval(StackNode *node);
+
+  StackNode *findTopmostParser(StateId state);
+  StackNode *makeStackNode(StateId state);
+  void writeParseGraph(char const *input) const;
+  void clearAllStackNodes();
+  void addTopmostParser(StackNode *parser);
+  void pullFromTopmostParsers(StackNode *parser);
+  bool canMakeProgress(StackNode *parser);
+  void dumpGSS(int tokenNumber) const;
+  void dumpGSSEdge(FILE *dest, StackNode const *src,
+                               StackNode const *target) const;
+  void printConfig() const;
+  void buildParserIndex();
+  void printParseErrorMessage(StateId lastToDie);
+  bool cleanupAfterParse(SemanticValue &treeTop);
+  bool nondeterministicParseToken();
+  static bool innerGlrParse(GLR &glr, LexerInterface &lexer, SemanticValue &treeTop);
+  SemanticValue doReductionAction(
+    int productionId, SemanticValue const *svals
+    SOURCELOCARG( SourceLoc loc ) );
+
+  void rwlProcessWorklist();
+  SiblingLink *rwlShiftNonterminal(StackNode *leftSibling, int lhsIndex,
+                                   SemanticValue /*owner*/ sval
+                                   SOURCELOCARG( SourceLoc loc ) );
+  int rwlEnqueueReductions(StackNode *parser, ActionEntry action,
+                           SiblingLink *sibLink);
+  void rwlCollectPathLink(
+    ReductionPathQueue::Path *proto, int popsRemaining,
+    StackNode *currentNode, SiblingLink *mustUseLink, SiblingLink *linkToAdd);
+  void rwlRecursiveEnqueue(
+    ReductionPathQueue::Path *proto,
+    int popsRemaining,
+    StackNode *currentNode,
+    SiblingLink *mustUseLink);
+  void rwlShiftTerminals();
+
+  void configCheck(char const *option, bool core, bool table);
+
+  string stackSummary() const;
+  void nodeSummary(stringBuilder &sb, StackNode const *node) const;
+  void innerStackSummary(stringBuilder &sb,
+                         SObjList<StackNode const> &printed,
+                         StackNode const *node) const;
+
+public:     // funcs
+  GLR(UserActions *userAct, ParseTables *tables);
+  ~GLR();
+
+  // ------- primary interface -------
+  // read the named grammar file (.bin extension, typically)
+  void readBinaryGrammar(char const *grammarFname);
+
+  // parse, using the token stream in 'lexer', and store the final
+  // semantic value in 'treeTop'
+  bool glrParse(LexerInterface &lexer, SemanticValue &treeTop);
+
+};
+
+
+#endif // GLR_H

Added: vendor/elsa/current/elkhound/glrconfig.h.in
===================================================================
--- vendor/elsa/current/elkhound/glrconfig.h.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/glrconfig.h.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,88 @@
+// glrconfig.h.in            see license.txt for copyright and terms of use
+// compile-time configuration options which affect the generated
+// GLR parser, and the interface to the user actions
+
+#ifndef GLRCONFIG_H
+#define GLRCONFIG_H
+
+
+// when NO_GLR_SOURCELOC is #defined, we disable all support for
+// automatically propagating source location information in the
+// parser; user actions can still refer to 'loc', but they just get
+// a dummy no-location value
+#ifndef GLR_SOURCELOC
+  #define GLR_SOURCELOC @GLR_SOURCELOC@        // set by ./configure
+#endif
+
+#if GLR_SOURCELOC
+  #define SOURCELOC(stuff) stuff
+
+  // this one adds a leading comma (I can't put that into the
+  // argument <stuff>, because then it looks like the macro is
+  // being passed 2 arguments)
+  #define SOURCELOCARG(stuff) , stuff
+
+  #define NOSOURCELOC(stuff)
+#else
+  #define SOURCELOC(stuff)
+  #define SOURCELOCARG(stuff)
+  #define NOSOURCELOC(stuff) stuff
+#endif
+
+
+// when enabled, NODE_COLUMN tracks in each stack node the
+// appropriate column to display it for in debugging dump.
+// in the new RWL core, this is required to always be 1.
+#ifndef ENABLE_NODE_COLUMNS
+  #define ENABLE_NODE_COLUMNS 1
+#endif
+#if ENABLE_NODE_COLUMNS
+  #define NODE_COLUMN(stuff) stuff
+#else
+  #define NODE_COLUMN(stuff)
+#endif
+
+
+// when enabled, YIELD_COUNT keeps track of the number of times a
+// given semantic value is yielded; this is useful for warning the
+// user when a merge is performed but one of the merged values has
+// already been yielded to another semantic action, which implies
+// that the induced parse forest is incomplete
+#ifndef ENABLE_YIELD_COUNT
+  #define ENABLE_YIELD_COUNT 1
+#endif
+#if ENABLE_YIELD_COUNT
+  #define YIELD_COUNT(stuff) stuff
+#else
+  #define YIELD_COUNT(stuff)
+#endif
+
+
+// when true, error entries in the action table are extracted into
+// their own bitmap; this then enables compression on the action
+// table, since it makes it sparse
+#ifndef ENABLE_EEF_COMPRESSION
+  #define ENABLE_EEF_COMPRESSION @eef@
+#endif
+
+// when true, the action and goto tables are compressed using
+// graph coloring
+#ifndef ENABLE_GCS_COMPRESSION
+  #define ENABLE_GCS_COMPRESSION @gcs@
+#endif
+
+// when true, action and goto *columns* are merged during GCS;
+// otherwise, only rows are merged
+#ifndef ENABLE_GCS_COLUMN_COMPRESSION
+  #define ENABLE_GCS_COLUMN_COMPRESSION @gcsc@
+#endif
+
+// when true, entries in the action and goto tables are a
+// 1-byte index into an appropriate map
+#ifndef ENABLE_CRS_COMPRESSION
+  #define ENABLE_CRS_COMPRESSION @crs@
+#endif
+
+
+
+#endif // GLRCONFIG_H

Added: vendor/elsa/current/elkhound/glrmain.cc
===================================================================
--- vendor/elsa/current/elkhound/glrmain.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/glrmain.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,56 @@
+// glrmain.cc            see license.txt for copyright and terms of use
+// simple 'main' to parse a file; used by some of the example
+// grammars (this file is *not* required for general use of
+// the Elkhound parser)
+
+#include <iostream.h>     // cout
+#include <stdlib.h>       // exit
+
+#include "trace.h"        // traceAddSys
+#include "parssppt.h"     // ParseTreeAndTokens, treeMain
+#include "ckheap.h"       // malloc_stats
+#include "srcloc.h"       // SourceLocManager
+#include "cc_lang.h"      // CCLang
+#include "parsetables.h"  // ParseTables
+
+// no bison-parser present, so define it myself
+Lexer2Token const *yylval = NULL;
+
+// what a mess..
+ParseTables *makeParseTables();
+UserActions *makeUserActions(StringTable &table, CCLang &lang);
+
+void doit(int argc, char **argv)
+{
+  traceAddSys("progress");
+  //traceAddSys("parse-tree");
+
+  SourceLocManager mgr;
+  SemanticValue treeTop;
+  CCLang lang;
+  ParseTreeAndTokens tree(lang, treeTop);
+  UserActions *user = makeUserActions(tree.lexer2.idTable, lang);
+  ParseTables *tables = makeParseTables();
+  tree.userAct = user;
+  tree.tables = tables;
+  if (!treeMain(tree, argc, argv)) {
+    // parse error
+    exit(2);
+  }
+
+  cout << "final parse result: " << treeTop << endl;
+
+  // global cleanup
+  delete user;
+  delete tables;
+  traceRemoveAll();
+}
+
+int main(int argc, char **argv)
+{
+  doit(argc, argv);
+
+  //malloc_stats();
+
+  return 0;
+}

Added: vendor/elsa/current/elkhound/gramanl.cc
===================================================================
--- vendor/elsa/current/elkhound/gramanl.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/gramanl.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5067 @@
+// gramanl.cc            see license.txt for copyright and terms of use
+// code for gramanl.h
+
+#include "gramanl.h"     // this module
+
+#include "bit2d.h"       // Bit2d
+#include "bitarray.h"    // BitArray
+#include "strtokp.h"     // StrtokParse
+#include "syserr.h"      // xsyserror
+#include "trace.h"       // tracing system
+#include "nonport.h"     // getMilliseconds
+#include "crc.h"         // crc32
+#include "flatutil.h"    // Flatten, xfer helpers
+#include "grampar.h"     // readGrammarFile
+#include "emitcode.h"    // EmitCode
+#include "strutil.h"     // replace
+#include "ckheap.h"      // numMallocCalls
+#include "genml.h"       // emitMLActionCode
+#include "ofstreamts.h"  // ofstreamTS
+
+#include <fstream.h>     // ofstream
+#include <stdlib.h>      // getenv
+#include <stdio.h>       // printf
+
+// for ParseTables::emitConstructionCode:
+//   linkdepend: parsetables.cc
+
+
+// for now, we'll just have these be global variables; if I later
+// decide I actually want more than one at a time, I can move these
+// into GrammarAnalysis and push the interfaces to accomodate
+
+// NOTE: only LALR(1) has been recently tested; in particular I
+// know that LR(1) is broken (3/26/02)
+
+// LR(0) does all reductions, regardless of what the next token is
+static bool const LR0 = false;
+
+// SLR(1) looks at a production's LHS's Follow
+static bool const SLR1 = false;
+
+// LR(1) computes context-sensitive follow for each item,
+// depending on how that item arises in the item-set DFA
+static bool const LR1 = false;
+
+// LALR(1) is like LR(1), except two states are merged if
+// they only differ in their items' lookaheads (so it has
+// the same # of states as SLR(1), while having some of the
+// context-sensitivity of LR(1))
+static bool const LALR1 = true;
+
+
+#if !defined(NDEBUG)     // track unauthorized malloc's
+  #define TRACK_MALLOC
+#endif
+
+#ifdef TRACK_MALLOC
+  // take initial snapsot
+  #define INITIAL_MALLOC_STATS() \
+    unsigned mallocCt = numMallocCalls();
+
+  // nothing should have been allocated recently; if it has, then
+  // print a warning
+  #define CHECK_MALLOC_STATS(desc)                                              \
+    {                                                                           \
+      unsigned newCt = numMallocCalls();                                        \
+      if (mallocCt != newCt) {                                                  \
+        cout << (newCt - mallocCt) << " malloc calls during " << desc << endl;  \
+        mallocCt = newCt;                                                       \
+        breaker();                                                              \
+      }                                                                         \
+    }
+
+  // some unavoidable allocation just happened, so just update counter
+  #define UPDATE_MALLOC_STATS() \
+    mallocCt = numMallocCalls();
+#else
+  #define INITIAL_MALLOC_STATS()
+  #define CHECK_MALLOC_STATS(desc)
+  #define UPDATE_MALLOC_STATS()
+#endif
+
+
+// ----------------- DottedProduction ------------------
+#if 0    // used?
+DottedProduction::DottedProduction(DottedProduction const &obj)
+{
+  prod = obj.prod;
+  dot = obj.dot;
+  afterDot = obj.afterDot;
+  firstSet = obj.firstSet;
+  canDeriveEmpty = obj.canDeriveEmpty;
+}
+#endif // 0
+
+
+DottedProduction::DottedProduction()
+{
+  init();
+}
+
+void DottedProduction::init()
+{
+  prod = NULL;
+  dot = -1;
+  afterDot = NULL;
+  canDeriveEmpty = false;
+  backPointer = NULL;
+}
+
+
+DottedProduction::~DottedProduction()
+{}
+
+
+// arbitrary integer unique to every symbol and preserved
+// across read/write
+int symbolIndex(Symbol const *s)
+{
+  if (s->isTerminal()) {
+    // make terminals negative since otherwise they'd
+    // collide with nonterminals
+    return -( s->asTerminalC().termIndex );
+  }
+  else {
+    return s->asNonterminalC().ntIndex;
+  }
+}
+
+
+#if 0
+bool DottedProduction::isEqual(DottedProduction const &obj) const
+{
+  return dot == obj.dot &&
+         prod == obj.prod;
+}
+#endif // 0
+
+
+void DottedProduction::setProdAndDot(Production const *p, int d)
+{
+  prod = p;
+  dot = d;
+
+  // computing this each time turned out to be significant
+  // according to the profiler, so we store it instead
+  bool dotAtEnd = (dot == prod->rhsLength());
+  afterDot = dotAtEnd? NULL : prod->right.nthC(dot)->sym;
+}
+
+Symbol const *DottedProduction::symbolBeforeDotC() const
+{
+  xassert(!isDotAtStart());
+  return prod->right.nthC(dot-1)->sym;
+}
+
+#if 0
+Symbol const *DottedProduction::symbolAfterDotC() const
+{
+  xassert(!isDotAtEnd());
+  return prod->right.nthC(dot)->sym;
+}
+#endif // 0
+
+
+void DottedProduction::print(ostream &os) const
+{
+  os << prod->left->name << " ->";
+
+  int position = 0;
+  for (ObjListIter<Production::RHSElt> iter(prod->right);
+       !iter.isDone(); iter.adv(), position++) {
+    if (position == dot) {
+      os << " .";
+    }
+    os << " " << iter.data()->sym->toString();
+  }
+  if (position == dot) {
+    os << " .";
+  }
+}
+
+
+// ---------------------- LRItem -------------------
+LRItem::LRItem(int numTerms, DottedProduction const *dp)
+  : dprod(dp),
+    lookahead(numTerms)
+{}
+
+LRItem::LRItem(LRItem const &obj)
+  : dprod(obj.dprod),
+    lookahead(obj.lookahead)
+{}
+
+LRItem::~LRItem()
+{}
+
+LRItem::LRItem(Flatten &flat)
+  : dprod(NULL),
+    lookahead(flat)
+{}
+
+void LRItem::xfer(Flatten &flat)
+{
+  lookahead.xfer(flat);
+}
+
+void LRItem::xferSerfs(Flatten &flat, GrammarAnalysis &g)
+{
+  if (flat.writing()) {
+    flat.writeInt(prodIndex());
+    flat.writeInt(getDot());
+  }
+  else {
+    // originally had these directly in the argument list,
+    // but order of eval is undefined!
+    int idx = flat.readInt();
+    int d = flat.readInt();
+    dprod = g.getDProdIndex(idx, d);
+  }
+}
+
+
+// compare two items in an arbitrary (but deterministic) way so that
+// sorting will always put a list of items into the same order, for
+// comparison purposes; this doesn't consider the lookahead
+STATICDEF int LRItem::diff(LRItem const *a, LRItem const *b, void*)
+{
+  // check the prodIndex first
+  int ret = a->prodIndex() - b->prodIndex();
+  if (ret) { return ret; }
+
+  // 'dot'
+  ret = a->getDot() - b->getDot();
+  return ret;
+}
+
+
+bool firstIncludes(Symbol const *sym, Terminal const *t)
+{
+  if (sym->isTerminal()) {
+    return sym == t;
+  }
+  else {
+    // this generalizes 'isExtendingShift'.. and while this did help
+    // eliminate one S/R in a grammar I was working on, there were
+    // others that could not be eliminated at all (they were not
+    // statically decidable), so this generalization might not be
+    // useful afterall
+    return sym->asNonterminalC().first.contains(t->termIndex);
+  }
+}
+
+bool LRItem::isExtendingShift(Nonterminal const *A, Terminal const *t) const
+{
+  return !dprod->isDotAtEnd() &&                      // shift
+         dprod->getProd()->left == A &&               // extending A
+         firstIncludes(dprod->symbolAfterDotC(), t);  // with t
+}
+
+
+void LRItem::print(ostream &os, GrammarAnalysis const &g) const
+{
+  dprod->print(os);
+  lookahead.print(os, g);      // prints the separating comma, if necessary
+}
+
+
+// ----------------- ItemSet -------------------
+ItemSet::ItemSet(StateId anId, int numTerms, int numNonterms)
+  : kernelItems(),
+    nonkernelItems(),
+    termTransition(NULL),      // inited below
+    nontermTransition(NULL),   // inited below
+    terms(numTerms),
+    nonterms(numNonterms),
+    dotsAtEnd(NULL),
+    numDotsAtEnd(0),
+    stateSymbol(NULL),
+    id(anId),
+    BFSparent(NULL)
+{
+  allocateTransitionFunction();
+}
+
+void ItemSet::allocateTransitionFunction()
+{
+  termTransition = new ItemSet* [terms];
+  nontermTransition = new ItemSet* [nonterms];
+
+  INTLOOP(t, 0, terms) {
+    termTransition[t] = (ItemSet*)NULL;      // means no transition on t
+  }
+  INTLOOP(n, 0, nonterms) {
+    nontermTransition[n] = (ItemSet*)NULL;
+  }
+}
+
+
+ItemSet::~ItemSet()
+{
+  delete[] termTransition;
+  delete[] nontermTransition;
+
+  if (dotsAtEnd) {
+    delete[] dotsAtEnd;
+  }
+}
+
+
+ItemSet::ItemSet(Flatten &flat)
+  : termTransition(NULL),
+    nontermTransition(NULL),
+    dotsAtEnd(NULL),
+    numDotsAtEnd(0),
+    stateSymbol(NULL),
+    BFSparent(NULL)
+{}
+
+
+Production *getNthProduction(Grammar *g, int n)
+{
+  if (0 <= n && n < g->productions.count()) {
+    return g->productions.nth(n);
+  }
+  else {
+    // my access path functions' contract is to
+    // return NULL on any error (as opposed to, say,
+    // an exception or assertion failure); this serves two
+    // purposes:
+    //   - the writing code can use it to determine the
+    //     maximum value of 'n'
+    //   - the reading code can use it to validate 'n',
+    //     since that comes from the input file
+    return NULL;
+  }
+}
+
+#if 0    // not needed, doesn't work
+DottedProduction *getNthDottedProduction(Production *p, int n)
+{
+  if (0 <= n && n < (p->rhsLength() + 1)) {
+    return p->getDProd(n);
+  }
+  else {
+    return NULL;
+  }
+}
+#endif // 0
+
+
+void ItemSet::xfer(Flatten &flat)
+{
+  xferObjList(flat, kernelItems);
+  xferObjList(flat, nonkernelItems);
+
+  flat.xferInt(terms);
+  flat.xferInt(nonterms);
+
+  // numDotsAtEnd and kernelItemsCRC are computed from
+  // other data
+  // NEW: but computing them requires the items, which I'm omitting
+
+  flat.xferInt(numDotsAtEnd);
+  flat.xferLong((long&)kernelItemsCRC);
+
+  flat.xferInt((int&)id);
+}
+
+
+int ticksComputeNonkernel = 0;
+
+void ItemSet::xferSerfs(Flatten &flat, GrammarAnalysis &g)
+{
+  // xfer the 'prod' fields of the items
+  {
+    MUTATE_EACH_OBJLIST(LRItem, kernelItems, k) {
+      k.data()->xferSerfs(flat, g);
+    }
+    MUTATE_EACH_OBJLIST(LRItem, nonkernelItems, n) {
+      n.data()->xferSerfs(flat, g);
+    }
+  }
+
+
+  #if 0
+    // 'kernelItems' and 'nonkernelItems': each one accessed as
+    //   g.productions.nth(???)->getDProd(???)
+    xferSObjList_twoLevelAccess(
+      flat,
+      kernelItems,               // serf list
+      static_cast<Grammar*>(&g), // root of access path
+      getNthProduction,          // first access path link
+      getNthDottedProduction);   // second access path link
+
+    #if 1
+      xferSObjList_twoLevelAccess(
+        flat,
+        nonkernelItems,            // serf list
+        static_cast<Grammar*>(&g), // root of access path
+        getNthProduction,          // first access path link
+        getNthDottedProduction);   // second access path link
+    #else
+      // instead of the above, let's try computing the nonkernel items
+      if (flat.reading()) {
+        int start = getMilliseconds();
+        g.itemSetClosure(*this);
+        ticksComputeNonkernel += (getMilliseconds() - start);
+      }
+    #endif
+  #endif // 0
+
+  // these need to be sorted for 'changedItems'; but since
+  // we're sorting by *address*, that's not necessarily
+  // preserved across read/write
+  // NEW: it should be stable now
+  //kernelItems.insertionSort(LRItem::diff);
+
+
+  // transition functions
+  if (flat.reading()) {
+    allocateTransitionFunction();
+  }
+  INTLOOP(t, 0, terms) {
+    //xferNullableSerfPtrToList(flat, termTransition[t], g.itemSets);
+    xferNullableSerfPtr(flat, termTransition[t]);
+  }
+  INTLOOP(n, 0, nonterms) {
+    //xferNullableSerfPtrToList(flat, nontermTransition[n], g.itemSets);
+    xferNullableSerfPtr(flat, nontermTransition[n]);
+  }
+
+
+  // dotsAtEnd, numDotsAtEnd, kernelItemsCRC
+  //if (flat.reading()) {
+  //  changedItems();
+  //}
+
+  if (flat.reading()) {
+    dotsAtEnd = new LRItem const * [numDotsAtEnd];
+  }
+  INTLOOP(p, 0, numDotsAtEnd) {
+    #if 0
+    xferSerfPtr_twoLevelAccess(
+      flat,
+      const_cast<LRItem*&>(dotsAtEnd[p]),   // serf
+      static_cast<Grammar*>(&g), // root of access path
+      getNthProduction,          // first access path link
+      getNthDottedProduction);   // second access path link
+    #endif // 0
+    xferSerfPtr(flat, dotsAtEnd[p]);
+  }
+
+  xferNullableSerfPtr(flat, stateSymbol);
+
+  xferNullableSerfPtrToList(flat, BFSparent, g.itemSets);
+}
+
+
+Symbol const *ItemSet::computeStateSymbolC() const
+{
+  // need only check kernel items since all nonkernel items
+  // have their dots at the left side
+  FOREACH_OBJLIST(LRItem, kernelItems, item) {
+    if (! item.data()->isDotAtStart() ) {
+      return item.data()->symbolBeforeDotC();
+    }
+  }
+  return NULL;
+}
+
+
+int ItemSet::bcheckTerm(int index) const
+{
+  xassert(0 <= index && index < terms);
+  return index;
+}
+
+int ItemSet::bcheckNonterm(int index) const
+{
+  xassert(0 <= index && index < nonterms);
+  return index;
+}
+
+ItemSet *&ItemSet::refTransition(Symbol const *sym)
+{
+  if (sym->isTerminal()) {
+    Terminal const &t = sym->asTerminalC();
+    return termTransition[bcheckTerm(t.termIndex)];
+  }
+  else {
+    Nonterminal const &nt = sym->asNonterminalC();
+    return nontermTransition[bcheckNonterm(nt.ntIndex)];
+  }
+}
+
+
+ItemSet const *ItemSet::transitionC(Symbol const *sym) const
+{
+  return const_cast<ItemSet*>(this)->refTransition(sym);
+}
+
+
+void ItemSet::setTransition(Symbol const *sym, ItemSet *dest)
+{
+  refTransition(sym) = dest;
+}
+
+
+void ItemSet::removeShift(Terminal const *sym)
+{
+  refTransition(sym) = NULL;
+}
+
+
+void ItemSet::addKernelItem(LRItem *item)
+{
+  // add it
+  kernelItems.appendUnique(item);
+}
+
+
+void ItemSet::sortKernelItems()
+{
+  // sort the items to facilitate equality checks
+  kernelItems.mergeSort(LRItem::diff);
+
+  // note: the caller must call changedItems
+}
+
+
+bool ItemSet::operator==(ItemSet const &obj) const
+{
+  // since common case is disequality, check the
+  // CRCs first, and only do full check if they
+  // match
+  if (kernelItemsCRC == obj.kernelItemsCRC) {
+    // since nonkernel items are entirely determined by kernel
+    // items, and kernel items are sorted, it's sufficient to
+    // check for kernel list equality
+    // OLD: when pointer equality was sufficient
+    //   return kernelItems.equalAsPointerLists(obj.kernelItems);
+    // NEW: use deep equality check
+    return kernelItems.equalAsLists(obj.kernelItems, LRItem::diff);
+  }
+  else {
+    // can't possibly be equal if CRCs differ
+    return false;
+  }
+}
+
+
+void ItemSet::addNonkernelItem(LRItem *item)
+{
+  nonkernelItems.appendUnique(item);
+
+  // note: the caller is supposed to call changedItems
+}
+
+
+void ItemSet::removeReduce(Production const *prod, Terminal const *sym)
+{
+  MUTATE_EACH_OBJLIST(LRItem, kernelItems, k) {
+    if (k.data()->isDotAtEnd() &&
+        k.data()->getProd() == prod) {
+      k.data()->laRemove(sym->termIndex);
+    }
+  }
+
+  MUTATE_EACH_OBJLIST(LRItem, nonkernelItems, n) {
+    if (n.data()->isDotAtEnd() &&
+        n.data()->getProd() == prod) {
+      n.data()->laRemove(sym->termIndex);
+    }
+  }
+
+  #if 0
+  ObjListMutator<LRItem> k(kernelItems);
+  while (!k.isDone()) {
+    if (k.data()->isDotAtEnd() &&
+        k.data()->getProd() == prod) {
+      k.deleteIt();
+    }
+    else {
+      k.adv();
+    }
+  }
+
+  changedItems();
+  #endif // 0
+}
+
+
+void ItemSet::getAllItems(SObjList<LRItem> &dest, bool nonkernel) const
+{
+  SObjListMutator<LRItem> mut(dest);
+
+  FOREACH_OBJLIST(LRItem, kernelItems, k) {
+    mut.append(const_cast<LRItem*>(k.data()));
+  }
+  if (nonkernel) {
+    FOREACH_OBJLIST(LRItem, nonkernelItems, n) {
+      mut.append(const_cast<LRItem*>(n.data()));
+    }
+  }
+}
+
+
+STATICDEF int ItemSet::diffById(ItemSet const *left, ItemSet const *right, void*)
+{
+  return left->id - right->id;
+}
+
+
+void ItemSet::throwAwayItems()
+{
+  // can't delete the whole lists because I need the
+  // reductions; among other things, 'dotsAtEnd' refers to them
+  deleteNonReductions(kernelItems);
+  deleteNonReductions(nonkernelItems);
+}
+
+void ItemSet::deleteNonReductions(ObjList<LRItem> &list)
+{
+  ObjListMutator<LRItem> mut(list);
+  while (!mut.isDone()) {
+    if (mut.data()->isDotAtEnd()) {
+      // keep it
+      mut.adv();
+    }
+    else {
+      // trash it
+      mut.deleteIt();     // also advances
+    }
+  }
+}
+
+
+// return the reductions that are ready in this state, given
+// that the next symbol is 'lookahead'
+void ItemSet::getPossibleReductions(ProductionList &reductions,
+                                    Terminal const *lookahead,
+                                    bool parsing) const
+{
+  // for each item with dot at end
+  loopi(numDotsAtEnd) {
+    LRItem const *item = dotsAtEnd[i];
+
+    if (LR0) {
+      // don't check the lookahead
+    }
+    else if (SLR1) {
+      // the follow of its LHS must include 'lookahead'
+      if (!item->getProd()->left->follow.contains(lookahead->termIndex)) {    // (constness)
+        if (parsing && tracingSys("parse")) {
+          trace("parse") << "state " << id
+                         << ", not reducing by "
+                         << item->getProd()->toString(false /*printType*/)
+                         << " because " << lookahead->toString()
+                         << " is not in follow of "
+                         << item->getProd()->left->name << endl;
+        }
+        continue;
+      }
+    }
+    else if (LALR1 || LR1) {
+      // the item's lookahead must include 'lookahead'
+      if (!item->laContains(lookahead->termIndex)) {
+        if (parsing && tracingSys("parse")) {
+          trace("parse") << "state " << id
+                         << ", not reducing by "
+                         << item->getProd()->toString(false /*printType*/)
+                         << " because " << lookahead->toString()
+                         << " is not in lookahead" << endl;
+        }
+        continue;
+      }
+    }
+    else {
+      xfailure("no LR variant specified?");
+    }
+
+    // ok, this one's ready
+    reductions.append(const_cast<Production*>(item->getProd()));       // (constness)
+  }
+}
+
+
+bool ItemSet::mergeLookaheadsInto(ItemSet &dest) const
+{
+  // will return true if any changes made
+  bool changes = false;
+
+  // iterate over both kernel lists simultaneously
+  ObjListIter<LRItem> srcIter(kernelItems);
+  ObjListMutator<LRItem> destIter(dest.kernelItems);
+  while (!srcIter.isDone() && !destIter.isDone()) {
+    LRItem const &srcItem = *(srcIter.data());
+    LRItem &destItem = *(destIter.data());
+
+    // the caller should already have established equality of the
+    // non-lookahead components of the kernel items
+    xassert(srcItem.equalNoLA(destItem));
+
+    // merge lookaheads
+    if (destItem.laMerge(srcItem)) {
+      changes = true;
+    }
+
+    srcIter.adv();
+    destIter.adv();
+  }
+
+  // kernel list lengths are supposed to be the same
+  xassert(srcIter.isDone() && destIter.isDone());
+
+  return changes;
+}
+
+
+bool ItemSet::hasExtendingShift(Nonterminal const *A, Terminal const *t) const
+{
+  FOREACH_OBJLIST(LRItem, kernelItems, iter1) {
+    if (iter1.data()->isExtendingShift(A, t)) { return true; }
+  }
+  FOREACH_OBJLIST(LRItem, nonkernelItems, iter2) {
+    if (iter2.data()->isExtendingShift(A, t)) { return true; }
+  }
+  return false;
+}
+
+
+Production const *ItemSet::getFirstReduction() const
+{
+  xassert(numDotsAtEnd >= 1);
+  return dotsAtEnd[0]->getProd();
+}
+
+
+void ItemSet::changedItems()
+{
+  // -- recompute dotsAtEnd --
+  // collect all items
+  SObjList<LRItem> items;      // (constness) 'items' shouldn't be used to modify the elements
+  getAllItems(items);
+
+  // count number with dots at end
+  int count = 0;
+  {
+    SFOREACH_OBJLIST(LRItem, items, itemIter) {
+      LRItem const *item = itemIter.data();
+
+      if (item->isDotAtEnd()) {
+        count++;
+      }
+    }
+  }
+
+  // get array of right size
+  if (dotsAtEnd  &&  count == numDotsAtEnd) {
+    // no need to reallocate, already correct size
+  }
+  else {
+    // throw old away
+    if (dotsAtEnd) {
+      delete[] dotsAtEnd;
+    }
+
+    // allocate new array
+    numDotsAtEnd = count;
+    dotsAtEnd = new LRItem const * [numDotsAtEnd];
+  }
+
+  // fill array
+  int index = 0;
+  SFOREACH_OBJLIST(LRItem, items, itemIter) {
+    LRItem const *item = itemIter.data();
+
+    if (item->isDotAtEnd()) {
+      dotsAtEnd[index] = item;
+      index++;
+    }
+  }
+
+  // verify both loops executed same number of times
+  xassert(index == count);
+
+  // compute CRC; in this function, I just allocate here since this
+  // function is already allocation-happy
+  GrowArray<DottedProduction const*> array(0 /*allocate later*/);
+  computeKernelCRC(array);
+
+  // compute this so we can throw away items later if we want to
+  stateSymbol = computeStateSymbolC();
+}
+
+
+void ItemSet::computeKernelCRC(GrowArray<DottedProduction const*> &array)
+{
+  int numKernelItems = kernelItems.count();
+
+  // expand as necessary, but don't get smaller
+  array.ensureAtLeast(numKernelItems);
+
+  // we will crc the prod/dot fields, using the pointer representation
+  // of 'dprod'; assumes the items have already been sorted!
+  int index = 0;
+  FOREACH_OBJLIST(LRItem, kernelItems, kitem) {
+    array[index] = kitem.data()->dprod;
+    index++;
+  }
+
+  // CRC the buffer
+  kernelItemsCRC = crc32((unsigned char const*)(array.getArray()),
+                         sizeof(array[0]) * numKernelItems);
+}
+
+
+void ItemSet::print(ostream &os, GrammarAnalysis const &g,
+                    bool nonkernel) const
+{
+  os << "ItemSet " << id << ":\n";
+
+  // collect all items
+  SObjList<LRItem> items;     // (constness) don't use 'item' to modify elements
+  getAllItems(items, nonkernel);
+
+  // for each item
+  SFOREACH_OBJLIST(LRItem, items, itemIter) {
+    LRItem const *item = itemIter.data();
+
+    // print its text
+    os << "  ";
+    item->print(os, g);
+    os << "      ";
+
+    // print any transitions on its after-dot symbol
+    if (!item->isDotAtEnd()) {
+      ItemSet const *is = transitionC(item->symbolAfterDotC());
+      if (is == NULL) {
+        // this happens if I print the item set before running closure,
+        // and also after prec/assoc disambiguation
+        os << "(no transition)";
+      }
+      else {
+        os << "--> " << is->id;
+      }
+    }
+    os << endl;
+  }
+
+  // print transition function directly, since I'm now throwing
+  // away items sometimes
+  for (int t=0; t<terms; t++) {
+    if (termTransition[t]) {
+      os << "  on terminal " << g.getTerminal(t)->name
+         << " go to " << termTransition[t]->id << endl;
+    }
+  }
+
+  for (int n=0; n<nonterms; n++) {
+    if (nontermTransition[n]) {
+      os << "  on nonterminal " << g.getNonterminal(n)->name
+         << " go to " << nontermTransition[n]->id << endl;
+    }
+  }
+
+  for (int p=0; p<numDotsAtEnd; p++) {
+    os << "  can reduce by " << dotsAtEnd[p]->getProd()->toString() << endl;
+  }
+}
+
+
+void ItemSet::writeGraph(ostream &os, GrammarAnalysis const &g) const
+{
+  // node: n <name> <desc>
+  os << "\nn ItemSet" << id << " ItemSet" << id << "/";
+    // rest of desc will follow
+
+  // collect all items
+  SObjList<LRItem> items;         // (constness) don't use 'items' to modify elements
+  getAllItems(items);
+
+  // for each item, print the item text
+  SFOREACH_OBJLIST(LRItem, items, itemIter) {
+    LRItem const *item = itemIter.data();
+
+    // print its text
+    os << "   ";
+    item->print(os, g);
+
+    // THIS IS A PROBLEM!  the item's output will include
+    // slashes too, if it has >1 lookahead token ... !
+    os << "/";      // line separator in my node format
+  }
+  os << endl;
+
+  // print transitions on terminals
+  INTLOOP(t, 0, terms) {
+    if (termTransition[t] != NULL) {
+      os << "e ItemSet" << id
+         << " ItemSet" << termTransition[t]->id << endl;
+    }
+  }
+
+  // print transitions on nonterminals
+  INTLOOP(nt, 0, nonterms) {
+    if (nontermTransition[nt] != NULL) {
+      os << "e ItemSet" << id
+         << " ItemSet" << nontermTransition[nt]->id << endl;
+    }
+  }
+}
+
+
+// ------------------------ GrammarAnalysis --------------------
+GrammarAnalysis::GrammarAnalysis()
+  : derivable(NULL),
+    indexedNonterms(NULL),
+    indexedTerms(NULL),
+    numNonterms(0),
+    numTerms(0),
+    productionsByLHS(NULL),
+    dottedProds(NULL),
+    indexedProds(NULL),
+    numProds(0),
+    initialized(false),
+    nextItemSetId(0),    // [ASU] starts at 0 too
+    itemSets(),
+    startState(NULL),
+    cyclic(false),
+    symOfInterest(NULL),
+    errors(0),
+    tables(NULL)
+{}
+
+
+GrammarAnalysis::~GrammarAnalysis()
+{
+  if (indexedNonterms != NULL) {
+    delete indexedNonterms;
+  }
+
+  if (indexedTerms != NULL) {
+    delete indexedTerms;
+  }
+
+  if (productionsByLHS != NULL) {
+    // empties all lists automatically because of "[]"
+    delete[] productionsByLHS;
+  }
+
+  if (indexedProds != NULL) {
+    delete[] indexedProds;
+  }
+
+  deleteDottedProductions();
+
+  if (derivable != NULL) {
+    delete derivable;
+  }
+
+  if (tables) {
+    delete tables;
+  }
+}
+
+
+Terminal const *GrammarAnalysis::getTerminal(int index) const
+{
+  xassert((unsigned)index < (unsigned)numTerms);
+  return indexedTerms[index];
+}
+
+Nonterminal const *GrammarAnalysis::getNonterminal(int index) const
+{
+  xassert((unsigned)index < (unsigned)numNonterms);
+  return indexedNonterms[index];
+}
+
+Production const *GrammarAnalysis::getProduction(int index) const
+{
+  xassert((unsigned)index < (unsigned)numProds);
+  return indexedProds[index];
+}
+
+ItemSet const *GrammarAnalysis::getItemSet(int index) const
+{
+  // no pretense of efficiency; this is only used interactively
+  FOREACH_OBJLIST(ItemSet, itemSets, iter) {
+    if (iter.data()->id == index) {
+      return iter.data();
+    }
+  }
+  return NULL;
+}
+
+
+void GrammarAnalysis::xfer(Flatten &flat)
+{
+  Grammar::xfer(flat);
+
+  xferOwnerPtr(flat, derivable);
+
+  // delay indexed[Non]Terms, productionsByLHS,
+  // and initialized
+
+  flat.xferInt(nextItemSetId);
+
+  xferObjList(flat, itemSets);
+  xferSerfPtrToList(flat, startState, itemSets);
+
+  flat.xferBool(cyclic);
+
+  // don't bother xferring 'symOfInterest', since it's
+  // only used for debugging
+
+  // 7/27/03: tables are no longer xferrable
+  //xferOwnerPtr(flat, tables);
+
+  // now do the easily-computable stuff
+  // NOTE: these functions are also called by initializeAuxData,
+  // so they need to serve both callers correctly
+  computeIndexedNonterms();
+  computeIndexedTerms();
+  computeProductionsByLHS();
+  createDottedProductions();
+
+  // do serfs after because if I want to compute the
+  // nonkernel items instead of storing them, I need
+  // the indices
+  MUTATE_EACH_OBJLIST(ItemSet, itemSets, iter) {
+    iter.data()->xferSerfs(flat, *this);
+  }
+
+  flat.xferBool(initialized);
+}
+
+
+void GrammarAnalysis::
+  printProductions(ostream &os, bool printCode) const
+{
+  if (cyclic) {
+    os << "(cyclic!) ";
+  }
+  Grammar::printProductions(os, printCode);
+}
+
+
+void GrammarAnalysis::
+  printProductionsAndItems(ostream &os, bool printCode) const
+{
+  printProductions(os, printCode);
+
+  FOREACH_OBJLIST(ItemSet, itemSets, iter) {
+    iter.data()->print(os, *this);
+  }
+}
+
+
+void printSymbols(ostream &os, ObjList<Symbol> const &list)
+{
+  for (ObjListIter<Symbol> iter(list);
+       !iter.isDone(); iter.adv()) {
+    os << "  " << *(iter.data()) << endl;
+  }
+}
+
+
+bool GrammarAnalysis::addDerivable(Nonterminal const *left, Nonterminal const *right)
+{
+  return addDerivable(left->ntIndex, right->ntIndex);
+}
+
+bool GrammarAnalysis::addDerivable(int left, int right)
+{
+  // Almost as an aside, I'd like to track cyclicity in grammars.
+  // It's always true that N ->* N, because 0 steps are allowed.
+  // A grammar is cyclic if N ->+ N, i.e. it derives itself in
+  // 1 or more steps.
+  //
+  // We can detect that fairly easily by tracking calls to
+  // this fn with left==right.  Since N ->* N in 0 steps is
+  // recorded during init (and *not* by calling this fn), the
+  // only calls to this with left==right will be when the
+  // derivability code detects a nonzero-length path.
+
+  if (left==right) {
+    Nonterminal *NT = indexedNonterms[left];    // ==right
+    if (!NT->cyclic) {
+      trace("derivable")
+        << "discovered that " << NT->name << " ->+ "
+        << NT->name << " (i.e. is cyclic)\n";
+      NT->cyclic = true;
+      cyclic = true;     // for grammar as a whole
+
+      // Even though we didn't know this already, it doesn't
+      // constitute a change in the ->* relation (which is what the
+      // derivability code cares about), so we do *not* report a
+      // change for the cyclicty detection.
+    }
+  }
+
+  // we only made a change, and hence should return true,
+  // if there was a 0 here before
+  return 0 == derivable->testAndSet(point(left, right));
+}
+
+
+bool GrammarAnalysis::canDerive(Nonterminal const *left, Nonterminal const *right) const
+{
+  return canDerive(left->ntIndex, right->ntIndex);
+}
+
+bool GrammarAnalysis::canDerive(int left, int right) const
+{
+  return 1 == derivable->get(point(left, right));
+}
+
+
+void GrammarAnalysis::initDerivableRelation()
+{
+  // two-dimensional matrix to represent token derivabilities
+  derivable = new Bit2d(point(numNonterms, numNonterms));
+
+  // initialize it
+  derivable->setall(0);
+  loopi(numNonterms) {
+    derivable->set(point(i,i));
+      // every nonterminal can derive itself in 0 or more steps
+      // (specifically, in 0 steps, at least)
+      //
+      // NOTE: we do *not* call addDerivable because that would
+      // mess up the cyclicity detection logic
+  }
+}
+
+
+bool GrammarAnalysis::canDeriveEmpty(Nonterminal const *nonterm) const
+{
+  return canDerive(nonterm, &emptyString);
+}
+
+
+bool GrammarAnalysis::sequenceCanDeriveEmpty(RHSEltList const &list) const
+{
+  RHSEltListIter iter(list);
+  return iterSeqCanDeriveEmpty(iter);
+}
+
+bool GrammarAnalysis::iterSeqCanDeriveEmpty(RHSEltListIter iter) const
+{
+  // look through the sequence beginning with 'iter'; if any members cannot
+  // derive emptyString, fail
+  for (; !iter.isDone(); iter.adv()) {
+    if (iter.data()->sym->isTerminal()) {
+      return false;    // terminals can't derive emptyString
+    }
+
+    if (!canDeriveEmpty(&( iter.data()->sym->asNonterminalC() ))) {
+      return false;    // nonterminal that can't derive emptyString
+    }
+  }
+
+  return true;
+}
+
+
+bool GrammarAnalysis::firstIncludes(Nonterminal const *NT, Terminal const *term) const
+{
+  return NT->first.contains(term->termIndex);
+}
+
+#if 0
+bool GrammarAnalysis::addFirst(Nonterminal *NT, Terminal *term)
+{
+  return NT->first.prependUnique(term);
+
+  // regarding non-constness of 'term':
+  // highly nonideal.. the problem is that by using annotations in
+  // the structures themselves, I have a hard time saying that I
+  // intend to modify the annotations but not the "key" data...
+  // this cast is really a symptom of that too.. (and, perhaps, also
+  // that I don't have a List class that promises to never permit
+  // modification of the pointed-to data.. but it's not clear I'd
+  // be better of using it here even if I had it)
+}
+#endif // 0
+
+
+bool GrammarAnalysis::followIncludes(Nonterminal const *NT, Terminal const *term) const
+{
+  return NT->follow.contains(term->termIndex);
+}
+
+#if 0
+// returns true if Follow(NT) is changed by adding 'term' to it
+bool GrammarAnalysis::addFollow(Nonterminal *NT, Terminal *term)
+{
+  return NT->follow.prependUnique(term);
+}
+#endif // 0
+
+
+// ----------------- Grammar algorithms --------------------------
+// create and initialize 'indexedNonterms'
+void GrammarAnalysis::computeIndexedNonterms()
+{
+  // map: ntIndex -> Nonterminal*
+  numNonterms = Grammar::numNonterminals();
+  indexedNonterms = new Nonterminal* [numNonterms];
+
+  // fill it
+  indexedNonterms[emptyStringIndex] = &emptyString;
+  int index = emptyStringIndex;
+  emptyString.ntIndex = index++;
+
+  for (ObjListMutator<Nonterminal> sym(nonterminals);
+       !sym.isDone(); index++, sym.adv()) {
+    indexedNonterms[index] = sym.data();    // map: index to symbol
+    sym.data()->ntIndex = index;            // map: symbol to index
+  }
+}
+
+
+// create and initialize 'indexedTerms'
+void GrammarAnalysis::computeIndexedTerms()
+{
+  // map: termIndex -> Terminal*
+  // the ids have already been assigned; but I'm going to continue
+  // to insist on a contiguous space starting at 0
+  numTerms = Grammar::numTerminals();
+  indexedTerms = new Terminal* [numTerms];
+  loopi(numTerminals()) {
+    indexedTerms[i] = NULL;      // used to track id duplication
+  }
+  for (ObjListMutator<Terminal> sym(terminals);
+       !sym.isDone(); sym.adv()) {
+    int index = sym.data()->termIndex;   // map: symbol to index
+    if (indexedTerms[index] != NULL) {
+      xfailure(stringc << "terminal index collision at index " << index);
+    }
+    indexedTerms[index] = sym.data();    // map: index to symbol
+  }
+}
+
+
+// set the first/follow of all nonterminals to the correct size
+void GrammarAnalysis::resetFirstFollow()
+{
+  MUTATE_EACH_NONTERMINAL(nonterminals, sym) {
+    sym.data()->first.reset(numTerminals());
+    sym.data()->follow.reset(numTerminals());
+  }
+}
+
+
+// create and initialize 'productionsByLHS' and 'indexedProds'
+void GrammarAnalysis::computeProductionsByLHS()
+{
+  // map: nonterminal -> productions with that nonterm on LHS
+  productionsByLHS = new SObjList<Production> [numNonterms];
+
+  // map: prodIndex -> production
+  numProds = productions.count();
+  indexedProds = new Production* [numProds];
+  memset(indexedProds, 0, sizeof(*indexedProds) * numProds);
+
+  // fill in both maps
+  {
+    MUTATE_EACH_PRODUCTION(productions, prod) {        // (constness)
+      int LHSindex = prod.data()->left->ntIndex;
+      xassert(LHSindex < numNonterms);
+
+      productionsByLHS[LHSindex].append(prod.data());
+      indexedProds[prod.data()->prodIndex] = prod.data();
+    }
+  }
+
+  // verify we filled the 'prodIndex' map
+  for (int id=0; id<numProds; id++) {
+    xassert(indexedProds[id] != NULL);
+  }
+}
+
+
+void GrammarAnalysis::createDottedProductions()
+{
+  // map: prodIndex x dotPosn -> DottedProduction
+  //DottedProduction const **
+  dottedProds = new DottedProduction* [numProds];
+  memset(dottedProds, 0, sizeof(*dottedProds) * numProds);
+
+  FOREACH_PRODUCTION(productions, iter) {
+    Production const *prod = iter.data();
+    int rhsLen = prod->rhsLength();
+    xassert(rhsLen >= 0);
+    int id = prod->prodIndex;
+
+    // one dottedproduction for every dot position, which is one
+    // more than the # of RHS elements
+    DottedProduction *array = new DottedProduction[rhsLen + 1];
+    dottedProds[id] = array;
+
+    // fill in each one
+    for (int posn=0; posn <= rhsLen; posn++) {
+      array[posn].setProdAndDot(prod, posn);
+    }
+  }
+
+  // verify we filled the whole table, i.e. that the production
+  // indices form a dense map
+  for (int id=0; id<numProds; id++) {
+    xassert(dottedProds[id] != NULL);
+  }
+}
+
+
+void GrammarAnalysis::deleteDottedProductions()
+{
+  if (dottedProds != NULL) {
+    for (int id=0; id<numProds; id++) {
+      delete[] dottedProds[id];
+    }
+    delete[] dottedProds;
+    dottedProds = NULL;
+  }
+}
+
+
+DottedProduction const *GrammarAnalysis::
+  getDProd(Production const *prod, int posn) const
+{
+  xassert(posn <= prod->rhsLength());
+  return &( dottedProds[prod->prodIndex][posn] );
+}
+
+DottedProduction const *GrammarAnalysis::
+  getDProdIndex(int prodIndex, int posn) const
+{
+  // go through the other fn to bounds-check 'posn'
+  return getDProd(getProduction(prodIndex), posn);
+}
+
+
+#ifndef NDEBUG
+DottedProduction const *GrammarAnalysis::
+  nextDProd(DottedProduction const *dp) const
+{
+  xassert(!dp->isDotAtEnd());
+  return dp + 1;
+}
+#endif // !NDEBUG
+
+
+// NOTE: the sequence of initialization actions in this function
+// and the functions it calls must interact properly with the
+// sequence in GrammarAnalysis::xfer
+void GrammarAnalysis::initializeAuxData()
+{
+  // at the moment, calling this twice leaks memory
+  xassert(!initialized);
+
+  computeIndexedNonterms();
+  computeIndexedTerms();
+  resetFirstFollow();
+
+  computeProductionsByLHS();
+  computeReachable();
+
+  // finish the productions before we compute the
+  // dotted productions
+  MUTATE_EACH_PRODUCTION(productions, prod) {
+    prod.data()->finished(numTerminals());
+  }
+
+  createDottedProductions();
+
+  // initialize the derivable relation
+  initDerivableRelation();
+
+  // mark the grammar as initialized
+  initialized = true;
+}
+
+
+void GrammarAnalysis::computeWhatCanDeriveWhat()
+{
+  xassert(initialized);
+
+
+  // iterate: propagate 'true' bits across the derivability matrix
+  // (i.e. compute transitive closure on the canDerive relation)
+  for (;;) {
+    int changes = 0;       // for this iter, # of times we set a matrix bit
+
+    // --------- first part: add new canDerive relations --------
+    // loop over all productions
+    for (ObjListIter<Production> prodIter(productions);
+         !prodIter.isDone(); prodIter.adv()) {
+      // convenient alias
+      Production const *prod = prodIter.data();
+
+      // since I don't include 'empty' explicitly in my rules, I won't
+      // conclude that anything can derive empty, which is a problem;
+      // so I special-case it here
+      if (prod->right.isEmpty()) {
+	addDerivable(prod->left, &emptyString);
+        continue;      	// no point in looping over RHS symbols since there are none
+      }
+
+      // iterate over RHS symbols, seeing if the LHS can derive that
+      // RHS symbol (by itself)
+      for (RHSEltListIter rightSym(prod->right);
+           !rightSym.isDone(); rightSym.adv()) {
+
+        if (rightSym.data()->sym->isTerminal()) {
+          // if prod->left derives a string containing a terminal,
+          // then it can't derive any nontermial alone (using this
+          // production, at least) -- empty is considered a nonterminal
+          break;
+        }
+
+        // otherwise, it's a nonterminal
+        Nonterminal const &rightNT = rightSym.data()->sym->asNonterminalC();
+
+        // check if we already know that LHS derives rightNT
+        if (canDerive(prod->left, &rightNT)) {
+          // we already know that prod->left derives rightSym,
+          // so let's not check it again
+        }
+
+        else {
+          // we are wondering if prod->left can derive rightSym.. for
+          // this to be true, every symbol that comes after rightSym
+          // must be able to derive emptySymbol (we've already verified
+          // by now that every symbol to the *left* can derive empty)
+          RHSEltListIter afterRightSym(rightSym);
+          bool restDeriveEmpty = true;
+          for (afterRightSym.adv();    // *after* right symbol
+               !afterRightSym.isDone(); afterRightSym.adv()) {
+
+            if (afterRightSym.data()->sym->isTerminal()  ||
+                  // if it's a terminal, it can't derive emptyString
+                !canDeriveEmpty(&( afterRightSym.data()->sym->asNonterminalC() ))) {
+                  // this symbol can't derive empty string (or, we don't
+                  // yet know that it can), so we conclude that prod->left
+                  // can't derive rightSym
+              restDeriveEmpty = false;
+              break;
+            }
+          }
+
+          if (restDeriveEmpty) {
+            // we have discovered that prod->left can derive rightSym
+            bool chgd = addDerivable(prod->left, &rightNT);
+            xassert(chgd);    // above, we verified we didn't already know this
+
+            changes++;
+
+            trace("derivable")
+              << "discovered (by production): " << prod->left->name
+              << " ->* " << rightNT.name << "\n";
+          }
+        }
+
+        // ok, we've considered prod->left deriving rightSym.  now, we
+        // want to consider whether prod->left can derive any of the
+        // symbols that follow rightSym in this production.  for this
+        // to be true, rightSym itself must derive the emptyString
+        if (!canDeriveEmpty(&rightNT)) {
+          // it doesn't -- no point in further consideration of
+          // this production
+          break;
+        }
+      } // end of loop over RHS symbols
+    } // end of loop over productions
+
+
+    // -------- second part: compute closure over existing relations ------
+    // I'll do this by computing R + R^2 -- that is, I'll find all
+    // paths of length 2 and add an edge between their endpoints.
+    // I do this, rather than computing the entire closure now, since
+    // on the next iter I will add more relations and have to re-do
+    // a full closure; iterative progress seems a better way.
+
+    // I don't consider edges (u,u) because it messes up my cyclicty
+    // detection logic.  (But (u,v) and (v,u) is ok, and in fact is
+    // what I want, for detecting cycles.)
+
+    // for each node u (except empty)
+    int numNonterms = numNonterminals();
+    for (int u=1; u<numNonterms; u++) {
+      // for each edge (u,v) where u != v
+      for (int v=0; v<numNonterms; v++) {
+        if (u==v || !canDerive(u,v)) continue;
+
+        // for each edge (v,w) where v != w
+        for (int w=0; w<numNonterms; w++) {
+          if (v==w || !canDerive(v,w)) continue;
+
+          // add an edge (u,w), if there isn't one already
+          if (addDerivable(u,w)) {
+            changes++;
+            trace("derivable")
+              << "discovered (by closure step): "
+              << indexedNonterms[u]->name << " ->* "
+              << indexedNonterms[w]->name << "\n";
+          }
+        }
+      }
+    }
+
+
+    // ------ finally: iterate until no changes -------
+    if (changes == 0) {
+      // didn't make any changes during the last iter, so
+      // everything has settled
+      break;
+    }
+  } // end of loop until settles
+
+
+  // I used to do all closure here and no closure in the loop.
+  // But that fails in cases where closure (when it reveals
+  // more things that derive emptyString) yields new opportunities
+  // for derives-relation discovery.  Therefore I now alternate
+  // between them, and at the end, no closure is necessary.
+}
+
+
+// set Nonterminal::superset to correspond to Nonterminal::subsets
+void GrammarAnalysis::computeSupersets()
+{
+  FOREACH_OBJLIST_NC(Nonterminal, nonterminals, iter1) {
+    Nonterminal *super = iter1.data();
+
+    SFOREACH_OBJLIST_NC(Nonterminal, super->subsets, iter2) {
+      Nonterminal *sub = iter2.data();
+
+      // for now, only handle 'super' as a partial function
+      if (sub->superset != NULL) {
+        xfailure(stringc << sub->name << " has more than one superset");
+      }
+      sub->superset = super;
+    }
+  }
+}
+
+
+// Compute, for each nonterminal, the "First" set, defined as:
+//
+//   First(N) = { x | N ->* x alpha }, where alpha is any sequence
+//                                     of terminals and nonterminals
+//
+// If N can derive emptyString, I'm going to say that empty is
+// *not* in First, despite what Aho/Sethi/Ullman says.  I do this
+// because I have that information readily as my derivable relation,
+// and because it violates the type system I've devised.
+//
+// I also don't "compute" First for terminals, since they are trivial
+// (First(x) = {x}).
+void GrammarAnalysis::computeFirst()
+{
+  bool tr = tracingSys("first");
+  int numTerms = numTerminals();
+
+  // iterate, looking for new First members, until no changes
+  int changes = 1;   // so the loop begins
+  while (changes > 0) {
+    changes = 0;
+
+    // for each production
+    for (ObjListMutator<Production> prodIter(productions);
+         !prodIter.isDone(); prodIter.adv()) {
+      // convenient aliases
+      Production *prod = prodIter.data();
+      Nonterminal *LHS = prod->left;
+        // the list iter is mutating because I modify LHS's First set
+
+      // compute First(RHS-sequence)
+      TerminalSet firstOfRHS(numTerms);
+      firstOfSequence(firstOfRHS, prod->right);
+
+      // store this back into 'prod'
+      prod->firstSet.merge(firstOfRHS);
+
+      // add everything in First(RHS-sequence) to First(LHS)
+      if (LHS->first.merge(firstOfRHS)) {
+        changes++;
+        if (tr) {
+          ostream &trs = trace("first");
+          trs << "added ";
+          firstOfRHS.print(trs, *this);
+          trs << " to " << LHS->name << " because of "
+              << prod->toString() << endl;
+        }
+      }
+    } // for (productions)
+  } // while (changes)
+
+  if (tr) {
+    FOREACH_NONTERMINAL(nonterminals, iter) {
+      Nonterminal const &nt = *(iter.data());
+
+      ostream &trs = trace("first") << " " << nt.name << ": ";
+      nt.first.print(trs, *this);
+      trs << endl;
+    }
+  }
+}
+
+
+// 'sequence' isn't const because we need to hand pointers over to
+// the 'destList', which isn't const; similarly for 'this'
+// (what I'd like here is to say that 'sequence' and 'this' are const
+// if 'destList' can't modify the things it contains)
+void GrammarAnalysis::firstOfSequence(TerminalSet &destList,
+                                      RHSEltList const &sequence)
+{
+  RHSEltListIter iter(sequence);
+  firstOfIterSeq(destList, iter);
+}
+
+// similar to above, 'sym' needs to be a mutator
+void GrammarAnalysis::firstOfIterSeq(TerminalSet &destList,
+                                     RHSEltListIter sym)
+{
+  //int numTerms = numTerminals();
+
+  // for each sequence member such that all
+  // preceeding members can derive emptyString
+  for (; !sym.isDone(); sym.adv()) {
+    // LHS -> x alpha   means x is in First(LHS)
+    if (sym.data()->sym->isTerminal()) {
+      destList.add(sym.data()->sym->asTerminal().termIndex);
+      break;    // stop considering RHS members since a terminal
+                // effectively "hides" all further symbols from First
+    }
+
+    // sym must be a nonterminal
+    Nonterminal const &nt = sym.data()->sym->asNonterminalC();
+
+    // anything already in nt's First should be added to destList
+    destList.merge(nt.first);
+
+    // if nt can't derive emptyString, then it blocks further
+    // consideration of right-hand side members
+    if (!canDeriveEmpty(&nt)) {
+      break;
+    }
+  } // for (RHS members)
+}
+
+
+void GrammarAnalysis::computeDProdFirsts()
+{
+  // for each production..
+  FOREACH_PRODUCTION(productions, prodIter) {
+    // for each dotted production where the dot is not at the end..
+    int rhsLen = prodIter.data()->rhsLength();
+    for (int posn=0; posn <= rhsLen; posn++) {
+      DottedProduction *dprod = getDProd_nc(prodIter.data(), posn);
+
+      // compute its first
+      RHSEltListIter symIter(dprod->getProd()->right, posn);
+      dprod->firstSet.reset(numTerms);
+      firstOfIterSeq(dprod->firstSet, symIter);
+
+      // can it derive empty?
+      dprod->canDeriveEmpty = iterSeqCanDeriveEmpty(symIter);
+    }
+  }
+}
+
+
+void GrammarAnalysis::computeFollow()
+{
+  int numTerms = numTerminals();
+
+  // loop until no changes
+  int changes = 1;
+  while (changes > 0) {
+    changes = 0;
+
+    // 'mutate' is needed because adding 'term' to the follow of 'nt'
+    // needs a mutable 'term' and 'nt'
+
+    // for each production
+    MUTATE_EACH_PRODUCTION(productions, prodIter) {
+      Production *prod = prodIter.data();
+
+      // for each RHS nonterminal member
+      MUTATE_EACH_OBJLIST(Production::RHSElt, prod->right, rightSym) {
+        if (rightSym.data()->sym->isTerminal()) continue;
+
+        // convenient alias
+        Nonterminal &rightNT = rightSym.data()->sym->asNonterminal();
+
+        // I'm not sure what it means to compute Follow(emptyString),
+        // so let's just not do so
+        if (&rightNT == &emptyString) {
+          continue;
+        }
+
+        // an iterator pointing to the symbol just after
+        // 'rightSym' will be useful below
+        RHSEltListMutator afterRightSym(rightSym);
+        afterRightSym.adv();    // NOTE: 'isDone()' may be true now
+
+        // rule 1:
+        // if there is a production A -> alpha B beta, then
+        // everything in First(beta) is in Follow(B)
+        {
+          // compute First(beta)
+          TerminalSet firstOfBeta(numTerms);
+          firstOfIterSeq(firstOfBeta, afterRightSym);
+
+          // put those into Follow(rightNT)
+          if (rightNT.follow.merge(firstOfBeta)) {
+            changes++;
+            if (&rightNT == symOfInterest) {
+              ostream &trs = trace("follow-sym");
+              trs << "Follow(" << rightNT.name
+                  << "): adding ";
+              firstOfBeta.print(trs, *this);
+              trs << " by first(RHS-tail) of " << *prod
+                  << endl;
+            }
+          }
+        }
+
+        // rule 2:
+        // if there is a production A -> alpha B, or a
+        // production A -> alpha B beta where beta ->* empty ...
+        if (iterSeqCanDeriveEmpty(afterRightSym)) {
+          // ... then everything in Follow(A) is in Follow(B)
+          if (rightNT.follow.merge(prod->left->follow)) {
+            changes++;
+            if (&rightNT == symOfInterest) {
+              ostream &trs = trace("follow-sym");
+              trs << "Follow(" << rightNT.name
+                  << "): adding ";
+              prod->left->follow.print(trs, *this);
+              trs << " by follow(LHS) of " << *prod
+                  << endl;
+            }
+          }
+        }
+
+      } // for each RHS nonterminal member
+    } // for each production
+  } // until no changes
+}
+
+
+// [ASU] alg 4.4, p.190
+void GrammarAnalysis::computePredictiveParsingTable()
+{
+  int numTerms = numTerminals();
+  int numNonterms = numNonterminals();
+
+  // the table will be a 2d array of lists of productions
+  ProductionList *table = new ProductionList[numTerms * numNonterms];     // (owner)
+  #define TABLE(term,nt) table[(term) + (nt)*numNonterms]
+
+  // for each production 'prod' (non-const iter because adding them
+  // to ProductionList, which doesn't promise to not change them)
+  MUTATE_EACH_PRODUCTION(productions, prodIter) {
+    Production *prod = prodIter.data();
+
+    // for each terminal 'term' in First(RHS)
+    TerminalSet firsts(numTerms);
+    firstOfSequence(firsts, prod->right);
+    for (int termIndex=0; termIndex<numTerms; termIndex++) {
+      if (!firsts.contains(termIndex)) continue;
+
+      // add 'prod' to table[LHS,term]
+      TABLE(prod->left->ntIndex, termIndex).prependUnique(prod);
+    }
+
+    // if RHS ->* emptyString, ...
+    if (sequenceCanDeriveEmpty(prod->right)) {
+      // ... then for each terminal 'term' in Follow(LHS), ...
+      for (int termIndex=0; termIndex<numTerms; termIndex++) {
+        if (!firsts.contains(termIndex)) continue;
+
+        // ... add 'prod' to table[LHS,term]
+        TABLE(prod->left->ntIndex, termIndex).prependUnique(prod);
+      }
+    }
+  }
+
+
+  // print the resulting table
+  ostream &os = trace("pred-table") << endl;
+
+  // for each nonterminal
+  INTLOOP(nonterm, 0, numNonterms) {
+    os << "Row " << indexedNonterms[nonterm]->name << ":\n";
+
+    // for each terminal
+    INTLOOP(term, 0, numTerms) {
+      os << "  Column " << indexedTerms[term]->name << ":";
+
+      // for each production in table[nonterm,term]
+      SFOREACH_PRODUCTION(TABLE(nonterm,term), prod) {
+        os << "   ";
+        prod.data()->print(os);
+      }
+
+      os << endl;
+    }
+  }
+
+  // cleanup
+  #undef TABLE
+  delete[] table;
+}
+
+
+// these hashtables are keyed using the DottedProduction,
+// but yield LRItems as values
+
+// for storing dotted productions in a hash table, this is
+// the hash function itself
+STATICDEF unsigned LRItem::hash(DottedProduction const *key)
+{
+  //DottedProduction const *dp = (DottedProduction const*)key;
+
+  // on the assumption few productions have 20 RHS elts..
+  //int val = dp->dot + (20 * dp->prod->prodIndex);
+
+  // just use the address.. they're all shared..
+  return HashTable::lcprngHashFn((void*)key);
+}
+
+// given the data, yield the key
+STATICDEF DottedProduction const *LRItem::dataToKey(LRItem *it)
+{
+  return it->dprod;
+}
+
+// compare two dotted production keys for equality; since dotted
+// productions are shared, pointer equality suffices
+STATICDEF bool LRItem::dpEqual(DottedProduction const *key1,
+                               DottedProduction const *key2)
+{
+  return key1 == key2;
+}
+
+
+// based on [ASU] figure 4.33, p.223
+// NOTE: sometimes this is called with nonempty nonkernel items...
+void GrammarAnalysis::itemSetClosure(ItemSet &itemSet)
+{
+  bool const tr = tracingSys("closure");
+  ostream &trs = trace("closure");     // trace stream
+  if (tr) {
+    trs << "computing closure of ";
+    itemSet.print(trs, *this);
+  }
+
+  // hashtable, list of items still yet to close; items are
+  // simultaneously in both the hash and the list, or not in either
+  #if 0
+  OwnerKHashArray<LRItem, DottedProduction> workhash(
+    &LRItem::dataToKey,
+    &LRItem::hash,
+    &LRItem::dpEqual, 13);
+  #endif // 0
+
+  // every 'item' on the worklist has item->dprod->backPointer == item;
+  // every 'dprod' not associated has dprod->backPointer == NULL
+  ArrayStack<LRItem*> worklist;
+
+  // scratch terminal set for singleItemClosure
+  TerminalSet scratchSet(numTerminals());
+
+  // and another for the items we've finished
+  OwnerKHashTable<LRItem, DottedProduction> finished(
+    &LRItem::dataToKey,
+    &LRItem::hash,
+    &LRItem::dpEqual, 13);
+  finished.setEnableShrink(false);
+
+  // put all the nonkernels we have into 'finished'
+  while (itemSet.nonkernelItems.isNotEmpty()) {
+    LRItem *dp = itemSet.nonkernelItems.removeFirst();
+    finished.add(dp->dprod, dp);
+  }
+
+  // first, close the kernel items -> worklist
+  FOREACH_OBJLIST(LRItem, itemSet.kernelItems, itemIter) {
+    singleItemClosure(finished, worklist, itemIter.data(), scratchSet);
+  }
+
+  while (worklist.isNotEmpty()) {
+    // pull the first production
+    LRItem *item = worklist.pop();
+    xassert(item->dprod->backPointer == item);     // was on worklist
+    item->dprod->backPointer = NULL;               // now off of worklist
+
+    // put it into list of 'done' items; this way, if this
+    // exact item is generated during closure, it will be
+    // seen and re-inserted (instead of duplicated)
+    finished.add(item->dprod, item);
+
+    // close it -> worklist
+    singleItemClosure(finished, worklist, item, scratchSet);
+  }
+
+  // move everything from 'finished' to the nonkernel items list
+  try {
+    for (OwnerKHashTableIter<LRItem, DottedProduction> iter(finished);
+         !iter.isDone(); iter.adv()) {
+      // temporarily, the item is owned both by the hashtable
+      // and the list
+      itemSet.nonkernelItems.prepend(iter.data());
+    }
+    finished.disownAndForgetAll();
+  }
+  catch (...) {
+    breaker();    // debug breakpoint
+
+    // resolve the multiple ownership by leaking some
+    finished.disownAndForgetAll();
+    throw;
+  }
+
+  // we potentially added a bunch of things
+  itemSet.changedItems();
+
+  if (tr) {
+    trs << "done with closure of state " << itemSet.id << endl;
+    itemSet.print(trs, *this);
+  }
+}
+
+
+void GrammarAnalysis
+  ::singleItemClosure(OwnerKHashTable<LRItem, DottedProduction> &finished,
+                      ArrayStack<LRItem*> &worklist,
+                      //OwnerKHashArray<LRItem, DottedProduction> &workhash,
+                      LRItem const *item, TerminalSet &newItemLA)
+{
+  INITIAL_MALLOC_STATS();
+
+  bool const tr = tracingSys("closure");
+  ostream &trs = trace("closure");     // trace stream
+
+  if (tr) {
+    trs << "  considering item ";
+    item->print(trs, *this);
+    trs << endl;
+  }
+
+  if (item->isDotAtEnd()) {
+    if (tr) {
+      trs << "    dot is at the end" << endl;
+    }
+    CHECK_MALLOC_STATS("return, dot at end");
+    return;
+  }
+
+  // in comments that follow, 'item' is broken down as
+  //   A -> alpha . B beta, LA
+
+  // get the symbol B (the one right after the dot)
+  Symbol const *B = item->symbolAfterDotC();
+  if (B->isTerminal()) {
+    if (tr) {
+      trs << "    symbol after the dot is a terminal" << endl;
+    }
+    CHECK_MALLOC_STATS("return, dot sym is terminal");
+    return;
+  }
+  int nontermIndex = B->asNonterminalC().ntIndex;
+
+  // could pull this out of even this fn, to the caller, but I don't
+  // see any difference in time when I make it static (which simulates
+  // the effect, though static itself is a bad idea because it makes
+  // the size constant through a whole run); but maybe when other things
+  // are faster I will be able to notice the difference, so I might
+  // revisit this
+  //TerminalSet newItemLA(numTerminals());
+
+  // for each production "B -> gamma"
+  SMUTATE_EACH_PRODUCTION(productionsByLHS[nontermIndex], prodIter) {    // (constness)
+    Production &prod = *(prodIter.data());
+    if (tr) {
+      trs << "    considering production " << prod << endl;
+    }
+
+    // key to good performance: do *no* dynamic allocation in this
+    // loop (one of two inner loops in the grammar analysis), until a
+    // new item is actually *needed* (which is the uncommon case); for
+    // example, all debug output statements are guarded by 'if (tr)'
+    // because otherwise they would allocate
+
+    // invariant of the indexed productions list
+    xassert(prod.left == B);
+
+    // construct "B -> . gamma, First(beta LA)";
+    // except, don't actually build it until later; in the meantime,
+    // determine which DP and lookahead it would use if created
+    DottedProduction const *newDP = getDProd(&prod, 0 /*dot at left*/);
+
+    // get beta (what follows B in 'item')
+    DottedProduction const *beta = nextDProd(item->dprod);
+
+    // get First(beta) -> new item's lookahead
+    newItemLA = beta->firstSet;
+
+    // if beta ->* epsilon, add LA
+    if (beta->canDeriveEmpty) {
+      newItemLA.merge(item->lookahead);
+    }
+
+    // except we do not want to put terminals in the lookahead set
+    // for which 'prod' is not allowed to reduce when they are next
+    if (prod.forbid) {
+      newItemLA.removeSet(*prod.forbid);
+    }
+
+    if (tr) {
+      trs << "      built item ";
+      // this is what LRItem::print would do if I actually
+      // constructed the object
+      newDP->print(trs);
+      newItemLA.print(trs, *this);
+      trs << endl;
+    }
+
+    // is 'newDP' already there?
+    // check in working and finished tables
+    bool inDoneList = true;
+    LRItem *already = newDP->backPointer;   // workhash.lookup(newDP);
+    if (already) {
+      inDoneList = false;
+    }
+    else {
+      already = finished.get(newDP);
+    }
+
+    if (already) {
+      // yes, it's already there
+      if (tr) {
+        trs << "      looks similar to ";
+        already->print(trs, *this);
+        trs << endl;
+      }
+
+      // but the new item may have additional lookahead
+      // components, so merge them with the old
+      if (already->lookahead.merge(newItemLA)) {
+        // merging changed 'already'
+        if (tr) {
+          trs << "      (chg) merged it to make ";
+          already->print(trs, *this);
+          trs << endl;
+        }
+
+        if (inDoneList) {
+          // pull from the 'done' list and put in worklist, since the
+          // lookahead changed
+          finished.remove(already->dprod);
+          CHECK_MALLOC_STATS("before worklist push");
+          worklist.push(already);
+          xassert(already->dprod->backPointer == NULL);   // was not on
+          already->dprod->backPointer = already;          // now is on worklist
+          UPDATE_MALLOC_STATS();     // allow expansion
+        }
+        else {
+          // 'already' is in the worklist, so that's fine
+        }
+      }
+      else {
+        if (tr) {
+          trs << "      this dprod already existed" << endl;
+        }
+      }
+    }
+    else {
+      CHECK_MALLOC_STATS("bunch of stuff before 'if'");
+
+      // it's not already there, so add it to worklist (but first
+      // actually create it!)
+      LRItem *newItem = new LRItem(numTerms, newDP);
+      newItem->lookahead.copy(newItemLA);
+      if (tr) {
+        trs << "      this dprod is new, queueing it to add" << endl;
+      }
+
+      worklist.push(newItem);
+      xassert(newItem->dprod->backPointer == NULL);
+      newItem->dprod->backPointer = newItem;
+
+      UPDATE_MALLOC_STATS();     // "new LRItem" or expansion of worklist
+    }
+
+    CHECK_MALLOC_STATS("processing of production");
+  } // for each production
+
+  CHECK_MALLOC_STATS("end of singleItemClosure");
+}
+
+
+// -------------- START of construct LR item sets -------------------
+ItemSet *GrammarAnalysis::makeItemSet()
+{
+  return new ItemSet((StateId)(nextItemSetId++),
+                     numTerminals(), numNonterminals());
+}
+
+void GrammarAnalysis::disposeItemSet(ItemSet *is)
+{
+  // we assume we're only doing this right after making it, as the
+  // point of this exercise is to avoid fragmenting the id space
+  nextItemSetId--;
+  xassert(is->id == nextItemSetId);
+  delete is;
+}
+
+
+// yield (by filling 'dest') a new itemset by moving the dot across
+// the productions in 'source' that have 'symbol' to the right of the
+// dot; do *not* compute the closure
+//
+// unusedTail:
+//   since 'dest' comes with a bunch of kernel items, some of which we
+//   most likely won't need, put the unused ones into 'unusedTail'
+//
+// array:
+//   since I don't want to allocate anything in here, we need scratch
+//   space for computing kernel CRCs
+void GrammarAnalysis::moveDotNoClosure(ItemSet const *source, Symbol const *symbol,
+                                       ItemSet *dest, ObjList<LRItem> &unusedTail,
+                                       GrowArray<DottedProduction const*> &array)
+{
+  //ItemSet *ret = makeItemSet();
+
+  // total # of items added
+  int appendCt=0;
+
+  // iterator for walking down dest's kernel list
+  ObjListMutator<LRItem> destIter(dest->kernelItems);
+
+  // iterator for walking both lists of items; switching from an
+  // implementation which used 'getAllItems' for performance reasons
+  ObjListIter<LRItem> srcIter(source->kernelItems);
+  int passCt=0;    // 0=kernelItems, 1=nonkernelItems
+  while (passCt < 2) {
+    if (passCt++ == 1) {
+      srcIter.reset(source->nonkernelItems);
+    }
+
+    // for each item
+    for (; !srcIter.isDone(); srcIter.adv()) {
+      LRItem const *item = srcIter.data();
+
+      if (item->isDotAtEnd() ||
+          item->symbolAfterDotC() != symbol) {
+        continue;    // can't move dot
+      }
+
+      // need to access destIter; if there are no more items, make more
+      if (destIter.isDone()) {
+        // the new item becomes the current 'data()'
+        destIter.insertBefore(new LRItem(numTerminals(), NULL /*dprod*/));
+      }
+
+      // move the dot; write dot-moved item into 'destIter'
+      LRItem *dotMoved = destIter.data();
+      dotMoved->dprod = nextDProd(item->dprod);
+      dotMoved->lookahead = item->lookahead;
+
+      // add the new item to the itemset I'm building
+      //ret->addKernelItem(dotMoved);   // UPDATE: it's already in the list
+      appendCt++;
+      destIter.adv();
+    }
+  }
+
+  // pull out any unused items into 'unusedItems'; it's important that
+  // this action not have to look at each unused item, because I want
+  // to be able to make a really big scratch item list and not pay for
+  // items I don't end up using
+  unusedTail.stealTailAt(appendCt, dest->kernelItems);
+
+  // verify we actually got something
+  xassert(appendCt > 0);
+
+  // we added stuff; sorting is needed both for the CRC below, and also
+  // for the lookahead merge step that follows a successful lookup
+  dest->sortKernelItems();
+
+  // recompute the one thing I need to do hashing
+  dest->computeKernelCRC(array);
+}
+
+
+// if 'list' contains something equal to 'itemSet', return that
+// equal object; otherwise, return NULL
+// 'list' is non-const because might return an element of it
+ItemSet *GrammarAnalysis::findItemSetInList(ObjList<ItemSet> &list,
+                                            ItemSet const *itemSet)
+{
+  // inefficiency: using iteration to check set membership
+
+  MUTATE_EACH_OBJLIST(ItemSet, list, iter) {
+    if (itemSetsEqual(iter.data(), itemSet)) {
+      return iter.data();
+    }
+  }
+  return NULL;
+}
+
+
+STATICDEF bool GrammarAnalysis::itemSetsEqual(ItemSet const *is1, ItemSet const *is2)
+{
+  // checks for equality of the kernel items
+  return *is1 == *is2;
+}
+
+
+// keys and data are the same
+STATICDEF ItemSet const *ItemSet::dataToKey(ItemSet *data)
+{
+  return data;
+}
+
+STATICDEF unsigned ItemSet::hash(ItemSet const *key)
+{
+  unsigned crc = key->kernelItemsCRC;
+  return HashTable::lcprngHashFn((void*)crc);
+}
+
+STATICDEF bool ItemSet::equalKey(ItemSet const *key1, ItemSet const *key2)
+{
+  return *key1 == *key2;
+}
+
+
+// [ASU] fig 4.34, p.224
+// puts the finished parse tables into 'itemSetsDone'
+void GrammarAnalysis::constructLRItemSets()
+{
+  bool tr = tracingSys("lrsets");
+
+  enum { BIG_VALUE = 100 };
+
+  // item sets yet to be processed; item sets are simultaneously in
+  // both the hash and the list, or not in either
+  OwnerKHashArray<ItemSet, ItemSet> itemSetsPending(
+    &ItemSet::dataToKey,
+    &ItemSet::hash,
+    &ItemSet::equalKey);
+
+  // item sets with all outgoing links processed
+  OwnerKHashTable<ItemSet, ItemSet> itemSetsDone(
+    &ItemSet::dataToKey,
+    &ItemSet::hash,
+    &ItemSet::equalKey);
+  itemSetsDone.setEnableShrink(false);
+
+  // to avoid allocating in the inner loop, we make a single item set
+  // which we'll fill with kernel items every time we think we *might*
+  // make a new state, and if it turns out we really do need a new
+  // state, then the kernel items in this one will be copied elsewhere
+  Owner<ItemSet> scratchState(
+    new ItemSet((StateId)-1 /*id*/, numTerms, numNonterms));
+
+  // fill the scratch state with lots of kernel items to start with;
+  // since these items will be re-used over and over, filling it now
+  // ensures good locality on those accesses (assuming malloc returns
+  // objects close together)
+  enum { INIT_LIST_LEN = BIG_VALUE };
+  for (int i=0; i<INIT_LIST_LEN; i++) {
+    // this is a dummy item; it allocates the bitmap for 'lookahead',
+    // but those bits and the 'dprod' pointer will be overwritten
+    // many times during the algorithm
+    LRItem *item = new LRItem(numTerms, NULL /*dottedprod*/);
+    scratchState->addKernelItem(item);
+  }
+
+  // similar to the scratch state, make a scratch array for the
+  // kernel CRC computation
+  GrowArray<DottedProduction const*> kernelCRCArray(BIG_VALUE);
+
+  // start by constructing closure of first production
+  // (basically assumes first production has start symbol
+  // on LHS, and no other productions have the start symbol
+  // on LHS)
+  {
+    ItemSet *is = makeItemSet();              // (owner)
+    startState = is;
+    LRItem *firstDP
+      = new LRItem(numTerms, getDProd(productions.first(), 0 /*dot at left*/));
+
+    // don't add this to the lookahead; we assume EOF is actually
+    // mentioned in the production already, and we won't contemplate
+    // executing this reduction within the normal parser core
+    // (see GLR::cleanupAfterParse)
+    //firstDP->laAdd(0 /*EOF token id*/);
+
+    is->addKernelItem(firstDP);
+    is->sortKernelItems();                    // redundant, but can't hurt
+    itemSetClosure(*is);                      // calls changedItems internally
+
+    // this makes the initial pending itemSet
+    itemSetsPending.push(is, is);             // (ownership transfer)
+  }
+
+  // track how much allocation we're doing
+  INITIAL_MALLOC_STATS();
+
+  // for each pending item set
+  while (itemSetsPending.isNotEmpty()) {
+    ItemSet *itemSet = itemSetsPending.pop();          // dequeue (owner)
+
+    CHECK_MALLOC_STATS("top of pending list loop");
+
+    // put it in the done set; note that we must do this *before*
+    // the processing below, to properly handle self-loops
+    itemSetsDone.add(itemSet, itemSet);                // (ownership transfer; 'itemSet' becomes serf)
+
+    // allows for expansion of 'itemSetsDone' hash
+    UPDATE_MALLOC_STATS();
+
+    if (tr) {
+      trace("lrsets") << "state " << itemSet->id
+                      << ", " << itemSet->kernelItems.count()
+                      << " kernel items and "
+                      << itemSet->nonkernelItems.count()
+                      << " nonkernel items" << endl;
+    }
+
+    // see below; this is part of a fix for a *very* subtle heisenbug
+    bool mustCloseMyself = false;
+
+    // for each production in the item set where the
+    // dot is not at the right end
+    //
+    // explicitly iterate over both lists because 'getAllItems'
+    // does allocation
+    ObjListIter<LRItem> itemIter(itemSet->kernelItems);
+    int passCt=0;    // 0=kernelItems, 1=nonkernelItems
+    while (passCt < 2) {
+      if (passCt++ == 1) {
+        itemIter.reset(itemSet->nonkernelItems);
+      }
+
+      for (; !itemIter.isDone(); itemIter.adv()) {
+        LRItem const *item = itemIter.data();
+        if (item->isDotAtEnd()) continue;
+
+        CHECK_MALLOC_STATS("top of item list loop");
+
+        if (tr) {
+          ostream &trs = trace("lrsets");
+          trs << "considering item ";
+          item->print(trs, *this);
+          trs << endl;
+        }
+
+        // get the symbol 'sym' after the dot (next to be shifted)
+        Symbol const *sym = item->symbolAfterDotC();
+
+        // in LALR(1), two items might have different lookaheads; more
+        // likely, re-expansions needs to propagate lookahead that
+        // wasn't present from an earlier expansion
+        if (!LALR1) {
+          // if we already have a transition for this symbol,
+          // there's nothing more to be done
+          if (itemSet->transitionC(sym) != NULL) {
+            continue;
+          }
+        }
+
+        // compute the itemSet (into 'scratchState') produced by moving
+        // the dot across 'sym'; don't take closure yet since we
+        // first want to check whether it is already present
+        //
+        // this call also yields the unused remainder of the kernel items,
+        // so we can add them back in at the end
+        ObjList<LRItem> unusedTail;
+        moveDotNoClosure(itemSet, sym, scratchState,
+                         unusedTail, kernelCRCArray);
+        ItemSet *withDotMoved = scratchState;    // clarify role from here down
+
+        CHECK_MALLOC_STATS("moveDotNoClosure");
+
+        // see if we already have it, in either set
+        ItemSet *already = itemSetsPending.lookup(withDotMoved);
+        bool inDoneList = false;
+        if (already == NULL) {
+          already = itemSetsDone.get(withDotMoved);
+          inDoneList = true;    // used if 'already' != NULL
+        }
+
+        // have it?
+        if (already != NULL) {
+          // we already have a state with at least equal kernel items, not
+          // considering their lookahead sets; so we have to merge the
+          // computed lookaheads with those in 'already'
+          if (withDotMoved->mergeLookaheadsInto(*already)) {
+            if (tr) {
+              trace("lrsets")
+                << "from state " << itemSet->id << ", found that the transition "
+                << "on " << sym->name << " yielded a state similar to "
+                << already->id << ", but with different lookahead" << endl;
+            }
+
+            CHECK_MALLOC_STATS("mergeLookaheadsInto");
+
+            // this changed 'already'; recompute its closure
+            if (already != itemSet) {
+              itemSetClosure(*already);
+            }
+            else {
+              // DANGER!  I'm already iterating over 'itemSet's item lists,
+              // and if I execute the closure algorithm it will invalidate
+              // my iterator.  so, postpone it
+              mustCloseMyself = true;
+            }
+
+            // and reconsider all of the states reachable from it
+            if (!inDoneList) {
+              // itemSetsPending contains 'already', it will be processed later
+            }
+            else {
+              // we thought we were done with this
+              xassertdb(itemSetsDone.get(already));
+
+              // but we're not: move it back to the 'pending' list
+              itemSetsDone.remove(already);
+              itemSetsPending.push(already, already);
+            }
+
+            // it's ok if closure makes more items, or if
+            // the pending list expands
+            UPDATE_MALLOC_STATS();
+          }
+
+          // we already have it, so throw away one we made
+          // UPDATE: we didn't allocate, so don't deallocate
+          //disposeItemSet(withDotMoved);     // deletes 'withDotMoved'
+
+          // and use existing one for setting the transition function
+          withDotMoved = already;
+        }
+        else {
+          // we don't already have it; need to actually allocate & copy
+          withDotMoved = makeItemSet();
+          FOREACH_OBJLIST(LRItem, scratchState->kernelItems, iter) {
+            withDotMoved->addKernelItem(new LRItem( *(iter.data()) ));
+          }
+
+          // finish it by computing its closure
+          itemSetClosure(*withDotMoved);
+
+          // then add it to 'pending'
+          itemSetsPending.push(withDotMoved, withDotMoved);
+
+          // takes into account:
+          //   - creation of 'withDotMoved' state
+          //   - creation of items to fill its kernel
+          //   - creation of nonkernel items during closure
+          //   - possible expansion of the 'itemSetsPending' hash
+          UPDATE_MALLOC_STATS();
+        }
+
+        // setup the transition function
+        itemSet->setTransition(sym, withDotMoved);
+
+        // finally, restore 'scratchState's kernel item list
+        scratchState->kernelItems.concat(unusedTail);
+
+        // make sure the link restoration process works as expected
+        xassertdb(scratchState->kernelItems.count() >= INIT_LIST_LEN);
+
+        CHECK_MALLOC_STATS("end of item loop");
+
+      } // for each item
+    } // 0=kernel, 1=nonkernel
+
+    CHECK_MALLOC_STATS("end of item set loop");
+
+    // now that we're finished iterating over the items, I can do the
+    // postponed closure
+    if (mustCloseMyself) {
+      itemSetClosure(*itemSet);
+      UPDATE_MALLOC_STATS();
+    }
+
+  } // for each item set
+
+  // we're done constructing item sets, so move all of them out
+  // of the 'itemSetsDone' hash and into 'this->itemSets'
+  try {
+    for (OwnerKHashTableIter<ItemSet, ItemSet> iter(itemSetsDone);
+         !iter.isDone(); iter.adv()) {
+      itemSets.prepend(iter.data());
+    }
+    itemSetsDone.disownAndForgetAll();
+  }
+  catch (...) {
+    breaker();
+    itemSetsDone.disownAndForgetAll();
+    throw;
+  }
+
+  // since we sometimes consider a state more than once, the
+  // states end up out of order; put them back in order
+  itemSets.mergeSort(ItemSet::diffById);
+
+
+  traceProgress(1) << "done with LR sets: " << itemSets.count()
+                   << " states\n";
+
+
+  // do the BFS now, since we want to print the sample inputs
+  // in the loop that follows
+  traceProgress(1) << "BFS tree on transition graph...\n";
+  computeBFSTree();
+
+  if (tracingSys("itemset-graph")) {
+    // write this info to a graph applet file
+    ofstreamTS out("lrsets.g");
+    if (!out) {
+      xsyserror("ofstream open");
+    }
+    out << "# lr sets in graph form\n";
+
+    FOREACH_OBJLIST(ItemSet, itemSets, itemSet) {
+      itemSet.data()->writeGraph(out, *this);
+    }
+  }
+}
+
+
+// print each item set
+void GrammarAnalysis::printItemSets(ostream &os, bool nonkernel) const
+{
+  FOREACH_OBJLIST(ItemSet, itemSets, itemSet) {
+    os << "State " << itemSet.data()->id
+       << ", sample input: " << sampleInput(itemSet.data()) << "\n"
+       << "  and left context: " << leftContextString(itemSet.data()) << "\n"
+       ;
+    itemSet.data()->print(os, *this, nonkernel);
+    os << "\n\n";
+  }
+}
+
+
+// --------------- END of construct LR item sets -------------------
+
+
+Symbol const *GrammarAnalysis::
+  inverseTransitionC(ItemSet const *source, ItemSet const *target) const
+{
+  // for each symbol..
+  FOREACH_TERMINAL(terminals, t) {
+    // see if it is the one
+    if (source->transitionC(t.data()) == target) {
+      return t.data();
+    }
+  }
+
+  FOREACH_NONTERMINAL(nonterminals, nt) {
+    if (source->transitionC(nt.data()) == target) {
+      return nt.data();
+    }
+  }
+
+  xfailure("GrammarAnalysis::inverseTransitionC: no transition from source to target");
+  return NULL;     // silence warning
+}
+
+
+void GrammarAnalysis::computeReachable()
+{
+  // start by clearing the reachability flags
+  MUTATE_EACH_NONTERMINAL(nonterminals, iter) {
+    iter.data()->reachable = false;
+  }
+
+  // do a DFS on the grammar, marking things reachable as
+  // they're encountered
+  computeReachableDFS(startSymbol);
+}
+
+
+void GrammarAnalysis::computeReachableDFS(Nonterminal *nt)
+{
+  if (nt->reachable) {
+    // already looked at this nonterminal
+    return;
+  }
+  nt->reachable = true;
+
+  // iterate over this nonterminal's rules
+  SFOREACH_PRODUCTION(productionsByLHS[nt->ntIndex], iter) {
+    // iterate over symbols in the rule RHS
+    FOREACH_OBJLIST(Production::RHSElt, iter.data()->right, jter) {
+      Production::RHSElt const *elt = jter.data();
+
+      if (elt->sym->isNonterminal()) {
+        // recursively analyze nonterminal elements
+        computeReachableDFS(elt->sym->ifNonterminal());
+      }
+      else {
+        // just mark terminals
+        elt->sym->reachable = true;
+      }
+    }
+  }
+}
+
+
+// --------------- LR support -------------------
+// decide what to do, and record the result into the two
+// boolean reference parameters
+void GrammarAnalysis::handleShiftReduceConflict(
+  bool &keepShift, bool &keepReduce, bool &dontWarn,
+  ItemSet const *state, Production const *prod, Terminal const *sym)
+{
+  // say that we're considering this conflict
+  trace("prec")
+    << "in state " << state->id << ", S/R conflict on token "
+    << sym->name << " with production " << *prod << endl;
+
+  // look at scannerless directives
+  {
+    // is this nonterm or any of its declared supersets maximal?
+    Nonterminal const *super = prod->left;
+    bool maximal = super->maximal;
+    while (!maximal && super->superset) {
+      super = super->superset;
+      maximal = super->maximal;
+    }
+
+    if (maximal) {
+      // see if this reduction can be removed due to a 'maximal' spec;
+      // in particular, is the shift going to extend 'super'?
+      if (state->hasExtendingShift(super, sym)) {
+        trace("prec") << "resolved in favor of SHIFT due to maximal munch\n";
+        keepReduce = false;
+        return;
+      }
+    }
+  }
+
+  if (!( prod->precedence && sym->precedence )) {
+    // one of the two doesn't have a precedence specification,
+    // so we can do nothing
+    trace("prec") << "will SPLIT because no disambiguation spec available" << endl;
+    return;
+  }
+
+  if (prod->precedence > sym->precedence) {
+    // production's precedence is higher, so we choose to reduce
+    // instead of shift
+    trace("prec") << "resolved in favor of REDUCE due to precedence\n";
+    keepShift = false;
+    return;
+  }
+
+  if (prod->precedence < sym->precedence) {
+    // symbol's precedence is higher, so we shift
+    trace("prec") << "resolved in favor of SHIFT due to precedence\n";
+    keepReduce = false;
+    return;
+  }
+
+  // precedences are equal, so we look at associativity (of token)
+  switch (sym->associativity) {
+    case AK_LEFT:
+      trace("prec") << "resolved in favor of REDUCE due to associativity\n";
+      keepShift = false;
+      return;
+
+    case AK_RIGHT:
+      trace("prec") << "resolved in favor of SHIFT due to associativity\n";
+      keepReduce = false;
+      return;
+
+    case AK_NONASSOC:
+      trace("pred") << "removed BOTH alternatives due to nonassociativity\n";
+      keepShift = false;
+      keepReduce = false;
+      return;
+
+    case AK_NEVERASSOC:
+      // the user claimed this token would never be involved in a conflict
+      trace("pred") << "neverassoc specification ERROR\n";
+      errors++;
+      cout << "token " << sym->name << " was declared 'prec', "
+           << "but it is involved in an associativity conflict with \""
+           << *prod << "\" in state " << state->id << endl;
+      return;
+
+    case AK_SPLIT:
+      // the user does not want disambiguation of this
+      trace("pred") << "will SPLIT because user asked to\n";
+      dontWarn = true;
+      return;
+
+    default:
+      xfailure("bad assoc code");
+  }
+}
+
+
+// given an LR transition graph, compute the BFS tree on top of it
+// and set the parent links to record the tree
+void GrammarAnalysis::computeBFSTree()
+{
+  // for the BFS, we need a queue of states yet to be processed, and a
+  // pile of 'done' states
+  SObjList<ItemSet> queue;
+  SObjList<ItemSet> done;
+
+  // initial entry in queue is root of BFS tree
+  queue.append(startState);
+
+  // it will be convenient to have all the symbols in a single list
+  // for iteration purposes
+  SymbolList allSymbols;       	  // (const list)
+  {
+    FOREACH_TERMINAL(terminals, t) {
+      allSymbols.append(const_cast<Terminal*>(t.data()));
+    }
+    FOREACH_NONTERMINAL(nonterminals, nt) {
+      allSymbols.append(const_cast<Nonterminal*>(nt.data()));
+    }
+  }
+
+  // loop until the queue is exhausted
+  while (queue.isNotEmpty()) {
+    // dequeue first element
+    ItemSet *source = queue.removeAt(0);
+
+    // mark it as done so we won't consider any more transitions to it
+    done.append(source);
+
+    // for each symbol...
+    SFOREACH_SYMBOL(allSymbols, sym) {
+      // get the transition on this symbol
+      ItemSet *target = source->transition(sym.data());
+
+      // if the target is done or already enqueued, or there is no
+      // transition on this symbol, we don't need to consider it
+      // further
+      if (target == NULL ||
+          done.contains(target) ||
+          queue.contains(target)) {
+        continue;
+      }
+
+      // the source->target link just examined is the first time
+      // we've encounted 'target', so that link becomes the BFS
+      // parent link
+      target->BFSparent = source;
+
+      // finally, enqueue the target so we'll explore its targets too
+      queue.append(target);
+    }
+  }
+}
+
+
+// --------------- parse table construction -------------------
+// given some potential parse actions, apply available disambiguation
+// to remove some of them; print warnings about conflicts, in some
+// situations
+void GrammarAnalysis::resolveConflicts(
+  ItemSet const *state,        // parse state in which the actions are possible
+  Terminal const *sym,         // lookahead symbol for these actions
+  ItemSet const *&shiftDest,   // (inout) if non-NULL, the state to which we can shift
+  ProductionList &reductions,  // (inout) list of possible reductions
+  bool allowAmbig,             // if false, always return at most 1 action
+  bool &printedConflictHeader, // (inout) true once we've printed the state header
+  int &sr, int &rr)            // (inout) counts of S/R and R/R conflicts, resp.
+{
+  // how many actions are there?
+  int actions = (shiftDest? 1 : 0) + reductions.count();
+  if (actions <= 1) {
+    return;      // no conflict
+  }
+
+  // count how many warning suppressions we have
+  int dontWarns = 0;
+
+  // static disambiguation for S/R conflicts
+  if (shiftDest) {
+    // we have (at least) a shift/reduce conflict, which is the
+    // situation in which prec/assoc specifications are used; consider
+    // all the possible reductions, so we can resolve S/R conflicts
+    // even when there are R/R conflicts present too
+    SObjListMutator<Production> mut(reductions);
+    while (!mut.isDone() && shiftDest != NULL) {
+      Production const *prod = mut.data();
+
+      bool keepShift=true, keepReduce=true, dontWarn=false;
+      handleShiftReduceConflict(keepShift, keepReduce, dontWarn, state, prod, sym);
+
+      if (!keepShift) {
+        actions--;
+        shiftDest = NULL;      // remove the shift
+      }
+
+      if (!keepReduce) {
+        actions--;
+        mut.remove();          // remove the reduction
+      }
+      else {
+        mut.adv();
+      }
+
+      if (dontWarn) {
+        dontWarns++;
+      }
+    }
+
+    // there is still a potential for misbehavior.. e.g., if there are two
+    // possible reductions (R1 and R2), and one shift (S), then the user
+    // could have specified prec/assoc to disambiguate, e.g.
+    //   R1 < S
+    //   S < R2
+    // so that R2 is the right choice; but if I consider (S,R2) first,
+    // I'll simply drop S, leaving no way to disambiguate R1 and R2 ..
+    // for now I'll just note the possibility...
+  }
+
+  // static disambiguation for R/R conflicts
+  if (reductions.count() > 1) {
+    // find the highest precedence
+    int highestPrec = 0;
+    SFOREACH_PRODUCTION(reductions, iter) {
+      int p = iter.data()->precedence;
+
+      if (p && p>highestPrec) {
+        highestPrec = p;
+      }
+    }
+
+    // remove any productions that are lower than 'highestPrec'
+    SObjListMutator<Production> mut(reductions);
+    while (!mut.isDone()) {
+      int p = mut.data()->precedence;
+
+      if (p && p<highestPrec) {
+        trace("prec")
+          << "in state " << state->id << ", R/R conflict on token "
+          << sym->name << ", removed production " << *(mut.data())
+          << " because " << p << "<" << highestPrec << endl;
+        mut.remove();
+        actions--;
+      }
+      else {
+        mut.adv();
+      }
+    }
+  }
+
+  // additional R/R resolution using subset directives
+  if (reductions.count() > 1) {
+    actions -= subsetDirectiveResolution(state, sym, reductions);
+  }
+
+  static char const *conflictSym = getenv("CONFLICT_SYMBOL");
+  bool canPrint = !conflictSym || 0==strcmp(sym->name, conflictSym);
+
+  // after the disambiguation, maybe now there's no conflicts?
+  // or, if conflicts remain, did we get at least that many warning
+  // suppressions?
+  if ((actions-dontWarns) <= 1) {
+    // don't print information about conflicts
+  }
+  else {
+    // print conflict info
+    if (canPrint && !printedConflictHeader) {
+      trace("conflict")
+        << "--------- state " << state->id << " ----------\n"
+        << "left context: " << leftContextString(state)
+        << endl
+        << "sample input: " << sampleInput(state)
+        << endl
+        ;
+      printedConflictHeader = true;
+    }
+
+    if (canPrint) {
+      trace("conflict")
+        << "conflict for symbol " << sym->name
+        << endl;
+     }
+
+    if (shiftDest) {
+      if (canPrint) {
+        trace("conflict") << "  shift, and move to state " << shiftDest->id << endl;
+      }
+      sr++;                 // shift/reduce conflict
+      rr += actions - 2;    // any reduces beyond first are r/r errors
+    }
+    else {
+      rr += actions - 1;    // all reduces beyond first are r/r errors
+    }
+
+    if (canPrint) {
+      SFOREACH_PRODUCTION(reductions, prod) {
+        trace("conflict") << "  reduce by rule " << *(prod.data()) << endl;
+      }
+    }
+  }
+
+  if (!allowAmbig && actions > 1) {
+    // force only one action, using Bison's disambiguation:
+    //   - prefer shift to reduce
+    //   - prefer the reduction which occurs first in the grammar file
+    if (shiftDest) {
+      reductions.removeAll();
+    }
+    else {
+      while (reductions.count() >= 2) {
+        // compare first and second
+        Production const *first = reductions.nth(0);
+        Production const *second = reductions.nth(1);
+
+        // production indices happen to be assigned in file order
+        if (first->prodIndex < second->prodIndex) {
+          reductions.removeItem(second);
+        }
+        else {
+          reductions.removeItem(first);
+        }
+      }
+    }
+  }
+}
+
+
+void reportUnexpected(int value, int expectedValue, char const *desc)
+{
+  if ((expectedValue == -1 && value>0) ||
+      (expectedValue != -1 && expectedValue != value)) {
+    cout << value << " " << desc;
+    if (expectedValue != -1) {
+      cout << " (expected " << expectedValue << ")";
+      if (tracingSys("requireExactStats")) {
+        cout << endl;
+        cout << "halting because 'requireExactStats' was specified" << endl;
+        exit(4);
+      }
+    }
+    cout << endl;
+  }
+}
+
+
+// the idea is we might be trying to do scannerless parsing, and
+// someone might say that Identifier has as subsets all the keywords,
+// so competing reductions should favor the subsets (the keywords)
+int GrammarAnalysis::subsetDirectiveResolution(
+  ItemSet const *state,        // parse state in which the actions are possible
+  Terminal const *sym,         // lookahead symbol for these actions
+  ProductionList &reductions)  // list to try to cut down
+{
+  int removed = 0;
+
+  // make a map of which nonterminals appear on the LHS of one
+  // of the reductions, and has a superset
+  BitArray map(numNonterms);
+  bool anyWithSuper = false;
+  {
+    SFOREACH_PRODUCTION(reductions, iter) {
+      Production const *p = iter.data();
+      if (p->left->superset) {
+        map.set(p->left->ntIndex);
+        anyWithSuper = true;
+      }
+    }
+  }
+
+  if (!anyWithSuper) {
+    return removed;     // nothing we can do
+  }
+
+  // walk over the reductions, removing those that have reductions
+  // to subsets also in the list
+  SObjListMutator<Production> mut(reductions);
+  while (!mut.isDone()) {
+    Production const *prod = mut.data();
+
+    SFOREACH_OBJLIST(Nonterminal, prod->left->subsets, iter) {
+      Nonterminal const *sub = iter.data();
+      if (map.test(sub->ntIndex)) {
+        trace("prec")
+          << "in state " << state->id
+          << ", R/R conflict on token " << sym->name
+          << ", removed production yielding " << prod->left->name
+          << " b/c another yields subset " << sub->name
+          << endl;
+        mut.remove();
+        removed++;
+        goto continue_outer_loop;
+      }
+    }
+
+    // didn't remove, must manually advance
+    mut.adv();
+
+    continue_outer_loop:;
+  }
+
+  return removed;
+}
+
+
+bool isAmbiguousNonterminal(Symbol const *sym)
+{
+  if (sym->isNonterminal()) {
+    Nonterminal const &nt = sym->asNonterminalC();
+    if (nt.mergeCode) {
+      return true;   // presence of merge() signals potential ambiguity
+    }
+  }
+  return false;
+}
+
+
+// The purpose of this function is to number the states (which have up
+// to this point been numbered arbitrarily) in such a way that all
+// states that have a given symbol on incoming arcs will be numbered
+// consecutively.  This is part of the table compression schemes
+// described in the Dencker et. al. paper (see parsetables.h).
+void GrammarAnalysis::renumberStates()
+{
+  // sort them into the right order
+  itemSets.mergeSort(&GrammarAnalysis::renumberStatesDiff, this);
+
+  // number them in that order
+  int n = 0;
+  FOREACH_OBJLIST_NC(ItemSet, itemSets, iter) {
+    ItemSet *s = iter.data();
+    if (n == 0) {
+      // the first element should always be the start state
+      xassert(s->id == 0);
+    }
+    else {
+      s->id = (StateId)n;
+    }
+
+    n++;
+  }
+}
+
+STATICDEF int GrammarAnalysis::renumberStatesDiff
+  (ItemSet const *left, ItemSet const *right, void *vgramanl)
+{
+  GrammarAnalysis *gramanl = (GrammarAnalysis*)vgramanl;
+
+  int ret;
+
+  // if for some reason I'm ever asked to compare a state to
+  // itself..
+  if (left == right) {
+    return 0;
+  }
+
+  // order them first by their incoming arc symbol; this effects
+  // the renumbering that the Code Reduction Scheme demands
+  {
+    Symbol const *ls = left->getStateSymbolC();
+    Symbol const *rs = right->getStateSymbolC();
+
+    // any state with no incoming arcs (start state) is first
+    ret = (int)(bool)ls - (int)(bool)rs;
+    if (ret) return ret;
+
+    // terminals come before nonterminals
+    ret = (int)(ls->isNonterminal()) - (int)(rs->isNonterminal());
+    if (ret) return ret;
+
+    // order by id within terms/nonterms
+    ret = ls->getTermOrNontermIndex() - rs->getTermOrNontermIndex();
+    if (ret) return ret;
+  }
+
+  // from this point on, the CRS would be happy with an arbitrary
+  // order, but I want the state numbering to be canonical so that
+  // I have an easier time debugging and comparing parse traces
+
+  // they have the same incoming arc symbol; now, sort by outgoing
+  // arc symbols
+
+  // first up: terminals
+  {
+    for (int t=0; t < gramanl->numTerminals(); t++) {
+      ItemSet const *ldest = left->getTermTransition(t);
+      ItemSet const *rdest = right->getTermTransition(t);
+
+      ret = (int)!ldest - (int)!rdest;
+      if (ret) return ret;
+
+      if (ldest && rdest) {
+        ret = ldest->id - rdest->id;
+        if (ret) return ret;
+      }
+    }
+  }
+
+  // next: nonterminals
+  {
+    for (int nt=0; nt < gramanl->numNonterminals(); nt++) {
+      ItemSet const *ldest = left->getNontermTransition(nt);
+      ItemSet const *rdest = right->getNontermTransition(nt);
+
+      ret = (int)!ldest - (int)!rdest;
+      if (ret) return ret;
+
+      if (ldest && rdest) {
+        ret = ldest->id - rdest->id;
+        if (ret) return ret;
+      }
+    }
+  }
+
+  // I suspect this will never be reached, since usually the
+  // transition function will be sufficient
+  // update: it happens often enough.. even in the arith grammar
+  //cout << "using reductions to distinguish states\n";
+
+  // finally, order by possible reductions
+  FOREACH_OBJLIST(Terminal, gramanl->terminals, termIter) {
+    ProductionList lpl, rpl;
+    left->getPossibleReductions(lpl, termIter.data(), false /*parsing*/);
+    right->getPossibleReductions(rpl, termIter.data(), false /*parsing*/);
+
+    // sort the productions before we can compare them...
+    lpl.insertionSort(&GrammarAnalysis::arbitraryProductionOrder);
+    rpl.insertionSort(&GrammarAnalysis::arbitraryProductionOrder);
+
+    ret = lpl.compareAsLists(rpl, &GrammarAnalysis::arbitraryProductionOrder);
+    if (ret) return ret;
+  }
+
+  // I used to throw an xfailure here, but that causes a problem
+  // because the 'itemSets' list is not well-formed, because we
+  // are in the middle of sorting it
+  cout << "two different states have identical transitions and "
+          "identical reductions!\n";
+  cout << "left=" << left->id
+       << ", sym is " << left->getStateSymbolC()->toString() << "\n";
+  left->print(cout, *gramanl);
+  cout << "right=" << right->id
+       << ", sym is " << right->getStateSymbolC()->toString() << "\n";
+  right->print(cout, *gramanl);
+
+  return 0;
+}
+
+STATICDEF int GrammarAnalysis::arbitraryProductionOrder
+  (Production const *left, Production const *right, void*)
+{
+  // compare LHS
+  int ret = left->left->ntIndex - right->left->ntIndex;
+  if (ret) return ret;
+
+  // RHS elts one at a time
+  return left->right.compareAsLists(right->right,
+    &GrammarAnalysis::arbitraryRHSEltOrder);
+}
+
+STATICDEF int GrammarAnalysis::arbitraryRHSEltOrder
+  (Production::RHSElt const *left, Production::RHSElt const *right, void*)
+{
+  int ret = (int)left->sym->isTerminal() - (int)right->sym->isTerminal();
+  if (ret) return ret;
+
+  return left->sym->getTermOrNontermIndex() - right->sym->getTermOrNontermIndex();
+}
+
+
+void GrammarAnalysis::computeParseTables(bool allowAmbig)
+{
+  tables = new ParseTables(numTerms, numNonterms, itemSets.count(), numProds,
+                           startState->id,
+                           0 /* slight hack: assume it's the first production */);
+
+  if (ENABLE_CRS_COMPRESSION) {
+    // first-state info
+    bool doingTerms = true;
+    int prevSymCode = -1;
+    FOREACH_OBJLIST(ItemSet, itemSets, iter) {
+      ItemSet const *state = iter.data();
+      Symbol const *sym = state->getStateSymbolC();
+      if (!sym) continue;     // skip start state
+      int symCode = sym->getTermOrNontermIndex();
+
+      if (sym->isTerminal() == doingTerms &&
+          symCode == prevSymCode) {
+        // continuing the current run, do nothing
+        continue;
+      }
+
+      if (sym->isNonterminal() && doingTerms) {
+        // transition from terminals to nonterminals
+        doingTerms = false;
+      }
+      else {
+        // continue current phase, with new code; states must
+        // already have been sorted into increasing order
+        xassert(sym->isTerminal() == doingTerms);
+        xassert(prevSymCode < symCode);
+      }
+
+      if (doingTerms) {
+        tables->setFirstWithTerminal(symCode, state->id);
+      }
+      else {
+        tables->setFirstWithNonterminal(symCode, state->id);
+      }
+
+      prevSymCode = symCode;
+    }
+  }
+
+  // count total number of conflicts of each kind
+  int sr=0, rr=0;
+
+  // for each state...
+  FOREACH_OBJLIST(ItemSet, itemSets, stateIter) {
+    ItemSet const *state = stateIter.data();
+    bool printedConflictHeader = false;
+
+    // ---- fill in this row in the action table ----
+    // for each possible lookahead...
+    for (int termId=0; termId < numTerms; termId++) {
+      Terminal const *terminal = getTerminal(termId);
+
+      // can shift?
+      ItemSet const *shiftDest = state->transitionC(terminal);
+
+      // can reduce?
+      ProductionList reductions;
+      state->getPossibleReductions(reductions, terminal,
+                                   false /*parsing*/);
+
+      // try to resolve conflicts; this may print warnings about
+      // the conflicts, depending on various factors; if 'allowAmbig'
+      // is false, this will remove all but one action
+      resolveConflicts(state, terminal, shiftDest, reductions,
+                       allowAmbig, printedConflictHeader, sr, rr);
+
+      // what to do in this cell
+      ActionEntry cellAction;
+
+      // still conflicts?
+      int actions = (shiftDest? 1 : 0) + reductions.count();
+      if (actions >= 2) {
+        // make a new ambiguous-action entry-set
+        ArrayStack<ActionEntry> set;
+
+        // fill in the actions
+        if (shiftDest) {
+          set.push(tables->encodeShift(shiftDest->id, termId));
+        }
+        SFOREACH_PRODUCTION(reductions, prodIter) {
+          set.push(tables->encodeReduce(prodIter.data()->prodIndex, state->id));
+        }
+        xassert(set.length() == actions);
+
+        cellAction = tables->encodeAmbig(set, state->id);
+      }
+
+      else {
+        // single action
+        if (shiftDest) {
+          xassert(reductions.count() == 0);
+          cellAction = tables->encodeShift(shiftDest->id, termId);
+        }
+        else if (reductions.isNotEmpty()) {
+          xassert(reductions.count() == 1);
+          cellAction = tables->encodeReduce(reductions.first()->prodIndex, state->id);
+        }
+        else {
+          cellAction = tables->encodeError();
+        }
+      }
+
+      // add this entry to the table
+      tables->setActionEntry(state->id, termId, cellAction);
+
+      // based on the contents of 'reductions', decide whether this
+      // state is delayed or not; to be delayed, the state must be
+      // able to reduce by a production which:
+      //   - has an ambiguous nonterminal as the last symbol on its RHS
+      //   - is not reducing to the *same* nonterminal as the last symbol
+      //     (rationale: eagerly reduce "E -> E + E")
+      // UPDATE: removed last condition because it actually makes things
+      // worse..
+      bool delayed = false;
+      if (reductions.isNotEmpty()) {    // no reductions: eager (irrelevant, actually)
+        SFOREACH_PRODUCTION(reductions, prodIter) {
+          Production const &prod = *prodIter.data();
+          if (prod.rhsLength() >= 1) {                 // nonempty RHS?
+            Symbol const *lastSym = prod.right.lastC()->sym;
+            if (isAmbiguousNonterminal(lastSym)        // last RHS ambig?
+                /*&& lastSym != prod.left*/) {         // not same as LHS?
+              delayed = true;
+            }
+          }
+        }
+      }
+    }
+
+    // ---- fill in this row in the goto table ----
+    // for each nonterminal...
+    for (int nontermId=0; nontermId<numNonterms; nontermId++) {
+      Nonterminal const *nonterminal = getNonterminal(nontermId);
+
+      // where do we go when we reduce to this nonterminal?
+      ItemSet const *gotoDest = state->transitionC(nonterminal);
+
+      GotoEntry cellGoto;
+      if (gotoDest) {
+        cellGoto = tables->encodeGoto(gotoDest->id, nonterminal->ntIndex);
+      }
+      else {
+        // this should never be accessed at parse time..
+        cellGoto = tables->encodeGotoError();
+      }
+
+      // fill in entry
+      tables->setGotoEntry(state->id, nontermId, cellGoto);
+    }
+
+    // get the state symbol
+    xassert((unsigned)(state->id) < (unsigned)(tables->getNumStates()));
+    tables->setStateSymbol(state->id,
+      encodeSymbolId(state->getStateSymbolC()));
+  }
+
+  // report on conflict counts
+  reportUnexpected(sr, expectedSR, "shift/reduce conflicts");
+  reportUnexpected(rr, expectedRR, "reduce/reduce conflicts");
+
+  // report on cyclicity
+  for (int nontermId=0; nontermId<numNonterms; nontermId++) {
+    Nonterminal const *nonterminal = getNonterminal(nontermId);
+    if (nonterminal->cyclic) {
+      cout << "grammar symbol " << nonterminal->name << " is cyclic\n";
+    }
+  }
+
+  // fill in 'prodInfo'
+  for (int p=0; p<numProds; p++) {
+    Production const *prod = getProduction(p);
+    tables->setProdInfo(p, prod->rhsLength(), prod->left->ntIndex);
+  }
+
+  // use the derivability relation to compute a total order
+  // on nonterminals
+  BitArray seen(numNonterms);
+  int nextOrdinal = numNonterms-1;
+  for (int nt=0; nt < numNonterms; nt++) {
+    // expand from 'nt' in case it's disconnected; this will be
+    // a no-op if we've already 'seen' it
+    topologicalSort(tables->getWritableNontermOrder(), nextOrdinal, nt, seen);
+  }
+  xassert(nextOrdinal == -1);    // should have used them all
+
+  if (ENABLE_EEF_COMPRESSION) {
+    tables->computeErrorBits();
+  }
+
+  if (ENABLE_GCS_COMPRESSION) {
+    if (ENABLE_GCS_COLUMN_COMPRESSION) {
+      tables->mergeActionColumns();
+    }
+    tables->mergeActionRows();
+
+    if (ENABLE_GCS_COLUMN_COMPRESSION) {
+      tables->mergeGotoColumns();
+    }
+    tables->mergeGotoRows();
+  }
+}
+
+
+// this is a depth-first traversal of the 'derivable' relation;
+// when we reach a nonterminal that can't derive any others not
+// already in the order, we give its entry the latest ordinal
+// that isn't already taken ('nextOrdinal')
+void GrammarAnalysis::topologicalSort(
+  NtIndex *order,    // table we're filling with ordinals
+  int &nextOrdinal,  // latest ordinal not yet used
+  NtIndex current,   // current nonterminal to expand
+  BitArray &seen)    // set of nonterminals we've already seen
+{
+  if (seen.test(current)) {
+    // already expanded this one
+    return;
+  }
+
+  // don't expand this one again
+  seen.set(current);
+
+  // look at all nonterminals this one can derive
+  for (int nt=0; nt < numNonterms; nt++) {
+    if (derivable->get(point(nt, current))) {
+      // 'nt' can derive 'current'; expand 'nt' first, thus making
+      // it later in the order, so we'll reduce to 'current' before
+      // reducing to 'nt' (when token spans are equal)
+      xassert((NtIndex)nt == nt);
+      topologicalSort(order, nextOrdinal, (NtIndex)nt, seen);
+    }
+  }
+
+  // finally, put 'current' into the order
+  order[current] = nextOrdinal;
+  nextOrdinal--;
+}
+
+
+SymbolId encodeSymbolId(Symbol const *sym)
+{
+  int ret;
+  if (!sym) {
+    ret = 0;
+  }
+  else if (sym->isTerminal()) {
+    ret = sym->asTerminalC().termIndex + 1;
+  }
+  else /*nonterminal*/ {
+    ret = - sym->asNonterminalC().ntIndex - 1;
+
+    // verify encoding of nonterminals is sufficiently wide
+    int idx = sym->asNonterminalC().ntIndex;
+    xassert((NtIndex)idx == idx);
+  }
+
+  // verify encoding is lossless
+  SymbolId ret2 = (SymbolId)ret;
+  xassert((int)ret2 == ret);
+  return ret2;
+}
+
+
+// --------------- sample inputs -------------------
+// yield a sequence of names of symbols (terminals and nonterminals) that
+// will lead to the given state, from the start state
+string GrammarAnalysis::leftContextString(ItemSet const *state) const
+{
+  SymbolList ctx;
+  leftContext(ctx, state);                // get as list
+  return symbolSequenceToString(ctx);	  // convert to string
+}
+
+
+// yield the left-context as a sequence of symbols
+// CONSTNESS: want output as list of const pointers
+void GrammarAnalysis::leftContext(SymbolList &output,
+                                  ItemSet const *state) const
+{
+  // since we have the BFS tree, generating sample input (at least, if
+  // it's allowed to contain nonterminals) is a simple matter of walking
+  // the tree towards the root
+
+  // for each parent..
+  while (state->BFSparent) {
+    // get that parent
+    ItemSet *parent = state->BFSparent;
+
+    // find a symbol on which we would transition from the parent
+    // to the current state
+    Symbol const *sym = inverseTransitionC(parent, state);
+
+    // prepend that symbol's name to our current context
+    output.prepend(const_cast<Symbol*>(sym));
+
+    // move to our parent and repeat
+    state = parent;
+  }
+}
+
+
+// compare two-element quantities where one dominates and the other is
+// only for tie-breaking; return <0/=0/>0 if a's quantities are
+// fewer/equal/grearter (this fn is a candidate for adding to a
+// library somewhere)
+int priorityCompare(int a_dominant, int b_dominant,
+                    int a_recessive, int b_recessive)
+{
+  if (a_dominant < b_dominant) return -1;
+  if (a_dominant > b_dominant) return +1;
+  return a_recessive - b_recessive;
+}
+
+int priorityFewer(int a_dominant, int b_dominant,
+                  int a_recessive, int b_recessive)
+{
+  return priorityCompare(a_dominant, b_dominant,
+                         a_recessive, b_recessive) < 1;
+}
+
+
+// sample input (terminals only) that can lead to a state
+string GrammarAnalysis::sampleInput(ItemSet const *state) const
+{
+  // get left-context as terminals and nonterminals
+  SymbolList symbols;
+  leftContext(symbols, state);
+
+  // reduce the nonterminals to terminals
+  TerminalList terminals;
+  if (!rewriteAsTerminals(terminals, symbols)) {
+    return string("(failed to reduce!!)");
+  }
+
+  // convert to a string
+  return terminalSequenceToString(terminals);
+}
+
+
+// given a sequence of symbols (terminals and nonterminals), use the
+// productions to rewrite it as a (hopefully minimal) sequence of
+// terminals only; return true if it works, false if we get stuck
+// in an infinite loop
+// CONSTNESS: ideally, 'output' would contain const ptrs to terminals
+bool GrammarAnalysis::rewriteAsTerminals(TerminalList &output, SymbolList const &input) const
+{
+  // we detect looping by noticing if we ever reduce via the same
+  // production more than once in a single vertical recursive slice
+  ProductionList reductionStack;      // starts empty
+
+  // start the recursive version
+  return rewriteAsTerminalsHelper(output, input, reductionStack);
+}
+
+
+// (nonterminals and terminals) -> terminals;
+// if this returns false, it's guaranteed to return with 'output'
+// unchanged from when the function was invoked
+bool GrammarAnalysis::
+  rewriteAsTerminalsHelper(TerminalList &output, SymbolList const &input,
+                           ProductionList &reductionStack) const
+{
+  // remember the initial 'output' length so we can restore
+  int origLength = output.count();
+
+  // walk down the input list, creating the output list by copying
+  // terminals and reducing nonterminals
+  SFOREACH_SYMBOL(input, symIter) {
+    Symbol const *sym = symIter.data();
+
+    if (sym->isEmptyString) {
+      // easy; no-op
+    }
+
+    else if (sym->isTerminal()) {
+      // no sweat, just copy it (er, copy the pointer)
+      output.append(const_cast<Terminal*>(&sym->asTerminalC()));
+    }
+
+    else {
+      // not too bad either, just reduce it, sticking the result
+      // directly into our output list
+      if (!rewriteSingleNTAsTerminals(output, &sym->asNonterminalC(),
+                                      reductionStack)) {
+        // oops.. restore 'output'
+        while (output.count() > origLength) {
+          output.removeAt(origLength);
+        }
+        return false;
+      }
+    }
+  }
+
+  // ok!
+  return true;
+}
+
+
+// for rewriting into sequences of terminals, we prefer rules with
+// fewer nonterminals on the RHS, and then (to break ties) rules with
+// fewer RHS symbols altogether; overriding all of this, if one
+// production's RHS contains a symbol already expanded, and the other
+// does not, then prefer the RHS which hasn't already been expanded
+int compareProductionsForRewriting(Production const *p1, Production const *p2,
+                                   void *extra)
+{
+  ProductionList *reductionStack = (ProductionList*)extra;
+
+  bool p1RHSSeen=false, p2RHSSeen=false;
+  SFOREACH_PRODUCTION(*reductionStack, iter) {
+    if (p1->rhsHasSymbol( iter.data()->left )) {
+      p1RHSSeen = true;
+    }
+    if (p2->rhsHasSymbol( iter.data()->left )) {
+      p2RHSSeen = true;
+    }
+  }
+
+  if (p1RHSSeen != p2RHSSeen) {
+    // e.g.: p1RHSSeen=true, so p2 is preferred; this will yield +1,
+    // meaning p1>p2, so p2 comes first in an increasing order sort
+    return (int)p1RHSSeen - (int)p2RHSSeen;
+  }
+
+  return priorityCompare(p1->numRHSNonterminals(), p2->numRHSNonterminals(),
+                         p1->rhsLength(), p2->rhsLength());
+}
+
+// nonterminal -> terminals
+// CONSTNESS: want 'reductionStack' to be list of const ptrs
+bool GrammarAnalysis::
+  rewriteSingleNTAsTerminals(TerminalList &output, Nonterminal const *nonterminal,
+                             ProductionList &reductionStack) const
+{
+  // get all of 'nonterminal's productions that are not recursive
+  ProductionList candidates;
+  FOREACH_PRODUCTION(productions, prodIter) {
+    Production const *prod = prodIter.data();
+    if (prod->left != nonterminal) continue;
+
+    // if 'prod' has 'nonterminal' on RHS, that would certainly
+    // lead to looping (though it's not the only way -- consider
+    // mutual recursion), so don't even consider it
+    if (prod->rhsHasSymbol(nonterminal)) {
+      continue;
+    }
+
+    // if this production has already been used, don't use it again
+    if (reductionStack.contains(prod)) {
+      continue;
+    }
+
+    // it's a candidate
+    candidates.prepend(const_cast<Production*>(prod));   // constness
+  }
+
+  if (candidates.isEmpty()) {
+    // I don't expect this... either the NT doesn't have any rules,
+    // or all of them are recursive (which means the language doesn't
+    // have any finite sentences)
+    trace("rewrite") << "couldn't find any unused, non-recursive rules for "
+                     << nonterminal->name << endl;
+    return false;
+  }
+
+  // sort them into order of preference
+  candidates.mergeSort(compareProductionsForRewriting, &reductionStack);
+
+  // try each in turn until one succeeds; this effectively uses
+  // backtracking when one fails
+  bool retval = false;
+  SFOREACH_PRODUCTION(candidates, candIter) {
+    Production const *prod = candIter.data();
+
+    // add chosen production to the stack
+    reductionStack.prepend(const_cast<Production*>(prod));
+
+    // now, the chosen rule provides a RHS, which is a sequence of
+    // terminals and nonterminals; recursively reduce that sequence
+    SymbolList rhsSymbols;
+    prod->getRHSSymbols(rhsSymbols);
+    retval = rewriteAsTerminalsHelper(output, rhsSymbols, reductionStack);
+
+    // remove chosen production from stack
+    Production *temp = reductionStack.removeFirst();
+    xassert(temp == prod);
+
+    if (retval) {
+      // success!
+      break;
+    }
+    else {
+      // failed; try the next production
+    }
+  }
+
+  // and we succeed only if we found a valid rewriting
+  return retval;
+}
+
+// --------------- END of sample inputs -------------------
+
+
+// this is mostly [ASU] algorithm 4.7, p.218-219: an SLR(1) parser
+void GrammarAnalysis::lrParse(char const *input)
+{
+  // tokenize the input
+  StrtokParse tok(input, " \t");
+
+  // parser state
+  int currentToken = 0;               // index of current token
+  StateId state = startState->id;     // current parser state
+  ArrayStack<StateId> stateStack;     // stack of parser states; top==state
+  stateStack.push(state);
+  ArrayStack<Symbol const*> symbolStack;    // stack of shifted symbols
+
+  // for each token of input
+  while (currentToken < tok) {
+    // map the token text to a symbol
+    Terminal *symbol = findTerminal(tok[currentToken]);     // (constness)
+
+    // consult action table
+    ActionEntry action = tables->getActionEntry(state, symbol->termIndex);
+
+    // see what kind of action it is
+    if (tables->isShiftAction(action)) {
+      // shift
+      StateId destState = tables->decodeShift(action, symbol->termIndex);
+
+      // push current state and symbol
+      state = destState;
+      stateStack.push(state);
+      symbolStack.push(symbol);
+
+      // next input symbol
+      currentToken++;
+
+      // debugging
+      trace("parse")
+        << "moving to state " << state
+        << " after shifting symbol " << symbol->name << endl;
+    }
+
+    else if (tables->isReduceAction(action)) {
+      // reduce
+      int prodIndex = tables->decodeReduce(action, state);
+      ParseTables::ProdInfo const &info = tables->getProdInfo(prodIndex);
+
+      // it is here that an action or tree-building step would
+      // take place
+
+      // pop as many symbols off stacks as there are symbols on
+      // the right-hand side of 'prod'
+      stateStack.popMany(info.rhsLen);
+      state = stateStack.top();
+      symbolStack.popMany(info.rhsLen);
+
+      // find out where to go
+      StateId destState = tables->decodeGoto(
+        tables->getGotoEntry(state, info.lhsIndex), info.lhsIndex);
+
+      // go there
+      state = destState;
+      stateStack.push(state);
+
+      // and push the reduced nonterminal
+      symbolStack.push(getNonterminal(info.lhsIndex));
+
+      // debugging
+      trace("parse")
+        << "moving to state " << state
+        << " after reducing by rule id " << prodIndex << endl;
+    }
+
+    else if (tables->isErrorAction(action)) {
+      // error
+      trace("parse")
+        << "no actions defined for symbol " << symbol->name
+        << " in state " << state << endl;
+      break;       // stop parsing
+    }
+
+    else {
+      // conflict
+      trace("parse")
+        << "conflict for symbol " << symbol->name
+        << " in state " << state
+        << "; possible actions:\n";
+
+      // get actions
+      ActionEntry *entry = tables->decodeAmbigAction(action, state);
+
+      // explain each one
+      for (int i=0; i<entry[0]; i++) {
+        action = entry[i+1];
+        if (tables->isShiftAction(action)) {
+          trace("parse") << "  shift, and move to state "
+                         << tables->decodeShift(action, symbol->termIndex) << endl;
+        }
+        else if (tables->isReduceAction(action)) {
+          trace("parse") << "  reduce by rule id "
+                         << tables->decodeReduce(action, state) << endl;
+        }
+        else {
+          // no other alternative makes sense
+          xfailure("bad code in ambiguous action table");
+        }
+      }
+
+      break;       // stop parsing
+    }
+  }
+
+  // print final contents of stack; if the parse was successful,
+  // I want to see what remains; if not, it's interesting anyway
+  trace("parse") << "final contents of stacks (right is top):\n";
+
+  ostream &os = trace("parse") << "  state stack:";
+  int i;
+  for (i=0; i < stateStack.length(); i++) {
+    os << " " << stateStack[i];
+  }
+  os << " <-- current" << endl;
+
+  os << "  symbol stack:";
+  for (i=0; i < symbolStack.length(); i++) {
+    os << " " << symbolStack[i]->name;
+  }
+  os << endl;
+}
+
+
+// ------------------- grammar transformations ------------------
+void GrammarAnalysis::addTreebuildingActions()
+{
+  #define STR(s) LITERAL_LOCSTRING(grammarStringTable.add(s))
+
+  // prepend an #include to the verbatim
+  {
+    StringRef extra = grammarStringTable.add(
+      "\n#include \"ptreenode.h\"     // PTreeNode\n");
+    verbatim.prepend(new LITERAL_LOCSTRING(extra));
+  }
+
+  // get handles to the strings we want to emit
+  LocString param = STR("n");
+  LocString dupCode = STR("return n;");    // dup is identity
+  LocString delCode = STR("");             // del is no-op
+  LocString svalType = STR("PTreeNode*");
+
+  // merge relies on chaining scheme for alternatives
+  LocString mergeParam1 = STR("L");
+  LocString mergeParam2 = STR("R");
+  LocString mergeCode = STR("L->addAlternative(R); return L;");
+
+  // write dup/del/merge for nonterminals
+  MUTATE_EACH_OBJLIST(Nonterminal, nonterminals, ntIter) {
+    Nonterminal *nt = ntIter.data();
+
+    nt->dupParam = param;
+    nt->dupCode = dupCode;
+
+    nt->delParam = param;
+    nt->delCode = delCode;
+
+    nt->type = svalType;
+
+    nt->mergeParam1 = mergeParam1;
+    nt->mergeParam2 = mergeParam2;
+    nt->mergeCode = mergeCode;
+  }
+
+  // write treebuilding actions for productions
+  MUTATE_EACH_OBJLIST(Production, productions, prodIter) {
+    Production *p = prodIter.data();
+
+    // build up the code
+    stringBuilder code;
+    code << "return new PTreeNode(\"" << p->left->name << " -> "
+         << encodeWithEscapes(p->rhsString(false /*printTags*/,
+                                           true /*quoteAliases*/))
+         << "\"";
+
+    int ct=1;
+    MUTATE_EACH_OBJLIST(Production::RHSElt, p->right, rIter) {
+      Production::RHSElt *elt = rIter.data();
+
+      // connect nonterminal subtrees; drop lexemes on the floor
+      if (elt->sym->isNonterminal()) {
+        // use a generic tag
+        string tag = stringc << "t" << ct++;
+        elt->tag = STR(tag.c_str());
+
+        code << ", " << tag;
+      }
+    }
+
+    code << ");";
+
+    // insert the code into the production
+    p->action = LocString(SL_UNKNOWN,
+                          grammarStringTable.add(code));
+  }
+
+  #undef STR
+}
+
+
+// ---------------------------- main --------------------------------
+void pretendUsed(...)
+{}
+
+
+void GrammarAnalysis::exampleGrammar()
+{
+  // at one time I was using this to verify my LR item set
+  // construction code; this function isn't even called anymore..
+  readGrammarFile(*this, "examples/asu419.gr");
+
+  char const *input[] = {
+    " id                 $",
+    " id + id            $",
+    " id * id            $",
+    " id + id * id       $",
+    " id * id + id       $",
+    " ( id + id ) * id   $",
+    " id + id + id       $",
+    " id + ( id + id )   $"
+  };
+
+  // verify we got what we expected
+  printProductions(trace("grammar") << endl);
+
+
+  // run analyses
+  runAnalyses(NULL);
+
+
+  // do some test parses
+  INTLOOP(i, 0, (int)TABLESIZE(input)) {
+    trace("parse") << "------ parsing: `" << input[i] << "' -------\n";
+    lrParse(input[i]);
+  }
+}
+
+
+void GrammarAnalysis::runAnalyses(char const *setsFname)
+{
+  // prepare for symbol of interest
+  {
+    char const *name = getenv("SYM_OF_INTEREST");
+    if (name != NULL) {
+      symOfInterest = findSymbolC(name);
+      if (!symOfInterest) {
+        cout << "warning: " << name << " isn't in the grammar\n";
+      }
+    }
+  }
+
+  // reset error count so it might be possible to reuse the object
+  // for another grammar
+  errors = 0;
+
+  checkWellFormed();
+
+  // precomputations
+  traceProgress(1) << "init...\n";
+  initializeAuxData();
+
+  traceProgress(1) << "derivability relation...\n";
+  computeWhatCanDeriveWhat();
+
+  computeSupersets();
+
+  traceProgress(1) << "first...\n";
+  computeFirst();
+  computeDProdFirsts();
+
+  traceProgress(1) << "follow...\n";
+  computeFollow();
+
+  // print results
+  {
+    ostream &tracer = trace("terminals") << "Terminals:\n";
+    printSymbols(tracer, toObjList(terminals));
+  }
+  {
+    ostream &tracer = trace("nonterminals") << "Nonterminals:\n";
+    tracer << "  " << emptyString << endl;
+    printSymbols(tracer, toObjList(nonterminals));
+  }
+
+  if (tracingSys("derivable")) {
+    derivable->print();
+  }
+
+  // testing closure
+  #if 0
+  {
+    // make a singleton set out of the first production, and
+    // with the dot at the start
+    ObjList<LRItem> itemSet;
+    LRItem *kernel = productions.nth(0)->getDProd(0);  // (serf)
+    itemSet.append(kernel);
+
+    // compute its closure
+    itemSetClosure(itemSet);
+
+    // print it
+    cout << "Closure of: ";
+    kernel->print(cout);
+    cout << endl;
+
+    SFOREACH_OBJLIST(LRItem, itemSet, dprod) {
+      cout << "  ";
+      dprod.data()->print(cout);
+      cout << endl;
+    }
+  }
+  #endif // 0
+
+
+  // LR stuff
+  traceProgress(1) << "LR item sets...\n";
+  constructLRItemSets();
+
+  traceProgress(1) << "state renumbering...\n";
+  renumberStates();
+
+  traceProgress(1) << "parse tables...\n";
+  computeParseTables(!tracingSys("deterministic"));
+
+  #if 0     // old code; need it for just a while longer
+  {
+    int sr=0, rr=0;           // numbers of each kind of conflict
+    findSLRConflicts(sr, rr);
+    if (sr + rr > 0) {
+      cout << sr << " shift/reduce conflicts and "
+           << rr << " reduce/reduce conflicts\n";
+    }
+  }
+  #endif // 0
+
+  // if we want to print, do so before throwing away the items
+  if (tracingSys("itemsets")) {
+    printProductionsAndItems(cout, true /*code*/);
+  }
+
+  // open debug output file
+  ofstream *setsOutput = NULL;
+  if (setsFname) {
+    setsOutput = new ofstream(setsFname);
+    if (!*setsOutput) {
+      cout << "couldn't open " << setsFname << " to write item sets\n";
+      delete setsOutput;
+      setsOutput = NULL;
+    }
+  }
+
+  // count the number of unreachable nonterminals & terminals
+  {
+    if (setsOutput) {
+      *setsOutput << "unreachable nonterminals:\n";
+    }
+    int ct=0;
+    FOREACH_NONTERMINAL(nonterminals, iter) {
+      if (!iter.data()->reachable) {
+        ct++;
+
+        if (setsOutput) {
+          *setsOutput << "  " << iter.data()->name << "\n";
+        }
+      }
+    }
+
+    reportUnexpected(ct, expectedUNRNonterms, "unreachable nonterminals");
+
+    // bison also reports the number of productions under all the
+    // unreachable nonterminals, but that doesn't seem especially
+    // useful to me
+
+    if (setsOutput) {
+      *setsOutput << "unreachable terminals:\n";
+    }
+    ct=0;
+    FOREACH_TERMINAL(terminals, jter) {
+      if (!jter.data()->reachable) {
+        ct++;
+
+        if (setsOutput) {
+          *setsOutput << "  " << jter.data()->name << "\n";
+        }
+      }
+    }
+
+    reportUnexpected(ct, expectedUNRTerms, "unreachable terminals");
+  }
+
+  // print the item sets
+  if (setsOutput) {
+    traceProgress() << "printing item sets to " << setsFname << " ..." << endl;
+    *setsOutput << "NOTE: Item set numbers can change depending on what flags\n"
+                << "are passed to 'elkhound'!\n\n\n";
+    // only print the nonkernel items if they're explicitly requested,
+    // since they are more noise than signal, usually
+    printItemSets(*setsOutput, tracingSys("nonkernel"));
+  }
+
+  // print information about all tokens
+  if (setsOutput) {
+    *setsOutput << "terminals:\n";
+    FOREACH_TERMINAL(terminals, iter) {
+      Terminal const *t = iter.data();
+      *setsOutput << "  ";
+      t->print(*setsOutput);
+      *setsOutput << "\n";
+    }
+
+    // and nonterminals
+    *setsOutput << "nonterminals:\n";
+    FOREACH_NONTERMINAL(nonterminals, ntIter) {
+      Nonterminal const *nt = ntIter.data();
+      *setsOutput << "  ";
+      nt->print(*setsOutput);
+      *setsOutput << "\n";
+    }
+
+    // and productions
+    *setsOutput << "productions:\n";
+    for (int p=0; p<numProds; p++) {
+      *setsOutput << "  ";
+      Production const *prod = getProduction(p);
+      prod->print(*setsOutput);
+      if (prod->forbid) {
+        *setsOutput << " forbid_next(";
+        prod->forbid->print(*setsOutput, *this, "");
+        *setsOutput << ")";
+      }
+      *setsOutput << "\n";
+    }
+  }
+
+
+  delete setsOutput;
+
+  // I don't need (most of) the item sets during parsing, so
+  // throw them away once I'm done analyzing the grammar
+  MUTATE_EACH_OBJLIST(ItemSet, itemSets, iter) {
+    iter.data()->throwAwayItems();
+  }
+
+
+  // another analysis
+  //computePredictiveParsingTable();
+
+  // silence warnings
+  //pretendUsed(a,b,c,d,e, S,A,B,C,D);
+}
+
+
+// ------------------ emitting action code -----------------------
+// prototypes for this section; some of them accept Grammar simply
+// because that's all they need; there's no problem upgrading them
+// to GrammarAnalysis
+void emitDescriptions(GrammarAnalysis const &g, EmitCode &out);
+void emitActionCode(GrammarAnalysis const &g, rostring hFname,
+                    rostring ccFname, rostring srcFname);
+void emitUserCode(EmitCode &out, LocString const &code, bool braces = true);
+void emitActions(Grammar const &g, EmitCode &out, EmitCode &dcl);
+void emitDupDelMerge(GrammarAnalysis const &g, EmitCode &out, EmitCode &dcl);
+void emitFuncDecl(Grammar const &g, EmitCode &out, EmitCode &dcl,
+                  char const *rettype, char const *params);
+void emitDDMInlines(Grammar const &g, EmitCode &out, EmitCode &dcl,
+                    Symbol const &sym);
+void emitSwitchCode(Grammar const &g, EmitCode &out,
+                    char const *signature, char const *switchVar,
+                    ObjList<Symbol> const &syms, int whichFunc,
+                    char const *templateCode, char const *actUpon);
+
+
+// yield the name of the inline function for this production; naming
+// design motivated by desire to make debugging easier
+string actionFuncName(Production const &prod)
+{
+  return stringc << "action" << prod.prodIndex
+                 << "_" << prod.left->name;
+}
+
+
+// emit the user's action code to a file
+void emitActionCode(GrammarAnalysis const &g, rostring hFname,
+                    rostring ccFname, rostring srcFname)
+{
+  EmitCode dcl(hFname);
+  if (!dcl) {
+    throw_XOpen(hFname);
+  }
+
+  string latchName = replace(replace(replace(
+                       stringToupper(hFname),
+                         ".", "_"),
+                         "/", "_"),
+                         "-", "_");
+
+  // prologue
+  dcl << "// " << hFname << "\n"
+      << "// *** DO NOT EDIT BY HAND ***\n"
+      << "// automatically generated by elkhound, from " << srcFname << "\n"
+      << "\n"
+      << "#ifndef " << latchName << "\n"
+      << "#define " << latchName << "\n"
+      << "\n"
+      << "#include \"useract.h\"     // UserActions\n"
+      << "\n"
+      ;
+
+  // insert the stand-alone verbatim sections
+  {FOREACH_OBJLIST(LocString, g.verbatim, iter) {
+    emitUserCode(dcl, *(iter.data()), false /*braces*/);
+  }}
+
+  // insert each of the context class definitions; the last one
+  // is the one whose name is 'g.actionClassName' and into which
+  // the action functions are inserted as methods
+  {
+    int ct=0;
+    FOREACH_OBJLIST(LocString, g.actionClasses, iter) {
+      if (ct++ > 0) {
+        // end the previous class; the following body will open
+        // another one, and the brace following the action list
+        // will close the last one
+        dcl << "};\n";
+      }
+
+      dcl << "\n"
+          << "// parser context class\n"
+          << "class ";
+      emitUserCode(dcl, *(iter.data()), false /*braces*/);
+  }}
+
+  // we end the context class with declarations of the action functions
+  dcl << "\n"
+      << "private:\n"
+      << "  USER_ACTION_FUNCTIONS      // see useract.h\n"
+      << "\n"
+      << "  // declare the actual action function\n"
+      << "  static SemanticValue doReductionAction(\n"
+      << "    " << g.actionClassName << " *ths,\n"
+      << "    int productionId, SemanticValue const *semanticValues"
+         SOURCELOC( << ",\n  SourceLoc loc" )
+      << ");\n"
+      << "\n"
+      << "  // declare the classifier function\n"
+      << "  static int reclassifyToken(\n"
+      << "    " << g.actionClassName << " *ths,\n"
+      << "    int oldTokenType, SemanticValue sval);\n"
+      << "\n"
+      ;
+
+  EmitCode out(ccFname);
+  if (!out) {
+    throw_XOpen(ccFname);
+  }
+
+  out << "// " << ccFname << "\n";
+  out << "// *** DO NOT EDIT BY HAND ***\n";
+  out << "// automatically generated by gramanl, from " << srcFname << "\n";
+  out << "\n";
+  #ifdef NO_GLR_SOURCELOC
+    // we need to make sure the USER_ACTION_FUNCTIONS use
+    // the declarations consistent with how we're printing
+    // the definitions
+    out << "#ifndef NO_GLR_SOURCELOC\n";
+    out << "  #define NO_GLR_SOURCELOC\n";
+    out << "#endif\n";
+  #else
+    out << "// GLR source location information is enabled\n";
+  #endif
+  out << "\n";
+  out << "#include \"" << sm_basename(hFname) << "\"     // " << g.actionClassName << "\n";
+  out << "#include \"parsetables.h\" // ParseTables\n";
+  out << "#include \"srcloc.h\"      // SourceLoc\n";
+  out << "\n";
+  out << "#include <assert.h>      // assert\n";
+  out << "#include <iostream.h>    // cout\n";
+  out << "#include <stdlib.h>      // abort\n";
+  out << "\n";
+
+  NOSOURCELOC(
+    out << "// parser-originated location information is disabled by\n"
+        << "// NO_GLR_SOURCELOC; any rule which refers to 'loc' will get this one\n"
+        << "static SourceLoc const loc = SL_UNKNOWN;\n"
+        << "\n\n";
+  )
+
+  emitDescriptions(g, out);
+  // 'emitDescriptions' prints two newlines itself..
+
+  // impl_verbatim sections
+  //
+  // 2005-06-23: Moved these to near the top of the file so that
+  // the actions can easily refer to them.
+  FOREACH_OBJLIST(LocString, g.implVerbatim, iter) {
+    emitUserCode(out, *(iter.data()), false /*braces*/);
+  }
+
+  emitActions(g, out, dcl);
+  out << "\n";
+  out << "\n";
+
+  emitDupDelMerge(g, out, dcl);
+  out << "\n";
+  out << "\n";
+
+  g.tables->finishTables();
+  g.tables->emitConstructionCode(out, string(g.actionClassName), "makeTables");
+
+  // I put this last in the context class, and make it public
+  dcl << "\n"
+      << "// the function which makes the parse tables\n"
+      << "public:\n"
+      << "  virtual ParseTables *makeTables();\n"
+      << "};\n"
+      << "\n"
+      << "#endif // " << latchName << "\n"
+      ;
+}
+
+
+void emitUserCode(EmitCode &out, LocString const &code, bool braces)
+{
+  out << "\n";
+  if (code.validLoc()) {
+    out << lineDirective(code.loc);
+  }
+
+  // 7/27/03: swapped so that braces are inside the line directive
+  if (braces) {
+    out << "{";
+  }
+
+  out << code;
+
+  // the final brace is on the same line so errors reported at the
+  // last brace go to user code
+  if (braces) {
+    out << " }";
+  }
+
+  if (code.validLoc()) {
+    out << "\n" << restoreLine;
+  }
+  out << "\n";
+}
+
+
+// bit of a hack: map "void" to "SemanticValue" so that the compiler
+// won't mind when I try to declare parameters of that type
+char const *notVoid(char const *type)
+{
+  if (!type) {
+    return "int";
+  }
+  else if (0==strcmp(type, "void")) {
+    return "SemanticValue";
+  }
+  else {
+    return type;
+  }
+}
+
+// yield the given type, but if it's NULL, then yield
+// something to use instead
+char const *typeString(char const *type, LocString const &tag)
+{
+  if (!type) {
+    xbase(stringc << tag.locString() << ": Production tag \"" << tag
+                  << "\" on a symbol with no type.\n");
+    return NULL;     // silence warning
+  }
+  else {
+    return notVoid(type);
+  }
+}
+
+
+// return true if the type starts with the word "enum"
+bool isEnumType(char const *type)
+{
+  return 0==strncmp(type, "enum", 4);
+}
+
+
+void emitDescriptions(GrammarAnalysis const &g, EmitCode &out)
+{
+  // emit a map of terminal ids to their names
+  {
+    out << "static char const *termNames[] = {\n";
+    for (int code=0; code < g.numTerminals(); code++) {
+      Terminal const *t = g.getTerminal(code);
+      if (!t) {
+        // no terminal for that code
+        out << "  \"(no terminal)\",  // " << code << "\n";
+      }
+      else {
+        out << "  \"" << t->name << "\",  // " << code << "\n";
+      }
+    }
+    out << "};\n"
+        << "\n";
+  }
+
+  // emit a function to describe terminals; at some point I'd like to
+  // extend my grammar format to allow the user to supply
+  // token-specific description functions, but for now I will just
+  // use the information easily available the synthesize one;
+  // I print "sval % 100000" so I get a 5-digit number, which is
+  // easy for me to compare for equality without adding much clutter
+  out << "string " << g.actionClassName
+      << "::terminalDescription(int termId, SemanticValue sval)\n"
+      << "{\n"
+      << "  return stringc << termNames[termId]\n"
+      << "                 << \"(\" << (sval % 100000) << \")\";\n"
+      << "}\n"
+      << "\n"
+      << "\n"
+      ;
+
+  // emit a map of nonterminal ids to their names
+  {
+    out << "static char const *nontermNames[] = {\n";
+    for (int code=0; code < g.numNonterminals(); code++) {
+      Nonterminal const *nt = g.getNonterminal(code);
+      if (!nt) {
+        // no nonterminal for that code
+        out << "  \"(no nonterminal)\",  // " << code << "\n";
+      }
+      else {
+        out << "  \"" << nt->name << "\",  // " << code << "\n";
+      }
+    }
+    out << "};\n"
+        << "\n";
+  }
+
+  // and a function to describe nonterminals also
+  out << "string " << g.actionClassName
+      << "::nonterminalDescription(int nontermId, SemanticValue sval)\n"
+      << "{\n"
+      << "  return stringc << nontermNames[nontermId]\n"
+      << "                 << \"(\" << (sval % 100000) << \")\";\n"
+      << "}\n"
+      << "\n"
+      << "\n"
+      ;
+
+  // emit functions to get access to the static maps
+  out << "char const *" << g.actionClassName
+      << "::terminalName(int termId)\n"
+      << "{\n"
+      << "  return termNames[termId];\n"
+      << "}\n"
+      << "\n"
+      << "char const *" << g.actionClassName
+      << "::nonterminalName(int nontermId)\n"
+      << "{\n"
+      << "  return nontermNames[nontermId];\n"
+      << "}\n"
+      << "\n"
+      ;
+}
+
+
+void emitActions(Grammar const &g, EmitCode &out, EmitCode &dcl)
+{
+  out << "// ------------------- actions ------------------\n";
+
+  // iterate over productions, emitting inline action functions
+  {FOREACH_OBJLIST(Production, g.productions, iter) {
+    Production const &prod = *(iter.data());
+
+    // there's no syntax for a typeless nonterminal, so this shouldn't
+    // be triggerable by the user
+    xassert(prod.left->type);
+
+    // put the production in comments above the defn
+    out << "// " << prod.toString() << "\n";
+
+    out << "inline " << prod.left->type << " "
+        << g.actionClassName << "::" << actionFuncName(prod)
+        << "("
+        SOURCELOC( << "SourceLoc loc" )
+        ;
+
+    dcl << "  " << prod.left->type << " " << actionFuncName(prod) << "("
+        SOURCELOC( << "SourceLoc loc" )
+        ;
+
+    int ct=0;
+    SOURCELOC( ct++ );    // if we printed the 'loc' param, count it
+
+    // iterate over RHS elements, emitting formals for each with a tag
+    FOREACH_OBJLIST(Production::RHSElt, prod.right, rhsIter) {
+      Production::RHSElt const &elt = *(rhsIter.data());
+      if (elt.tag.length() == 0) continue;
+
+      if (ct++ > 0) {
+        out << ", ";
+        dcl << ", ";
+      }
+
+      out << typeString(elt.sym->type, elt.tag);
+      dcl << typeString(elt.sym->type, elt.tag);
+
+      // the tag becomes the formal parameter's name
+      out << " " << elt.tag;
+      dcl << " " << elt.tag;
+    }
+
+    out << ")";
+    dcl << ");\n";
+
+    // now insert the user's code, to execute in this environment of
+    // properly-typed semantic values
+    emitUserCode(out, prod.action);
+  }}
+
+  out << "\n";
+
+  // main action function; calls the inline functions emitted above
+  out << "/*static*/ SemanticValue " << g.actionClassName << "::doReductionAction(\n"
+      << "  " << g.actionClassName << " *ths,\n"
+      << "  int productionId, SemanticValue const *semanticValues"
+      SOURCELOC( << ",\n  SourceLoc loc" )
+      << ")\n";
+  out << "{\n";
+  out << "  switch (productionId) {\n";
+
+  // iterate over productions
+  FOREACH_OBJLIST(Production, g.productions, iter) {
+    Production const &prod = *(iter.data());
+
+    out << "    case " << prod.prodIndex << ":\n";
+    out << "      return (SemanticValue)(ths->" << actionFuncName(prod) << "("
+        SOURCELOC( << "loc" )
+        ;
+
+    // iterate over RHS elements, emitting arguments for each with a tag
+    int index = -1;      // index into 'semanticValues'
+    int ct=0;
+    SOURCELOC( ct++ );   // count 'loc' if it is passed
+    FOREACH_OBJLIST(Production::RHSElt, prod.right, rhsIter) {
+      Production::RHSElt const &elt = *(rhsIter.data());
+
+      // we have semantic values in the array for all RHS elements,
+      // even if they didn't get a tag
+      index++;
+
+      if (elt.tag.length() == 0) continue;
+
+      if (ct++ > 0) {
+        out << ", ";
+      }
+
+      // cast SemanticValue to proper type
+      out << "(" << typeString(elt.sym->type, elt.tag) << ")";
+      if (isEnumType(elt.sym->type)) {
+        // egcs-1.1.2 complains when I cast from void* to enum, even
+        // when there is a cast!  so let's put an intermediate cast
+        // to int
+        out << "(int)";
+      }
+      out << "(semanticValues[" << index << "])";
+    }
+
+    out << ")";     // end of argument list
+
+    if (0==strcmp(prod.left->type, "void")) {
+      // cute hack: turn the expression into a comma expression, with
+      // the value returned being 0
+      out << ", 0";
+    }
+
+    out << ");\n";
+  }
+
+  out << "    default:\n";
+  out << "      assert(!\"invalid production code\");\n";
+  out << "      return (SemanticValue)0;   // silence warning\n";
+  out << "  }\n";
+  out << "}\n";
+
+
+  // now emit the UserActions function which returns the doReductionAction
+  // function pointer
+  out << "\n";
+  out << "UserActions::ReductionActionFunc " << g.actionClassName << "::getReductionAction()\n";
+  out << "{\n";
+  out << "  return (ReductionActionFunc)&" << g.actionClassName << "::doReductionAction;\n";
+  out << "}\n";
+
+}
+
+
+void emitDupDelMerge(GrammarAnalysis const &g, EmitCode &out, EmitCode &dcl)
+{
+  out << "// ---------------- dup/del/merge/keep nonterminals ---------------\n"
+      << "\n";
+
+  // emit inlines for dup/del/merge of nonterminals
+  FOREACH_OBJLIST(Nonterminal, g.nonterminals, ntIter) {
+    emitDDMInlines(g, out, dcl, *(ntIter.data()));
+  }
+
+  // emit dup-nonterm
+  emitSwitchCode(g, out,
+    "SemanticValue $acn::duplicateNontermValue(int nontermId, SemanticValue sval)",
+    "nontermId",
+    (ObjList<Symbol> const&)g.nonterminals,
+    0 /*dupCode*/,
+    "      return (SemanticValue)dup_$symName(($symType)sval);\n",
+    NULL);
+
+  // emit del-nonterm
+  emitSwitchCode(g, out,
+    "void $acn::deallocateNontermValue(int nontermId, SemanticValue sval)",
+    "nontermId",
+    (ObjList<Symbol> const&)g.nonterminals,
+    1 /*delCode*/,
+    "      del_$symName(($symType)sval);\n"
+    "      return;\n",
+    "deallocate nonterm");
+
+  // emit merge-nonterm
+  emitSwitchCode(g, out,
+    "SemanticValue $acn::mergeAlternativeParses(int nontermId, SemanticValue left,\n"
+    "                                           SemanticValue right"
+    SOURCELOC(",  SourceLoc loc")
+    ")",
+    "nontermId",
+    (ObjList<Symbol> const&)g.nonterminals,
+    2 /*mergeCode*/,
+    "      return (SemanticValue)merge_$symName(($symType)left, ($symType)right);\n",
+    "merge nonterm");
+
+  // emit keep-nonterm
+  emitSwitchCode(g, out,
+    "bool $acn::keepNontermValue(int nontermId, SemanticValue sval)",
+    "nontermId",
+    (ObjList<Symbol> const&)g.nonterminals,
+    3 /*keepCode*/,
+    "      return keep_$symName(($symType)sval);\n",
+    NULL);
+
+
+  out << "\n";
+  out << "// ---------------- dup/del/classify terminals ---------------\n";
+  // emit inlines for dup/del of terminals
+  FOREACH_OBJLIST(Terminal, g.terminals, termIter) {
+    emitDDMInlines(g, out, dcl, *(termIter.data()));
+  }
+
+  // emit dup-term
+  emitSwitchCode(g, out,
+    "SemanticValue $acn::duplicateTerminalValue(int termId, SemanticValue sval)",
+    "termId",
+    (ObjList<Symbol> const&)g.terminals,
+    0 /*dupCode*/,
+    "      return (SemanticValue)dup_$symName(($symType)sval);\n",
+    NULL);
+
+  // emit del-term
+  emitSwitchCode(g, out,
+    "void $acn::deallocateTerminalValue(int termId, SemanticValue sval)",
+    "termId",
+    (ObjList<Symbol> const&)g.terminals,
+    1 /*delCode*/,
+    "      del_$symName(($symType)sval);\n"
+    "      return;\n",
+    "deallocate terminal");
+
+  // emit classify-term
+  emitSwitchCode(g, out,
+    "/*static*/ int $acn::reclassifyToken($acn *ths, int oldTokenType, SemanticValue sval)",
+    "oldTokenType",
+    (ObjList<Symbol> const&)g.terminals,
+    4 /*classifyCode*/,
+    "      return ths->classify_$symName(($symType)sval);\n",
+    NULL);
+
+  // and the virtual method which returns the classifier
+  out << "UserActions::ReclassifyFunc " << g.actionClassName << "::getReclassifier()\n"
+      << "{\n"
+      << "  return (ReclassifyFunc)&" << g.actionClassName << "::reclassifyToken;\n"
+      << "}\n";
+}
+
+
+// emit both the function decl for the .h file, and the beginning of
+// the function definition for the .cc file
+void emitFuncDecl(Grammar const &g, EmitCode &out, EmitCode &dcl,
+                  char const *rettype, char const *params)
+{
+  out << "inline " << rettype << " " << g.actionClassName
+      << "::" << params;
+
+  dcl << "  inline " << rettype << " " << params << ";\n";
+}
+
+
+void emitDDMInlines(Grammar const &g, EmitCode &out, EmitCode &dcl,
+                    Symbol const &sym)
+{
+  Terminal const *term = sym.ifTerminalC();
+  Nonterminal const *nonterm = sym.ifNonterminalC();
+  char const *symType = notVoid(sym.type);
+
+  if (sym.dupCode) {
+    emitFuncDecl(g, out, dcl, symType,
+      stringc << "dup_" << sym.name
+              << "(" << symType << " " << sym.dupParam << ") ");
+    emitUserCode(out, sym.dupCode);
+  }
+
+  if (sym.delCode) {
+    emitFuncDecl(g, out, dcl, "void",
+      stringc << "del_" << sym.name
+              << "(" << symType << " "
+              << (sym.delParam? sym.delParam : "") << ") ");
+    emitUserCode(out, sym.delCode);
+  }
+
+  if (nonterm && nonterm->mergeCode) {
+    emitFuncDecl(g, out, dcl, symType,
+      stringc << "merge_" << sym.name
+              << "(" << symType << " " << nonterm->mergeParam1
+              << ", " << symType << " " << nonterm->mergeParam2 << ") ");
+    emitUserCode(out, nonterm->mergeCode);
+  }
+
+  if (nonterm && nonterm->keepCode) {
+    emitFuncDecl(g, out, dcl, "bool",
+      stringc << "keep_" << sym.name
+              << "(" << symType << " " << nonterm->keepParam << ") ");
+    emitUserCode(out, nonterm->keepCode);
+  }
+
+  if (term && term->classifyCode) {
+    emitFuncDecl(g, out, dcl, "int",
+      stringc << "classify_" << sym.name
+              << "(" << symType << " " << term->classifyParam << ") ");
+    emitUserCode(out, term->classifyCode);
+  }
+}
+
+bool noDeclaredType(char const *type)
+{
+  // right now, terminals with no declared type have a NULL type
+  // field while nonterminals get "void".. I should make it
+  // uniform (probably NULL), but right now I am lazy
+  return !type || (0==strcmp(type, "void"));
+}
+
+void emitSwitchCode(Grammar const &g, EmitCode &out,
+                    char const *signature, char const *switchVar,
+                    ObjList<Symbol> const &syms, int whichFunc,
+                    char const *templateCode, char const *actUpon)
+{
+  out << replace(signature, "$acn", string(g.actionClassName)) << "\n"
+         "{\n"
+         "  switch (" << switchVar << ") {\n";
+
+  FOREACH_OBJLIST(Symbol, syms, symIter) {
+    Symbol const &sym = *(symIter.data());
+
+    if (whichFunc==0 && sym.dupCode ||
+        whichFunc==1 && sym.delCode ||
+        whichFunc==2 && sym.asNonterminalC().mergeCode ||
+        whichFunc==3 && sym.asNonterminalC().keepCode ||
+        whichFunc==4 && sym.asTerminalC().classifyCode) {
+      out << "    case " << sym.getTermOrNontermIndex() << ":\n";
+      out << replace(replace(templateCode,
+               "$symName", string(sym.name)),
+               "$symType", notVoid(sym.type));
+    }
+    else if (whichFunc==0 && noDeclaredType(sym.type)) {
+      // dup for symbol with no declared type: don't complain
+      out << "    case " << sym.getTermOrNontermIndex() << ":\n";
+      out << "      return sval;\n";
+    }
+    else if (whichFunc==1 && noDeclaredType(sym.type)) {
+      // del for no declared type
+      out << "    case " << sym.getTermOrNontermIndex() << ":\n";
+      out << "      break;\n";
+    }
+  }
+
+  out << "    default:\n";
+  switch (whichFunc) {
+    default:
+      xfailure("bad func code");
+
+    case 0:    // unspecified dup
+      if (!g.useGCDefaults) {
+        // not using GC, return NULL so silent sharing doesn't happen
+        out << "      return (SemanticValue)0;\n";
+      }
+      else {
+        // using GC, sharing is fine
+        out << "      return sval;\n";
+      }
+      break;
+
+    case 1:    // unspecified del
+      if (!g.useGCDefaults) {
+        // warn about unspec'd del, since it's probably a memory leak
+        if (syms.firstC()->isNonterminal()) {
+          // use the nonterminal map
+          out << "      cout << \"WARNING: there is no action to deallocate nonterm \"\n"
+                 "           << nontermNames[" << switchVar << "] << endl;\n";
+        }
+        else {
+          // use the terminal map
+          out << "      cout << \"WARNING: there is no action to deallocate terminal \"\n"
+                 "           << termNames[" << switchVar << "] << endl;\n";
+        }
+      }
+      else {
+        // in gc mode, just ignore del
+        out << "      break;\n";
+      }
+      break;
+
+    case 2: {  // unspecified merge: warn, but then use left (arbitrarily)
+      char const *w = g.defaultMergeAborts? "error: " : "WARNING: ";
+      out << "      cout << toString(loc) \n"
+          << "           << \": " << w << "there is no action to merge nonterm \"\n"
+          << "           << nontermNames[" << switchVar << "] << endl;\n";
+      if (g.defaultMergeAborts) {
+        out << "      abort();\n";
+      }
+      else {
+        out << "      return left;\n";
+      }
+      break;
+    }
+
+    case 3:    // unspecified keep: keep it
+      out << "      return true;\n";
+      break;
+
+    case 4:    // unspecified classifier: identity map
+      out << "      return oldTokenType;\n";
+      break;
+  }
+
+  out << "  }\n"
+         "}\n"
+         "\n";
+}
+
+
+// ------------------------- main --------------------------
+// TODO: split this into its own source file
+#ifdef GRAMANL_MAIN
+
+#include "bflatten.h"          // BFlatten
+#include "test.h"              // ARGS_MAIN
+#include "gramast.ast.gen.h"   // GrammarAST
+
+#include <stdio.h>             // remove
+#include <stdlib.h>            // system
+
+
+int inner_entry(int argc, char **argv)
+{
+  #define SHIFT argc--; argv++ /* user ; */
+
+  char const *progName = argv[0];
+  SHIFT;
+
+  // disable 'Exception thrown' reports
+  xBase::logExceptions = false;
+
+  // as long as this remains 0-length, it means to use
+  // the default naming scheme
+  string prefix;
+
+  // true to use ML, false to use C
+  bool useML = false;
+
+  // when true, if there is an error, do not leave partially-written
+  // output files
+  bool leavePartialOutputs = false;
+
+  while (argv[0] && argv[0][0] == '-') {
+    char const *op = argv[0]+1;
+    if (0==strcmp(op, "tr")) {
+      SHIFT;
+      traceAddMultiSys(argv[0]);
+      SHIFT;
+    }
+    else if (0==strcmp(op, "v")) {
+      SHIFT;
+      traceAddSys("progress");
+    }
+    else if (0==strcmp(op, "o")) {
+      SHIFT;
+      prefix = argv[0];
+      SHIFT;
+    }
+    else if (0==strcmp(op, "testRW")) {
+      SHIFT;
+      cout << "The testRW option has been removed because I wasn't using\n"
+              "it, and the code that implements it has bit-rotted.\n";
+      exit(3);
+    }
+    else if (0==strcmp(op, "ocaml")) {
+      SHIFT;
+      useML = true;
+    }
+    else if (0==strcmp(op, "leavePartial")) {
+      SHIFT;
+      leavePartialOutputs = true;
+    }
+    else if (0==strcmp(op, "help") || 0==strcmp(op, "-help")) {
+      SHIFT;
+      goto printUsage;
+    }
+    else {
+      cout << "unknown option: " << argv[0] << endl;
+      exit(2);
+    }
+  }
+
+  if (!argv[0]) {
+  printUsage:
+    cout << "usage: " << progName << " [options] filename.gr [extension.gr [...]]\n"
+            "  Generates parse tables to parse with the given grammar.\n"
+            "  The optional extension modules can add rules, etc.\n"
+            "\n"
+            "options:\n"
+            "  -tr <traceFlags>: turn on some flags (separate with commas):\n"
+            "      conflict    : print LALR(1) conflicts\n"
+            "      prec        : show how prec/assoc are used to resolve conflicts\n"
+            "      lrtable     : print LR parsing tables to <prefix>.out\n"
+            "                    (which also includes info about unreachable symbols)\n"
+            "      nonkernel   : include non-kernel items in <prefix>.out\n"
+            "      treebuild   : replace given actions with treebuilding actions\n"
+            "      grammar     : echo grammar to stdout (after merging modules)\n"
+            "  -v              : print stages of processing\n"
+            "  -o <prefix>     : name outputs <prefix>.h and <prefix>.cc\n"
+            "                    (default is filename.gen.h, filename.gen.cc)\n"
+            "  -ocaml          : generate ocaml parser instead of C++ parser\n"
+            "  -leavePartial   : do not delete output files in case of error\n"
+            ;
+    return 0;
+  }
+
+  if (!prefix.length()) {
+    // default naming scheme
+    prefix = replace(argv[0], ".gr", "");
+  }
+
+  SourceLocManager mgr;
+
+  // parse the grammar
+  string grammarFname = argv[0];
+  SHIFT;
+  Owner<GrammarAST> ast(parseGrammarFile(grammarFname, useML));
+
+  // parse and merge its extension modules
+  while (argv[0]) {
+    Owner<GrammarAST> ext(parseGrammarFile(argv[0], useML));
+
+    traceProgress() << "merging module: " << argv[0] << endl;
+    mergeGrammar(ast, ext);
+
+    SHIFT;
+  }
+
+  // parse the AST into a Grammar
+  GrammarAnalysis g;
+  if (useML) {
+    g.targetLang = "OCaml";
+  }
+  parseGrammarAST(g, ast);
+  ast.del();              // done with it
+
+  if (tracingSys("treebuild")) {
+    cout << "replacing given actions with treebuilding actions\n";
+    g.addTreebuildingActions();
+  }
+  g.printProductions(trace("grammar") << endl);
+
+  string setsFname = stringc << prefix << ".out";
+  g.runAnalyses(tracingSys("lrtable")? setsFname.c_str() : NULL);
+  if (g.errors) {
+    return 2;
+  }
+
+  if (!useML) {
+    // emit some C++ code
+    string hFname = stringc << prefix << ".h";
+    string ccFname = stringc << prefix << ".cc";
+    traceProgress() << "emitting C++ code to " << ccFname
+                    << " and " << hFname << " ...\n";
+
+    try {
+      emitActionCode(g, hFname, ccFname, grammarFname);
+    }
+    catch (...) {
+      if (!leavePartialOutputs) {
+        cout << "(deleting output files due to error)\n";
+        remove(hFname.c_str());
+        remove(ccFname.c_str());
+      }
+      else {
+        cout << "(note: partial output files have not been deleted)\n";
+      }
+      throw;
+    }
+  }
+  else {
+    // emit some ML code
+    string mliFname = stringc << prefix << ".mli";
+    string mlFname = stringc << prefix << ".ml";
+    traceProgress() << "emitting OCaml code to " << mlFname
+                    << " and " << mliFname << " ...\n";
+
+    try {
+      emitMLActionCode(g, mliFname, mlFname, grammarFname);
+    }
+    catch (...) {
+      if (!leavePartialOutputs) {
+        cout << "(deleting output files due to error)\n";
+        remove(mliFname.c_str());
+        remove(mlFname.c_str());
+      }
+      else {
+        cout << "(note: partial output files have not been deleted)\n";
+      }
+      throw;
+    }
+  }
+
+  // before using 'xfer' we have to tell it about the string table
+  flattenStrTable = &grammarStringTable;
+
+  // write it in a bison-compatible format as well
+  if (tracingSys("bison")) {
+    string bisonFname = stringc << prefix << ".y";
+    traceProgress() << "writing bison-compatible grammar to " << bisonFname << endl;
+    ofstreamTS out(bisonFname.c_str());
+    g.printAsBison(out);
+  }
+
+  traceProgress() << "done\n";
+
+  // this doesn't work
+  if (tracingSys("explore")) {
+    grammarExplorer(g);
+  }
+
+  return 0;
+}
+
+void entry(int argc, char **argv)
+{
+  int ret = inner_entry(argc, argv);
+  if (ret != 0) {
+    exit(ret);
+  }
+}
+
+ARGS_MAIN
+
+#endif // GRAMANL_MAIN

Added: vendor/elsa/current/elkhound/gramanl.h
===================================================================
--- vendor/elsa/current/elkhound/gramanl.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/gramanl.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,626 @@
+// gramanl.h            see license.txt for copyright and terms of use
+// grammar analysis module; separated from grammar.h to
+//   reduce mixing of representation and algorithm; this
+//   module should be entirely algorithm
+
+// Author: Scott McPeak, April 2000
+// Updates: March 2002
+
+// references:
+//
+//   [ASU]  Aho, Sethi Ullman.  Compilers: Principles,
+//          Techniques, and Tools.  Addison-Wesley,
+//          Reading, MA.  1986.  Second printing (3/88).
+//          [A classic reference for LR parsing.]
+
+
+#ifndef __GRAMANL_H
+#define __GRAMANL_H
+
+#include "grammar.h"      // Grammar and friends
+#include "ohashtbl.h"     // OwnerHashTable
+#include "okhashtbl.h"    // OwnerKHashTable
+#include "okhasharr.h"    // OwnerKHashArray
+#include "glrconfig.h"    // SOURCELOC
+#include "parsetables.h"  // ParseTables, GrowArray
+
+// forward decls
+class Bit2d;              // bit2d.h
+class BitArray;           // bitarray.h
+class EmitCode;           // emitcode.h
+
+// this file
+class GrammarAnalysis;
+
+
+// ---------------- DottedProduction --------------------
+// a production, with an indicator that says how much of this
+// production has been matched by some part of the input string
+// (exactly which part of the input depends on where this appears
+// in the algorithm's data structures)
+class DottedProduction {
+// ------ representation ------
+private:    // data
+  Production const *prod;        // (serf) the base production
+  int dot;                       // 0 means it's before all RHS symbols, 1 means after first, etc.
+
+// -------- annotation ----------
+private:    // data
+  // performance optimization: NULL if dot at end, or else pointer
+  // to the symbol right after the dot
+  Symbol *afterDot;
+
+public:     // data    
+  // First of the sentential form that follows the dot; this set
+  // is computed by GrammarAnalysis::computeDProdFirsts
+  TerminalSet firstSet;
+  
+  // also computed by computeDProdFirsts, this is true if the
+  // sentential form can derive epsilon (the empty string)
+  bool canDeriveEmpty;
+
+  // during item set closure, I need a way to map from dotted prods to
+  // the items which use them; so rather than use a hash table, I'll
+  // just annotate the dprods themselves with backpointers; these
+  // backpointers *must* be maintained as NULL when there's no
+  // association
+  mutable class LRItem *backPointer;
+
+private:    // funcs
+  void init();
+
+public:	    // funcs
+  //DottedProduction(DottedProduction const &obj);
+
+  // need the grammar passed during creation so we know how big
+  // to make 'lookahead'
+  //DottedProduction(GrammarAnalysis const &g);       // for later filling-in
+  //DottedProduction(/*GrammarAnalysis const &g,*/ Production *p, int d);
+  DottedProduction();     // for creating arrays of them
+  ~DottedProduction();
+
+  // no point to flattening these because they're easily re-computable
+  #if 0
+  DottedProduction(Flatten&);
+  void xfer(Flatten &flat);
+  void xferSerfs(Flatten &flat, GrammarAnalysis &g);
+  #endif // 0
+
+  // simple queries
+  Production const *getProd() const { return prod; }
+  int getDot() const { return dot; }
+  bool isDotAtStart() const { return dot==0; }
+  bool isDotAtEnd() const { return afterDot==NULL; }
+
+  // no need for equality now, since all DPs with the same
+  // prod/dot are shared
+  //bool isEqual(DottedProduction const &obj) const;
+  //bool operator== (DottedProduction const &obj) const;
+
+  // call this to change prod and dot
+  void setProdAndDot(Production const *p, int d);
+
+  // dot must not be at the start (left edge)
+  Symbol const *symbolBeforeDotC() const;
+  Symbol *symbolBeforeDot() { return const_cast<Symbol*>(symbolBeforeDotC()); }
+
+  // dot must not be at the end (right edge)
+  Symbol const *symbolAfterDotC() const { return afterDot; }
+  Symbol *symbolAfterDot() { return const_cast<Symbol*>(symbolAfterDotC()); }
+
+  // print to cout as 'A -> B . c D' (no newline)
+  void print(ostream &os/*, GrammarAnalysis const &g*/) const;
+  OSTREAM_OPERATOR(DottedProduction)
+};
+
+// lists of dotted productions
+typedef ObjList<DottedProduction> DProductionList;
+typedef ObjListIter<DottedProduction> DProductionListIter;
+typedef SObjList<DottedProduction> SDProductionList;
+typedef SObjListIter<DottedProduction> SDProductionListIter;
+
+#define FOREACH_DOTTEDPRODUCTION(list, iter) FOREACH_OBJLIST(DottedProduction, list, iter)
+#define MUTATE_EACH_DOTTEDPRODUCTION(list, iter) MUTATE_EACH_OBJLIST(DottedProduction, list, iter)
+#define SFOREACH_DOTTEDPRODUCTION(list, iter) SFOREACH_OBJLIST(DottedProduction, list, iter)
+#define SMUTATE_EACH_DOTTEDPRODUCTION(list, iter) SMUTATE_EACH_OBJLIST(DottedProduction, list, iter)
+
+
+// --------------- LRItem ---------------
+// a dotted production with a lookahead; whereas each production
+// has a fixed number of dotted versions of that production, there
+// can be lots of items, because of the differing lookahead sets
+// (I prefer the name "LRItem" to simply "Item" because the latter
+// easily collides with other uses)
+class LRItem {
+public:    // data
+  DottedProduction const *dprod;  // (serf) production and dot position
+  TerminalSet lookahead;          // lookahead symbols
+
+public:    // funcs
+  LRItem(LRItem const &obj);
+  ~LRItem();
+
+  // need 'numTerms' to tell how big to make 'lookahead'
+  LRItem(int numTerms, DottedProduction const *dp);
+
+  LRItem(Flatten&);
+  void xfer(Flatten &flat);
+  void xferSerfs(Flatten &flat, GrammarAnalysis &g);
+
+  // comparison
+  static int diff(LRItem const *a, LRItem const *b, void*);
+  bool equalNoLA(LRItem const &obj) const
+    { return dprod == obj.dprod; }
+
+  // manipulate the lookahead set
+  bool laContains(int terminalId) const
+    { return lookahead.contains(terminalId); }
+  void laAdd(int terminalId)
+    { lookahead.add(terminalId); }
+  void laRemove(int terminalId)
+    { lookahead.remove(terminalId); }
+  void laCopy(LRItem const &obj)
+    { lookahead.copy(obj.lookahead); }
+  bool laMerge(LRItem const &obj)     // returns true if merging changed lookahead
+    { return lookahead.merge(obj.lookahead); }
+  bool laIsEqual(LRItem const &obj) const
+    { return lookahead.isEqual(obj.lookahead); }
+
+  // pass-thru queries into 'dprod'
+  Production const *getProd() const
+    { return dprod->getProd(); }
+  int getDot() const
+    { return dprod->getDot(); }
+  bool isDotAtStart() const
+    { return dprod->isDotAtStart(); }
+  bool isDotAtEnd() const
+    { return dprod->isDotAtEnd(); }
+  Symbol const *symbolBeforeDotC() const
+    { return dprod->symbolBeforeDotC(); }
+  Symbol const *symbolAfterDotC() const
+    { return dprod->symbolAfterDotC(); }
+    
+  int prodIndex() const
+    { return getProd()->prodIndex; }
+
+  // stuff for insertion into a hash table
+  static unsigned hash(DottedProduction const *key);
+  static DottedProduction const *dataToKey(LRItem *dp);
+  static bool dpEqual(DottedProduction const *key1, DottedProduction const *key2);
+
+  // true if this item is "A -> alpha * t beta"
+  bool isExtendingShift(Nonterminal const *A, Terminal const *t) const;
+
+  void print(ostream &os, GrammarAnalysis const &g) const;
+};
+
+
+// ---------------- ItemSet -------------------
+// a set of dotted productions, and the transitions between
+// item sets, as in LR(0) set-of-items construction
+class ItemSet {
+public:     // intended to be read-only public
+  // kernel items: the items that define the set; except for
+  // the special case of the initial item in the initial state,
+  // the kernel items are distinguished by having the dot *not*
+  // at the left edge
+  ObjList<LRItem> kernelItems;
+
+  // nonkernel items: those derived as the closure of the kernel
+  // items by expanding symbols to the right of dots; here I am
+  // making the choice to materialize them, rather than derive
+  // them on the spot as needed (and may change this decision)
+  ObjList<LRItem> nonkernelItems;
+
+private:    // data
+  // transition function (where we go on shifts); NULL means no transition
+  //   Map : (Terminal id or Nonterminal id)  -> ItemSet*
+  ItemSet **termTransition;		     // (owner ptr to array of serf ptrs)
+  ItemSet **nontermTransition;		     // (owner ptr to array of serf ptrs)
+
+  // bounds for above
+  int terms;
+  int nonterms;
+
+  // profiler reports I'm spending significant time rifling through
+  // the items looking for those that have the dot at the end; so this
+  // array will point to all such items
+  LRItem const **dotsAtEnd;                  // (owner ptr to array of serf ptrs)
+  int numDotsAtEnd;                          // number of elements in 'dotsAtEnd'
+
+  // profiler also reports I'm still spending time comparing item sets; this
+  // stores a CRC of the numerically sorted kernel item pointer addresses,
+  // concatenated into a buffer of sufficient size
+  unsigned long kernelItemsCRC;
+
+  // need to store this, because I can't compute it once I throw
+  // away the items
+  Symbol const *stateSymbol;
+
+public:	    // data
+  // numerical state id, should be unique among item sets
+  // in a particular grammar's sets
+  StateId id;
+
+  // it's useful to have a BFS tree superimposed on the transition
+  // graph; for example, it makes it easy to generate sample inputs
+  // for each state.  so we store the parent pointer; we can derive
+  // child pointers by looking at all outgoing transitions, and
+  // filtering for those whose targets' parent pointers equal 'this'.
+  // the start state's parent is NULL, since it is the root of the
+  // BFS tree
+  ItemSet *BFSparent;                        // (serf)
+
+private:    // funcs
+  int bcheckTerm(int index) const;
+  int bcheckNonterm(int index) const;
+  ItemSet *&refTransition(Symbol const *sym);
+
+  void allocateTransitionFunction();
+  Symbol const *computeStateSymbolC() const;
+
+  void deleteNonReductions(ObjList<LRItem> &list);
+
+public:     // funcs
+  ItemSet(StateId id, int numTerms, int numNonterms);
+  ~ItemSet();
+
+  ItemSet(Flatten&);
+  void xfer(Flatten &flat);
+  void xferSerfs(Flatten &flat, GrammarAnalysis &g);
+
+  // ---- item queries ----
+  // the set of items names a symbol as the symbol used
+  // to reach this state -- namely, the symbol that appears
+  // to the left of a dot.  this fn retrieves that symbol
+  // (if all items have dots at left edge, returns NULL; this
+  // would be true only for the initial state)
+  Symbol const *getStateSymbolC() const { return stateSymbol; }
+
+  // equality is defined as having the same items (basic set equality)
+  bool operator== (ItemSet const &obj) const;
+
+  // sometimes it's convenient to have all items mixed together
+  // (CONSTNESS: allows modification of items...)
+  void getAllItems(SObjList<LRItem> &dest, bool nonkernel=true) const;
+
+  // used for sorting by id
+  static int diffById(ItemSet const *left, ItemSet const *right, void*);
+
+  // ---- transition queries ----
+  // query transition fn for an arbitrary symbol; returns
+  // NULL if no transition is defined
+  ItemSet const *transitionC(Symbol const *sym) const;
+  ItemSet *transition(Symbol const *sym)
+    { return const_cast<ItemSet*>(transitionC(sym)); }
+
+  // alternate interface; also might return NULL
+  ItemSet const *getTermTransition(int termId) const
+    { return termTransition[bcheckTerm(termId)]; }
+  ItemSet const *getNontermTransition(int nontermId) const
+    { return nontermTransition[bcheckNonterm(nontermId)]; }
+
+  // get the list of productions that are ready to reduce, given
+  // that the next input symbol is 'lookahead' (i.e. in the follow
+  // of a production's LHS); parsing=true means we are actually
+  // parsing input, so certain tracing output is appropriate;
+  // 'reductions' is a list of const Productions
+  void getPossibleReductions(ProductionList &reductions,
+                             Terminal const *lookahead,
+                             bool parsing) const;
+
+
+  // assuming this itemset has at least one reduction ready (an assertion
+  // checks this), retrieve the first one
+  Production const *getFirstReduction() const;
+
+  // ---- item mutations ----
+  // add a kernel item; used while constructing the state
+  void addKernelItem(LRItem * /*owner*/ item);
+
+  // after adding all kernel items, call this
+  void sortKernelItems();
+
+  // add a nonkernel item; used while computing closure; this
+  // item must not already be in the item set
+  void addNonkernelItem(LRItem * /*owner*/ item);
+
+  // computes things derived from the item set lists:
+  // dotsAtEnd, numDotsAtEnd, kernelItemsCRC, stateSymbol;
+  // do this after adding things to the items lists
+  void changedItems();
+
+  // a part of 'changedItems', this is used in a specialized way
+  // during LR item set construction; it leaves 'this' in a somewhat
+  // half-baked state (if changedItems is not also called), so some
+  // care needs to be taken when using this directly
+  void computeKernelCRC(GrowArray<DottedProduction const*> &array);
+
+  // remove the reduce using 'prod' on lookahead 'sym;
+  // calls 'changedItems' internally
+  void removeReduce(Production const *prod, Terminal const *sym);
+
+  // throw away information not needed during parsing
+  void throwAwayItems();
+
+  // 'dest' has already been established to have the same kernel
+  // items as 'this' -- so merge all the kernel lookahead items
+  // of 'this' into 'dest'; return 'true' if any changes were made
+  // to 'dest'
+  bool mergeLookaheadsInto(ItemSet &dest) const;
+
+  // true if this itemset has an item "A -> alpha * t beta", i.e.
+  // one that would extend 'A' by shifting 't'
+  bool hasExtendingShift(Nonterminal const *A, Terminal const *t) const;
+
+  // ---- transition mutations ----
+  // set transition on 'sym' to be 'dest'
+  void setTransition(Symbol const *sym, ItemSet *dest);
+
+  // remove the the shift on 'sym'
+  void removeShift(Terminal const *sym);
+
+  // ------ hashtable stuff --------
+  static ItemSet const *dataToKey(ItemSet *data);
+  static unsigned hash(ItemSet const *key);
+  static bool equalKey(ItemSet const *key1, ItemSet const *key2);
+
+  // ---- debugging ----
+  void writeGraph(ostream &os, GrammarAnalysis const &g) const;
+  void print(ostream &os, GrammarAnalysis const &g, bool nonkernel=true) const;
+};
+
+
+// ---------------------- GrammarAnalysis -------------------
+class GrammarAnalysis : public Grammar {
+protected:  // data
+  // if entry i,j is true, then nonterminal i can derive nonterminal j
+  // (this is a graph, represented (for now) as an adjacency matrix)
+  enum { emptyStringIndex = 0 };
+  Bit2d *derivable;                     // (owner)
+
+  // index the symbols on their integer ids
+  Nonterminal **indexedNonterms;        // (owner -> serfs) ntIndex -> Nonterminal
+  Terminal **indexedTerms;              // (owner -> serfs) termIndex -> Terminal
+  // numNonterms==Grammar::numNonterminals(), numTerms==Grammar::numTerminals()
+  int numNonterms;                      // length of 'indexedNonterms' array
+  int numTerms;                         //   "     "         terms       "
+
+  // during itemSetClosure, profiling reports we spend a lot of time
+  // walking the list of productions looking for those that have a given
+  // symbol on the LHS; so let's index produtions by LHS symbol index;
+  // this array has 'numNonterms' elements, mapping each nonterminal to
+  // the list of productions with that nonterminal on the LHS
+  SObjList<Production> *productionsByLHS;    // (owner ptr to array)
+
+  // map of production x dotPosition -> DottedProduction;
+  // each element of the 'dottedProds' array is a pointer to an
+  // array of DottedProduction objects
+  DottedProduction **dottedProds;       // (owner ptr to array of owners)
+  
+  // index of productions by id
+  Production **indexedProds;            // (owner -> serfs) prodIndex -> Production
+  int numProds;                         // length of 'dottedProds'
+
+  // only true after initializeAuxData has been called
+  bool initialized;
+
+  // used to assign itemset ids while the item sets are being
+  // initially constructed; later, they get renumbered into a
+  // canonical order
+  int nextItemSetId;
+
+  // the LR parsing tables
+  ObjList<ItemSet> itemSets;
+  
+  // distinguished start state; NOTE: much of the grammar analysis
+  // code currently assumes (and checks) that state 0 is the start
+  // state, so if you want to do something different, that code might
+  // need to be changed
+  ItemSet *startState;                  // (serf)
+
+public:	    // data
+  // true if any nonterminal can derive itself (with no extra symbols
+  // surrounding it) in 1 or more steps
+  bool cyclic;
+
+  // symbol of interest; various diagnostics are printed when
+  // certain things happen with it (e.g. the first application
+  // is to print whenever something is added to this sym's
+  // follow)
+  Symbol const *symOfInterest;
+
+  // incremented each time we encounter an error that we can recover from
+  int errors;
+
+  // parse tables
+  ParseTables *tables;                  // (owner)
+
+private:    // funcs
+  // ---- analyis init ----
+  // call this after grammar is completely built
+  void initializeAuxData();
+  void computeIndexedNonterms();
+  void computeIndexedTerms();
+  void computeProductionsByLHS();
+  void computeReachable();
+  void computeReachableDFS(Nonterminal *nt);
+  void resetFirstFollow();
+  void computeDProdFirsts();
+  void computeSupersets();
+
+  // ---- dotted productions ----
+  void createDottedProductions();
+  void deleteDottedProductions();
+  DottedProduction const *getDProd(Production const *prod, int posn) const;
+  DottedProduction *getDProd_nc(Production const *prod, int posn)
+    { return const_cast<DottedProduction*>(getDProd(prod, posn)); }
+
+  // given a dprod, yield the one obtained by moving the dot one
+  // place to the right
+  DottedProduction const *nextDProd(DottedProduction const *dp) const
+    #ifdef NDEBUG
+      { return dp+1; }      // take advantage of physical co-location
+    #endif
+      ;                     // debug version checks bounds
+
+  // ---- derivability ----
+  // iteratively compute every pair A,B such that A can derive B
+  void computeWhatCanDeriveWhat();
+  void initDerivableRelation();
+
+  // add a derivability relation; returns true if this makes a change
+  bool addDerivable(Nonterminal const *left, Nonterminal const *right);
+  bool addDerivable(int leftNtIndex, int rightNtIndex);
+
+  // private derivability interface
+  bool canDerive(int leftNtIndex, int rightNtIndex) const;
+  bool sequenceCanDeriveEmpty(RHSEltList const &list) const;
+  bool iterSeqCanDeriveEmpty(RHSEltListIter iter) const;
+
+  // ---- First ----
+  void computeFirst();
+  //bool addFirst(Nonterminal *NT, Terminal *term);
+  void firstOfSequence(TerminalSet &destList, RHSEltList const &sequence);
+  void firstOfIterSeq(TerminalSet &destList, RHSEltListIter sym);
+
+  // ---- Follow ----
+  void computeFollow();
+  //bool addFollow(Nonterminal *NT, Terminal *term);
+
+  // ---- LR item sets ----
+  ItemSet *makeItemSet();
+  void disposeItemSet(ItemSet *is);
+  void moveDotNoClosure(ItemSet const *source, Symbol const *symbol,
+                        ItemSet *dest, ObjList<LRItem> &unusedTail,
+                        GrowArray<DottedProduction const*> &array);
+  ItemSet *findItemSetInList(ObjList<ItemSet> &list,
+                             ItemSet const *itemSet);
+  static bool itemSetsEqual(ItemSet const *is1, ItemSet const *is2);
+
+  void constructLRItemSets();
+  void lrParse(char const *input);
+
+  void handleShiftReduceConflict(
+    bool &keepShift, bool &keepReduce, bool &dontWarn,
+    ItemSet const *state, Production const *prod, Terminal const *sym);
+
+  void resolveConflicts(
+    ItemSet const *state,        // parse state in which the actions are possible
+    Terminal const *sym,         // lookahead symbol for these actions
+    ItemSet const *&shiftDest,   // (inout) if non-NULL, the state to which we can shift
+    ProductionList &reductions,  // (inout) list of possible reductions
+    bool allowAmbig,             // if false, always return at most 1 action
+    bool &printedConflictHeader, // (inout) true once we've printed the state header
+    int &sr, int &rr);           // (inout) counts of S/R and R/R conflicts, resp.
+  void computeParseTables(bool allowAmbig);
+
+  int subsetDirectiveResolution(
+    ItemSet const *state,        // parse state in which the actions are possible
+    Terminal const *sym,         // lookahead symbol for these actions
+    ProductionList &reductions); // list to try to cut down
+  
+  void renumberStates();
+  static int renumberStatesDiff
+    (ItemSet const *left, ItemSet const *right, void *vgramanl);
+  static int arbitraryProductionOrder
+    (Production const *left, Production const *right, void*);
+  static int arbitraryRHSEltOrder
+    (Production::RHSElt const *left, Production::RHSElt const *right, void*);
+
+  void computeBFSTree();
+
+  // misc
+  void computePredictiveParsingTable();
+    // non-const because have to add productions to lists
+
+  void topologicalSort(NtIndex *order,  int &nextOrdinal,
+                       NtIndex current, BitArray &seen);
+  
+  // the inverse of transition: map a target state to the symbol that
+  // would transition to that state (from the given source state)
+  Symbol const *inverseTransitionC(ItemSet const *source,
+                                   ItemSet const *target) const;
+
+  // sample input helpers
+  void leftContext(SymbolList &output, ItemSet const *state) const;
+  bool rewriteAsTerminals(TerminalList &output, SymbolList const &input) const;
+  bool rewriteAsTerminalsHelper(TerminalList &output, SymbolList const &input,
+				ProductionList &reductionStack) const;
+  bool rewriteSingleNTAsTerminals(TerminalList &output, Nonterminal const *nonterminal,
+				  ProductionList &reductionStack) const;
+
+  // let's try this .. it needs to access 'itemSets'
+  friend void ItemSet::xferSerfs(Flatten &flat, GrammarAnalysis &g);
+
+  void singleItemClosure(OwnerKHashTable<LRItem, DottedProduction> &finished,
+                         ArrayStack<LRItem*> &worklist,
+                         //OwnerKHashArray<LRItem, DottedProduction> &workhash,
+                         LRItem const *item, TerminalSet &scratchSet);
+
+public:	    // funcs
+  GrammarAnalysis();
+  ~GrammarAnalysis();
+
+  // access symbols by index
+  Terminal const *getTerminal(int index) const;
+  Nonterminal const *getNonterminal(int index) const;
+  Production const *getProduction(int index) const;
+
+  ItemSet const *getItemSet(int index) const;
+  int numItemSets() const { return nextItemSetId; }
+
+  // faster access to counts
+  int numTerminals() const { return numTerms; }
+  int numNonterminals() const { return numNonterms; }
+
+  // binary read/write
+  void xfer(Flatten &flat);
+
+  // essentially, my 'main()' while experimenting
+  void exampleGrammar();
+
+  // overrides base class to add a little bit of the
+  // annotated info
+  void printProductions(ostream &os, bool printCode=true) const;
+
+  // print lots of stuff
+  void printProductionsAndItems(ostream &os, bool printCode=true) const;
+
+  // when grammar is built, this runs all analyses and stores
+  // the results in this object's data fields; write the LR item
+  // sets to the given file (or don't, if NULL)
+  void runAnalyses(char const *setsFname);
+
+  // print the item sets to a stream (optionally include nonkernel items)
+  void printItemSets(ostream &os, bool nonkernel) const;
+
+  // given a grammar, replace all of its actions with actions that
+  // will build a straightforward parse tree using the facilities
+  // of ptreenode.h; the rules will need the user to already have
+  // done some necessary work in the verbatim preamble, such as
+  // #including ptreenode.h
+  void addTreebuildingActions();
+
+  // ---- grammar queries ----
+  bool canDerive(Nonterminal const *lhs, Nonterminal const *rhs) const;
+  bool canDeriveEmpty(Nonterminal const *lhs) const;
+
+  bool firstIncludes(Nonterminal const *NT, Terminal const *term) const;
+  bool followIncludes(Nonterminal const *NT, Terminal const *term) const;
+
+  // ---- sample inputs and contexts ----
+  string sampleInput(ItemSet const *state) const;
+  string leftContextString(ItemSet const *state) const;
+  
+  // ---- moved out of private ----
+  void itemSetClosure(ItemSet &itemSet);
+  DottedProduction const *getDProdIndex(int prodIndex, int posn) const;
+};
+
+
+// in gramexpl.cc: interactive grammar experimentation system
+void grammarExplorer(GrammarAnalysis &g);
+
+
+#endif // __GRAMANL_H

Added: vendor/elsa/current/elkhound/gramast.ast
===================================================================
--- vendor/elsa/current/elkhound/gramast.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/gramast.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,96 @@
+// gramast.ast            see license.txt for copyright and terms of use
+// grammar AST, in a new experimental format
+
+verbatim {
+  #include "locstr.h"       // LocString
+  #include "asockind.h"     // AssocKind
+}
+
+// the entire grammar spec
+class GrammarAST (ASTList<TopForm> forms) {
+  // annotations, filled in during initial checking, pointing
+  // to some things that are supposed to exist and be unique
+  public TF_terminals *terms;
+  public TF_nonterm *firstNT;    // textually first nonterminal
+  
+  public bool allowContinuedNonterminals = false;
+  
+  ctor { terms=NULL; firstNT=NULL; };
+}
+
+
+// toplevel form
+class TopForm {
+  // definition of the parser context class; the first token
+  // in 'body' is the class name
+  -> TF_context(LocString body);
+  
+  // arbitrary verbatim section, emitted into either the interface
+  // (isImpl=false) or implementation (isImpl=true) file
+  -> TF_verbatim(bool isImpl, LocString code);
+
+  // declarative option; semantics vary based on 'name'
+  -> TF_option(LocString name, int value);
+
+  // definition of tokens
+  -> TF_terminals(ASTList<TermDecl> decls,     // ids and aliases
+                  ASTList<TermType> types,     // type annotations
+                  ASTList<PrecSpec> prec);     // precedence and associativity
+
+  // a nonterminal, with productions
+  -> TF_nonterm(
+    LocString name,                    // nonterm name
+    LocString type,                    // semantic value type
+    ASTList<SpecFunc> funcs,           // special situation action functions
+    ASTList<ProdDecl> productions,     // productions (right-hand side alternatives)
+    ASTList<LocString> subsets         // preference subset nonterminals (for scannerless)
+  );
+}
+
+
+
+// token with lexer code 'code' and grammar name 'name', with grammar
+// alias 'alias'
+class TermDecl (int code, LocString name, LocString alias);
+
+// declaration that token with grammar name 'name' has semantic
+// values with C type 'type'
+class TermType (LocString name, LocString type, ASTList<SpecFunc> funcs);
+
+// a set of equal-precedence tokens (named either by name or by alias),
+// and the 'kind' which tells how they associate; 'prec' is interpreted
+// such that larger values have higher precedence
+class PrecSpec (AssocKind kind, int prec, ASTList<LocString> tokens);
+
+
+// specification function: formals + code
+class SpecFunc (LocString name, ASTList<LocString> formals, LocString code)
+{
+  public LocString nthFormal(int i) const
+    { return *( formals.nthC(i) ); };
+}
+
+
+enum ProdDeclKind {
+  PDK_NEW,        // new production (most productions are new)
+  PDK_DELETE,     // means to delete the production from the base spec
+  PDK_REPLACE,    // replace original production with this one
+};
+
+// production: rhs description, and code to execute upon recognition
+class ProdDecl (SourceLoc loc, ProdDeclKind kind, ASTList<RHSElt> rhs, LocString actionCode);
+
+// one of the things that appears after the '->', i.e. the
+// right-hand-side elements
+class RHSElt {
+  -> RH_name(LocString tag, LocString name);         // tagged terminal or nonterminal reference
+  -> RH_string(LocString tag, LocString str);        // tagged terminal reference by string alias
+  
+  // assigns a specific precedence level to a rule
+  -> RH_prec(LocString tokName);                  
+
+  // forbids a rule from being used when a given token
+  // is next in the input
+  -> RH_forbid(LocString tokName);
+}
+

Added: vendor/elsa/current/elkhound/gramast.cc
===================================================================
--- vendor/elsa/current/elkhound/gramast.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/gramast.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,79 @@
+// gramast.cc            see license.txt for copyright and terms of use
+// code for gramast.h
+
+#error This module is obsolete; use gramast.gen.{cc,h} instead.
+
+#include "gramast.h"      // this module
+#include "macros.h"       // STATIC_ASSERT
+
+string astTypeToString(int type)
+{
+  static struct {
+    int code;
+    char const *name;
+  } const arr[] = {
+    #define N(code) { code, #code },
+    N(AST_INTEGER)
+    N(AST_STRING)
+    N(AST_NAME)
+    
+    N(AST_TOPLEVEL)
+    N(AST_TERMINALS)
+    N(AST_TERMDECL)
+    N(AST_ALIASES)
+    N(AST_NONTERM)
+    N(AST_NTBODY)
+    N(AST_NTNAME)
+    N(AST_BASECLASSES)
+    N(AST_ATTR)
+    N(AST_FORM)
+    N(AST_RHSALTS)
+    N(AST_RHS)
+    N(AST_TAGGEDNAME)
+    N(AST_TAGGEDSTRING)
+    N(AST_FORMBODY)
+    N(AST_FORMGROUPBODY)
+    N(AST_ACTION)
+    N(AST_CONDITION)
+    N(AST_FUNDECL)
+    N(AST_FUNCTION)
+    N(AST_FUNEXPR)
+    N(AST_TREENODEBASE)
+    N(AST_TREECOMPARE)
+    N(AST_DECLARATION)
+    N(AST_LITERALCODE)
+    N(AST_NAMEDLITERALCODE)
+
+    N(EXP_ATTRREF)
+    N(EXP_FNCALL)
+    N(EXP_LIST)
+    N(EXP_NEGATE)
+    N(EXP_NOT)
+    N(EXP_MULT)
+    N(EXP_DIV)
+    N(EXP_MOD)
+    N(EXP_PLUS)
+    N(EXP_MINUS)
+    N(EXP_LT)
+    N(EXP_GT)
+    N(EXP_LTE)
+    N(EXP_GTE)
+    N(EXP_EQ)
+    N(EXP_NEQ)
+    N(EXP_AND)
+    N(EXP_OR)
+    N(EXP_COND)
+    #undef N
+  };
+
+  STATIC_ASSERT(TABLESIZE(arr) == NUM_AST_CODES-1);
+
+  loopi(TABLESIZE(arr)) {
+    if (arr[i].code == type) {
+      return arr[i].name;
+    }
+  }
+  
+  xfailure("bad type code");
+  return NULL;   // silence warning
+}

Added: vendor/elsa/current/elkhound/gramast.h
===================================================================
--- vendor/elsa/current/elkhound/gramast.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/gramast.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,95 @@
+// gramast.h            see license.txt for copyright and terms of use
+// declarations for the grammar AST
+
+#ifndef __GRAMAST_H
+#define __GRAMAST_H
+
+#error This file is now obsolete.  Use gramast.ast.gen.h instead.
+
+#include "ast.h"       // basic ast stuff
+#include "str.h"       // string
+
+
+// node type codes
+enum ASTTypeCode {
+  // ---- leaves ----
+  // tokens
+  AST_INTEGER=1,         // ASTIntLeaf
+  AST_STRING,            // ASTStringLeaf
+  AST_NAME,              // ASTNameLeaf
+
+  // ---- internal nodes ----
+  // grammar tree components
+  AST_TOPLEVEL,          // list of toplevel forms
+
+  AST_TERMINALS,         // list of terminal declarations
+  AST_TERMDECL,          // terminal: numeric-code, aliases
+  AST_ALIASES,           // list of terminal aliases
+  
+  AST_NONTERM,           // nonterminal: ntname, (form or ntbody)
+  AST_NTBODY,            // list of nonterminal body elements
+  AST_NTNAME,            // name, [baseclasses]
+  AST_BASECLASSES,       // list of base class nonterminal names
+
+  AST_ATTR,              // attribute decl: name
+  AST_FORM,              // form: rhs, [formbody]
+  AST_RHSALTS,           // list of ALT_RHSs
+  AST_RHS,               // list of RHS elements
+  AST_TAGGEDNAME,        // tagged name: tag, name
+  AST_TAGGEDSTRING,      // tagged string: tag, string
+
+  AST_FORMBODY,          // list of form body elements
+  AST_FORMGROUPBODY,     // list of formGroup body elements
+
+  AST_ACTION,            // action: attr, expr
+  AST_CONDITION,         // condition: expr
+  AST_FUNDECL,           // fundecl: name, body
+  AST_FUNCTION,          // fun: name, body
+  AST_FUNEXPR,           // fun: name, expr-body
+
+  AST_TREENODEBASE,      // base class: string
+  AST_TREECOMPARE,       // name1, name2, expr
+  AST_DECLARATION,       // decl: decl body
+  
+  AST_LITERALCODE,       // code-tag, body
+  AST_NAMEDLITERALCODE,  // code-tag, body, name
+
+  // attribute-expression components
+  EXP_ATTRREF,           // reference to an attribute
+  EXP_FNCALL,            // function call
+  EXP_LIST,              // expression list
+
+  EXP_NEGATE,            // unary operators
+  EXP_NOT,
+
+  EXP_MULT,              // binary operators
+  EXP_DIV,
+  EXP_MOD,
+  EXP_PLUS,
+  EXP_MINUS,
+  EXP_LT,
+  EXP_GT,
+  EXP_LTE,
+  EXP_GTE,
+  EXP_EQ,
+  EXP_NEQ,
+  EXP_AND,
+  EXP_OR,
+
+  EXP_COND,              // ternary operator
+  
+  NUM_AST_CODES          // plus one, actually
+};
+
+                                 
+// map type to descriptive string
+string astTypeToString(int type);
+
+
+// why did I differentiate between string and name??
+typedef ASTSimpleLeaf<int, AST_INTEGER> ASTIntLeaf;
+typedef ASTSimpleLeaf<string, AST_STRING> ASTStringLeaf;
+typedef ASTSimpleLeaf<string, AST_NAME> ASTNameLeaf;
+
+
+#endif // __GRAMAST_H

Added: vendor/elsa/current/elkhound/gramexpl.cc
===================================================================
--- vendor/elsa/current/elkhound/gramexpl.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/gramexpl.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,142 @@
+// gramexpl.cc            see license.txt for copyright and terms of use
+// interactively query and modify a grammar; primary purpose
+// is to assist diagnosing SLR conflict reports
+
+#include "gramanl.h"    // GrammarAnalysis
+#include "strtokp.h"    // StrtokParse
+
+#include <iostream.h>   // cin/cout
+
+
+void grammarExplorer(GrammarAnalysis &g)
+{
+  cout << "exploring the grammar:\n";
+
+  #if 0
+  for (;;) {
+    cout << "commands:\n"
+            "  terminals\n"
+            "  nonterminals\n"
+            "  productions <nonterm-id>\n"
+            "  state <state-id>\n"
+            "  suppress-except <term-id> (-1 to disable)\n"
+            "  reach <state-id>\n"
+            "  track-la <state-id> <prod-id> <term-id>\n"
+            "  quit\n";
+    cout << "command> ";
+    cout.flush();
+
+    char buf[80];
+    cin >> buf;     // buffer overrun potential, don't care
+    if (cin.eof()) break;
+
+    StrtokParse tok(buf, " \n\t");
+    if (tok == 0) continue;
+
+    try {
+      if (0==strcmp(tok[0], "terminals")) {
+        for (int i=0; i < g.numTerminals(); i++) {
+          Terminal const *t = g.getTerminal(i);
+          t->print(cout);
+        }
+      }
+
+      else if (0==strcmp(tok[0], "nonterminals")) {
+        for (int i=0; i < g.numNonterminals(); i++) {
+          Nonterminal const *nt = g.getNonterminal(i);
+          nt->print(cout);
+        }
+      }
+
+      else if (0==strcmp(tok[0], "productions")) {
+        int id = atoi(tok[1]);
+        Nonterminal const *nt = g.getNonterminal(i);
+        int ct=0;
+        FOREACH_PRODUCTION(g.productions, iter) {
+          if (iter.data()->left == nt) {
+            cout << "[" << ct << "] ";   // production id
+            iter.data()->print(cout);
+          }
+          ct++;
+        }
+      }
+
+      else if (0==strcmp(tok[0], "state")) {
+        ItemSet const *is = g.getItemSet(atoi(tok[1]));
+        is->print(cout, g);
+      }
+
+      else if (0==strcmp(tok[0], "suppress-except")) {
+        int id = atoi(tok[1]);
+        Terminal const *t = (id==-1? NULL : g.getTerminal(atoi(tok[1])));
+        DottedProduction::lookaheadSuppressExcept = t;
+        if (t) {
+          cout << "suppressing  " << t->name << endl;
+        }
+        else {
+          cout << "suppressing nothing\n";
+        }
+      }
+
+      else if (0==strcmp(tok[0], "reach")) {
+        int targetId = atoi(tok[1]);
+
+        // consider every state..
+        for (int i=0; i < g.numItemSets(); i++) {
+          ItemSet const *set = g.getItemSet(i);
+
+          // iterate over all possible symbols to find transitions
+          for (int termId=0; termId < g.numTerminals(); termId++) {
+            ItemSet const *dest = set->transitionC(g.getTerminal(termId));
+            if (dest && dest->id == targetId) {
+              dest->print(cout, g);
+            }
+          }
+          for (int nontermId=0; nontermId < g.numNonterminals(); nontermId++) {
+            ItemSet const *dest = set->transitionC(g.getNonterminal(nontermId));
+            if (dest && dest->id == targetId) {
+              dest->print(cout, g);
+            }
+          }
+        }
+      }
+
+      else if (0==strcmp(tok[0], "track-la")) {
+        int stateId = atoi(tok[1]);
+        ItemSet const *set = g.getItemSet(stateId);
+
+        int prodId = atoi(tok[2]);                 
+        Production const *prod = g.productions.nth(prodId);
+
+        int termId = atoi(tok[3]);                         
+        Terminal const *term = g.getTerminal(termId);
+        
+        
+
+
+
+
+
+
+      }
+      else if (0==strcmp(tok[0], "quit")) {
+      }
+      else {
+        cout << "unknown command: " << tok[0] << endl;
+      }
+    }
+    catch (xArrayBounds &) {
+      cout << "too few arguments to " << tok[0] << endl;
+    }
+
+
+
+
+
+
+
+
+  #endif // 0
+
+}
+

Added: vendor/elsa/current/elkhound/gramlex.lex
===================================================================
--- vendor/elsa/current/elkhound/gramlex.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/gramlex.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,399 @@
+/* grammar.lex
+ * lexical analyzer for my grammar input format
+ *
+ * The variety of syntaxes for embedded literal code cause this lexer
+ * to have some of the context sensitivity usually associated with a
+ * parser.  This context doesn't nest arbitrarily deeply, so the
+ * language recognized is still regular, but clearly there's some
+ * design tension.
+ */
+
+/* ----------------- C definitions -------------------- */
+%{
+
+// pull in my declaration of the lexer class -- this defines
+// the additional lexer state, some of which is used in the
+// action rules below (this is in the ../ast/ directory now)
+#include "gramlex.h"
+
+// pull in the bison-generated token codes
+#include "grampar.codes.h"
+
+#include <string.h>     // strchr, strrchr
+
+// for maintaining column count
+#define TOKEN_START  tokenStartLoc = fileState.loc /* user ; */
+#define UPD_COL      \
+  fileState.loc = sourceLocManager->advCol(fileState.loc, yyleng)  /* user ; */
+#define TOK_UPD_COL  TOKEN_START; UPD_COL  /* user ; */
+
+%}
+
+
+/* -------------------- flex options ------------------ */
+/* no wrapping is needed; setting this means we don't have to link with libfl.a */
+%option noyywrap
+
+/* don't use the default-echo rules */
+%option nodefault
+
+/* generate a c++ lexer */
+%option c++
+
+/* and I will define the class */
+%option yyclass="GrammarLexer"
+
+
+/* ------------------- definitions -------------------- */
+/* any character, including newline */
+ANY       (.|"\n")
+
+/* any character except newline */
+ANYBUTNL  .
+
+/* starting character in a name */
+LETTER    [a-zA-Z_]
+
+/* starting character in a numeric literal */
+DIGIT     [0-9]
+
+/* double-quote */
+DQUOTE    "\""
+
+/* character that can appear in a quoted string */
+/* (I currently don't have any backslash codes, but I want to
+ * leave open that possibility, so for now backslashes are illegal) */
+STRCHR    [^\n\\\"]
+
+/* non-newline whitespace */
+HWHITE    [ \t\f\v\r]
+
+
+/* --------------- start conditions ------------------- */
+/* eating a comment delimited by slash-star and star-slash; note
+ * that we remember our current state when entering C_COMMENT,
+ * and restore it on exit */
+%x C_COMMENT
+
+/* looking for the file name in an "include" directive */
+%x INCLUDE
+
+/* recovering from an error by skipping to the next newline */
+%x EAT_TO_NEWLINE
+
+/* gathering literal embedded code; the delimiter is specified
+ * in the 'embedFinish' variable */
+%x LITCODE
+
+/* tokenizing the right-hand side of a production; this one is not
+ * exclusive because tokenization is virtually the same in RHS
+ * mode as in INITIAL mode */
+%s RHS
+
+/* tokenizing parameter list of a function, leading into the
+ * embedded code that is its body */
+%s FUN
+
+/* looking for the start of a type that follows "token" or "nonterm",
+ * or the TOK_NAME meaning the type has been omitted */
+%s OPTIONAL_TYPE
+
+
+/* ---------------------- rules ----------------------- */
+%%
+
+  /* -------- whitespace ------ */
+"\n" {
+  newLine();
+}
+
+{HWHITE}+ {
+  UPD_COL;
+}
+
+  /* -------- comments -------- */
+"/""*" {
+  /* C-style comments */
+  TOKEN_START;
+  UPD_COL;
+  prevState = YY_START;
+  BEGIN(C_COMMENT);
+}
+
+<C_COMMENT>{
+  "*/" {
+    /* end of comment */
+    UPD_COL;
+    BEGIN(prevState);
+  }
+
+  . {
+    /* anything but slash-star or newline -- eat it */
+    UPD_COL;
+  }
+
+  "\n" {
+    newLine();
+  }
+
+  <<EOF>> {
+    UPD_COL;      // <<EOF>> yyleng is 1!
+    errorUnterminatedComment();
+    return TOK_EOF;
+  }
+}
+
+
+"//".*"\n" {
+  /* C++-style comment -- eat it */
+  TOKEN_START;
+  advCol(yyleng-1);   // don't count newline
+  newLine();          // count it here
+}
+
+
+  /* -------- punctuators, operators, keywords --------- */
+"}"                TOK_UPD_COL;  return TOK_RBRACE;
+":"                TOK_UPD_COL;  return TOK_COLON;
+")"                TOK_UPD_COL;  return TOK_RPAREN;
+","                TOK_UPD_COL;  return TOK_COMMA;
+
+"terminals"        TOK_UPD_COL;  return TOK_TERMINALS;
+"precedence"       TOK_UPD_COL;  return TOK_PRECEDENCE;
+"option"           TOK_UPD_COL;  return TOK_OPTION;
+"expect"           TOK_UPD_COL;  return TOK_EXPECT;
+"subsets"          TOK_UPD_COL;  return TOK_SUBSETS;
+"replace"          TOK_UPD_COL;  return TOK_REPLACE;
+"delete"           TOK_UPD_COL;  return TOK_DELETE;
+"forbid_next"      TOK_UPD_COL;  return TOK_FORBID_NEXT;
+
+
+  /* ----------- sequences that begin literal code ------------ */
+  /* for the time being, a "[" will always start an embedded sequence;
+   * eventually, I'll remove this in favor of the brace- and paren-
+   * delimited embedded sequences */
+"[" {
+  TOK_UPD_COL;
+  BEGIN(LITCODE);
+  beginEmbed(']', TOK_LIT_CODE);
+}
+
+  /* the "->" operator moves us into RHS mode, which is special because
+   * in this mode any "{" is interpreted as the beginning of an embedded
+   * section of literal code */
+"->" {
+  TOK_UPD_COL;
+  BEGIN(RHS);
+  return TOK_ARROW;
+}
+
+  /* "{" in a RHS begins embedded */
+<RHS,FUN>"{" {
+  TOK_UPD_COL;
+  BEGIN(LITCODE);
+  beginEmbed('}', TOK_LIT_CODE);
+}
+
+  /* otherwise it's just a "{" */
+<INITIAL>"{" {
+  TOK_UPD_COL;
+  return TOK_LBRACE;
+}
+
+  /* since right-hand-sides can end with either embedded code or a simple
+   * ";", the semicolon gets out of RHS mode */
+<INITIAL,RHS>";" {
+  TOK_UPD_COL;
+  BEGIN(INITIAL);     // if in RHS, reset to INITIAL
+  return TOK_SEMICOLON;
+}
+
+  /* "token" and "nonterm" are always followed by an optional type,
+   * and then a TOK_NAME.  So, until we see a TOK_NAME, "(" will mean
+   * the start of an embedded sequence. */
+"token"|"nonterm" {
+  TOK_UPD_COL;
+  BEGIN(OPTIONAL_TYPE);
+  return yytext[0]=='t'? TOK_TOKEN : TOK_NONTERM;
+}
+
+  /* so now this begins embedded */
+<OPTIONAL_TYPE>"(" {
+  TOK_UPD_COL;
+  BEGIN(LITCODE);
+  beginEmbed(')', TOK_LIT_CODE);
+}
+
+  /* otherwise it's just itself */
+<INITIAL,RHS,FUN>"(" {
+  TOK_UPD_COL;
+  return TOK_LPAREN;
+}
+
+  /* function beginning */
+"fun" {
+  TOK_UPD_COL;
+  BEGIN(FUN);            // treat "{" as beginning literal code
+  return TOK_FUN;
+}
+
+  /* verbatim beginning */
+"verbatim"|"impl_verbatim" {
+  TOK_UPD_COL;
+  BEGIN(FUN);            // close enough
+  return yytext[0]=='v'? TOK_VERBATIM : TOK_IMPL_VERBATIM;
+}
+
+
+  /* --------- embedded literal code --------- */
+  /* no TOKEN_START here; we'll use the tokenStartLoc that
+   * was computed in the opening punctuation */
+<LITCODE>{
+  [^\]\})\n]+ {
+    UPD_COL;
+    embedded->handle(yytext, yyleng, embedFinish);
+  }
+
+  "\n" {
+    newLine();
+    embedded->handle(yytext, yyleng, embedFinish);
+  }
+
+  ("]"|"}"|")") {
+    UPD_COL;
+    if (embedded->zeroNesting()) {
+      // done
+      BEGIN(INITIAL);
+
+      // check for balanced delimiter
+      if (embedFinish != yytext[0]) {
+        err("unbalanced literal code delimiter");
+      }
+
+      // don't add "return" or ";"
+      embedded->exprOnly = false;
+
+      // can't extract anything
+      embedded->isDeclaration = false;
+
+      // caller can get text from embedded->text
+      return embedMode;
+    }
+    else {
+      // delimeter paired within the embedded code, mostly ignore it
+      embedded->handle(yytext, yyleng, embedFinish);
+    }
+  }
+
+  <<EOF>> {
+    err(stringc << "hit end of file while looking for final `"
+                << embedFinish << "'");
+    yyterminate();
+  }
+}
+
+
+  /* embedded *type* description */
+"context_class" {
+  /* caller will get text from yytext and yyleng */
+  TOK_UPD_COL;
+
+  /* drop into literal-code processing */
+  BEGIN(LITCODE);
+
+  /* I reset the initial nesting to -1 so that the '{' at the
+   * beginning of the class body sets nesting to 0, thus when
+   * I see the final '}' I'll see that at level 0 and stop */
+  beginEmbed('}', TOK_LIT_CODE, -1);
+
+  return TOK_CONTEXT_CLASS;
+}
+
+
+  /* ---------- includes ----------- */
+"include" {
+  TOK_UPD_COL;    /* hence no TOKEN_START in INCLUDE area */
+  BEGIN(INCLUDE);
+}
+
+<INCLUDE>{
+  {HWHITE}*"("{HWHITE}*{DQUOTE}{STRCHR}+{DQUOTE}{HWHITE}*")" {
+    /* e.g.: ("filename") */
+    /* file name to include */
+    UPD_COL;
+
+    /* find quotes */
+    char *leftq = strchr(yytext, '"');
+    char *rightq = strchr(leftq+1, '"');
+    xassert(leftq && rightq);
+
+    /* extract filename string */
+    includeFileName = addString(leftq+1, rightq-leftq-1);
+
+    /* go back to normal processing */
+    BEGIN(INITIAL);
+    return TOK_INCLUDE;
+  }
+
+  {ANY}      {
+    /* anything else: malformed */
+    UPD_COL;
+    errorMalformedInclude();
+
+    /* rudimentary error recovery.. */
+    BEGIN(EAT_TO_NEWLINE);
+  }
+}
+
+<EAT_TO_NEWLINE>{
+  .+ {
+    UPD_COL;
+    /* not newline, eat it */
+  }
+
+  "\n" {
+    /* get out of here */
+    newLine();
+    BEGIN(INITIAL);
+  }
+}
+
+  /* -------- name literal --------- */
+{LETTER}({LETTER}|{DIGIT})* {
+  /* get text from yytext and yyleng */
+  TOK_UPD_COL;
+  if (YY_START == OPTIONAL_TYPE) {
+    BEGIN(INITIAL);      // bail out of OPTIONAL_TYPE mode
+  }
+  return TOK_NAME;
+}
+
+  /* -------- numeric literal ------ */
+{DIGIT}+ {
+  TOK_UPD_COL;
+  integerLiteral = strtoul(yytext, NULL, 10 /*radix*/);
+  return TOK_INTEGER;
+}
+
+  /* ----------- string literal ----- */
+{DQUOTE}{STRCHR}*{DQUOTE} {
+  TOK_UPD_COL;
+  stringLiteral = addString(yytext+1, yyleng-2);        // strip quotes
+  return TOK_STRING;
+}
+
+  /* --------- illegal ------------- */
+{ANY} {
+  TOK_UPD_COL;
+  errorIllegalCharacter(yytext[0]);
+}
+
+
+%%
+/* -------------------- additional C code -------------------- */
+
+// identify tokens representing embedded text
+bool isGramlexEmbed(int code)
+{
+  return code == TOK_LIT_CODE;
+}

Added: vendor/elsa/current/elkhound/grammar.cc
===================================================================
--- vendor/elsa/current/elkhound/grammar.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grammar.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1291 @@
+// grammar.cc            see license.txt for copyright and terms of use
+// code for grammar.h
+
+#include "grammar.h"   // this module
+#include "syserr.h"    // xsyserror
+#include "strtokp.h"   // StrtokParse
+#include "trace.h"     // trace
+#include "exc.h"       // xBase
+#include "strutil.h"   // quoted, parseQuotedString
+#include "flatten.h"   // Flatten
+#include "flatutil.h"  // various xfer helpers
+
+#include <stdarg.h>    // variable-args stuff
+#include <stdio.h>     // FILE, etc.
+#include <ctype.h>     // isupper
+#include <stdlib.h>    // atoi
+
+
+// print a variable value
+#define PVAL(var) os << " " << #var "=" << var;
+
+
+StringTable grammarStringTable;
+
+
+// ---------------------- Symbol --------------------
+Symbol::Symbol(LocString const &n, bool t, bool e)
+  : name(n),
+    isTerm(t),
+    isEmptyString(e),
+    type(NULL),
+    dupParam(NULL),
+    dupCode(),
+    delParam(NULL),
+    delCode(),
+    reachable(false)
+{}
+
+Symbol::~Symbol()
+{}
+
+
+Symbol::Symbol(Flatten &flat)
+  : name(flat),
+    isTerm(false),
+    isEmptyString(false),
+    type(NULL),
+    dupParam(NULL),
+    delParam(NULL)
+{}
+
+void Symbol::xfer(Flatten &flat)
+{
+  // have to break constness to unflatten
+  const_cast<LocString&>(name).xfer(flat);
+  flat.xferBool(const_cast<bool&>(isTerm));
+  flat.xferBool(const_cast<bool&>(isEmptyString));
+
+  flattenStrTable->xfer(flat, type);
+
+  flattenStrTable->xfer(flat, dupParam);
+  dupCode.xfer(flat);
+
+  flattenStrTable->xfer(flat, delParam);
+  delCode.xfer(flat);
+  
+  flat.xferBool(reachable);
+}
+
+
+int Symbol::getTermOrNontermIndex() const
+{
+  if (isTerminal()) {
+    return asTerminalC().termIndex;
+  }
+  else {
+    return asNonterminalC().ntIndex;
+  }
+}
+
+
+void Symbol::print(ostream &os) const
+{
+  os << name;
+  if (type) {
+    os << "[" << type << "]";
+  }
+  os << ":";
+  PVAL(isTerm);
+}
+
+
+void Symbol::printDDM(ostream &os) const
+{
+  // don't print anything if no handlers
+  if (!anyDDM()) return;
+
+  // print with roughly the same syntax as input
+  os << "  " << (isTerminal()? "token" : "nonterm");
+  if (type) {
+    os << "[" << type << "]";
+  }
+  os << " " << name << " {\n";
+
+  internalPrintDDM(os);
+
+  os << "  }\n";
+}
+
+
+void Symbol::internalPrintDDM(ostream &os) const
+{
+  if (dupCode.isNonNull()) {
+    os << "    dup(" << dupParam << ") [" << dupCode << "]\n";
+  }
+
+  if (delCode.isNonNull()) {
+    os << "    del(" << (delParam? delParam : "") << ") [" << delCode << "]\n";
+  }
+}
+
+
+bool Symbol::anyDDM() const
+{
+  return dupCode.isNonNull() ||
+         delCode.isNonNull();
+}
+
+
+Terminal const &Symbol::asTerminalC() const
+{
+  xassert(isTerminal());
+  return (Terminal const &)(*this);
+}
+
+Nonterminal const &Symbol::asNonterminalC() const
+{
+  xassert(isNonterminal());
+  return (Nonterminal const &)(*this);
+}
+
+
+Terminal const *Symbol::ifTerminalC() const
+{
+  return isTerminal()? (Terminal const *)this : NULL;
+}
+
+Nonterminal const *Symbol::ifNonterminalC() const
+{
+  return isNonterminal()? (Nonterminal const *)this : NULL;
+}
+
+
+
+// -------------------- Terminal ------------------------
+Terminal::Terminal(Flatten &flat)
+  : Symbol(flat),
+    alias(flat),
+    classifyParam(NULL)
+{}
+
+void Terminal::xfer(Flatten &flat)
+{
+  Symbol::xfer(flat);
+
+  alias.xfer(flat);
+
+  flat.xferInt(precedence);
+  flat.xferInt((int&)associativity);
+
+  flat.xferInt(termIndex);
+
+  flattenStrTable->xfer(flat, classifyParam);
+  classifyCode.xfer(flat);
+}
+
+
+void Terminal::print(ostream &os) const
+{
+  os << "[" << termIndex << "]";
+  if (precedence) {
+    os << "(" << ::toString(associativity) << " " << precedence << ")";
+  }
+  os << " ";
+  Symbol::print(os);
+}
+
+
+void Terminal::internalPrintDDM(ostream &os) const
+{
+  Symbol::internalPrintDDM(os);
+
+  if (classifyCode.isNonNull()) {
+    os << "    classify(" << classifyParam << ") [" << classifyCode << "]\n";
+  }
+}
+
+
+bool Terminal::anyDDM() const
+{
+  return Symbol::anyDDM() ||
+         classifyCode.isNonNull();
+}
+
+
+string Terminal::toString(bool quoteAliases) const
+{
+  if (alias.length() > 0) {
+    if (quoteAliases) {
+      return stringc << "\"" << ::toString(alias) << "\"";
+    }
+    else {
+      return ::toString(alias);
+    }
+  }
+  else {
+    return ::toString(name);
+  }
+}
+
+
+// ----------------- Nonterminal ------------------------
+Nonterminal::Nonterminal(LocString const &name, bool isEmpty)
+  : Symbol(name, false /*terminal*/, isEmpty),
+    mergeParam1(NULL),
+    mergeParam2(NULL),
+    mergeCode(),
+    keepParam(NULL),
+    keepCode(),
+    maximal(false),
+    subsets(),
+    ntIndex(-1),
+    cyclic(false),
+    first(0),
+    follow(0),
+    superset(NULL)
+{}
+
+Nonterminal::~Nonterminal()
+{}
+
+
+Nonterminal::Nonterminal(Flatten &flat)
+  : Symbol(flat),
+    mergeParam1(NULL),
+    mergeParam2(NULL),
+    keepParam(NULL),
+    first(flat),
+    follow(flat),
+    superset(NULL)
+{}
+
+void Nonterminal::xfer(Flatten &flat)
+{
+  Symbol::xfer(flat);
+
+  flattenStrTable->xfer(flat, mergeParam1);
+  flattenStrTable->xfer(flat, mergeParam2);
+  mergeCode.xfer(flat);
+
+  flattenStrTable->xfer(flat, keepParam);
+  keepCode.xfer(flat);
+}
+
+void Nonterminal::xferSerfs(Flatten &flat, Grammar &g)
+{
+  // annotation
+  flat.xferInt(ntIndex);
+  flat.xferBool(cyclic);
+  first.xfer(flat);
+  follow.xfer(flat);
+}
+
+
+void Nonterminal::print(ostream &os, Grammar const *grammar) const
+{
+  os << "[" << ntIndex << "] ";
+  Symbol::print(os);
+
+  // cyclic?
+  if (cyclic) {
+    os << " (cyclic!)";
+  }
+
+  if (grammar) {
+    // first
+    os << " first={";
+    first.print(os, *grammar);
+    os << "}";
+
+    // follow
+    os << " follow={";
+    follow.print(os, *grammar);
+    os << "}";
+  }
+}
+
+
+void Nonterminal::internalPrintDDM(ostream &os) const
+{
+  Symbol::internalPrintDDM(os);
+  
+  if (mergeCode.isNonNull()) {
+    os << "    merge(" << mergeParam1 << ", " << mergeParam2
+       << ") [" << mergeCode << "]\n";
+  }
+
+  if (keepCode.isNonNull()) {
+    os << "    keep(" << keepParam << ") [" << keepCode << "]\n";
+  }
+}
+
+
+bool Nonterminal::anyDDM() const
+{
+  return Symbol::anyDDM() ||
+         mergeCode.isNonNull() ||
+         keepCode.isNonNull();
+}
+
+
+// -------------------- TerminalSet ------------------------
+STATICDEF Terminal const *TerminalSet::suppressExcept = NULL;
+
+TerminalSet::TerminalSet(int numTerms)
+{
+  init(numTerms);
+}
+
+TerminalSet::TerminalSet(TerminalSet const &obj)
+{
+  init(obj.bitmapLen * 8);    // close enough; same # of bytes at least
+  copy(obj);
+}
+
+void TerminalSet::init(int numTerms)
+{
+  if (numTerms != 0) {
+    // allocate enough space for one bit per terminal; I assume
+    // 8 bits per byte
+    bitmapLen = (numTerms + 7) / 8;
+    bitmap = new unsigned char[bitmapLen];
+
+    // initially the set will be empty
+    memset(bitmap, 0, bitmapLen);
+  }
+  else {
+    // intended for situations where reset() will be called later
+    // to allocate some space
+    bitmapLen = 0;
+    bitmap = NULL;
+  }
+}
+
+
+TerminalSet::~TerminalSet()
+{
+  if (bitmap) {
+    delete[] bitmap;
+  }
+}
+
+
+TerminalSet::TerminalSet(Flatten&)
+  : bitmap(NULL)
+{}
+
+void TerminalSet::xfer(Flatten &flat)
+{
+  flat.xferInt(bitmapLen);
+
+  if (bitmapLen > 0) {
+    if (flat.reading()) {
+      bitmap = new unsigned char[bitmapLen];
+    }
+    flat.xferSimple(bitmap, bitmapLen);
+  }
+}
+
+
+void TerminalSet::reset(int numTerms)
+{
+  if (bitmap) {
+    delete[] bitmap;
+  }
+  init(numTerms);
+}
+
+
+unsigned char *TerminalSet::getByte(int id) const
+{
+  int offset = (unsigned)id / 8;
+  xassert(offset < bitmapLen);
+
+  return bitmap + offset;
+}
+
+
+bool TerminalSet::contains(int id) const
+{
+  unsigned char *p = getByte(id);
+  return (*p >> getBit(id)) & 1 == 1;
+}
+
+
+bool TerminalSet::isEqual(TerminalSet const &obj) const
+{
+  xassert(obj.bitmapLen == bitmapLen);
+  return 0==memcmp(bitmap, obj.bitmap, bitmapLen);
+}
+
+
+void TerminalSet::add(int id)
+{
+  unsigned char *p = getByte(id);
+  *p |= (unsigned char)(1 << getBit(id));
+}
+
+
+void TerminalSet::remove(int id)
+{                             
+  unsigned char *p = getByte(id);
+  *p &= (unsigned char)(~(1 << getBit(id)));
+}
+
+
+void TerminalSet::clear()
+{
+  memset(bitmap, 0, bitmapLen);
+}
+
+
+void TerminalSet::copy(TerminalSet const &obj)
+{
+  xassert(obj.bitmapLen == bitmapLen);
+  memcpy(bitmap, obj.bitmap, bitmapLen);
+}
+
+
+bool TerminalSet::merge(TerminalSet const &obj)
+{
+  bool changed = false;
+  for (int i=0; i<bitmapLen; i++) {
+    unsigned before = bitmap[i];
+    unsigned after = before | obj.bitmap[i];
+    if (after != before) {
+      changed = true;
+      bitmap[i] = after;
+    }
+  }
+  return changed;
+}
+
+
+bool TerminalSet::removeSet(TerminalSet const &obj)
+{
+  xassertdb(obj.bitmapLen == bitmapLen);
+  bool changed = false;
+  for (int i=0; i<bitmapLen; i++) {
+    unsigned before = bitmap[i];
+    unsigned after = before & ~(obj.bitmap[i]);
+    if (after != before) {
+      changed = true;
+      bitmap[i] = after;
+    }
+  }
+  return changed;
+}
+
+
+void TerminalSet::print(ostream &os, Grammar const &g, char const *lead) const
+{
+  int ct=0;
+  FOREACH_TERMINAL(g.terminals, iter) {
+    Terminal const *t = iter.data();
+    if (!contains(t->termIndex)) continue;
+
+    if (suppressExcept &&                  // suppressing..
+        suppressExcept != t) continue;     // and this isn't the exception
+
+    if (ct++ == 0) {
+      // by waiting until now to print this, if the set has no symbols
+      // (e.g. we're in SLR(1) mode), then the comma won't be printed
+      // either
+      os << lead;
+    }
+    else {
+      os << "/";
+    }
+
+    os << t->toString();
+  }
+}
+
+
+// -------------------- Production::RHSElt -------------------------
+Production::RHSElt::~RHSElt()
+{}
+
+
+Production::RHSElt::RHSElt(Flatten &flat)
+  : sym(NULL),
+    tag(flat)
+{}
+
+void Production::RHSElt::xfer(Flatten &flat)
+{
+  tag.xfer(flat);
+}
+
+void Production::RHSElt::xferSerfs(Flatten &flat, Grammar &g)
+{
+  xferSerfPtr(flat, sym);
+}
+
+
+
+// -------------------- Production -------------------------
+Production::Production(Nonterminal *L, char const *Ltag)
+  : left(L),
+    right(),
+    precedence(0),
+    forbid(NULL),
+    rhsLen(-1),
+    prodIndex(-1),
+    firstSet(0)       // don't allocate bitmap yet
+{}
+
+Production::~Production()
+{
+  if (forbid) {
+    delete forbid;
+  }
+}
+
+
+Production::Production(Flatten &flat)
+  : left(NULL),
+    forbid(NULL),
+    action(flat),
+    firstSet(flat)
+{}
+
+void Production::xfer(Flatten &flat)
+{
+  xferObjList(flat, right);
+  action.xfer(flat);
+  flat.xferInt(precedence);
+  xferNullableOwnerPtr(flat, forbid);
+
+  flat.xferInt(rhsLen);
+  flat.xferInt(prodIndex);
+  firstSet.xfer(flat);
+}
+
+void Production::xferSerfs(Flatten &flat, Grammar &g)
+{
+  // must break constness in xfer
+
+  xferSerfPtrToList(flat, const_cast<Nonterminal*&>(left),
+                          g.nonterminals);
+
+  // xfer right's 'sym' pointers
+  MUTATE_EACH_OBJLIST(RHSElt, right, iter) {
+    iter.data()->xferSerfs(flat, g);
+  }
+
+  // compute derived data
+  if (flat.reading()) {
+    computeDerived();
+  }
+}
+
+
+#if 0   // optimized away, using 'rhsLen' instead
+int Production::rhsLength() const
+{
+  if (!right.isEmpty()) {
+    // I used to have code here which handled this situation by returning 0;
+    // since it should now never happen, I'll check that here instead
+    xassert(!right.nthC(0)->sym->isEmptyString);
+  }
+
+  return right.count();
+}
+#endif // 0
+
+
+#if 0    // useful for verifying 'finish' is called before rhsLen
+int Production::rhsLength() const
+{
+  xassert(rhsLen != -1);     // otherwise 'finish' wasn't called
+  return rhsLen;
+}
+#endif // 0
+
+
+int Production::numRHSNonterminals() const
+{
+  int ct = 0;
+  FOREACH_OBJLIST(RHSElt, right, iter) {
+    if (iter.data()->sym->isNonterminal()) {
+      ct++;
+    }
+  }
+  return ct;
+}
+
+
+bool Production::rhsHasSymbol(Symbol const *sym) const
+{
+  FOREACH_OBJLIST(RHSElt, right, iter) {
+    if (iter.data()->sym == sym) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+void Production::getRHSSymbols(SymbolList &output) const
+{
+  FOREACH_OBJLIST(RHSElt, right, iter) {
+    output.append(iter.data()->sym);
+  }
+}
+
+
+void Production::append(Symbol *sym, LocString const &tag)
+{
+  // my new design decision (6/26/00 14:24) is to disallow the
+  // emptyString nonterminal from explicitly appearing in the
+  // productions
+  xassert(!sym->isEmptyString);
+
+  right.append(new RHSElt(sym, tag));
+}
+
+
+void Production::finished(int numTerms)
+{
+  computeDerived();
+  firstSet.reset(numTerms);
+}
+
+void Production::computeDerived()
+{
+  rhsLen = right.count();
+}
+
+
+// basically strcmp but without the segfaults when s1 or s2
+// is null; return true if strings are equal
+// update: now that they're StringRef, simple "==" suffices
+bool tagCompare(StringRef s1, StringRef s2)
+{
+  return s1 == s2;
+}
+
+
+int Production::findTag(StringRef tag) const
+{
+  // walk RHS list looking for a match
+  ObjListIter<RHSElt> tagIter(right);
+  int index=1;
+  for(; !tagIter.isDone(); tagIter.adv(), index++) {
+    if (tagCompare(tagIter.data()->tag, tag)) {
+      return index;
+    }
+  }
+
+  // not found
+  return -1;
+}
+
+
+// assemble a possibly tagged name for printing
+string taggedName(rostring name, char const *tag)
+{
+  if (tag == NULL || tag[0] == 0) {
+    return string(name);
+  }
+  else {
+    return stringb(tag << ":" << name);
+  }
+}
+
+
+string Production::symbolTag(int index) const
+{
+  // no longer have tags for LHS
+  xassert(index != 0);
+
+  // find index in RHS list
+  index--;
+  return string(right.nthC(index)->tag);
+}
+
+
+Symbol const *Production::symbolByIndexC(int index) const
+{
+  // check LHS
+  if (index == 0) {
+    return left;
+  }
+
+  // find index in RHS list
+  index--;
+  return right.nthC(index)->sym;
+}
+
+
+#if 0
+DottedProduction const *Production::getDProdC(int dotPlace) const
+{
+  xassert(0 <= dotPlace && dotPlace < numDotPlaces);
+  return &dprods[dotPlace];
+}    
+#endif // 0
+
+
+// it's somewhat unfortunate that I have to be told the
+// total number of terminals, but oh well
+void Production::addForbid(Terminal *t, int numTerminals)
+{
+  if (!forbid) {
+    forbid = new TerminalSet(numTerminals);
+  }
+
+  forbid->add(t->termIndex);
+}
+
+
+void Production::print(ostream &os) const
+{
+  os << toString();
+}
+
+
+string Production::toString(bool printType, bool printIndex) const
+{
+  // LHS "->" RHS
+  stringBuilder sb;
+  if (printIndex) {
+    sb << "[" << prodIndex << "] ";
+  }
+
+  sb << left->name;
+  if (printType && left->type) {
+    sb << "[" << left->type << "]";
+  }
+  sb << " -> " << rhsString();
+  
+  if (printType && precedence) {
+    // take this as licence to print prec too
+    sb << " %prec(" << precedence << ")";
+  }
+  return sb;
+}
+
+
+string Production::rhsString(bool printTags, bool quoteAliases) const
+{
+  stringBuilder sb;
+
+  if (right.isNotEmpty()) {
+    // print the RHS symbols
+    int ct=0;
+    FOREACH_OBJLIST(RHSElt, right, iter) {
+      RHSElt const &elt = *(iter.data());
+
+      if (ct++ > 0) {
+        sb << " ";
+      }
+
+      string symName;
+      if (elt.sym->isNonterminal()) {
+        symName = elt.sym->name;
+      }
+      else {
+        // print terminals as aliases if possible
+        symName = elt.sym->asTerminalC().toString(quoteAliases);
+      }
+
+      if (printTags) {
+        // print tag if present
+        sb << taggedName(symName, elt.tag);
+      }
+      else {
+        sb << symName;
+      }
+    }
+  }
+
+  else {
+    // empty RHS
+    sb << "empty";
+  }
+
+  return sb;
+}
+
+
+string Production::toStringMore(bool printCode) const
+{
+  stringBuilder sb;
+  sb << toString();
+
+  if (printCode && !action.isNull()) {
+    sb << "\t\t[" << action.strref() << "]";
+  }
+
+  sb << "\n";
+
+  return sb;
+}
+
+
+// ------------------ Grammar -----------------
+Grammar::Grammar()
+  : startSymbol(NULL),
+    emptyString(LocString(HERE_SOURCELOC, "empty"),
+                true /*isEmptyString*/),
+    targetLang("C++"),
+    useGCDefaults(false),
+    defaultMergeAborts(false),
+    expectedSR(-1),
+    expectedRR(-1),
+    expectedUNRNonterms(-1),
+    expectedUNRTerms(-1)
+{}
+
+
+Grammar::~Grammar()
+{}
+
+
+void Grammar::xfer(Flatten &flat)
+{
+  // owners
+  flat.checkpoint(0xC7AB4D86);
+  xferObjList(flat, nonterminals);
+  xferObjList(flat, terminals);
+  xferObjList(flat, productions);
+
+  // emptyString is const
+
+  xferObjList(flat, verbatim);
+
+  actionClassName.xfer(flat);
+  xferObjList(flat, actionClasses);
+
+  xferObjList(flat, implVerbatim);
+                               
+  targetLang.xfer(flat);
+  flat.xferBool(useGCDefaults);
+  flat.xferBool(defaultMergeAborts);
+
+  flat.xferInt(expectedSR);
+  flat.xferInt(expectedRR);
+  flat.xferInt(expectedUNRNonterms);
+  flat.xferInt(expectedUNRTerms);
+
+  // serfs
+  flat.checkpoint(0x8580AAD2);
+
+  MUTATE_EACH_OBJLIST(Nonterminal, nonterminals, nt) {
+    nt.data()->xferSerfs(flat, *this);
+  }
+  MUTATE_EACH_OBJLIST(Production, productions, p) {
+    p.data()->xferSerfs(flat, *this);
+  }
+
+  xferSerfPtrToList(flat, startSymbol, nonterminals);
+
+  flat.checkpoint(0x2874DB95);
+}
+
+
+int Grammar::numTerminals() const
+{
+  return terminals.count();
+}
+
+int Grammar::numNonterminals() const
+{                                
+  // everywhere, we regard emptyString as a nonterminal
+  return nonterminals.count() + 1;
+}
+
+
+void Grammar::printSymbolTypes(ostream &os) const
+{
+  os << "Grammar terminals with types or precedence:\n";
+  FOREACH_OBJLIST(Terminal, terminals, term) {
+    Terminal const &t = *(term.data());
+    t.printDDM(os);
+    if (t.precedence) {
+      os << "  " << t.name << " " << ::toString(t.associativity)
+         << " %prec " << t.precedence << endl;
+    }
+  }
+
+  os << "Grammar nonterminals with types:\n";
+  FOREACH_OBJLIST(Nonterminal, nonterminals, nt) {
+    nt.data()->printDDM(os);
+  }
+}
+
+
+void Grammar::printProductions(ostream &os, bool code) const
+{
+  os << "Grammar productions:\n";
+  for (ObjListIter<Production> iter(productions);
+       !iter.isDone(); iter.adv()) {
+    os << "  " << iter.data()->toStringMore(code);
+  }
+}
+
+
+#if 0
+void Grammar::addProduction(Nonterminal *lhs, Symbol *firstRhs, ...)
+{
+  va_list argptr;                   // state for working through args
+  Symbol *arg;
+  va_start(argptr, firstRhs);       // initialize 'argptr'
+
+  Production *prod = new Production(lhs, NULL /*tag*/);
+  prod->append(firstRhs, NULL /*tag*/);
+  for(;;) {
+    arg = va_arg(argptr, Symbol*);  // get next argument
+    if (arg == NULL) {
+      break;    // end of list
+    }
+
+    prod->append(arg, NULL /*tag*/);
+  }
+
+  addProduction(prod);
+}
+#endif // 0
+
+
+void Grammar::addProduction(Production *prod)
+{
+  // I used to add emptyString if there were 0 RHS symbols,
+  // but I've now switched to not explicitly saying that
+
+  prod->prodIndex = productions.count();
+  productions.append(prod);
+  
+  // if the start symbol isn't defined yet, we can here
+  // implement the convention that the LHS of the first
+  // production is the start symbol
+  if (startSymbol == NULL) {
+    startSymbol = prod->left;
+  }
+}
+
+
+// add a token to those we know about
+bool Grammar::declareToken(LocString const &symbolName, int code, 
+                           LocString const &alias)
+{
+  // verify that this token hasn't been declared already
+  if (findSymbolC(symbolName)) {
+    cout << "token " << symbolName << " has already been declared\n";
+    return false;
+  }
+
+  // create a new terminal class
+  Terminal *term = getOrMakeTerminal(symbolName);
+
+  // assign fields specified in %token declaration
+  term->termIndex = code;
+  term->alias = alias;
+
+  return true;
+}
+
+
+// well-formedness check
+void Grammar::checkWellFormed() const
+{
+  // after removing some things, now there's nothing to check...
+}
+
+
+// syntax for identifying tokens in Bison output
+string bisonTokenName(Terminal const *t)
+{
+  // this worked with older versions of Bison
+  //return stringc << "\"" << t->name << "\"";
+
+  // but the newer ones don't like quoted terminal names..
+  return string(t->name.str);
+}
+
+// print the grammar in a form that Bison likes
+void Grammar::printAsBison(ostream &os) const
+{
+  os << "/* automatically generated grammar */\n\n";
+
+  os << "/* -------- tokens -------- */\n";
+  FOREACH_TERMINAL(terminals, term) {
+    // I'll surround all my tokens with quotes and see how Bison likes it
+    // TODO: the latest bison does *not* like it!
+    os << "%token " << bisonTokenName(term.data()) << " "
+       << term.data()->termIndex << "\n";
+  }
+  os << "\n\n";
+
+  os << "/* -------- precedence and associativity ---------*/\n"
+        "/* low precedence */\n";
+  {
+    // first, compute the highest precedence used anywhere in the grammar
+    int highMark=0;
+    FOREACH_TERMINAL(terminals, iter) {
+      highMark = max(iter.data()->precedence, highMark);
+    }
+            
+    // map AssocKind to bison declaration; map stuff bison doesn't
+    // have to %nonassoc
+    static char const * const kindMap[NUM_ASSOC_KINDS] =
+      { "%left", "%right", "%nonassoc", "%nonassoc", "%nonassoc" };
+
+    // now iterate over the precedence levels (level 0 is skipped
+    // because it means 'unspecified')
+    for (int level=1; level <= highMark; level++) {
+      AssocKind kind = NUM_ASSOC_KINDS;   // means we haven't seen any kind yet
+      FOREACH_TERMINAL(terminals, iter) {
+        Terminal const *t = iter.data();
+
+        if (t->precedence == level) {
+          if (kind == NUM_ASSOC_KINDS) {
+            // first token at this level
+            kind = t->associativity;
+            os << kindMap[kind];
+          }
+          else if (kind != t->associativity) {
+            xfailure("different associativities at same precedence?!");
+          }
+
+          // print the token itself
+          os << " " << bisonTokenName(t);
+        }
+      }
+
+      // end of the level
+      os << "\n";
+    }
+  }
+  os << "/* high precedence */\n"
+        "\n\n";
+
+  os << "/* -------- productions ------ */\n"
+        "%%\n\n";
+  // print every nonterminal's rules
+  FOREACH_NONTERMINAL(nonterminals, nt) {
+    // look at every rule where this nonterminal is on LHS
+    bool first = true;
+    FOREACH_PRODUCTION(productions, prod) {
+      if (prod.data()->left == nt.data()) {
+
+        if (first) {
+          os << nt.data()->name << ":";
+        }
+        else {       
+          os << "\n";
+          INTLOOP(i, 0, nt.data()->name.length()) {
+            os << " ";
+          }
+          os << "|";
+        }
+
+        // print RHS symbols
+        FOREACH_OBJLIST(Production::RHSElt, prod.data()->right, symIter) {
+          Symbol const *sym = symIter.data()->sym;
+          if (sym != &emptyString) {
+            if (sym->isTerminal()) {
+              os << " " << bisonTokenName(&( sym->asTerminalC() ));
+            }
+            else {
+              os << " " << sym->name;
+            }
+          }
+        }
+
+        // or, if empty..
+        if (prod.data()->rhsLength() == 0) {
+          os << " /* empty */";
+        }
+
+        // precedence?
+        if (prod.data()->precedence) {
+          // search for a terminal with the required precedence level
+          bool found=false;
+          FOREACH_TERMINAL(terminals, iter) {
+            if (iter.data()->precedence == prod.data()->precedence) {
+              // found suitable token
+              os << " %prec " << bisonTokenName(iter.data());
+              found = true;
+              break;
+            }
+          }
+          if (!found) {
+            cout << "warning: cannot find token for precedence level "
+                 << prod.data()->precedence << endl;
+            os << " /* no token precedence level "/* */
+               << prod.data()->precedence << " */";
+          }
+        }
+
+        // dummy action to help while debugging
+        os << " { $$=" << prod.data()->prodIndex << "; }";
+
+        first = false;
+      }
+    }
+
+    if (first) {
+      // no rules..
+      os << "/* no rules for " << nt.data()->name << " */";
+    }
+    else {
+      // finish the rules with a semicolon
+      os << "\n";
+      INTLOOP(i, 0, nt.data()->name.length()) {
+        os << " ";
+      }
+      os << ";";
+    }
+
+    os << "\n\n";
+  }
+}
+
+
+
+// ------------------- symbol access -------------------
+Nonterminal const *Grammar::findNonterminalC(char const *name) const
+{
+  // check for empty first, since it's not in the list
+  if (emptyString.name.equals(name)) {
+    return &emptyString;
+  }
+
+  FOREACH_NONTERMINAL(nonterminals, iter) {
+    if (iter.data()->name.equals(name)) {
+      return iter.data();
+    }
+  }
+  return NULL;
+}
+
+
+Terminal const *Grammar::findTerminalC(char const *name) const
+{
+  FOREACH_TERMINAL(terminals, iter) {
+    if (iter.data()->name.equals(name) ||
+        iter.data()->alias.equals(name)) {
+      return iter.data();
+    }
+  }
+  return NULL;
+}
+
+
+Symbol const *Grammar::findSymbolC(char const *name) const
+{
+  // try nonterminals
+  Nonterminal const *nt = findNonterminalC(name);
+  if (nt) {
+    return nt;
+  }
+
+  // now try terminals; if it fails, we fail
+  return findTerminalC(name);
+}
+
+
+
+Nonterminal *Grammar::getOrMakeNonterminal(LocString const &name)
+{
+  Nonterminal *nt = findNonterminal(name);
+  if (nt != NULL) {
+    return nt;
+  }
+
+  nt = new Nonterminal(name);
+  nonterminals.append(nt);
+  return nt;
+}
+
+Terminal *Grammar::getOrMakeTerminal(LocString const &name)
+{
+  Terminal *term = findTerminal(name);
+  if (term != NULL) {
+    return term;
+  }
+
+  term = new Terminal(name);
+  terminals.append(term);
+  return term;
+}
+
+Symbol *Grammar::getOrMakeSymbol(LocString const &name)
+{
+  Symbol *sym = findSymbol(name);
+  if (sym != NULL) {
+    return sym;
+  }
+
+  // Since name is not already defined, we don't know whether
+  // it will be a nonterminal or a terminal.  For now, I will
+  // use the lexical convention that nonterminals are
+  // capitalized and terminals are not.
+  if (isupper(name[0])) {
+    return getOrMakeNonterminal(name);
+  }
+  else {
+    return getOrMakeTerminal(name);
+  }
+}
+
+
+int Grammar::getProductionIndex(Production const *prod) const
+{
+  int ret = productions.indexOf(prod);
+  xassert(ret != -1);
+  return ret;
+}
+
+
+string symbolSequenceToString(SymbolList const &list)
+{
+  stringBuilder sb;   // collects output
+
+  bool first = true;
+  SFOREACH_SYMBOL(list, sym) {
+    if (!first) {
+      sb << " ";
+    }
+
+    if (sym.data()->isTerminal()) {
+      sb << sym.data()->asTerminalC().toString();
+    }
+    else {
+      sb << sym.data()->name;
+    }
+    first = false;
+  }
+
+  return sb;
+}
+
+
+string terminalSequenceToString(TerminalList const &list)
+{
+  // this works because access is read-only
+  return symbolSequenceToString(reinterpret_cast<SymbolList const&>(list));
+}
+
+
+// ------------------ emitting C++ code ---------------------
+#if 0     // not done
+void Grammar::emitSelfCC(ostream &os) const
+{
+  os << "void buildGrammar(Grammar *g)\n"
+        "{\n";
+
+  FOREACH_OBJLIST(Terminal, terminals, termIter) {
+    Terminal const *term = termIter.data();
+
+    os << "g->declareToken(" << term->name
+       << ", " << term->termIndex
+       << ", " << quoted(term->alias)
+       << ");\n";
+  }
+
+  FOREACH_OBJLIST(Nonterminal, nonterminals, ntIter) {
+    Nonterminal const *nt = ntIter.data();
+
+    os << ...
+  }
+
+  os << "}\n";
+
+  // todo: more
+}
+#endif // 0

Added: vendor/elsa/current/elkhound/grammar.h
===================================================================
--- vendor/elsa/current/elkhound/grammar.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grammar.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,569 @@
+// grammar.h            see license.txt for copyright and terms of use
+// representation and algorithms for context-free grammars
+
+// Author: Scott McPeak, April 2000
+
+// Unfortunately, representation and algorithm tend to get
+// mixed together.  Separating them entirely is possible,
+// but syntactically inconvenient.  So, instead, I try to
+// document the separation in comments.  Specifically,
+// sections beginning with ---- representation ---- are data
+// for representation of the underlying concept, while
+// sections with ---- annotation ---- are data created by
+// algorithms manipulating the data.
+
+// Another measure is I've split all grammar-wide algorithm
+// stuff into GrammarAnalysis (gramanl.h).  Things should
+// only be put into Grammar if they are directly related
+// to the grammar representation.  (However, constitutent
+// objects like Production will continue to be a mix.)
+
+#ifndef __GRAMMAR_H
+#define __GRAMMAR_H
+
+#include <iostream.h>    // ostream
+
+#include "str.h"         // string
+#include "objlist.h"     // ObjList
+#include "sobjlist.h"    // SObjList
+#include "util.h"        // OSTREAM_OPERATOR, INTLOOP
+#include "locstr.h"      // LocString, StringRef
+#include "strobjdict.h"  // StringObjDict
+#include "owner.h"       // Owner
+#include "asockind.h"    // AssocKind
+
+class StrtokParse;       // strtokp.h
+
+// fwds defined below
+class Symbol;
+class Terminal;
+class Nonterminal;
+class Production;
+class DottedProduction;
+class Grammar;
+
+// transitional definitions
+typedef StringObjDict<LocString> LitCodeDict;
+typedef LocString LiteralCode;
+
+
+// everywhere in the Grammar specification we have a StringRef, it
+// refers to this string table
+extern StringTable grammarStringTable;
+
+
+// ---------------- Symbol --------------------
+// either a nonterminal or terminal symbol
+class Symbol {
+// ------ representation ------
+public:
+  LocString const name;     // symbol's name in grammar
+  bool const isTerm;        // true: terminal (only on right-hand sides of productions)
+                            // false: nonterminal (can appear on left-hand sides)
+  bool const isEmptyString; // true only for the emptyString nonterminal
+
+  StringRef type;           // C type of semantic value
+
+  StringRef dupParam;       // name of parameter to 'dup'
+  LocString dupCode;        // code to duplicate a semantic value
+
+  StringRef delParam;       // param name; may be NULL to indicate not used
+  LocString delCode;        // code
+  
+// ----------- annotation ------------
+public:
+  bool reachable;           // computed by constructLRItemSets; true when nonterminal reachable from start symbol
+
+protected:  // funcs
+  virtual void internalPrintDDM(ostream &os) const;
+
+public:      // funcs
+  Symbol(LocString const &n, bool t, bool e = false);
+  virtual ~Symbol();
+
+  Symbol(Flatten&);
+  void xfer(Flatten &flat);
+
+  // symmetric selectors
+  bool isTerminal() const { return isTerm; }
+  bool isNonterminal() const { return !isTerm; }
+
+  // both terminals and nonterminals have ids; this gets the
+  // id for whichever kind this object happens to be
+  int getTermOrNontermIndex() const;
+
+  // casting
+  Terminal const &asTerminalC() const;       // checks 'isTerminal' for cast safety
+  Terminal &asTerminal()
+    { return const_cast<Terminal&>(asTerminalC()); }
+
+  Nonterminal const &asNonterminalC() const;
+  Nonterminal &asNonterminal()
+    { return const_cast<Nonterminal&>(asNonterminalC()); }
+
+  // cast or NULL
+  Terminal const *ifTerminalC() const;
+  Terminal *ifTerminal()
+    { return const_cast<Terminal*>(ifTerminalC()); }
+
+  Nonterminal const *ifNonterminalC() const;
+  Nonterminal *ifNonterminal() 
+    { return const_cast<Nonterminal*>(ifNonterminalC()); }
+
+  // debugging
+  // print as '$name: isTerminal=$isTerminal' (no newline)
+  virtual void print(ostream &os) const;
+  OSTREAM_OPERATOR(Symbol)
+
+  // print 'token[type] name { dup.. del.. merge.. }' (with newlines)
+  void printDDM(ostream &os) const;
+
+  // true if any of the handlers were specified
+  virtual bool anyDDM() const;
+
+  virtual string toString() const { return string(name); }
+};
+
+// I have several needs for serf lists of symbols, so let's use this for now
+typedef SObjList<Symbol> SymbolList;
+typedef SObjListIter<Symbol> SymbolListIter;
+typedef SObjListMutator<Symbol> SymbolListMutator;
+
+#define FOREACH_SYMBOL(list, iter) FOREACH_OBJLIST(Symbol, list, iter)
+#define MUTATE_EACH_SYMBOL(list, iter) MUTATE_EACH_OBJLIST(Symbol, list, iter)
+#define SFOREACH_SYMBOL(list, iter) SFOREACH_OBJLIST(Symbol, list, iter)
+#define SMUTATE_EACH_SYMBOL(list, iter) SMUTATE_EACH_OBJLIST(Symbol, list, iter)
+
+// format: "s1 s2 s3"
+string symbolSequenceToString(SymbolList const &list);
+
+
+// ---------------- Terminal --------------------
+// something that only appears on the right-hand side of
+// productions, and is an element of the source language
+// NOTE:  This is really a terminal *class*, in that it's possible
+// for several different tokens to be classified into the same
+// terminal class (e.g. "foo" and "bar" are both identifiers)
+class Terminal : public Symbol {
+// -------- representation ---------
+public:     // data
+  // whereas 'name' is the canonical name for the terminal class,
+  // this field is an alias; for example, if the canonical name is
+  // L2_EQUALEQUAL, the alias might be "=="; the alias should *not*
+  // include actual double-quote characters
+  // if the alias is "", there is no alias
+  LocString alias;
+
+  // parsgen-time conflict resolution: if a shift/reduce conflict
+  // occurs between a production and a symbol, both with specified
+  // precedence (not 0), then the one with the numerically higher
+  // precedence will be used
+  int precedence;
+
+  // if, in the above scenario, the precedence values are the same,
+  // then the associativity kind will be used to decide which to use
+  AssocKind associativity;
+
+  StringRef classifyParam;      // name of parameter to 'classify'
+  LocString classifyCode;       // code to reclassify a token type
+
+// ------ annotation ------
+public:     // data
+  // terminal class index - this terminal's id; -1 means unassigned
+  int termIndex;
+
+protected:  // funcs  
+  virtual void internalPrintDDM(ostream &os) const;
+
+public:     // funcs
+  Terminal(LocString const &name)        // canonical name for terminal class
+    : Symbol(name, true /*terminal*/),
+      alias(),
+      precedence(0),
+      associativity(AK_NONASSOC),
+      classifyParam(NULL),
+      termIndex(-1)
+  {}
+
+  Terminal(Flatten &flat);
+  void xfer(Flatten &flat);
+
+  virtual void print(ostream &os) const;
+  OSTREAM_OPERATOR(Terminal)
+
+  virtual bool anyDDM() const;
+
+  // return alias if defined, name otherwise
+  virtual string toString(bool quoteAliases = false) const;
+};
+
+typedef SObjList<Terminal> TerminalList;
+typedef SObjListIter<Terminal> TerminalListIter;
+
+#define FOREACH_TERMINAL(list, iter) FOREACH_OBJLIST(Terminal, list, iter)
+#define MUTATE_EACH_TERMINAL(list, iter) MUTATE_EACH_OBJLIST(Terminal, list, iter)
+#define SFOREACH_TERMINAL(list, iter) SFOREACH_OBJLIST(Terminal, list, iter)
+#define SMUTATE_EACH_TERMINAL(list, iter) SMUTATE_EACH_OBJLIST(Terminal, list, iter)
+
+// casting aggregates
+inline ObjList<Symbol> const &toObjList(ObjList<Terminal> const &list)
+  { return reinterpret_cast< ObjList<Symbol>const& >(list); }
+
+// format: "t1 t2 t3"
+string terminalSequenceToString(TerminalList const &list);
+
+
+// ----------------- TerminalSet -------------------
+// used for the lookahead sets of LR items, and for the First()
+// sets of production RHSs
+class TerminalSet {
+private:    // data
+  unsigned char *bitmap;      // (owner) bitmap of terminals, indexed by
+                              // terminal id; lsb of byte 0 is index 0
+  int bitmapLen;              // # of bytes in 'bitmap'
+
+public:     // data
+  // printing customization: when non-NULL only print tokens if
+  // it includes this token, and then *only* print this one
+  static Terminal const *suppressExcept;
+
+private:    // funcs
+  void init(int numTerms);
+  unsigned char *getByte(int terminalId) const;
+  int getBit(int terminalId) const
+    { return ((unsigned)terminalId % 8); }
+
+public:     // funcs
+  TerminalSet(int numTerms=0);                   // allocate new set, initially empty
+  TerminalSet(TerminalSet const &obj);
+  ~TerminalSet();
+
+  TerminalSet& operator= (TerminalSet const &obj)
+    { copy(obj); return *this; }
+
+  TerminalSet(Flatten&);
+  void xfer(Flatten &flat);
+
+  // call this to re-allocate at a new size; set is emptied
+  void reset(int numTerms);
+                                               
+  // true when the # of symbols is 0; an unfinished state
+  bool nullMap() const { return bitmap==NULL; }
+
+  bool contains(int terminalId) const;
+  
+  // NOTE: can only compare dotted productions which have the
+  // same number of symbols (assertion fail otherwise)
+  bool isEqual(TerminalSet const &obj) const;
+
+  void add(int terminalId);
+  void remove(int terminalId);
+  void clear();
+
+  void copy(TerminalSet const &obj);      // lengths must be the same
+  bool merge(TerminalSet const &obj);     // union; returns true if merging changed set
+  bool removeSet(TerminalSet const &obj); // intersect with complement; returns true if this changed set
+
+  void print(ostream &os, Grammar const &g, char const *lead = ", ") const;
+};
+
+
+// ---------------- Nonterminal --------------------
+// something that can appear on the left-hand side of a production
+// (or, emptyString, since we classify that as a nonterminal also)
+class Nonterminal : public Symbol {
+// ---------- representation --------
+public:
+  StringRef mergeParam1;    // param name for first alternative
+  StringRef mergeParam2;    // and 2nd alt
+  LocString mergeCode;      // code to resolve then
+
+  StringRef keepParam;      // name of parameter to 'keep'
+  LocString keepCode;       // code to decide whether to keep a reduction
+
+  bool maximal;             // if true, use maximal munch disambiguation
+  
+  SObjList<Nonterminal> subsets;      // preferred subsets (for scannerless)
+
+protected:  // funcs
+  virtual void internalPrintDDM(ostream &os) const;
+
+public:     // funcs
+  Nonterminal(LocString const &name, bool isEmptyString=false);
+  virtual ~Nonterminal();
+
+  Nonterminal(Flatten &flat);
+  void xfer(Flatten &flat);
+  void xferSerfs(Flatten &flat, Grammar &g);
+
+  virtual void print(ostream &os, Grammar const *grammer = NULL) const;
+  OSTREAM_OPERATOR(Nonterminal)
+
+  virtual bool anyDDM() const;
+
+// ------ annotation ------
+public:     // data
+  int ntIndex;           // nonterminal index; see Grammar::computeWhatCanDeriveWhat
+  bool cyclic;           // true if this can derive itself in 1 or more steps
+  TerminalSet first;     // set of terminals that can be start of a string derived from 'this'
+  TerminalSet follow;    // set of terminals that can follow a string derived from 'this'
+  Nonterminal *superset; // inverse of 'subsets'
+};
+
+typedef SObjList<Nonterminal> NonterminalList;
+typedef SObjListIter<Nonterminal> NonterminalListIter;
+
+#define FOREACH_NONTERMINAL(list, iter) FOREACH_OBJLIST(Nonterminal, list, iter)
+#define MUTATE_EACH_NONTERMINAL(list, iter) MUTATE_EACH_OBJLIST(Nonterminal, list, iter)
+#define SFOREACH_NONTERMINAL(list, iter) SFOREACH_OBJLIST(Nonterminal, list, iter)
+#define SMUTATE_EACH_NONTERMINAL(list, iter) SMUTATE_EACH_OBJLIST(Nonterminal, list, iter)
+
+// casting aggregates
+inline ObjList<Symbol> const &toObjList(ObjList<Nonterminal> const &list)
+  { return reinterpret_cast< ObjList<Symbol>const& >(list); }
+
+
+// ---------------- Production --------------------
+// a rewrite rule
+class Production {
+// ------ representation ------
+public:     // types
+  class RHSElt {
+  public:
+    Symbol *sym;                // (serf) rhs element symbol
+
+    // tags applied to the symbols for purposes of unambiguous naming in
+    // actions, and for self-commenting value as role indicators; an
+    // empty tag ("") is allowed and means there is no tag
+    LocString tag;             // tag for this symbol; can be ""
+
+  public:
+    RHSElt(Symbol *s, LocString const &t) : sym(s), tag(t) {}
+    ~RHSElt();
+
+    RHSElt(Flatten&);
+    void xfer(Flatten &flat);
+    void xferSerfs(Flatten &flat, Grammar &g);
+  };
+
+public:	    // data
+  // fundamental context-free grammar (CFG) component
+  Nonterminal * const left;     // (serf) left hand side; must be nonterminal
+  ObjList<RHSElt> right;        // right hand side; terminals & nonterminals
+  int precedence;               // precedence level for disambiguation (0 for none specified)
+  TerminalSet *forbid;          // (nullable owner) forbidden next tokens
+
+  // user-supplied reduction action code
+  LocString action;
+
+private:    // funcs
+  void computeDerived();
+
+public:	    // funcs
+  Production(Nonterminal *left, char const *leftTag);
+  ~Production();
+
+  Production(Flatten &flat);
+  void xfer(Flatten &flat);
+  void xferSerfs(Flatten &flat, Grammar &g);
+
+  // length *not* including emptySymbol, if present
+  // UPDATE: I'm now disallowing emptySymbol from ever appearing in 'right'
+  int rhsLength() const { return rhsLen; }
+
+  // number of nonterminals on RHS
+  int numRHSNonterminals() const;
+
+  // true if the given symbol appears in 'right'
+  bool rhsHasSymbol(Symbol const *sym) const;
+
+  // retrieve the RHS as a list of symbols, rather than as a list of RHSElts
+  void getRHSSymbols(SymbolList &output) const;
+
+  // append a RHS symbol
+  void append(Symbol *sym, LocString const &tag);
+
+  // call this when production is built, so it can compute annotations
+  // (this is called by GrammarAnalysis::initializeAuxData, from
+  // inside runAnalyses)
+  void finished(int numTerms);
+
+  // find a symbol by tag; returns 1 for first RHS symbol, 2 for
+  // second, etc.; returns -1 if the tag doesn't match anything
+  int findTag(StringRef tag) const;
+
+  // given an index as returned by 'findTaggedSymbol', translate that
+  // back into a tag
+  string symbolTag(int symbolIndex) const;
+
+  // or translate a symbol index into a symbol
+  Symbol const *symbolByIndexC(int symbolIndex) const;
+  Symbol *symbolByIndex(int symbolIndex)
+    { return const_cast<Symbol*>(symbolByIndexC(symbolIndex)); }
+
+  #if 0
+  // retrieve an item
+  DottedProduction const *getDProdC(int dotPlace) const;
+  DottedProduction *getDProd(int dotPlace)
+    { return const_cast<DottedProduction*>(getDProdC(dotPlace)); }
+  #endif // 0
+
+  // add a terminal to the 'forbid' set
+  void addForbid(Terminal *t, int totalNumTerminals);
+
+  // print 'A -> B c D' (no newline)
+  string toString(bool printType = true, bool printIndex = true) const;
+
+  // this one prints 'B c D' for above example rule
+  string rhsString(bool printTags = true, bool quoteAliases = false) const;
+
+  void print(ostream &os) const;
+  OSTREAM_OPERATOR(Production)
+
+  // print entire input syntax, with newlines, e.g.
+  //   A -> B c D { return foo; }
+  string toStringMore(bool printCode) const;
+
+// ------ annotation ------
+private:    // data
+  int rhsLen;                   // right.count()
+
+public:     // data
+  int prodIndex;                // unique production id
+  TerminalSet firstSet;         // First(RHS); computed by GrammarAnalysis::computeFirst
+};
+
+typedef SObjList<Production> ProductionList;
+typedef SObjListIter<Production> ProductionListIter;
+
+#define FOREACH_PRODUCTION(list, iter) FOREACH_OBJLIST(Production, list, iter)
+#define MUTATE_EACH_PRODUCTION(list, iter) MUTATE_EACH_OBJLIST(Production, list, iter)
+#define SFOREACH_PRODUCTION(list, iter) SFOREACH_OBJLIST(Production, list, iter)
+#define SMUTATE_EACH_PRODUCTION(list, iter) SMUTATE_EACH_OBJLIST(Production, list, iter)
+
+typedef ObjList<Production::RHSElt> RHSEltList;
+typedef ObjListIter<Production::RHSElt> RHSEltListIter;
+typedef ObjListMutator<Production::RHSElt> RHSEltListMutator;
+
+
+// ---------------- Grammar --------------------
+// represent a grammar: nonterminals, terminals, productions, and start-symbol
+class Grammar {
+// ------ representation ------
+public:	    // data
+  ObjList<Nonterminal> nonterminals;    // (owner list)
+  ObjList<Terminal> terminals;          // (owner list)
+  ObjList<Production> productions;      // (owner list)
+  Nonterminal *startSymbol;             // (serf) a particular nonterminal
+
+  // the special terminal for the empty string; does not appear in the
+  // list of nonterminals or terminals for a grammar, but can be
+  // referenced by productions, etc.; the decision to explicitly have
+  // such a symbol, instead of letting it always be implicit, is
+  // motivated by things like the derivability relation, where it's
+  // nice to treat empty like any other symbol
+  Nonterminal emptyString;
+
+  // sections of verbatim code emitted into the interface file, before
+  // the parser context class body
+  ObjList<LocString> verbatim;
+
+  // name of the class into which the action functions are placed
+  LocString actionClassName;
+
+  // verbatim action class declaration, and additional codes from
+  // extension modules to append to it (but see note of 11/13/04
+  // in grampar.cc)
+  ObjList<LocString> actionClasses;
+
+  // code emitted into the implementation file at the end
+  ObjList<LocString> implVerbatim;
+
+  // ---- declarative options ----
+  // name of the target language; nominally "C++"
+  string targetLang;
+
+  // when true, the default dup/del is what's expected for a
+  // garbage-collected system: dup() is the identity function,
+  // and del() is a no-op
+  bool useGCDefaults;
+
+  // when true, unspecified merge() functions abort()
+  bool defaultMergeAborts;
+
+  // expected numbers of various anomalies; -1 means no
+  // expectation has been supplied; this informtion is used
+  // to control what is reported after grammar analysis
+  int expectedSR;                       // shift/reduce conflicts
+  int expectedRR;                       // reduce/reduce conflicts
+  int expectedUNRNonterms;              // # unreachable nonterminals
+  int expectedUNRTerms;                 // # unreachable terminals
+
+public:     // funcs
+  Grammar();                            // set everything manually
+  ~Grammar();
+
+  // read/write as binary file
+  void xfer(Flatten &flat);
+
+  // simple queries
+  int numTerminals() const;
+  int numNonterminals() const;
+
+
+  // ---- building a grammar ----
+  // declare a new token exists, with name and optional alias;
+  // return false if it's already declared
+  bool declareToken(LocString const &symbolName, int code, 
+                    LocString const &alias);
+
+  // add a new production; the rhs arg list must be terminated with a NULL
+  //void addProduction(Nonterminal *lhs, Symbol *rhs, ...);
+
+  // add a pre-constructed production
+  void addProduction(Production *prod);
+
+  // ---------- outputting a grammar --------------
+  // print the list of symbols with type annotations
+  void printSymbolTypes(ostream &os) const;
+
+  // print the current list of productions
+  void printProductions(ostream &os, bool printCode=true) const;
+
+  // emit C++ code to construct this grammar later
+  void emitSelfCC(ostream &os) const;
+
+  // ---- whole-grammar stuff ----
+  // after adding all rules, check that all nonterminals have
+  // at least one rule; also checks referential integrity
+  // in actions and conditions; throw exception if there is a
+  // problem
+  void checkWellFormed() const;
+
+  // output grammar in Bison's syntax
+  // (coincidentally, when bison dumps its table with '-v', its table
+  // dump syntax is similar to my input syntax)
+  void printAsBison(ostream &os) const;
+
+  // ---- symbol access ----
+  #define SYMBOL_ACCESS(Thing)                              \
+    /* retrieve, return NULL if not there */                \
+    Thing const *find##Thing##C(char const *name) const;    \
+    Thing *find##Thing(char const *name)                    \
+      { return const_cast<Thing*>(find##Thing##C(name)); }  \
+                                                            \
+    /* retrieve, or create it if not already there */       \
+    Thing *getOrMake##Thing(LocString const &name);
+
+  SYMBOL_ACCESS(Symbol)        // findSymbolC, findSymbol, getOrMakeSymbol
+  SYMBOL_ACCESS(Terminal)      // findTerminal{C,}, getOrMakeTerminal
+  SYMBOL_ACCESS(Nonterminal)   // findNonterminal{C,}, getOrMakeNonterminal
+  #undef SYMBOL_ACCESS
+
+  // map a production to a unique index
+  int getProductionIndex(Production const *prod) const;
+};
+
+
+#endif // __GRAMMAR_H
+

Added: vendor/elsa/current/elkhound/grammar.txt
===================================================================
--- vendor/elsa/current/elkhound/grammar.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grammar.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+This file has been superceded by manual.html.

Added: vendor/elsa/current/elkhound/grampar.cc
===================================================================
--- vendor/elsa/current/elkhound/grampar.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grampar.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1378 @@
+// grampar.cc            see license.txt for copyright and terms of use
+// additional C++ code for the grammar parser; in essence,
+// build the grammar internal representation out of what
+// the user supplies in a .gr file
+
+#include "grampar.h"         // this module
+#include "gramlex.h"         // GrammarLexer
+#include "trace.h"           // tracing debug functions
+#include "gramast.ast.gen.h" // grammar AST nodes
+#include "grammar.h"         // Grammar, Production, etc.
+#include "owner.h"           // Owner (redundant dependency; dot's layout is better with it though)
+#include "syserr.h"          // xsyserror
+#include "strutil.h"         // quoted
+#include "grampar.tab.h"     // token constant codes, union YYSTYPE
+#include "array.h"           // GrowArray
+#include "mlsstr.h"          // MLSubstrate
+
+#include <fstream.h>         // ifstream
+#include <ctype.h>           // isspace, isalnum
+
+#define LIT_STR(s) LocString(SL_INIT, grammarStringTable.add(s))
+
+
+// ------------------------- Environment ------------------------
+Environment::Environment(Grammar &G)
+  : g(G),
+    prevEnv(NULL),
+    nontermDecls(),
+    errorCount(0),
+    errors(errorCount)
+{}
+
+Environment::Environment(Environment &prev)
+  : g(prev.g),
+    prevEnv(&prev),
+    nontermDecls(prev.nontermDecls),
+    errorCount(-1000),      // should never be used
+    errors(prev.errors)     // copy parent's 'errors' reference
+{}
+
+Environment::~Environment()
+{}
+
+
+// -------------------- XASTParse --------------------
+STATICDEF string XASTParse::
+  constructMsg(LocString const &tok, rostring msg)
+{
+  if (tok.validLoc()) {
+    if (tok.isNonNull()) {
+      return stringc << tok.locString() << ": near " << tok
+                     << ", " << msg;
+    }
+    else {
+      return stringc << tok.locString() << ": " << msg;
+    }
+  }
+  else {
+    return string(msg);
+  }
+}
+
+XASTParse::XASTParse(LocString const &tok, rostring m)
+  : xBase(constructMsg(tok, m)),
+    failToken(tok),
+    message(m)
+{}
+
+
+XASTParse::XASTParse(XASTParse const &obj)
+  : xBase(obj),
+    DMEMB(failToken),
+    DMEMB(message)
+{}
+
+XASTParse::~XASTParse()
+{}
+
+
+// -------------------- AST parser support ---------------------
+// fwd-decl of parsing fns
+void astParseGrammar(Grammar &g, GrammarAST *treeTop);
+void astParseTerminals(Environment &env, TF_terminals const &terms);
+void astParseDDM(Environment &env, Symbol *sym,
+                 ASTList<SpecFunc> const &funcs);
+void astParseNonterm(Environment &env, TF_nonterm const *nt);
+void astParseProduction(Environment &env, Nonterminal *nonterm,
+                        ProdDecl const *prod);
+
+
+// really a static semantic error, more than a parse error..
+void astParseError(LocString const &failToken, rostring msg)
+{
+  THROW(XASTParse(failToken, msg));
+}
+
+void astParseError(SourceLoc loc, rostring msg)
+{
+  LocString locstr(loc, NULL);
+  THROW(XASTParse(locstr, msg));
+}
+
+void astParseError(rostring msg)
+{
+  LocString ls;   // no location info
+  THROW(XASTParse(ls, msg));
+}
+
+// print the same message, but keep going anyway
+void astParseErrorCont(Environment &env, LocString const &failToken,
+                       rostring msg)
+{
+  XASTParse x(failToken, msg);
+  cout << x.why() << endl;
+  env.errors++;
+}
+
+
+// to put as the catch block; so far it's kind of ad-hoc where
+// I actually put 'try' blocks..
+#define CATCH_APPLY_CONTEXT(tok)        \
+  catch (XASTParse &x) {                \
+    /* leave unchanged */               \
+    throw x;                            \
+  }                                     \
+  catch (xBase &x) {                    \
+    /* add context */                   \
+    astParseError(tok, x.why());        \
+    throw 0;     /* silence warning */  \
+  }
+
+
+// ---------------------- AST "parser" --------------------------
+// set the annotation pointers
+void setAnnotations(GrammarAST *ast)
+{
+  // work through the toplevel forms
+  FOREACH_ASTLIST_NC(TopForm, ast->forms, iter) {
+    ASTSWITCH(TopForm, iter.data()) {
+      ASTCASE(TF_terminals, t) {
+        if (!ast->terms) {
+          ast->terms = t;
+        }
+        else {
+          // 12/07/04: Allow more than one 'terminals' section,
+          // by simply concatenating them.  This is useful when
+          // I want to merge two grammars together textually.
+          ast->terms->decls.concat(t->decls);
+          ast->terms->types.concat(t->types);
+          ast->terms->prec.concat(t->prec);
+        }
+      }
+
+      ASTNEXT(TF_nonterm, nt) {
+        if (!ast->firstNT) {
+          ast->firstNT = nt;
+        }
+      }
+
+      ASTENDCASED
+    }
+  }
+
+  if (!ast->terms) {
+    astParseError("'Terminals' specification is missing");
+  }
+  if (!ast->firstNT) {
+    astParseError("you have to have at least one nonterminal");
+  }
+}
+
+
+LocString extractActionClassName(LocString const &body)
+{
+  // find start of first token
+  char const *start = body.str;
+  while (isspace(*start)) start++;
+
+  // find end of first token
+  char const *p = start;
+  while (isspace(*p)) p++;
+  while (isalnum(*p) || *p=='_') p++;
+  
+  // yield that, with the same source location
+  return LocString(body.loc, grammarStringTable.add(
+    substring(start, p-start).c_str()));
+}
+
+
+// handle TF_verbatim and TF_option
+void astParseOptions(Grammar &g, GrammarAST *ast)
+{
+  // handle TF_verbatim and TF_option
+  FOREACH_ASTLIST_NC(TopForm, ast->forms, iter) {
+    ASTSWITCH(TopForm, iter.data()) {
+      ASTCASE(TF_context, c) {
+        // overwrite the context class name, and append to
+        // its body verbatim list
+        g.actionClassName = extractActionClassName(c->body);
+
+        // 11/13/04: There is a subtle problem with keeping the body
+        // from the base specification, when the following conditions
+        // hold:
+        //   - the base spec is compiled on its own (w/o the extension)
+        //   - some translation unit "A" sees the resulting .gr.gen.h file
+        //   - the extension spec is compiled
+        //   - some translation unit "B" sees the resulting .gr.gen.h file
+        //   - A and B are linked together in one executable
+        // In that case, the context_class from the base will have an
+        // inconsistent definition in A and B, since in A it will be
+        // whatever the user wrote plus, the declarations for the
+        // action functions, whereas in B it will be just what the
+        // user wrote, since the action functions end up in the
+        // extension context_class.
+        //
+        // What is even more subtle is the *manifestation* of this
+        // problem, which is linking problems with vtables.  C++
+        // compilers do not explicitly check that classes declared in
+        // multiple translation units have identical declarations
+        // (token for token), but they *do* of course rely on them
+        // being so.  That reliance shows up in the decisions
+        // regarding which module has the vtable, among other places.
+        // So this problem did not show up immediately, and was only
+        // revealed as initially mysterious portability problems
+        // (since my development toolchain happend to be fairly
+        // lenient w.r.t. vtable placement).
+        //
+        // Therefore the new policy is that context_classes from the
+        // base are *not* emitted, and consequently it is impossible
+        // to inherit from them in subsequent context_classes.  The
+        // user must put data/functions that are meant to be shared
+        // into a common base class that is *not* the context_class
+        // of any grammar or extension.
+        //
+        // old:
+        //g.actionClasses.append(new LocString(c->body));
+        //
+        // new:
+        g.actionClasses.deleteAll();
+        g.actionClasses.append(new LocString(c->body));
+      }
+
+      ASTNEXT(TF_verbatim, v) {
+        if (v->isImpl) {
+          g.implVerbatim.append(new LocString(v->code));
+        }
+        else {
+          g.verbatim.append(new LocString(v->code));
+        }
+      }
+
+      ASTNEXT(TF_option, op) {
+        LocString const &name = op->name;
+        int value = op->value;
+        bool boolVal = !!value;
+
+        if (name.equals("useGCDefaults")) {
+          g.useGCDefaults = boolVal;
+        }
+        else if (name.equals("defaultMergeAborts")) {
+          g.defaultMergeAborts = boolVal;
+        }
+        else if (name.equals("shift_reduce_conflicts")) {
+          g.expectedSR = value;
+        }
+        else if (name.equals("reduce_reduce_conflicts")) {
+          g.expectedRR = value;
+        }
+        else if (name.equals("unreachable_nonterminals")) {
+          g.expectedUNRNonterms = value;
+        }
+        else if (name.equals("unreachable_terminals")) {
+          g.expectedUNRTerms = value;
+        }
+        else if (name.equals("lang_OCaml")) {
+          //g.targetLang = "OCaml";
+          //
+          // I'm retarded.. I need to know if we're parsing ocaml *before*
+          // we actually parse it, otherwise I can't skip the embedded
+          // action fragments properly!
+          astParseError(name, "The `lang_OCaml' option has been replaced with "
+                              "the `-ocaml' command-line switch.  Please use "
+                              "that instead.  (Sorry for the inconvenience.)");
+        }
+        else if (name.equals("allow_continued_nonterminals")) {
+          ast->allowContinuedNonterminals = boolVal;
+        }
+        else {
+          astParseError(name, "unknown option name");
+        }
+      }
+
+      ASTENDCASED
+    }
+  }
+}
+
+
+// map the grammar definition AST into a Grammar data structure
+void astParseGrammar(Grammar &g, GrammarAST *ast)
+{
+  // default, empty environment
+  Environment env(g);
+
+  // handle TF_terminals
+  astParseTerminals(env, *(ast->terms));
+
+  // process all nonterminal declarations first, so while we're
+  // looking at their bodies we can tell if one isn't declared
+  {
+    FOREACH_ASTLIST_NC(TopForm, ast->forms, iter) {
+      if (!iter.data()->isTF_nonterm()) continue;
+      TF_nonterm *nt = iter.data()->asTF_nonterm();
+
+      // check for already declared
+      if (env.nontermDecls.isMapped(nt->name)) {
+        if (!ast->allowContinuedNonterminals) {
+          astParseError(nt->name, "nonterminal already declared "
+            "(if this is intentional, look up \"allow_continued_nonterminals\" "
+            "in manual.html)");
+        }
+        else {
+          // check for consistent type
+          if (!nt->type.equals(env.nontermDecls.queryf(nt->name)->type)) {
+            astParseError(nt->name, "continued nonterminal with different type");
+          }
+          
+          // just allow it; it seems the parser just iterates over
+          // all the TF_nonterms, and will do the right thing
+          continue;
+        }
+      }
+
+      // make the Grammar object to represent the new nonterminal
+      env.g.getOrMakeNonterminal(nt->name);
+
+      // add this decl to our running list (in the original environment)
+      //
+      // 12/09/04: As far as I can tell, 'nontermDecls' is in fact not
+      // used except for right here, to check whether a nonterminal
+      // declaration is duplicated.
+      env.nontermDecls.add(nt->name, nt);
+    }
+  }
+
+  // process nonterminal bodies
+  {
+    FOREACH_ASTLIST(TopForm, ast->forms, iter) {
+      if (!iter.data()->isTF_nonterm()) continue;
+      TF_nonterm const *nt = iter.data()->asTF_nontermC();
+
+      // new environment since it can contain a grouping construct
+      // (at this very moment it actually can't because there is no syntax..)
+      Environment newEnv(env);
+
+      // parse it
+      astParseNonterm(newEnv, nt);
+    }
+  }
+
+  if (!g.actionClassName.str) {
+    astParseError("you must specify a context class; for example:\n"
+                  "  context_class Context : public UserActions {};\n");
+  }
+
+  if (env.errors) {
+    astParseError("halting due to previously reported errors");
+  }
+}
+
+
+// validate 'name'
+Terminal *astParseToken(Environment &env, LocString const &name)
+{
+  Terminal *t = env.g.findTerminal(name);
+  if (!t) {
+    astParseError(name, "undeclared token");
+  }
+  return t;
+}
+
+
+// needed to ensure the GrowArray below has its values initialized
+// to false when the array expands
+class InitFalseBool {
+public:
+  bool b;
+public:
+  InitFalseBool() : b(false) {}
+};
+
+
+void astParseTerminals(Environment &env, TF_terminals const &terms)
+{
+  // basic declarations
+  {
+    int maxCode = 0;
+    GrowArray<InitFalseBool> codeHasTerm(200);
+    FOREACH_ASTLIST(TermDecl, terms.decls, iter) {
+      TermDecl const &term = *(iter.data());
+
+      // process the terminal declaration
+      int code = term.code;
+      StringRef name = term.name;
+      trace("grampar") << "token: code=" << code
+                       << ", name=" << name << endl;
+
+      if (!env.g.declareToken(term.name, code, term.alias)) {
+        astParseError(term.name, "token already declared");
+      }
+
+      // track what terminals have codes
+      maxCode = max(code, maxCode);
+      codeHasTerm.ensureIndexDoubler(code);
+      codeHasTerm[code].b = true;
+    }
+
+    // fill in any gaps in the code space; this is required because
+    // later analyses assume the terminal code space is dense
+    SourceLoc dummyLoc(HERE_SOURCELOC);
+    for (int i=0; i<maxCode; i++) {
+      if (!codeHasTerm[i].b) {
+        LocString dummy(dummyLoc, grammarStringTable.add(
+          stringc << "__dummy_filler_token" << i));
+        env.g.declareToken(dummy, i, dummy);
+      }
+    }
+  }
+
+  // type annotations
+  {                  
+    FOREACH_ASTLIST(TermType, terms.types, iter) {
+      TermType const &type = *(iter.data());
+      trace("grampar") << "token type: name=" << type.name
+                       << ", type=" << type.type << endl;
+
+      // look up the name
+      Terminal *t = astParseToken(env, type.name);
+      if (t->type) {
+        astParseError(type.name, "this token already has a type");
+      }
+
+      // annotate with declared type
+      t->type = type.type;
+
+      // parse the dup/del/merge spec
+      astParseDDM(env, t, type.funcs);
+    }
+  }
+
+  // precedence specifications
+  {
+    FOREACH_ASTLIST(PrecSpec, terms.prec, iter) {
+      PrecSpec const &spec = *(iter.data());
+
+      FOREACH_ASTLIST(LocString, spec.tokens, tokIter) {
+        LocString const &tokName = *(tokIter.data());
+        trace("grampar") << "prec: " << toString(spec.kind)
+                         << " " << spec.prec << " " << tokName;
+
+        // look up the token
+        Terminal *t = astParseToken(env, tokName);
+        if (t->precedence) {
+          astParseError(tokName,
+            stringc << tokName << " already has a specified precedence");
+        }
+
+        if (spec.prec == 0) {
+          // 0 means precedence isn't specified
+          astParseError(tokName,
+            "you can't use 0 as a precedence level, because that value "
+            "is used internally to mean something else");
+        }
+
+        // apply spec
+        t->precedence = spec.prec;
+        t->associativity = spec.kind;
+      }
+    }
+  }
+}
+
+
+void astParseDDM(Environment &env, Symbol *sym,
+                 ASTList<SpecFunc> const &funcs)
+{
+  Terminal *term = sym->ifTerminal();
+  Nonterminal *nonterm = sym->ifNonterminal();
+
+  FOREACH_ASTLIST(SpecFunc, funcs, iter) {
+    SpecFunc const &func = *(iter.data());
+    int numFormals = func.formals.count();
+
+    // decide what to do based on the name
+
+    if (func.name.equals("dup")) {
+      if (numFormals != 1) {
+        astParseError(func.name, "'dup' function must have one formal parameter");
+      }
+      if (sym->dupParam) {
+        astParseError(func.name, "duplicate 'dup' function");
+      }
+      sym->dupParam = func.nthFormal(0);
+      sym->dupCode = func.code;
+    }
+
+    else if (func.name.equals("del")) {
+      if (numFormals == 0) {
+        // not specified is ok, since it means the 'del' function
+        // doesn't use its parameter
+        sym->delParam = NULL;
+      }
+      else if (numFormals == 1) {
+        sym->delParam = func.nthFormal(0);
+      }
+      else {
+        astParseError(func.name, "'del' function must have either zero or one formal parameters");
+      }
+
+      if (sym->delCode) {
+        astParseError(func.name, "duplicate 'del' function");
+      }
+      sym->delCode = func.code;
+    }
+
+    else if (func.name.equals("merge")) {
+      if (nonterm) {
+        if (numFormals != 2) {
+          astParseError(func.name, "'merge' function must have two formal parameters");
+        }
+        if (nonterm->mergeParam1) {
+          astParseError(func.name, "duplicate 'merge' function");
+        }
+        nonterm->mergeParam1 = func.nthFormal(0);
+        nonterm->mergeParam2 = func.nthFormal(1);
+        nonterm->mergeCode = func.code;
+      }
+      else {
+        astParseError(func.name, "'merge' can only be applied to nonterminals");
+      }
+    }
+
+    else if (func.name.equals("keep")) {
+      if (nonterm) {
+        if (numFormals != 1) {
+          astParseError(func.name, "'keep' function must have one formal parameter");
+        }
+        if (nonterm->keepParam) {
+          astParseError(func.name, "duplicate 'keep' function");
+        }
+        nonterm->keepParam = func.nthFormal(0);
+        nonterm->keepCode = func.code;
+      }
+      else {
+        astParseError(func.name, "'keep' can only be applied to nonterminals");
+      }
+    }
+
+    else if (func.name.equals("classify")) {
+      if (term) {
+        if (numFormals != 1) {
+          astParseError(func.name, "'classify' function must have one formal parameter");
+        }
+        if (term->classifyParam) {
+          astParseError(func.name, "duplicate 'classify' function");
+        }
+        term->classifyParam = func.nthFormal(0);
+        term->classifyCode = func.code;
+      }
+      else {
+        astParseError(func.name, "'classify' can only be applied to terminals");
+      }
+    }
+
+    else if (func.name.equals("maximal")) {
+      if (nonterm) {
+        if (nonterm->maximal) {
+          astParseError(func.name, "duplicate 'maximal' declaration");
+        }
+        nonterm->maximal = true;     // function body has no meaning
+      }
+      else {
+        astParseError(func.name, "'maximal' can only be applied to nonterminals");
+      }
+    }
+
+    else {
+      astParseError(func.name,
+        stringc << "unrecognized spec function \"" << func.name << "\"");
+    }
+  }
+}
+
+
+void addDefaultTypesActions(Grammar &g, GrammarAST *ast)
+{
+  // language defaults
+  StringRef defaultType, defaultAction;
+  if (g.targetLang.equals("OCaml")) {
+    defaultType = grammarStringTable.add("unit");
+    defaultAction = grammarStringTable.add("()");
+  }
+  else /*C*/ {
+    defaultType = grammarStringTable.add("void");
+    defaultAction = grammarStringTable.add("return;");
+  }
+
+  // hook to allow me to force defaults everywhere (this is useful
+  // when I want to try a grammar written for one language using
+  // another language's core)
+  bool forceDefaults = tracingSys("forceDefaultActions");
+
+  // iterate over nonterminals
+  FOREACH_ASTLIST_NC(TopForm, ast->forms, iter) {
+    if (!iter.data()->isTF_nonterm()) { continue; }
+    TF_nonterm *nt = iter.data()->asTF_nonterm();
+
+    // default type
+    if (forceDefaults || nt->type.isNull()) {
+      nt->type.str = defaultType;
+    }
+
+    // iterate over productions
+    FOREACH_ASTLIST_NC(ProdDecl, nt->productions, iter2) {
+      ProdDecl *pd = iter2.data();
+
+      // default action
+      if (forceDefaults || pd->actionCode.isNull()) {
+        pd->actionCode.str = defaultAction;
+      }
+                          
+      if (forceDefaults) {
+        // clear RHSElt tags, since otherwise the lack of types
+        // will provoke errors; and default actions don't refer to
+        // the RHSElts anyway
+        StringRef empty = grammarStringTable.add("");
+        FOREACH_ASTLIST_NC(RHSElt, pd->rhs, iter3) {
+          ASTSWITCH(RHSElt, iter3.data()) {
+            ASTCASE(RH_name, n)
+              n->tag.str = empty;
+
+            ASTNEXT(RH_string, s)
+              s->tag.str = empty;
+            
+            ASTENDCASED
+          }
+        }
+      }
+    }
+  }
+}
+
+
+void synthesizeStartRule(Grammar &g, GrammarAST *ast)
+{
+  // get the first nonterminal; this is the user's start symbol
+  TF_nonterm *firstNT = ast->firstNT;
+
+  // find the name of the user's EOF token
+  TermDecl const *eof = NULL;
+  FOREACH_ASTLIST(TermDecl, ast->terms->decls, iter) {
+    if (iter.data()->code == 0) {
+      eof = iter.data();
+      break;
+    }
+  }
+  if (!eof) {
+    astParseError("you have to have an EOF token, with code 0");
+  }
+
+  // build a start production
+  RHSElt *rhs1 = new RH_name(LIT_STR("top").clone(), firstNT->name.clone());
+  RHSElt *rhs2 = new RH_name(LIT_STR("").clone(), eof->name.clone());
+  ASTList<RHSElt> *rhs = new ASTList<RHSElt>();
+  rhs->append(rhs1);
+  rhs->append(rhs2);
+  char const *action = g.targetLang.equals("OCaml")? " top " :
+                       firstNT->type.equals("void")? " return; " :
+                                                     " return top; ";
+  ProdDecl *startProd = new ProdDecl(SL_INIT, PDK_NEW, rhs, LIT_STR(action).clone());
+
+  // build an even earlier start symbol
+  TF_nonterm *earlyStartNT
+    = new TF_nonterm(
+        LIT_STR("__EarlyStartSymbol").clone(),   // name
+        firstNT->type.clone(),                   // type
+        NULL,                                    // empty list of functions
+        new ASTList<ProdDecl>(startProd),        // productions
+        NULL                                     // subsets
+      );
+
+  // put it into the AST
+  ast->forms.prepend(earlyStartNT);
+}
+
+
+void astParseNonterm(Environment &env, TF_nonterm const *nt)
+{
+  LocString const &name = nt->name;
+
+  // get the Grammar object that represents the nonterminal
+  Nonterminal *nonterm = env.g.findNonterminal(name);
+  xassert(nonterm);
+
+  nonterm->type = nt->type;
+
+  // iterate over the productions
+  FOREACH_ASTLIST(ProdDecl, nt->productions, iter) {
+    astParseProduction(env, nonterm, iter.data());
+  }
+
+  // parse dup/del/merge
+  astParseDDM(env, nonterm, nt->funcs);
+  
+  // record subsets                       
+  {
+    FOREACH_ASTLIST(LocString, nt->subsets, iter) {
+      LocString const *ls = iter.data();
+      Nonterminal *sub = env.g.findNonterminal(*ls);
+      if (!sub) {
+        astParseError(*ls, "nonexistent nonterminal");
+      }
+
+      // note that, since context-free language inclusion is
+      // undecidable (Hopcroft/Ullman), we can't actually check that
+      // the given nonterminals really are in the subset relation
+      nonterm->subsets.prepend(sub);
+    }
+  }
+}
+
+
+void astParseProduction(Environment &env, Nonterminal *nonterm,
+                        ProdDecl const *prodDecl)
+{
+  // is this the special start symbol I inserted?
+  bool synthesizedStart = nonterm->name.equals("__EarlyStartSymbol");
+
+  // build a production; use 'this' as the tag for LHS elements
+  Production *prod = new Production(nonterm, "this");
+
+  // put the code into it
+  prod->action = prodDecl->actionCode;
+
+  // deal with RHS elements
+  FOREACH_ASTLIST(RHSElt, prodDecl->rhs, iter) {
+    RHSElt const *n = iter.data();
+    LocString symName;
+    LocString symTag;
+    bool isString = false;
+    bool isAnnotation = false;
+
+    // pull various info out of the AST node
+    ASTSWITCHC(RHSElt, n) {
+      ASTCASEC(RH_name, tname) {
+        symName = tname->name;
+        symTag = tname->tag;
+      }
+
+      ASTNEXTC(RH_string, ts) {
+        symName = ts->str;
+        symTag = ts->tag;
+        isString = true;
+      }
+
+      ASTNEXTC(RH_prec, p) {
+        Terminal *t = astParseToken(env, p->tokName);
+        if (!t) { break; }
+
+        // apply the specified precedence
+        prod->precedence = t->precedence;
+        isAnnotation = true;
+      }
+
+      ASTNEXTC(RH_forbid, f) {
+        Terminal *t = astParseToken(env, f->tokName);
+        if (!t) { break; }
+
+        prod->addForbid(t, env.g.numTerminals());
+        isAnnotation = true;
+      }
+
+      ASTDEFAULTC {
+        xfailure("bad RHSElt kind");
+      }
+
+      ASTENDCASEC
+    }
+
+    if (isAnnotation) {
+      // code below is for things other than annotations
+      continue;
+    }
+
+    // see which (if either) thing this name already is
+    Terminal *term = env.g.findTerminal(symName);
+    Nonterminal *nonterm = env.g.findNonterminal(symName);
+    if (term && nonterm) {
+      if (isString) {
+        astParseError(symName, "token alias has same name as a nonterminal");
+      }
+      else {
+        astParseError(symName, "token and nonterminal have same name");
+      }
+      nonterm = NULL;                // error recovery
+    }
+
+    // syntax rules
+    if (isString  &&  !term) {
+      astParseError(symName, "terminals must be declared");
+    }
+
+    if (!term && !nonterm) {
+      astParseErrorCont(env, symName, "undeclared symbol");
+
+      // synthesize one anyway so we can find more errors
+      nonterm = env.g.getOrMakeNonterminal(symName);
+    }
+
+    if (term && term->termIndex==0 && !synthesizedStart) {
+      astParseError(symName, "you cannot use the EOF token in your rules");
+    }
+
+    if (symTag.equals("loc")) {
+      // bad because loc is the name of the automatically-propagated
+      // source location information
+      astParseErrorCont(env, symTag, "cannot use \"loc\" as a tag");
+    }
+
+    // whenever we see a terminal, copy its precedence spec to
+    // the production; thus, the last symbol appearing in the
+    // production will be the one that gives the precedence
+    if (term) {
+      prod->precedence = term->precedence;
+    }
+
+    // decide which symbol to put in the production
+    Symbol *s;
+    if (nonterm) {
+      s = nonterm;            // could do these two with a bitwise OR
+    }                         // if I were feeling extra clever today
+    else {
+      s = term;
+    }
+
+    if (s->isEmptyString) {
+      // "empty" is a syntactic convenience; it doesn't get
+      // added to the production
+    }
+    else {
+      // add it to the production
+      prod->append(s, symTag);
+    }
+  }
+
+  // after constructing the production we need to do this
+  // update: no we don't -- GrammarAnalysis takes care of it (and
+  // complains if we do)
+  //prod->finished();
+
+  // add production to grammar
+  env.g.addProduction(prod);
+}
+
+
+// ----------------------- parser support ---------------------
+// Bison parser calls this to get a token
+int grampar_yylex(YYSTYPE *lvalp, void *parseParam)
+{
+  ParseParams *par = (ParseParams*)parseParam;
+  GrammarLexer &lexer = par->lexer;
+
+  int code = lexer.yylexInc();
+
+  try {
+    // yield semantic values for some things
+    // note that the yielded semantic value must be consistent with
+    // what is declared for these token types in grampar.y
+    switch (code) {
+      case TOK_INTEGER:
+        lvalp->num = lexer.integerLiteral;
+        break;
+
+      case TOK_STRING:
+        lvalp->str = new LocString(lexer.curLoc(), lexer.stringLiteral);
+        break;
+
+      case TOK_NAME:
+        lvalp->str = new LocString(lexer.curLoc(), lexer.curToken());
+        break;
+
+      case TOK_LIT_CODE:
+        lvalp->str = new LocString(lexer.curLoc(), lexer.curFuncBody());
+        break;
+
+      case TOK_ARROW:
+        lvalp->loc = lexer.curLoc();
+        break;
+
+      default:
+        lvalp->str = NULL;        // any attempt to use will segfault
+    }
+  }
+  catch (xBase &x) {
+    // e.g. malformed fundecl
+    cout << lexer.curLocStr() << ": " << x << endl;
+
+    // optimistically try just skipping the bad token
+    return grampar_yylex(lvalp, parseParam);
+  }
+
+  return code;
+}
+
+
+void grampar_yyerror(char const *message, void *parseParam)
+{
+  ParseParams *par = (ParseParams*)parseParam;
+  cout << par->lexer.curLocStr() << ": " << message << endl;
+}
+
+
+// ---------------------- merging -----------------------
+void mergeContext(GrammarAST *base, TF_context * /*owner*/ ext)
+{
+  // do simple append, since the grammar parser above knows how
+  // to handle multiple context classes
+  base->forms.append(ext);
+
+  #if 0
+  // find 'base' context
+  TF_context *baseContext = NULL;
+  FOREACH_ASTLIST_NC(TopForm, base->forms, iter) {
+    if (iter.data()->isTF_context()) {
+      baseContext = iter.data()->asTF_context();
+      break;
+    }
+  }
+
+  if (!baseContext) {
+    // base does not have a context class, so 'ext' becomes it
+    base->forms.append(ext);
+  }
+
+  else if (baseContext->name.str == ext->name.str) {
+    // same name; I'd like to append the code to what's already
+    // there, but that's tricky because the location won't
+    // be right..
+    astParseError(ext->name, "context append not implemented");
+  }
+
+  else {
+    // different name, replace the old
+    base->forms.removeItem(baseContext);
+    delete baseContext;
+    base->forms.append(ext);
+  }
+  #endif // 0
+}
+
+
+void mergeOption(GrammarAST *base, TF_option * /*owner*/ ext)
+{                    
+  // find option with the same name
+  FOREACH_ASTLIST_NC(TopForm, base->forms, iter) {
+    if (!iter.data()->isTF_option()) continue;
+    TF_option *op = iter.data()->asTF_option();
+    
+    if (op->name.str == ext->name.str) {
+      // replace the old value
+      op->value = ext->value;
+      delete ext;
+      return;
+    }
+  }
+
+  // otherwise, just add the new option
+  base->forms.append(ext);
+}
+
+
+void mergeTerminals(GrammarAST *base, TF_terminals * /*owner*/ ext)
+{
+  FOREACH_ASTLIST_NC(TopForm, base->forms, iter) {
+    if (iter.data()->isTF_terminals()) {
+      TF_terminals *t = iter.data()->asTF_terminals();
+      
+      // there's no point to changing codes, so all the
+      // TermDecls just get added (collisions are detected
+      // later, during AST parsing)
+      t->decls.concat(ext->decls);
+      
+      // in fact, I'll do the same for the others, even though
+      // it might make sense to do some replacement; my immediate
+      // needs don't include replacement at this level
+      t->types.concat(ext->types);
+      t->prec.concat(ext->prec);
+      
+      delete ext;
+      return;
+    }
+  }
+  
+  // no TF_terminals in 'base'.. unusual, but easy to handle
+  base->forms.append(ext);
+}
+
+
+void mergeSpecFunc(TF_nonterm *base, SpecFunc * /*owner*/ ext)
+{
+  // find an existing spec func with the same name
+  FOREACH_ASTLIST_NC(SpecFunc, base->funcs, iter) {
+    SpecFunc *f = iter.data();
+    if (f->name.str == ext->name) {
+      // replace the old code with the extension code
+      base->funcs.removeItem(f);
+      delete f;
+      break;
+    }
+  }
+
+  // just add it
+  base->funcs.append(ext);
+}
+
+
+bool equalRHSElt(RHSElt const *elt1, RHSElt const *elt2)
+{
+  if (elt1->kind() != elt2->kind()) {
+    return false;
+  }
+
+  // if the RHS names a terminal, this isn't perfect because one might
+  // use an alias.. but I don't have the necessary information to detect
+  // that, since I haven't yet computed the associated Symbols
+  if (elt1->isRH_name()) {
+    return elt1->asRH_nameC()->name.str == elt2->asRH_nameC()->name.str;
+  }
+  if (elt1->isRH_string()) {
+    return elt1->asRH_stringC()->str.str == elt2->asRH_stringC()->str.str;
+  }
+  if (elt1->isRH_prec()) {
+    // this means you can't change the precedence..
+    return elt1->asRH_precC()->tokName.str == elt2->asRH_precC()->tokName.str;
+  }
+
+  xfailure("unknown RHSElt kind");
+  return false;     // silence warning
+}
+
+
+bool equalRHS(ProdDecl const *prod1, ProdDecl const *prod2)
+{
+  if (prod1->rhs.count() != prod2->rhs.count()) {
+    return false;
+  }
+
+  for (ASTListIter<RHSElt> iter1(prod1->rhs), iter2(prod2->rhs);
+       !iter1.isDone(); iter1.adv(), iter2.adv()) {
+    if (!equalRHSElt(iter1.data(), iter2.data())) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+void mergeProduction(TF_nonterm *base, ProdDecl *ext)
+{
+  bool found = false;
+
+  // look for a production with an identical RHS
+  FOREACH_ASTLIST_NC(ProdDecl, base->productions, iter) {
+    ProdDecl *prod = iter.data();
+
+    // check RHSs for equality
+    if (equalRHS(prod, ext)) {
+      found = true;
+
+      if (ext->kind == PDK_NEW) {
+        astParseError(ext->loc,
+                      "production has the same RHS as an existing production; "
+                      "if intent is to replace, use the 'replace' keyword");
+        // not reached
+      }
+
+      // delete old
+      base->productions.removeItem(prod);
+      delete prod;
+
+      if (ext->kind == PDK_DELETE) {
+        delete ext;       // drop new on the floor, too
+        return;
+      }
+
+      // will replace old with new
+      xassert(ext->kind == PDK_REPLACE);
+      break;
+    }
+  }
+
+  if (ext->kind != PDK_NEW && !found) {
+    astParseError(ext->loc,
+                  "production marked with 'delete' or 'replace' does not match "
+                  "any in the base specification");
+  }
+
+  // add the production
+  base->productions.append(ext);
+}
+
+
+void mergeNonterminal(GrammarAST *base, TF_nonterm * /*owner*/ ext)
+{
+  // find an existing nonterminal with the same name
+  TF_nonterm *exist = NULL;
+  FOREACH_ASTLIST_NC(TopForm, base->forms, iter) {
+    if (iter.data()->isTF_nonterm() &&
+        iter.data()->asTF_nonterm()->name.str == ext->name) {
+      exist = iter.data()->asTF_nonterm();
+    }
+  }
+
+  if (!exist) {
+    // no pre-existing, just append it
+    base->forms.append(ext);
+    return;
+  }
+
+  // make sure the types agree
+  if (exist->type.str != ext->type) {
+    astParseError(ext->type, "cannot redefine the type of a nonterminal");
+  }
+
+  // merge the spec funcs
+  while (ext->funcs.isNotEmpty()) {
+    mergeSpecFunc(exist, ext->funcs.removeFirst());
+  }
+
+  // merge the productions
+  while (ext->productions.isNotEmpty()) {
+    mergeProduction(exist, ext->productions.removeFirst());
+  }
+
+  delete ext;
+}
+
+
+void mergeGrammar(GrammarAST *base, GrammarAST *ext)
+{
+  // work through all the forms in 'ext', removing each
+  // one; it will then either be added to 'base', or
+  // discarded entirely
+  while (ext->forms.isNotEmpty()) {
+    TopForm *form = ext->forms.removeFirst();
+
+    ASTSWITCH(TopForm, form) {
+      ASTCASE(TF_context, c) {
+        mergeContext(base, c);
+      }
+
+      ASTNEXT(TF_verbatim, v) {
+        // verbatims simply accumulate
+        base->forms.append(v);
+      }
+
+      ASTNEXT(TF_option, op) {
+        mergeOption(base, op);
+      }
+
+      ASTNEXT(TF_terminals, t) {
+        mergeTerminals(base, t);
+      }
+
+      ASTNEXT(TF_nonterm, n) {
+        mergeNonterminal(base, n);
+      }
+      
+      ASTDEFAULT {
+        xfailure("doh");
+      }
+      
+      ASTENDCASE
+    }
+  }
+}
+
+
+// ---------------- external interface -------------------
+bool isGramlexEmbed(int code);     // defined in gramlex.lex
+
+GrammarAST *parseGrammarFile(rostring origFname, bool useML)
+{
+  string fname = origFname;
+
+  #ifndef NDEBUG
+  if (tracingSys("yydebug")) {
+    yydebug = true;    // this flag goes away when NDEBUG is specified..
+  }
+  #endif // NDEBUG
+
+  // open input file
+  Owner<ifstream> in;
+  if (fname.empty()) {
+    fname = "<stdin>";
+  }
+  else {
+    in = new ifstream(fname.c_str());
+    if (!*in) {
+      xsyserror("open", stringc << "error opening input file " << fname);
+    }
+  }
+
+  // choose embedded language              
+  EmbeddedLang *embed = NULL;
+  if (useML) {
+    embed = new MLSubstrate;
+  }
+  
+  // build lexer
+  GrammarLexer lexer(isGramlexEmbed,
+                     grammarStringTable,
+                     fname.c_str(),
+                     in.xfr(),
+                     embed);
+  if (embed) {
+    // install the refined error reporter
+    embed->err = &lexer.altReporter;
+  }
+
+  ParseParams params(lexer);
+
+  traceProgress() << "parsing grammar source: " << fname << endl;
+  int retval = grampar_yyparse(&params);
+  if (retval==0 && lexer.errors==0) {
+    GrammarAST *ret = params.treeTop;
+
+    if (tracingSys("printGrammarAST")) {
+      // print AST
+      cout << "AST:\n";
+      ret->debugPrint(cout, 2);
+    }
+
+    return ret;
+  }
+  else {
+    xbase("parsing finished with an error");
+    return NULL;     // silence warning
+  }
+}
+
+
+void parseGrammarAST(Grammar &g, GrammarAST *treeTop)
+{
+  setAnnotations(treeTop);
+  
+  // look at TF_options before synthesizing start rule,
+  // so we can know what language is the target
+  astParseOptions(g, treeTop);
+
+  // fill in default types and actions
+  addDefaultTypesActions(g, treeTop);
+
+  // synthesize a rule "TrueStart -> Start EOF"
+  synthesizeStartRule(g, treeTop);
+
+  // parse the AST into a Grammar
+  traceProgress() << "parsing grammar AST..\n";
+  astParseGrammar(g, treeTop);
+
+  // then check grammar properties; throws exception
+  // on failure
+  traceProgress() << "beginning grammar analysis..\n";
+  g.checkWellFormed();
+}
+
+
+void readGrammarFile(Grammar &g, rostring fname)
+{
+  // make sure the tree gets deleted
+  Owner<GrammarAST> treeTop(parseGrammarFile(fname, false /*useML*/));
+
+  parseGrammarAST(g, treeTop);
+
+  treeTop.del();
+
+  // hmm.. I'd like to restore this functionality...
+  //if (ASTNode::nodeCount > 0) {
+  //  cout << "leaked " << ASTNode::nodeCount << " AST nodes\n";
+  //}
+}
+
+
+// ----------------------- test code -----------------------
+#ifdef TEST_GRAMPAR
+
+#include "bflatten.h"     // BFlatten
+#include <stdlib.h>       // system
+
+int main(int argc, char **argv)
+{
+  if (argc < 2) {
+    cout << "usage: " << argv[0] << " [-tr flags] filename.gr\n";
+    cout << "  interesting trace flags:\n";
+    cout << "    keep-tmp      do not delete the temporary files\n";
+    //cout << "    cat-grammar   print the ascii rep to the screen\n";
+    return 0;
+  }
+
+  traceAddSys("progress");
+  TRACE_ARGS();
+
+  bool printCode = true;
+
+  // read the file
+  Grammar g1;
+  readGrammarFile(g1, argv[1]);
+
+  // and print the grammar
+  char const g1Fname[] = "grammar.g1.tmp";
+  traceProgress() << "printing initial grammar to " << g1Fname << "\n";
+  {
+    ofstream out(g1Fname);
+    g1.printSymbolTypes(out);
+    g1.printProductions(out, printCode);
+  }
+
+  //if (tracingSys("cat-grammar")) {
+    system("cat grammar.g1.tmp");
+  //}
+
+  // before using 'xfer' we have to tell it about the string table
+  flattenStrTable = &grammarStringTable;
+
+  // write it to a binary file
+  char const binFname[] = "grammar.bin.tmp";
+  traceProgress() << "writing initial grammar to " << binFname << "\n";
+  {
+    BFlatten flat(binFname, false /*reading*/);
+    g1.xfer(flat);
+  }
+
+  // read it back
+  traceProgress() << "reading grammar from " << binFname << "\n";
+  Grammar g2;
+  {
+    BFlatten flat(binFname, true /*reading*/);
+    g2.xfer(flat);
+  }
+
+  // print that too
+  char const g2Fname[] = "grammar.g2.tmp";
+  traceProgress() << "printing just-read grammar to " << g2Fname << "\n";
+  {
+    ofstream out(g2Fname);
+    g2.printSymbolTypes(out);
+    g2.printProductions(out, printCode);
+  }
+
+  // compare the two written files
+  int result = system(stringc << "diff " << g1Fname << " " << g2Fname);
+  if (result != 0) {
+    cout << "the two ascii representations differ!!\n";
+    return 4;
+  }
+
+  // remove the temp files
+  if (!tracingSys("keep-tmp")) {
+    remove(g1Fname);
+    remove(g2Fname);
+    remove(binFname);
+  }
+
+  cout << "successfully parsed, printed, wrote, and read a grammar!\n";
+  return 0;
+}
+
+#endif // TEST_GRAMPAR

Added: vendor/elsa/current/elkhound/grampar.codes.h
===================================================================
--- vendor/elsa/current/elkhound/grampar.codes.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grampar.codes.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+# define YYTOKENTYPE
+#define TOK_INTEGER 258
+#define TOK_NAME 259
+#define TOK_STRING 260
+#define TOK_LIT_CODE 261
+#define TOK_LBRACE 262
+#define TOK_RBRACE 263
+#define TOK_COLON 264
+#define TOK_SEMICOLON 265
+#define TOK_ARROW 266
+#define TOK_LPAREN 267
+#define TOK_RPAREN 268
+#define TOK_COMMA 269
+#define TOK_TERMINALS 270
+#define TOK_TOKEN 271
+#define TOK_NONTERM 272
+#define TOK_FUN 273
+#define TOK_VERBATIM 274
+#define TOK_IMPL_VERBATIM 275
+#define TOK_PRECEDENCE 276
+#define TOK_OPTION 277
+#define TOK_EXPECT 278
+#define TOK_CONTEXT_CLASS 279
+#define TOK_SUBSETS 280
+#define TOK_DELETE 281
+#define TOK_REPLACE 282
+#define TOK_FORBID_NEXT 283
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1

Added: vendor/elsa/current/elkhound/grampar.h
===================================================================
--- vendor/elsa/current/elkhound/grampar.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grampar.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,133 @@
+// grampar.h            see license.txt for copyright and terms of use
+// declarations for bison-generated grammar parser
+
+#ifndef __GRAMPAR_H
+#define __GRAMPAR_H
+
+#include "typ.h"          // NULL
+#include "sobjlist.h"     // SObjList
+#include "exc.h"          // xBase
+#include "strsobjdict.h"  // StringSObjDict
+#include "locstr.h"       // LocString
+
+// linkdepend: grampar.tab.cc
+
+// fwd decl
+class GrammarAST;         // gramast.ast
+class TF_nonterm;         // gramast.ast
+class GrammarLexer;       // ../ast/gramlex.h
+class StringTable;        // strtable.h
+
+
+// -------- rest of the program's view of parser ------------
+// name of extra parameter to yyparse (i.e. the context in
+// which the parser operates, instead of that being stored
+// in some collection of globals)
+#define YYPARSE_PARAM parseParam
+
+// type of thing extra param points at
+struct ParseParams {
+  GrammarAST *treeTop;    // set when parsing finishes; AST tree top
+  GrammarLexer &lexer;    // lexer we're using
+
+public:
+  ParseParams(GrammarLexer &L) :
+    treeTop(NULL),
+    lexer(L)
+  {}
+};
+
+// caller interface to Bison-generated parser; starts parsing
+// (whatever stream lexer is reading) and returns 0 for success and
+// 1 for error; the extra parameter is available to actions to use
+int grampar_yyparse(void *YYPARSE_PARAM);
+
+// when this is set to true, bison parser emits info about
+// actions as it's taking them (shared by all instances of
+// bison-generated parsers in a given program)
+extern int yydebug;
+
+
+// ---------- Bison's view of the rest of the program --------
+// Bison calls this to get each token; returns token code,
+// or 0 for eof; semantic value for returned token can be
+// put into '*lvalp'
+// TODO: Paul Hilfinger reports there's a problem saying "union
+// YYSTYPE"; he's using bison 1.34 I think, so I need to upgrade
+// and see what the problem is (suspect my 'sed' pattern isn't
+// matching, in the Makefile)
+int grampar_yylex(union YYSTYPE *lvalp, void *parseParam);
+
+// error printer
+void grampar_yyerror(char const *message, void *parseParam);
+
+
+// ---------------- grampar's parsing structures ---------------
+class Grammar;    // fwd
+
+// while walking the AST, we do a kind of recursive evaluation
+// to handle things like inherited actions and self-updating
+// (eval'd at grammar parse time) action expressions
+class Environment {
+public:      // data
+  // grammar we're playing with (stored here because it's
+  // more convenient than passing it to every fn separately)
+  Grammar &g;
+
+  // env in which we're nested, if any
+  Environment *prevEnv;      // (serf)
+
+  // maps from a nonterminal name to its declaration, if that
+  // nonterminal has in fact been declared already
+  StringSObjDict<TF_nonterm> nontermDecls;
+
+  // count of recoverable errors; only the one in the
+  // topmost environment is used
+  int errorCount;
+  
+  // reference to the one we're really using
+  int &errors;
+
+public:
+  Environment(Grammar &G);             // new env
+  Environment(Environment &prevEnv);   // nested env
+  ~Environment();
+};
+
+
+// --------------- grampar's external interface -----------
+// parse grammar file 'fname' into grammar 'g', throwing exceptions
+// if there are problems
+void readGrammarFile(Grammar &g, rostring fname);
+
+// just do the parsing stage
+GrammarAST *parseGrammarFile(rostring fname, bool useML);
+
+// merge two grammar descriptions; neither argument is consumed,
+// but subtrees of the 2nd argument get moved into the first tree
+void mergeGrammar(GrammarAST *base, GrammarAST *ext);
+
+// GrammarAST -> Grammar
+void parseGrammarAST(Grammar &g, GrammarAST *treeTop);
+
+
+// thrown when there is an error parsing the AST
+class XASTParse : public xBase {
+public:    // data
+  // token at or near failure
+  LocString failToken;
+
+  // what is wrong
+  string message;
+
+private:   // funcs
+  static string constructMsg(LocString const &tok, rostring msg);
+
+public:    // funcs
+  XASTParse(LocString const &tok, rostring msg);
+  XASTParse(XASTParse const &obj);
+  ~XASTParse();
+};
+
+
+#endif // __GRAMPAR_H

Added: vendor/elsa/current/elkhound/grampar.tab.cc
===================================================================
--- vendor/elsa/current/elkhound/grampar.tab.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grampar.tab.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2056 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     TOK_INTEGER = 258,
+     TOK_NAME = 259,
+     TOK_STRING = 260,
+     TOK_LIT_CODE = 261,
+     TOK_LBRACE = 262,
+     TOK_RBRACE = 263,
+     TOK_COLON = 264,
+     TOK_SEMICOLON = 265,
+     TOK_ARROW = 266,
+     TOK_LPAREN = 267,
+     TOK_RPAREN = 268,
+     TOK_COMMA = 269,
+     TOK_TERMINALS = 270,
+     TOK_TOKEN = 271,
+     TOK_NONTERM = 272,
+     TOK_FUN = 273,
+     TOK_VERBATIM = 274,
+     TOK_IMPL_VERBATIM = 275,
+     TOK_PRECEDENCE = 276,
+     TOK_OPTION = 277,
+     TOK_EXPECT = 278,
+     TOK_CONTEXT_CLASS = 279,
+     TOK_SUBSETS = 280,
+     TOK_DELETE = 281,
+     TOK_REPLACE = 282,
+     TOK_FORBID_NEXT = 283
+   };
+#endif
+/* Tokens.  */
+#define TOK_INTEGER 258
+#define TOK_NAME 259
+#define TOK_STRING 260
+#define TOK_LIT_CODE 261
+#define TOK_LBRACE 262
+#define TOK_RBRACE 263
+#define TOK_COLON 264
+#define TOK_SEMICOLON 265
+#define TOK_ARROW 266
+#define TOK_LPAREN 267
+#define TOK_RPAREN 268
+#define TOK_COMMA 269
+#define TOK_TERMINALS 270
+#define TOK_TOKEN 271
+#define TOK_NONTERM 272
+#define TOK_FUN 273
+#define TOK_VERBATIM 274
+#define TOK_IMPL_VERBATIM 275
+#define TOK_PRECEDENCE 276
+#define TOK_OPTION 277
+#define TOK_EXPECT 278
+#define TOK_CONTEXT_CLASS 279
+#define TOK_SUBSETS 280
+#define TOK_DELETE 281
+#define TOK_REPLACE 282
+#define TOK_FORBID_NEXT 283
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 6 "grampar.y"
+
+
+#include "grampar.h"        // yylex, etc.
+#include "gramast.ast.gen.h"// grammar syntax AST definition
+#include "gramlex.h"        // GrammarLexer
+#include "owner.h"          // Owner
+
+#include <stdlib.h>         // malloc, free
+#include <iostream.h>       // cout
+
+// enable debugging the parser
+#ifndef NDEBUG
+  #define YYDEBUG 1
+#endif
+
+// name of extra parameter to yylex
+#define YYLEX_PARAM parseParam
+
+// make it call my yylex
+#define yylex(lv, param) grampar_yylex(lv, param)
+
+// Bison calls yyerror(msg) on error; we need the extra
+// parameter too, so the macro shoehorns it in there
+#define yyerror(msg) grampar_yyerror(msg, YYPARSE_PARAM)
+
+// rename the externally-visible parsing routine to make it
+// specific to this instance, so multiple bison-generated
+// parsers can coexist
+#define yyparse grampar_yyparse
+
+
+// grab the parameter
+#define PARAM ((ParseParams*)parseParam)
+
+// return a locstring for 'str' with no location information
+#define noloc(str)                                                    \
+  new LocString(SL_UNKNOWN,      /* unknown location */               \
+                PARAM->lexer.strtable.add(str))
+                
+// locstring for NULL, with no location
+#define nolocNULL()                                                   \
+  new LocString(SL_UNKNOWN, NULL)
+
+// return a locstring with same location info as something else
+// (passed as a pointer to a SourceLocation)
+#define sameloc(otherLoc, str)                                        \
+  new LocString(otherLoc->loc, PARAM->lexer.strtable.add(str))
+
+// interpret the word into an associativity kind specification
+AssocKind whichKind(LocString * /*owner*/ kind);
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 105 "grampar.y"
+{
+  int num;
+  LocString *str;
+  SourceLoc loc;
+
+  ASTList<TopForm> *topFormList;
+  TopForm *topForm;
+
+  ASTList<TermDecl> *termDecls;
+  TermDecl *termDecl;
+  ASTList<TermType> *termTypes;
+  TermType *termType;
+  ASTList<PrecSpec> *precSpecs;
+
+  ASTList<SpecFunc> *specFuncs;
+  SpecFunc *specFunc;
+  ASTList<LocString> *stringList;
+
+  ASTList<ProdDecl> *prodDecls;
+  ProdDecl *prodDecl;
+  ASTList<RHSElt> *rhsList;
+  RHSElt *rhsElt;
+}
+/* Line 193 of yacc.c.  */
+#line 229 "grampar.tab.c"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+#line 242 "grampar.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  3
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   112
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  29
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  28
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  59
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  106
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   283
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     5,     6,     9,    11,    13,    15,    17,
+      19,    23,    26,    29,    33,    38,    45,    46,    49,    54,
+      60,    62,    63,    64,    67,    72,    79,    80,    85,    86,
+      92,    93,    96,    98,   100,   101,   104,   111,   112,   114,
+     116,   120,   125,   134,   135,   138,   142,   147,   152,   154,
+     156,   157,   160,   162,   166,   168,   172,   177,   182,   183
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      30,     0,    -1,    31,    -1,    -1,    31,    32,    -1,    33,
+      -1,    34,    -1,    35,    -1,    36,    -1,    50,    -1,    24,
+       6,    10,    -1,    19,     6,    -1,    20,     6,    -1,    22,
+       4,    10,    -1,    22,     4,     3,    10,    -1,    15,     7,
+      37,    40,    42,     8,    -1,    -1,    37,    38,    -1,     3,
+       9,     4,    10,    -1,     3,     9,     4,     5,    10,    -1,
+       6,    -1,    -1,    -1,    40,    41,    -1,    16,    39,     4,
+      10,    -1,    16,    39,     4,     7,    46,     8,    -1,    -1,
+      21,     7,    43,     8,    -1,    -1,    43,     4,     3,    44,
+      10,    -1,    -1,    44,    45,    -1,     4,    -1,     5,    -1,
+      -1,    46,    47,    -1,    18,     4,    12,    48,    13,     6,
+      -1,    -1,    49,    -1,     4,    -1,    49,    14,     4,    -1,
+      17,    39,     4,    52,    -1,    17,    39,     4,     7,    46,
+      51,    56,     8,    -1,    -1,    51,    52,    -1,    11,    54,
+      53,    -1,    27,    11,    54,    53,    -1,    26,    11,    54,
+      10,    -1,     6,    -1,    10,    -1,    -1,    54,    55,    -1,
+       4,    -1,     4,     9,     4,    -1,     5,    -1,     4,     9,
+       5,    -1,    21,    12,    45,    13,    -1,    28,    12,    45,
+      13,    -1,    -1,    25,    49,    10,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   162,   162,   167,   168,   172,   173,   174,   175,   176,
+     180,   185,   186,   191,   192,   203,   208,   209,   217,   219,
+     224,   225,   229,   230,   234,   236,   241,   242,   247,   248,
+     253,   254,   258,   259,   265,   266,   270,   275,   276,   280,
+     281,   292,   295,   300,   301,   305,   306,   307,   311,   312,
+     316,   317,   326,   327,   328,   329,   330,   331,   335,   336
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "TOK_INTEGER", "TOK_NAME", "TOK_STRING",
+  "TOK_LIT_CODE", "\"{\"", "\"}\"", "\":\"", "\";\"", "\"->\"", "\"(\"",
+  "\")\"", "\",\"", "\"terminals\"", "\"token\"", "\"nonterm\"", "\"fun\"",
+  "\"verbatim\"", "\"impl_verbatim\"", "\"precedence\"", "\"option\"",
+  "\"expect\"", "\"context_class\"", "\"subsets\"", "\"delete\"",
+  "\"replace\"", "\"forbid_next\"", "$accept", "StartSymbol",
+  "TopFormList", "TopForm", "ContextClass", "Verbatim", "Option",
+  "Terminals", "TermDecls", "TerminalDecl", "Type", "TermTypes",
+  "TermType", "Precedence", "PrecSpecs", "NameOrStringList",
+  "NameOrString", "SpecFuncs", "SpecFunc", "FormalsOpt", "Formals",
+  "Nonterminal", "Productions", "Production", "Action", "RHS", "RHSElt",
+  "Subsets", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    29,    30,    31,    31,    32,    32,    32,    32,    32,
+      33,    34,    34,    35,    35,    36,    37,    37,    38,    38,
+      39,    39,    40,    40,    41,    41,    42,    42,    43,    43,
+      44,    44,    45,    45,    46,    46,    47,    48,    48,    49,
+      49,    50,    50,    51,    51,    52,    52,    52,    53,    53,
+      54,    54,    55,    55,    55,    55,    55,    55,    56,    56
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     0,     2,     1,     1,     1,     1,     1,
+       3,     2,     2,     3,     4,     6,     0,     2,     4,     5,
+       1,     0,     0,     2,     4,     6,     0,     4,     0,     5,
+       0,     2,     1,     1,     0,     2,     6,     0,     1,     1,
+       3,     4,     8,     0,     2,     3,     4,     4,     1,     1,
+       0,     2,     1,     3,     1,     3,     4,     4,     0,     3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       3,     0,     2,     1,     0,    21,     0,     0,     0,     0,
+       4,     5,     6,     7,     8,     9,    16,    20,     0,    11,
+      12,     0,     0,    22,     0,     0,    13,    10,     0,    17,
+      26,    34,    50,     0,     0,    41,    14,     0,    21,     0,
+      23,     0,    43,     0,    50,    50,     0,     0,    28,    15,
+       0,    35,    58,    52,    54,    48,    49,     0,     0,    45,
+      51,     0,     0,     0,    18,     0,     0,     0,     0,    44,
+       0,     0,     0,     0,    47,    46,    19,    34,    24,     0,
+      27,    37,    39,     0,    42,    53,    55,    32,    33,     0,
+       0,     0,    30,     0,    38,    59,     0,    56,    57,    25,
+       0,     0,    40,    29,    31,    36
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     1,     2,    10,    11,    12,    13,    14,    23,    29,
+      18,    30,    40,    41,    66,   100,    89,    42,    51,    93,
+      83,    15,    52,    35,    59,    43,    60,    70
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -74
+static const yytype_int8 yypact[] =
+{
+     -74,    39,    21,   -74,     1,    26,    31,    49,    48,    50,
+     -74,   -74,   -74,   -74,   -74,   -74,   -74,   -74,    53,   -74,
+     -74,    10,    51,    55,     4,    52,   -74,   -74,    54,   -74,
+      -7,   -74,   -74,    56,    57,   -74,   -74,    60,    26,    58,
+     -74,    61,    41,    -3,   -74,   -74,     7,    62,   -74,   -74,
+      66,   -74,     8,    63,   -74,   -74,   -74,    59,    64,   -74,
+     -74,     0,    -3,    65,   -74,    37,    18,    67,    69,   -74,
+      70,    44,    46,    46,   -74,   -74,   -74,   -74,   -74,    71,
+     -74,    69,   -74,    32,   -74,   -74,   -74,   -74,   -74,    47,
+      68,    -2,   -74,    72,    73,   -74,    76,   -74,   -74,   -74,
+      19,    77,   -74,   -74,   -74,   -74
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -74,   -74,   -74,   -74,   -74,   -74,   -74,   -74,   -74,   -74,
+      74,   -74,   -74,   -74,   -74,   -74,   -73,     5,   -74,   -74,
+      -4,   -74,   -74,    34,    22,     9,   -74,   -74
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+      90,    53,    54,    55,    53,    54,    99,    56,    16,    38,
+      74,    31,    63,    25,    39,    32,    50,    64,    57,    32,
+      26,    57,    79,    87,    88,    58,    80,   104,    58,   103,
+      33,    34,    17,    68,    33,    34,     4,    19,     5,     3,
+       6,     7,    95,     8,    77,     9,    96,    78,    85,    86,
+      87,    88,    21,    61,    62,    20,    22,    24,    28,    50,
+      97,    27,    36,    37,    46,    48,    65,    44,    45,    49,
+      67,    72,    71,    82,    92,    76,    73,    94,    84,    81,
+     102,    98,    91,   105,    75,   101,    69,    96,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    47
+};
+
+static const yytype_int8 yycheck[] =
+{
+      73,     4,     5,     6,     4,     5,     8,    10,     7,    16,
+      10,     7,     5,     3,    21,    11,    18,    10,    21,    11,
+      10,    21,     4,     4,     5,    28,     8,   100,    28,    10,
+      26,    27,     6,    25,    26,    27,    15,     6,    17,     0,
+      19,    20,    10,    22,     7,    24,    14,    10,     4,     5,
+       4,     5,     4,    44,    45,     6,     6,     4,     3,    18,
+      13,    10,    10,     9,     4,     7,     4,    11,    11,     8,
+       4,    12,     9,     4,     3,    10,    12,    81,     8,    12,
+       4,    13,    77,     6,    62,    13,    52,    14,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    38
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    30,    31,     0,    15,    17,    19,    20,    22,    24,
+      32,    33,    34,    35,    36,    50,     7,     6,    39,     6,
+       6,     4,     6,    37,     4,     3,    10,    10,     3,    38,
+      40,     7,    11,    26,    27,    52,    10,     9,    16,    21,
+      41,    42,    46,    54,    11,    11,     4,    39,     7,     8,
+      18,    47,    51,     4,     5,     6,    10,    21,    28,    53,
+      55,    54,    54,     5,    10,     4,    43,     4,    25,    52,
+      56,     9,    12,    12,    10,    53,    10,     7,    10,     4,
+       8,    12,     4,    49,     8,     4,     5,     4,     5,    45,
+      45,    46,     3,    48,    49,    10,    14,    13,    13,     8,
+      44,    13,     4,    10,    45,     6
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  /* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 163 "grampar.y"
+    { ((ParseParams*)parseParam)->treeTop = new GrammarAST((yyvsp[(1) - (1)].topFormList)); (yyval.num)=0; ;}
+    break;
+
+  case 3:
+#line 167 "grampar.y"
+    { (yyval.topFormList) = new ASTList<TopForm>; ;}
+    break;
+
+  case 4:
+#line 168 "grampar.y"
+    { ((yyval.topFormList)=(yyvsp[(1) - (2)].topFormList))->append((yyvsp[(2) - (2)].topForm)); ;}
+    break;
+
+  case 5:
+#line 172 "grampar.y"
+    { (yyval.topForm) = (yyvsp[(1) - (1)].topForm); ;}
+    break;
+
+  case 6:
+#line 173 "grampar.y"
+    { (yyval.topForm) = (yyvsp[(1) - (1)].topForm); ;}
+    break;
+
+  case 7:
+#line 174 "grampar.y"
+    { (yyval.topForm) = (yyvsp[(1) - (1)].topForm); ;}
+    break;
+
+  case 8:
+#line 175 "grampar.y"
+    { (yyval.topForm) = (yyvsp[(1) - (1)].topForm); ;}
+    break;
+
+  case 9:
+#line 176 "grampar.y"
+    { (yyval.topForm) = (yyvsp[(1) - (1)].topForm); ;}
+    break;
+
+  case 10:
+#line 181 "grampar.y"
+    { (yyval.topForm) = new TF_context((yyvsp[(2) - (3)].str)); ;}
+    break;
+
+  case 11:
+#line 185 "grampar.y"
+    { (yyval.topForm) = new TF_verbatim(false, (yyvsp[(2) - (2)].str)); ;}
+    break;
+
+  case 12:
+#line 186 "grampar.y"
+    { (yyval.topForm) = new TF_verbatim(true, (yyvsp[(2) - (2)].str)); ;}
+    break;
+
+  case 13:
+#line 191 "grampar.y"
+    { (yyval.topForm) = new TF_option((yyvsp[(2) - (3)].str), 1); ;}
+    break;
+
+  case 14:
+#line 192 "grampar.y"
+    { (yyval.topForm) = new TF_option((yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].num)); ;}
+    break;
+
+  case 15:
+#line 204 "grampar.y"
+    { (yyval.topForm) = new TF_terminals((yyvsp[(3) - (6)].termDecls), (yyvsp[(4) - (6)].termTypes), (yyvsp[(5) - (6)].precSpecs)); ;}
+    break;
+
+  case 16:
+#line 208 "grampar.y"
+    { (yyval.termDecls) = new ASTList<TermDecl>; ;}
+    break;
+
+  case 17:
+#line 209 "grampar.y"
+    { ((yyval.termDecls)=(yyvsp[(1) - (2)].termDecls))->append((yyvsp[(2) - (2)].termDecl)); ;}
+    break;
+
+  case 18:
+#line 218 "grampar.y"
+    { (yyval.termDecl) = new TermDecl((yyvsp[(1) - (4)].num), (yyvsp[(3) - (4)].str), sameloc((yyvsp[(3) - (4)].str), "")); ;}
+    break;
+
+  case 19:
+#line 220 "grampar.y"
+    { (yyval.termDecl) = new TermDecl((yyvsp[(1) - (5)].num), (yyvsp[(3) - (5)].str), (yyvsp[(4) - (5)].str)); ;}
+    break;
+
+  case 20:
+#line 224 "grampar.y"
+    { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
+    break;
+
+  case 21:
+#line 225 "grampar.y"
+    { (yyval.str) = nolocNULL(); ;}
+    break;
+
+  case 22:
+#line 229 "grampar.y"
+    { (yyval.termTypes) = new ASTList<TermType>; ;}
+    break;
+
+  case 23:
+#line 230 "grampar.y"
+    { ((yyval.termTypes)=(yyvsp[(1) - (2)].termTypes))->append((yyvsp[(2) - (2)].termType)); ;}
+    break;
+
+  case 24:
+#line 235 "grampar.y"
+    { (yyval.termType) = new TermType((yyvsp[(3) - (4)].str), (yyvsp[(2) - (4)].str), new ASTList<SpecFunc>); ;}
+    break;
+
+  case 25:
+#line 237 "grampar.y"
+    { (yyval.termType) = new TermType((yyvsp[(3) - (6)].str), (yyvsp[(2) - (6)].str), (yyvsp[(5) - (6)].specFuncs)); ;}
+    break;
+
+  case 26:
+#line 241 "grampar.y"
+    { (yyval.precSpecs) = new ASTList<PrecSpec>; ;}
+    break;
+
+  case 27:
+#line 242 "grampar.y"
+    { (yyval.precSpecs) = (yyvsp[(3) - (4)].precSpecs); ;}
+    break;
+
+  case 28:
+#line 247 "grampar.y"
+    { (yyval.precSpecs) = new ASTList<PrecSpec>; ;}
+    break;
+
+  case 29:
+#line 249 "grampar.y"
+    { ((yyval.precSpecs)=(yyvsp[(1) - (5)].precSpecs))->append(new PrecSpec(whichKind((yyvsp[(2) - (5)].str)), (yyvsp[(3) - (5)].num), (yyvsp[(4) - (5)].stringList))); ;}
+    break;
+
+  case 30:
+#line 253 "grampar.y"
+    { (yyval.stringList) = new ASTList<LocString>; ;}
+    break;
+
+  case 31:
+#line 254 "grampar.y"
+    { ((yyval.stringList)=(yyvsp[(1) - (2)].stringList))->append((yyvsp[(2) - (2)].str)); ;}
+    break;
+
+  case 32:
+#line 258 "grampar.y"
+    { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
+    break;
+
+  case 33:
+#line 259 "grampar.y"
+    { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
+    break;
+
+  case 34:
+#line 265 "grampar.y"
+    { (yyval.specFuncs) = new ASTList<SpecFunc>; ;}
+    break;
+
+  case 35:
+#line 266 "grampar.y"
+    { ((yyval.specFuncs)=(yyvsp[(1) - (2)].specFuncs))->append((yyvsp[(2) - (2)].specFunc)); ;}
+    break;
+
+  case 36:
+#line 271 "grampar.y"
+    { (yyval.specFunc) = new SpecFunc((yyvsp[(2) - (6)].str), (yyvsp[(4) - (6)].stringList), (yyvsp[(6) - (6)].str)); ;}
+    break;
+
+  case 37:
+#line 275 "grampar.y"
+    { (yyval.stringList) = new ASTList<LocString>; ;}
+    break;
+
+  case 38:
+#line 276 "grampar.y"
+    { (yyval.stringList) = (yyvsp[(1) - (1)].stringList); ;}
+    break;
+
+  case 39:
+#line 280 "grampar.y"
+    { (yyval.stringList) = new ASTList<LocString>((yyvsp[(1) - (1)].str)); ;}
+    break;
+
+  case 40:
+#line 281 "grampar.y"
+    { ((yyval.stringList)=(yyvsp[(1) - (3)].stringList))->append((yyvsp[(3) - (3)].str)); ;}
+    break;
+
+  case 41:
+#line 293 "grampar.y"
+    { (yyval.topForm) = new TF_nonterm((yyvsp[(3) - (4)].str), (yyvsp[(2) - (4)].str), new ASTList<SpecFunc>,
+                                     new ASTList<ProdDecl>((yyvsp[(4) - (4)].prodDecl)), NULL); ;}
+    break;
+
+  case 42:
+#line 296 "grampar.y"
+    { (yyval.topForm) = new TF_nonterm((yyvsp[(3) - (8)].str), (yyvsp[(2) - (8)].str), (yyvsp[(5) - (8)].specFuncs), (yyvsp[(6) - (8)].prodDecls), (yyvsp[(7) - (8)].stringList)); ;}
+    break;
+
+  case 43:
+#line 300 "grampar.y"
+    { (yyval.prodDecls) = new ASTList<ProdDecl>; ;}
+    break;
+
+  case 44:
+#line 301 "grampar.y"
+    { ((yyval.prodDecls)=(yyvsp[(1) - (2)].prodDecls))->append((yyvsp[(2) - (2)].prodDecl)); ;}
+    break;
+
+  case 45:
+#line 305 "grampar.y"
+    { (yyval.prodDecl) = new ProdDecl((yyvsp[(1) - (3)].loc), PDK_NEW, (yyvsp[(2) - (3)].rhsList), (yyvsp[(3) - (3)].str)); ;}
+    break;
+
+  case 46:
+#line 306 "grampar.y"
+    { (yyval.prodDecl) = new ProdDecl((yyvsp[(2) - (4)].loc), PDK_REPLACE,(yyvsp[(3) - (4)].rhsList), (yyvsp[(4) - (4)].str)); ;}
+    break;
+
+  case 47:
+#line 307 "grampar.y"
+    { (yyval.prodDecl) = new ProdDecl((yyvsp[(2) - (4)].loc), PDK_DELETE, (yyvsp[(3) - (4)].rhsList), nolocNULL()); ;}
+    break;
+
+  case 48:
+#line 311 "grampar.y"
+    { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
+    break;
+
+  case 49:
+#line 312 "grampar.y"
+    { (yyval.str) = nolocNULL(); ;}
+    break;
+
+  case 50:
+#line 316 "grampar.y"
+    { (yyval.rhsList) = new ASTList<RHSElt>; ;}
+    break;
+
+  case 51:
+#line 317 "grampar.y"
+    { ((yyval.rhsList)=(yyvsp[(1) - (2)].rhsList))->append((yyvsp[(2) - (2)].rhsElt)); ;}
+    break;
+
+  case 52:
+#line 326 "grampar.y"
+    { (yyval.rhsElt) = new RH_name(sameloc((yyvsp[(1) - (1)].str), ""), (yyvsp[(1) - (1)].str)); ;}
+    break;
+
+  case 53:
+#line 327 "grampar.y"
+    { (yyval.rhsElt) = new RH_name((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ;}
+    break;
+
+  case 54:
+#line 328 "grampar.y"
+    { (yyval.rhsElt) = new RH_string(sameloc((yyvsp[(1) - (1)].str), ""), (yyvsp[(1) - (1)].str)); ;}
+    break;
+
+  case 55:
+#line 329 "grampar.y"
+    { (yyval.rhsElt) = new RH_string((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ;}
+    break;
+
+  case 56:
+#line 330 "grampar.y"
+    { (yyval.rhsElt) = new RH_prec((yyvsp[(3) - (4)].str)); ;}
+    break;
+
+  case 57:
+#line 331 "grampar.y"
+    { (yyval.rhsElt) = new RH_forbid((yyvsp[(3) - (4)].str)); ;}
+    break;
+
+  case 58:
+#line 335 "grampar.y"
+    { (yyval.stringList) = NULL; ;}
+    break;
+
+  case 59:
+#line 336 "grampar.y"
+    { (yyval.stringList) = (yyvsp[(2) - (3)].stringList); ;}
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 1821 "grampar.tab.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (yymsg);
+	  }
+	else
+	  {
+	    yyerror (YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 340 "grampar.y"
+
+/* ------------------ extra C code ------------------ */
+AssocKind whichKind(LocString * /*owner*/ kind)
+{ 
+  // delete 'kind' however we exit
+  Owner<LocString> killer(kind);
+  
+  #define CHECK(syntax, value)   \
+    if (kind->equals(syntax)) {  \
+      return value;              \
+    }
+  CHECK("left", AK_LEFT);
+  CHECK("right", AK_RIGHT);
+  CHECK("nonassoc", AK_NONASSOC);
+  CHECK("prec", AK_NEVERASSOC);
+  CHECK("assoc_split", AK_SPLIT);
+  #undef CHECK
+
+  xbase(stringc << kind->locString()
+                << ": invalid associativity kind: " << *kind);
+}
+

Added: vendor/elsa/current/elkhound/grampar.tab.h
===================================================================
--- vendor/elsa/current/elkhound/grampar.tab.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grampar.tab.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,136 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     TOK_INTEGER = 258,
+     TOK_NAME = 259,
+     TOK_STRING = 260,
+     TOK_LIT_CODE = 261,
+     TOK_LBRACE = 262,
+     TOK_RBRACE = 263,
+     TOK_COLON = 264,
+     TOK_SEMICOLON = 265,
+     TOK_ARROW = 266,
+     TOK_LPAREN = 267,
+     TOK_RPAREN = 268,
+     TOK_COMMA = 269,
+     TOK_TERMINALS = 270,
+     TOK_TOKEN = 271,
+     TOK_NONTERM = 272,
+     TOK_FUN = 273,
+     TOK_VERBATIM = 274,
+     TOK_IMPL_VERBATIM = 275,
+     TOK_PRECEDENCE = 276,
+     TOK_OPTION = 277,
+     TOK_EXPECT = 278,
+     TOK_CONTEXT_CLASS = 279,
+     TOK_SUBSETS = 280,
+     TOK_DELETE = 281,
+     TOK_REPLACE = 282,
+     TOK_FORBID_NEXT = 283
+   };
+#endif
+/* Tokens.  */
+#define TOK_INTEGER 258
+#define TOK_NAME 259
+#define TOK_STRING 260
+#define TOK_LIT_CODE 261
+#define TOK_LBRACE 262
+#define TOK_RBRACE 263
+#define TOK_COLON 264
+#define TOK_SEMICOLON 265
+#define TOK_ARROW 266
+#define TOK_LPAREN 267
+#define TOK_RPAREN 268
+#define TOK_COMMA 269
+#define TOK_TERMINALS 270
+#define TOK_TOKEN 271
+#define TOK_NONTERM 272
+#define TOK_FUN 273
+#define TOK_VERBATIM 274
+#define TOK_IMPL_VERBATIM 275
+#define TOK_PRECEDENCE 276
+#define TOK_OPTION 277
+#define TOK_EXPECT 278
+#define TOK_CONTEXT_CLASS 279
+#define TOK_SUBSETS 280
+#define TOK_DELETE 281
+#define TOK_REPLACE 282
+#define TOK_FORBID_NEXT 283
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 105 "grampar.y"
+{
+  int num;
+  LocString *str;
+  SourceLoc loc;
+
+  ASTList<TopForm> *topFormList;
+  TopForm *topForm;
+
+  ASTList<TermDecl> *termDecls;
+  TermDecl *termDecl;
+  ASTList<TermType> *termTypes;
+  TermType *termType;
+  ASTList<PrecSpec> *precSpecs;
+
+  ASTList<SpecFunc> *specFuncs;
+  SpecFunc *specFunc;
+  ASTList<LocString> *stringList;
+
+  ASTList<ProdDecl> *prodDecls;
+  ProdDecl *prodDecl;
+  ASTList<RHSElt> *rhsList;
+  RHSElt *rhsElt;
+}
+/* Line 1529 of yacc.c.  */
+#line 129 "grampar.tab.h"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+

Added: vendor/elsa/current/elkhound/grampar.y
===================================================================
--- vendor/elsa/current/elkhound/grampar.y	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/grampar.y	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,360 @@
+/* grammar.y            see license.txt for copyright and terms of use
+ * parser for grammar files with new ast format */
+
+
+/* C declarations */
+%{
+
+#include "grampar.h"        // yylex, etc.
+#include "gramast.ast.gen.h"// grammar syntax AST definition
+#include "gramlex.h"        // GrammarLexer
+#include "owner.h"          // Owner
+
+#include <stdlib.h>         // malloc, free
+#include <iostream.h>       // cout
+
+// enable debugging the parser
+#ifndef NDEBUG
+  #define YYDEBUG 1
+#endif
+
+// name of extra parameter to yylex
+#define YYLEX_PARAM parseParam
+
+// make it call my yylex
+#define yylex(lv, param) grampar_yylex(lv, param)
+
+// Bison calls yyerror(msg) on error; we need the extra
+// parameter too, so the macro shoehorns it in there
+#define yyerror(msg) grampar_yyerror(msg, YYPARSE_PARAM)
+
+// rename the externally-visible parsing routine to make it
+// specific to this instance, so multiple bison-generated
+// parsers can coexist
+#define yyparse grampar_yyparse
+
+
+// grab the parameter
+#define PARAM ((ParseParams*)parseParam)
+
+// return a locstring for 'str' with no location information
+#define noloc(str)                                                    \
+  new LocString(SL_UNKNOWN,      /* unknown location */               \
+                PARAM->lexer.strtable.add(str))
+                
+// locstring for NULL, with no location
+#define nolocNULL()                                                   \
+  new LocString(SL_UNKNOWN, NULL)
+
+// return a locstring with same location info as something else
+// (passed as a pointer to a SourceLocation)
+#define sameloc(otherLoc, str)                                        \
+  new LocString(otherLoc->loc, PARAM->lexer.strtable.add(str))
+
+// interpret the word into an associativity kind specification
+AssocKind whichKind(LocString * /*owner*/ kind);
+
+%}
+
+
+/* ================== bison declarations =================== */
+// don't use globals
+%pure_parser
+
+
+/* ===================== tokens ============================ */
+/* tokens that have many lexical spellings */
+%token <num> TOK_INTEGER
+%token <str> TOK_NAME
+%token <str> TOK_STRING
+%token <str> TOK_LIT_CODE
+
+/* punctuators */
+%token TOK_LBRACE "{"
+%token TOK_RBRACE "}"
+%token TOK_COLON ":"
+%token TOK_SEMICOLON ";"
+%token <loc> TOK_ARROW "->"
+%token TOK_LPAREN "("
+%token TOK_RPAREN ")"
+%token TOK_COMMA ","
+
+/* keywords */
+%token TOK_TERMINALS "terminals"
+%token TOK_TOKEN "token"
+%token TOK_NONTERM "nonterm"
+%token TOK_FUN "fun"
+%token TOK_VERBATIM "verbatim"
+%token TOK_IMPL_VERBATIM "impl_verbatim"
+%token TOK_PRECEDENCE "precedence"
+%token TOK_OPTION "option"
+%token TOK_EXPECT "expect"
+%token TOK_CONTEXT_CLASS "context_class"
+%token TOK_SUBSETS "subsets"
+%token TOK_DELETE "delete"
+%token TOK_REPLACE "replace"
+%token TOK_FORBID_NEXT "forbid_next"
+
+// left, right, nonassoc: they're not keywords, since "left" and "right"
+// are common names for RHS elements; instead, we parse them as names
+// and interpret them after lexing
+
+
+/* ===================== types ============================ */
+/* all pointers are owner pointers */
+%union {
+  int num;
+  LocString *str;
+  SourceLoc loc;
+
+  ASTList<TopForm> *topFormList;
+  TopForm *topForm;
+
+  ASTList<TermDecl> *termDecls;
+  TermDecl *termDecl;
+  ASTList<TermType> *termTypes;
+  TermType *termType;
+  ASTList<PrecSpec> *precSpecs;
+
+  ASTList<SpecFunc> *specFuncs;
+  SpecFunc *specFunc;
+  ASTList<LocString> *stringList;
+
+  ASTList<ProdDecl> *prodDecls;
+  ProdDecl *prodDecl;
+  ASTList<RHSElt> *rhsList;
+  RHSElt *rhsElt;
+}
+
+%type <num> StartSymbol
+%type <str> Type Action
+
+%type <topFormList> TopFormList
+%type <topForm> TopForm ContextClass Verbatim Option Terminals Nonterminal
+
+%type <termDecls> TermDecls
+%type <termDecl> TerminalDecl
+%type <termTypes> TermTypes
+%type <termType> TermType
+%type <precSpecs> Precedence PrecSpecs
+%type <stringList> NameOrStringList
+%type <str> NameOrString
+
+%type <specFuncs> SpecFuncs
+%type <specFunc> SpecFunc
+%type <stringList> FormalsOpt Formals Subsets
+
+%type <prodDecls> Productions
+%type <prodDecl> Production
+%type <rhsList> RHS
+%type <rhsElt> RHSElt
+
+
+/* ===================== productions ======================= */
+%%
+
+/* The actions in this file simply build an Abstract Syntax Tree (AST)
+ * for later processing. */
+
+
+/* start symbol */
+/* yields: int (dummy value) */
+StartSymbol: TopFormList     
+               { ((ParseParams*)parseParam)->treeTop = new GrammarAST($1); $$=0; }
+           ;
+
+/* yields: ASTList<TopForm> */
+TopFormList: /*empty*/              { $$ = new ASTList<TopForm>; }
+           | TopFormList TopForm    { ($$=$1)->append($2); }
+           ;
+           
+/* yields: TopForm */
+TopForm: ContextClass               { $$ = $1; }
+       | Verbatim                   { $$ = $1; }
+       | Option                     { $$ = $1; }
+       | Terminals                  { $$ = $1; }
+       | Nonterminal                { $$ = $1; }
+       ;
+
+/* yields: TopForm (always TF_context) */
+ContextClass: "context_class" TOK_LIT_CODE ";"
+                { $$ = new TF_context($2); }
+            ;
+
+/* yields: TopForm (always TF_verbatim) */
+Verbatim: "verbatim" TOK_LIT_CODE          { $$ = new TF_verbatim(false, $2); }
+        | "impl_verbatim" TOK_LIT_CODE     { $$ = new TF_verbatim(true, $2); }
+        ;
+
+/* yields: TopForm (always TF_option) */
+/* options without specified values default to a value of 1 */
+Option: "option" TOK_NAME ";"              { $$ = new TF_option($2, 1); }
+      | "option" TOK_NAME TOK_INTEGER ";"  { $$ = new TF_option($2, $3); }
+      ;
+
+
+/* ------ terminals ------ */
+/*
+ * the terminals are the grammar symbols that appear only on the RHS of
+ * forms; they are the output of the lexer; the Terminals list declares
+ * all of the terminals that will appear in the rules
+ */
+/* yields: TopForm (always TF_terminals) */
+Terminals: "terminals" "{" TermDecls TermTypes Precedence "}"
+             { $$ = new TF_terminals($3, $4, $5); }
+         ;
+
+/* yields: ASTList<TermDecl> */
+TermDecls: /* empty */                             { $$ = new ASTList<TermDecl>; }
+         | TermDecls TerminalDecl                  { ($$=$1)->append($2); }
+         ;
+
+/* each terminal has an integer code which is the integer value the
+ * lexer uses to represent that terminal.  it is followed by a
+ * canonical name, and an optional alias; the name/alias appears in
+ * the forms, rather than the integer code itself */
+/* yields: TermDecl */
+TerminalDecl: TOK_INTEGER ":" TOK_NAME ";"
+                { $$ = new TermDecl($1, $3, sameloc($3, "")); }
+            | TOK_INTEGER ":" TOK_NAME TOK_STRING ";"
+                { $$ = new TermDecl($1, $3, $4); }
+            ;
+
+/* yields: LocString */
+Type: TOK_LIT_CODE                    { $$ = $1; }
+    | /* empty */                     { $$ = nolocNULL(); }
+    ;
+
+/* yields: ASTList<TermType> */
+TermTypes: /* empty */                { $$ = new ASTList<TermType>; }
+         | TermTypes TermType         { ($$=$1)->append($2); }
+         ;
+
+/* yields: TermType */
+TermType: "token" Type TOK_NAME ";"
+            { $$ = new TermType($3, $2, new ASTList<SpecFunc>); }
+        | "token" Type TOK_NAME "{" SpecFuncs "}"
+            { $$ = new TermType($3, $2, $5); }
+        ;
+
+/* yields: ASTList<PrecSpec> */
+Precedence: /* empty */                      { $$ = new ASTList<PrecSpec>; }
+          | "precedence" "{" PrecSpecs "}"   { $$ = $3; }
+          ;
+
+/* yields: ASTList<PrecSpec> */
+PrecSpecs: /* empty */
+             { $$ = new ASTList<PrecSpec>; }
+         | PrecSpecs TOK_NAME TOK_INTEGER NameOrStringList ";"
+             { ($$=$1)->append(new PrecSpec(whichKind($2), $3, $4)); }
+         ;
+
+/* yields: ASTList<LocString> */
+NameOrStringList: /* empty */                     { $$ = new ASTList<LocString>; }
+                | NameOrStringList NameOrString   { ($$=$1)->append($2); }
+                ;
+
+/* yields: LocString */
+NameOrString: TOK_NAME       { $$ = $1; }
+            | TOK_STRING     { $$ = $1; }
+            ;
+
+
+/* ------ specification functions ------ */
+/* yields: ASTList<SpecFunc> */
+SpecFuncs: /* empty */                { $$ = new ASTList<SpecFunc>; }
+         | SpecFuncs SpecFunc         { ($$=$1)->append($2); }
+         ;
+
+/* yields: SpecFunc */
+SpecFunc: TOK_FUN TOK_NAME "(" FormalsOpt ")" TOK_LIT_CODE
+            { $$ = new SpecFunc($2, $4, $6); }
+        ;
+
+/* yields: ASTList<LocString> */
+FormalsOpt: /* empty */               { $$ = new ASTList<LocString>; }
+          | Formals                   { $$ = $1; }
+          ;
+
+/* yields: ASTList<LocString> */
+Formals: TOK_NAME                     { $$ = new ASTList<LocString>($1); }
+       | Formals "," TOK_NAME         { ($$=$1)->append($3); }
+       ;
+
+
+/* ------ nonterminals ------ */
+/*
+ * a nonterminal is a grammar symbol that appears on the LHS of forms;
+ * the body of the Nonterminal declaration specifies the the RHS forms,
+ * attribute info, etc.
+ */
+/* yields: TopForm (always TF_nonterm) */
+Nonterminal: "nonterm" Type TOK_NAME Production
+               { $$ = new TF_nonterm($3, $2, new ASTList<SpecFunc>,
+                                     new ASTList<ProdDecl>($4), NULL); }
+           | "nonterm" Type TOK_NAME "{" SpecFuncs Productions Subsets "}"
+               { $$ = new TF_nonterm($3, $2, $5, $6, $7); }
+           ;
+
+/* yields: ASTList<ProdDecl> */
+Productions: /* empty */                   { $$ = new ASTList<ProdDecl>; }
+           | Productions Production        { ($$=$1)->append($2); }
+           ;
+
+/* yields: ProdDecl */
+Production: TOK_ARROW RHS Action                { $$ = new ProdDecl($1, PDK_NEW, $2, $3); }
+          | "replace" TOK_ARROW RHS Action      { $$ = new ProdDecl($2, PDK_REPLACE,$3, $4); }
+          | "delete" TOK_ARROW RHS ";"          { $$ = new ProdDecl($2, PDK_DELETE, $3, nolocNULL()); }
+          ;
+
+/* yields: LocString */
+Action: TOK_LIT_CODE                       { $$ = $1; }
+      | ";"                                { $$ = nolocNULL(); }
+      ;
+
+/* yields: ASTList<RHSElt> */
+RHS: /* empty */                           { $$ = new ASTList<RHSElt>; }
+   | RHS RHSElt                            { ($$=$1)->append($2); }
+   ;
+
+/*
+ * each element on the RHS of a form can have a tag, which appears before a
+ * colon (':') if present; the tag is required if that symbol's attributes
+ * are to be referenced anywhere in the actions or conditions for the form
+ */
+/* yields: RHSElt */
+RHSElt: TOK_NAME                { $$ = new RH_name(sameloc($1, ""), $1); }
+      | TOK_NAME ":" TOK_NAME   { $$ = new RH_name($1, $3); }
+      | TOK_STRING              { $$ = new RH_string(sameloc($1, ""), $1); }
+      | TOK_NAME ":" TOK_STRING { $$ = new RH_string($1, $3); }
+      | "precedence" "(" NameOrString ")"    { $$ = new RH_prec($3); }
+      | "forbid_next" "(" NameOrString ")"   { $$ = new RH_forbid($3); }
+      ;
+        
+/* yields: ASTList<LocString> */
+Subsets: /*empty*/                  { $$ = NULL; }
+       | "subsets" Formals ";"      { $$ = $2; }
+       ;
+
+
+%%
+/* ------------------ extra C code ------------------ */
+AssocKind whichKind(LocString * /*owner*/ kind)
+{ 
+  // delete 'kind' however we exit
+  Owner<LocString> killer(kind);
+  
+  #define CHECK(syntax, value)   \
+    if (kind->equals(syntax)) {  \
+      return value;              \
+    }
+  CHECK("left", AK_LEFT);
+  CHECK("right", AK_RIGHT);
+  CHECK("nonassoc", AK_NONASSOC);
+  CHECK("prec", AK_NEVERASSOC);
+  CHECK("assoc_split", AK_SPLIT);
+  #undef CHECK
+
+  xbase(stringc << kind->locString()
+                << ": invalid associativity kind: " << *kind);
+}

Added: vendor/elsa/current/elkhound/in/L1.in1
===================================================================
--- vendor/elsa/current/elkhound/in/L1.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/L1.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+  // ---- symbol access ----
+  #define SYMBOL_ACCESS(Thing)                              \
+    /* retrieve, return NULL if not there */                \
+    Thing const *find##Thing##C(char const *name) const;    \
+    Thing *find##Thing(char const *name)                    \
+      { return const_cast<Thing*>(find##Thing##C(name)); }  \
+                                                            \
+    /* retrieve, or create it if not already there */       \
+    Thing *getOrMake##Thing(char const *name);
+
+  SYMBOL_ACCESS(Symbol)        // findSymbolC, findSymbol, getOrMakeSymbol
+  SYMBOL_ACCESS(Terminal)      //   likewise
+  SYMBOL_ACCESS(Nonterminal)   //   ..
+  #undef SYMBOL_ACCESS
+
+  // the inverse of transition: map a target state to the symbol that
+  // would transition to that state (from the given source state)
+  Symbol const *inverseTransitionC(ItemSet const *source,
+                                   ItemSet const *target) const;

Added: vendor/elsa/current/elkhound/in/asu419.in
===================================================================
--- vendor/elsa/current/elkhound/in/asu419.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/asu419.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+id
+id + id
+id * id
+id + id * id
+id * id + id
+( id + id ) * id
+id + id + id
+id + ( id + id )

Added: vendor/elsa/current/elkhound/in/bb10.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb10.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb10.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b+b+b+b+b+b+b+b+b+b+b;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb100.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb100.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb100.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      ;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb1000.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb1000.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb1000.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,121 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 1
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 2
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 3
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 4
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 5
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 6
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 7
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 8
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 9
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b    // 10
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      ;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb12.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb12.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb12.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb12.c
+// "construction of efficient generalized lr parsers": i == 12
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b+b+b+b+b+b +b+b;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb14.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb14.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb14.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb14.c
+// "construction of efficient generalized lr parsers": i == 14
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b+b+b+b+b+b +b+b +b+b;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb16.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb16.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb16.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb16.c
+// "construction of efficient generalized lr parsers": i == 16
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b+b+b+b+b+b +b+b +b+b +b+b;
+
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb18.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb18.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb18.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb18.c
+// "construction of efficient generalized lr parsers": i == 18
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b+b+b+b+b+b +b+b +b+b +b+b +b+b;
+
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb20.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb20.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb20.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      ;
+
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb200.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb200.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb200.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      ;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb300.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb300.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb300.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      ;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb400.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb400.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb400.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      ;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb5.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb5.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb5.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb5.c
+// "construction of efficient generalized lr parsers": i == 5
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b;
+
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb50.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb50.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb50.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      ;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb500.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb500.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb500.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,66 @@
+// bb10.c
+// "construction of efficient generalized lr parsers": i == 10
+
+int main()
+{
+  int a, b;
+  
+  a = b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      +b+b+b+b+b+b+b+b+b+b
+      ;
+  
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb6.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb6.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb6.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb6.c
+// "construction of efficient generalized lr parsers": i == 6
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b +b;
+
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb7.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb7.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb7.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb7.c
+// "construction of efficient generalized lr parsers": i == 7
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b +b+b;
+
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb8.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb8.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb8.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb8.c
+// "construction of efficient generalized lr parsers": i == 8
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b+b+b+b;
+
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bb9.c
===================================================================
--- vendor/elsa/current/elkhound/in/bb9.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bb9.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// bb9.c
+// "construction of efficient generalized lr parsers": i == 9
+
+int main()
+{
+  int a, b;
+
+  a = b+b+b+b+b+b+b+b+b+b;
+
+  return a;
+}

Added: vendor/elsa/current/elkhound/in/bsort.c.in4
===================================================================
--- vendor/elsa/current/elkhound/in/bsort.c.in4	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/bsort.c.in4	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+#/* bsort.c (translated to C) */
+#/* sample functionality + driver */
+#
+##include <stdio.h>           /* printf */
+##include <stdlib.h>          /* rand() */
+
+
+#/* --------------- FUNCTIONALITY --------------------------- */
+#/* sort the array into ascending order */
+void foo ( int * a , int b )
+{
+  int x , y ;
+
+  for ( x = 2 ; x <= b ; x ++ ) { 	       
+    for ( y = x - 1 ; y >= 1 ; y -- ) {       
+      
+      if ( a [ y - 1 ]  >  a [ y ] ) {     
+        
+        int z = a [ y ] ;	       
+        a [ y ] = a [ y - 1 ] ;
+        a [ y - 1 ] = z ;
+      }
+    }
+  }
+}
+
+
+void f ( int * a , int b )
+{
+  foo ( a , b ) ;
+}
+
+$

Added: vendor/elsa/current/elkhound/in/castprob.in1
===================================================================
--- vendor/elsa/current/elkhound/in/castprob.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/castprob.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+( x ) ( x )

Added: vendor/elsa/current/elkhound/in/castprob.in2
===================================================================
--- vendor/elsa/current/elkhound/in/castprob.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/castprob.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+( x ) ( x ) ( x )

Added: vendor/elsa/current/elkhound/in/cc.in1
===================================================================
--- vendor/elsa/current/elkhound/in/cc.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cc.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,80 @@
+// cc.in1
+// testing various constructs in c++ parser
+
+class Foo;
+
+int foo()
+{
+  int a = B::c;
+  a = ::d;
+  a = e;
+  
+  Foo f;
+  f.~Foo();
+  
+  int *p = new int;
+  p = new int(5);
+  p = new int[6];
+  delete[] p;
+  delete p;
+  
+  (a.*b)();
+  (a->*b)();
+  
+  throw up;
+
+  try {
+    fizzle();
+  }
+  catch (int) {
+    frazzle();
+  }
+  catch (float f) {
+    floozy();
+  }
+  catch (...) {
+    armageddon();
+  }
+}
+
+class Foo {
+  virtual int slam();
+};
+
+class Bar : public Foo {
+  friend float kazam(int y);
+
+  Bar& operator = (Bar const &obj);
+
+public:
+  explicit Bar(int y);
+
+  operator int () const;
+  
+  mutable int x;
+};
+
+Bar::Bar()
+  : x(5)
+{
+  printf("hi\n");
+}
+
+
+int foobar()
+{
+  // ambiguous at the moment
+  //List<Apple> apples;
+}
+
+
+int x;
+char y;
+float z;
+
+
+  // ptr to a function; isFunction = 0
+  int (*ptrToFn)(int);
+
+  // function that returns a pointer to a fn; isFunction = 1
+  int (*  fn(char)  )(int);

Added: vendor/elsa/current/elkhound/in/cc.in2
===================================================================
--- vendor/elsa/current/elkhound/in/cc.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cc.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,87 @@
+// cond.cc
+// code for cond.h
+
+#include "cond.h"      // this module
+#include "trace.h"     // trace
+#include "glrtree.h"   // AttrContext
+#include "util.h"      // TVAL
+#include "exc.h"       // xBase
+
+
+// ----------------------- Condition --------------------
+Condition::~Condition()
+{}
+
+
+// --------------------- ExprCondition ---------------------
+ExprCondition::~ExprCondition()
+{
+  delete expr;
+}
+
+
+bool ExprCondition::test(AttrContext const &actx) const
+{
+  int val = expr->eval(actx);
+  if (val != 0 && val != 1) {
+    xfailure(stringb("ExprCondition value must be 0 or 1 (was: " << val << ")"));
+  }
+
+  return val==1;
+}
+
+
+string ExprCondition::toString(Production const *prod) const
+{
+  return expr->toString(prod);
+}
+
+
+// -------------------- Conditions -------------------------
+Conditions::Conditions()
+{}
+
+Conditions::~Conditions()
+{}
+
+
+bool Conditions::test(AttrContext const &actx) const
+{
+  FOREACH_OBJLIST(Condition, conditions, iter) {
+    try {
+      if (!iter.data()->test(actx)) {
+	trace("conditions") 
+	  << "condition " << iter.data()->toString(actx.reductionC().production)
+	  << " not satisfied\n";
+	return false;
+      }
+    }
+    catch (xBase &x) {
+      cout << "condition " << iter.data()->toString(actx.reductionC().production)
+           << " failed with exception: " << x << endl;
+      return false;
+    }
+  }
+  return true;
+}
+
+
+string Conditions::toString(Production const *prod) const
+{
+  stringBuilder sb;
+  FOREACH_OBJLIST(Condition, conditions, iter) {
+    sb << "  %condition { " << iter.data()->toString(prod) << " }\n";
+  }
+  return sb;
+}
+
+
+void Conditions::parse(Production const *prod, char const *conditionText)
+{
+  TVAL(conditionText);
+
+  // it's just an expression
+  AExprNode *expr = parseAExpr(prod, conditionText);    // (owner)
+
+  conditions.append(new ExprCondition(transferOwnership(expr)));
+}

Added: vendor/elsa/current/elkhound/in/cc.in3
===================================================================
--- vendor/elsa/current/elkhound/in/cc.in3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cc.in3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// cc.in3
+// pathological case testing precedence of "::"
+
+mytype ::foo () {}

Added: vendor/elsa/current/elkhound/in/cc.in4
===================================================================
--- vendor/elsa/current/elkhound/in/cc.in4	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cc.in4	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,500 @@
+// grammar.h
+// representation and algorithms for context-free grammars
+
+// Author: Scott McPeak, April 2000
+
+// Unfortunately, representation and algorithm tend to get
+// mixed together.  Separating them entirely is possible,
+// but syntactically inconvenient.  So, instead, I try to
+// document the separation in comments.  Specifically,
+// sections beginning with ---- representation ---- are data
+// for representation of the underlying concept, while
+// sections with ---- annotation ---- are data created by
+// algorithms manipulating the data.
+
+// Another measure is I've split all grammar-wide algorithm
+// stuff into GrammarAnalysis (gramanl.h).  Things should
+// only be put into Grammar if they are directly related
+// to the grammar representation.  (However, constitutent
+// objects like Production will continue to be a mix.)
+
+#ifndef __GRAMMAR_H
+#define __GRAMMAR_H
+
+#include <iostream.h>  // ostream
+
+#include "str.h"       // string
+#include "objlist.h"   // ObjList
+#include "sobjlist.h"  // SObjList
+#include "util.h"      // OSTREAM_OPERATOR, INTLOOP
+#include "action.h"    // Actions
+#include "cond.h"      // Conditions
+
+class StrtokParse;     // strtokp.h
+
+// fwds defined below
+class Symbol;
+class Terminal;
+class Nonterminal;
+class Production;
+class DottedProduction;
+class Grammar;
+
+
+// ---------------- Symbol --------------------
+// either a nonterminal or terminal symbol
+class Symbol {
+// ------ representation ------
+public:
+  string const name;        // symbol's name in grammar
+  bool const isTerm;        // true: terminal (only on right-hand sides of productions)
+                            // false: nonterminal (can appear on left-hand sides)
+  bool isEmptyString;       // true only for the emptyString nonterminal
+
+public:
+  Symbol(char const *n, bool t)
+    : name(n), isTerm(t), isEmptyString(false) {}
+  virtual ~Symbol();
+
+  // uniform selectors
+  bool isTerminal() const { return isTerm; }
+  bool isNonterminal() const { return !isTerm; }
+
+  // casting
+  Terminal const &asTerminalC() const;       // checks 'isTerminal' for cast safety
+  Terminal &asTerminal()
+    { return const_cast<Terminal&>(asTerminalC()); }
+
+  Nonterminal const &asNonterminalC() const;
+  Nonterminal &asNonterminal()
+    { return const_cast<Nonterminal&>(asNonterminalC()); }
+
+  // debugging
+  virtual void print(ostream &os) const;
+  OSTREAM_OPERATOR(Symbol);
+    // print as '$name: isTerminal=$isTerminal' (no newline)
+};
+
+// I have several needs for serf lists of symbols, so let's use this for now
+typedef SObjList<Symbol> SymbolList;
+typedef SObjListIter<Symbol> SymbolListIter;
+typedef SObjListMutator<Symbol> SymbolListMutator;
+
+#define FOREACH_SYMBOL(list, iter) FOREACH_OBJLIST(Symbol, list, iter)
+#define MUTATE_EACH_SYMBOL(list, iter) MUTATE_EACH_OBJLIST(Symbol, list, iter)
+#define SFOREACH_SYMBOL(list, iter) SFOREACH_OBJLIST(Symbol, list, iter)
+#define SMUTATE_EACH_SYMBOL(list, iter) SMUTATE_EACH_OBJLIST(Symbol, list, iter)
+
+// format: "s1 s2 s3"
+string symbolSequenceToString(SymbolList const &list);
+
+
+// ---------------- Terminal --------------------
+// something that only appears on the right-hand side of
+// productions, and is an element of the source language
+// NOTE:  This is really a terminal *class*, in that it's possible
+// for several different tokens to be classified into the same
+// terminal class (e.g. "foo" and "bar" are both identifiers)
+class Terminal : public Symbol {
+// ------ annotation ------
+public:     // data
+  // terminal class index - this terminal's id; -1 means unassigned
+  int termIndex;
+
+  // whereas 'name' is the canonical name for the terminal class,
+  // this field is an alias; for example, if the canonical name is
+  // L2_EQUALEQUAL, the alias might be "==" (i.e. the alias
+  // should include quotes if the grammar should have them too);
+  // if the alias's is NULL or "", there is no alias
+  string alias;
+
+public:     // funcs
+  Terminal(char const *name)        // canonical name for terminal class
+    : Symbol(name, true /*terminal*/),
+      termIndex(-1),
+      alias(NULL) {}
+
+  virtual void print(ostream &os) const;
+  OSTREAM_OPERATOR(Terminal);
+                          
+  // return alias if defined, name otherwise
+  string toString() const;
+};
+
+typedef SObjList<Terminal> TerminalList;
+typedef SObjListIter<Terminal> TerminalListIter;
+
+#define FOREACH_TERMINAL(list, iter) FOREACH_OBJLIST(Terminal, list, iter)
+#define MUTATE_EACH_TERMINAL(list, iter) MUTATE_EACH_OBJLIST(Terminal, list, iter)
+#define SFOREACH_TERMINAL(list, iter) SFOREACH_OBJLIST(Terminal, list, iter)
+#define SMUTATE_EACH_TERMINAL(list, iter) SMUTATE_EACH_OBJLIST(Terminal, list, iter)
+
+// casting aggregates
+inline ObjList<Symbol> const &toObjList(ObjList<Terminal> const &list)
+  { return reinterpret_cast< ObjList<Symbol>const& >(list); }
+
+// format: "t1 t2 t3"
+string terminalSequenceToString(TerminalList const &list);
+
+
+// ---------------- Nonterminal --------------------
+// something that can appear on the left-hand side of a production
+// (or, emptyString, since we classify that as a nonterminal also)
+class Nonterminal : public Symbol {
+// ------ annotation ------
+public:     // funcs
+  int ntIndex;           // nonterminal index; see Grammar::computeWhatCanDeriveWhat
+  bool cyclic;           // true if this can derive itself in 1 or more steps
+  TerminalList first;    // set of terminals that can be start of a string derived from 'this'
+  TerminalList follow;   // set of terminals that can follow a string derived from 'this'
+
+public:     // funcs
+  Nonterminal(char const *name);
+  virtual ~Nonterminal();
+
+  virtual void print(ostream &os) const;
+  OSTREAM_OPERATOR(Nonterminal);
+};
+
+typedef SObjList<Nonterminal> NonterminalList;
+typedef SObjListIter<Nonterminal> NonterminalListIter;
+
+#define FOREACH_NONTERMINAL(list, iter) FOREACH_OBJLIST(Nonterminal, list, iter)
+#define MUTATE_EACH_NONTERMINAL(list, iter) MUTATE_EACH_OBJLIST(Nonterminal, list, iter)
+#define SFOREACH_NONTERMINAL(list, iter) SFOREACH_OBJLIST(Nonterminal, list, iter)
+#define SMUTATE_EACH_NONTERMINAL(list, iter) SMUTATE_EACH_OBJLIST(Nonterminal, list, iter)
+
+// casting aggregates
+inline ObjList<Symbol> const &toObjList(ObjList<Nonterminal> const &list)
+  { return reinterpret_cast< ObjList<Symbol>const& >(list); }
+
+
+// ---------------- Production --------------------
+// a rewrite rule
+class Production {
+// ------ representation ------
+public:	    // data
+  // fundamental context-free grammar (CFG) component
+  Nonterminal * const left;     // (serf) left hand side; must be nonterminal
+  SymbolList right;             // (serf) right hand side; terminals & nonterminals
+
+  // tags applied to the symbols for purposes of unambiguous naming in
+  // actions, and for self-commenting value as role indicators; an
+  // empty tag (NULL or "") is allowed and means there is no tag
+  string leftTag;      	       	// tag for LHS symbol
+  ObjList<string> rightTags;    // tag for each RHS symbol, in order
+
+  // NOTE: 'right' and 'rightTags' should always have the same number of
+  // elements.  they are public to avoid syntactic (and possible runtime,
+  // if repr. changes) overhead of access via member fn.  use 'append' to
+  // add new elements.
+
+  // extras
+  Conditions conditions;       	// every condition must be satisfied for a rule to be used
+  Actions actions;              // when used, a rule has these effects
+
+public:	    // funcs
+  Production(Nonterminal *left, char const *leftTag);
+  ~Production();
+
+  // length *not* including emptySymbol, if present
+  // UPDATE: I'm now disallowing emptySymbol from ever appearing in 'right'
+  int rhsLength() const;
+
+  // number of nonterminals on RHS
+  int numRHSNonterminals() const;
+
+  // append a RHS symbol
+  void append(Symbol *sym, char const *tag);
+
+  // call this when production is built, so it can compute dprods
+  void finished();
+
+  // find a symbol by name and tag (tag can be NULL); returns 0 to
+  // identify LHS symbol, 1 for first RHS symbol, 2 for second, etc.;
+  // returns -1 if the name/tag doesn't match anything
+  int findTaggedSymbol(char const *name, char const *tag) const;
+
+  // given an index as returned by 'findTaggedSymbol', translate that
+  // back into a string consisting of name and optional tag
+  string taggedSymbolName(int symbolIndex) const;
+
+  // retrieve an item
+  DottedProduction const *getDProdC(int dotPlace) const;
+  DottedProduction *getDProd(int dotPlace)
+    { return const_cast<DottedProduction*>(getDProdC(dotPlace)); }
+
+  // print 'A -> B c D' (no newline)
+  string toString() const;
+  string rhsString() const;       // 'B c D' for above example rule
+  void print(ostream &os) const;
+  OSTREAM_OPERATOR(Production);
+
+  // print entire input syntax, with newlines, e.g.
+  //   A -> B c D
+  //     %action { A.x = B.x }
+  //     %condition { B.y > D.y }
+  string toStringWithActions() const;
+
+// ------ annotation ------
+private:    // data
+  int numDotPlaces;             // after finished(): equals rhsLength()+1
+  DottedProduction *dprods;     // (owner) array of dotted productions
+};
+
+typedef SObjList<Production> ProductionList;
+typedef SObjListIter<Production> ProductionListIter;
+
+#define FOREACH_PRODUCTION(list, iter) FOREACH_OBJLIST(Production, list, iter)
+#define MUTATE_EACH_PRODUCTION(list, iter) MUTATE_EACH_OBJLIST(Production, list, iter)
+#define SFOREACH_PRODUCTION(list, iter) SFOREACH_OBJLIST(Production, list, iter)
+#define SMUTATE_EACH_PRODUCTION(list, iter) SMUTATE_EACH_OBJLIST(Production, list, iter)
+
+
+// ---------------- DottedProduction --------------------
+// a production, with an indicator that says how much of this
+// production has been matched by some part of the input string
+// (exactly which part of the input depends on where this appears
+// in the algorithm's data structures)
+class DottedProduction {
+// ------ representation ------
+public:	    // data
+  Production * const prod;       // (serf) the base production
+  int const dot;                 // 0 means it's before all RHS symbols, 1 means after first, etc.
+  bool const dotAtEnd;           // performance optimization
+
+public:	    // funcs
+  DottedProduction()       // for later filling-in
+    : prod(NULL), dot(-1), dotAtEnd(false) {}
+  DottedProduction(Production *p, int d)
+    : prod(NULL), dot(-1), dotAtEnd(false)     // silence warning about const init
+    { setProdAndDot(p, d); }
+
+  bool isDotAtStart() const { return dot==0; }
+  bool isDotAtEnd() const { return dotAtEnd; }
+
+  // call this to change prod and dot; don't change them directly
+  // (I didn't make them private because of the syntactic hassle
+  // of accessing them.  Instead I hacked them as 'const'.)
+  void setProdAndDot(Production *p, int d) /*mutable*/;
+
+  // dot must not be at the start (left edge)
+  Symbol const *symbolBeforeDotC() const;
+  Symbol *symbolBeforeDot() { return const_cast<Symbol*>(symbolBeforeDotC()); }
+
+  // dot must not be at the end (right edge)
+  Symbol const *symbolAfterDotC() const;
+  Symbol *symbolAfterDot() { return const_cast<Symbol*>(symbolAfterDotC()); }
+
+  // print to cout as 'A -> B . c D' (no newline)
+  void print(ostream &os) const;
+  OSTREAM_OPERATOR(DottedProduction);
+};
+
+// (serf) lists of dotted productions
+typedef SObjList<DottedProduction> DProductionList;
+typedef SObjListIter<DottedProduction> DProductionListIter;
+
+#define FOREACH_DOTTEDPRODUCTION(list, iter) FOREACH_OBJLIST(DottedProduction, list, iter)
+#define MUTATE_EACH_DOTTEDPRODUCTION(list, iter) MUTATE_EACH_OBJLIST(DottedProduction, list, iter)
+#define SFOREACH_DOTTEDPRODUCTION(list, iter) SFOREACH_OBJLIST(DottedProduction, list, iter)
+#define SMUTATE_EACH_DOTTEDPRODUCTION(list, iter) SMUTATE_EACH_OBJLIST(DottedProduction, list, iter)
+
+
+// ---------------- ItemSet -------------------
+// a set of dotted productions, and the transitions between
+// item sets, as in LR(0) set-of-items construction
+class ItemSet {
+private:    // data
+  // kernel items: the items that define the set; except for
+  // the special case of the initial item in the initial state,
+  // the kernel items are distinguished by having the dot *not*
+  // at the left edge
+  DProductionList kernelItems;
+
+  // nonkernel items: those derived as the closure of the kernel
+  // items by expanding symbols to the right of dots; here I am
+  // making the choice to materialize them, rather than derive
+  // them on the spot as needed (and may change this decision)
+  DProductionList nonkernelItems;
+
+  // transition function (where we go on shifts)
+  //   Map : (Terminal id or Nonterminal id)  -> ItemSet*
+  ItemSet **termTransition;		     // (owner ptr to array of serf ptrs)
+  ItemSet **nontermTransition;		     // (owner ptr to array of serf ptrs)
+
+  // bounds for above
+  int terms;
+  int nonterms;
+
+  // profiler reports I'm spending significant time rifling through
+  // the items looking for those that have the dot at the end; so this
+  // array will point to all such items
+  DottedProduction const **dotsAtEnd;        // (owner ptr to array of serf ptrs)
+  int numDotsAtEnd;                          // number of elements in 'dotsAtEnd'
+  
+  // profiler also reports I'm still spending time comparing item sets; this
+  // stores a CRC of the numerically sorted kernel item pointer addresses,
+  // concatenated into a buffer of sufficient size
+  unsigned long kernelItemsCRC;
+
+public:	    // data
+  // numerical state id, should be unique among item sets
+  // in a particular grammar's sets
+  int id;
+
+  // it's useful to have a BFS tree superimposed on the transition
+  // graph; for example, it makes it easy to generate sample inputs
+  // for each state.  so we store the parent pointer; we can derive
+  // child pointers by looking at all outgoing transitions, and
+  // filtering for those whose targets' parent pointers equal 'this'.
+  // the start state's parent is NULL, since it is the root of the
+  // BFS tree
+  ItemSet *BFSparent;                        // (serf)
+
+private:    // funcs
+  int bcheckTerm(int index);
+  int bcheckNonterm(int index);
+  ItemSet *&refTransition(Symbol const *sym);
+                      
+  // computes things derived from the item set lists
+  void changedItems();
+
+public:     // funcs
+  ItemSet(int id, int numTerms, int numNonterms);
+  ~ItemSet();
+
+  // ---- item queries ----
+  // the set of items names a symbol as the symbol used
+  // to reach this state -- namely, the symbol that appears
+  // to the left of a dot.  this fn retrieves that symbol
+  // (if all items have dots at left edge, returns NULL; this
+  // would be true only for the initial state)
+  Symbol const *getStateSymbolC() const;
+
+  // equality is defined as having the same items (basic set equality)
+  bool operator== (ItemSet const &obj) const;
+
+  // sometimes it's convenient to have all items mixed together
+  // (CONSTNESS: allows modification of items...)
+  void getAllItems(DProductionList &dest) const;
+
+  // ---- transition queries ----
+  // query transition fn for an arbitrary symbol; returns
+  // NULL if no transition is defined
+  ItemSet const *transitionC(Symbol const *sym) const;
+  ItemSet *transition(Symbol const *sym)
+    { return const_cast<ItemSet*>(transitionC(sym)); }
+
+  // get the list of productions that are ready to reduce, given
+  // that the next input symbol is 'lookahead' (i.e. in the follow
+  // of a production's LHS); parsing=true means we are actually
+  // parsing input, so certain tracing output is appropriate
+  void getPossibleReductions(ProductionList &reductions,
+                             Terminal const *lookahead,
+                             bool parsing) const;
+
+  // ---- item mutations ----
+  // add a kernel item; used while constructing the state
+  void addKernelItem(DottedProduction *item);
+
+  // add a nonkernel item; used while computing closure; this
+  // item must not already be in the item set
+  void addNonkernelItem(DottedProduction *item);
+
+  // ---- transition mutations ----
+  // set transition on 'sym' to be 'dest'
+  void setTransition(Symbol const *sym, ItemSet *dest);
+
+  // ---- debugging ----
+  void writeGraph(ostream &os) const;
+  void print(ostream &os) const;
+  OSTREAM_OPERATOR(ItemSet);
+};
+
+
+// ---------------- Grammar --------------------
+// represent a grammar: nonterminals, terminals, productions, and start-symbol
+class Grammar {
+// ------ representation ------
+public:	    // data
+  ObjList<Nonterminal> nonterminals;    // (owner list)
+  ObjList<Terminal> terminals;          // (owner list)
+  ObjList<Production> productions;      // (owner list)
+  Nonterminal *startSymbol;             // (serf) a particular nonterminal
+
+  // the special terminal for the empty string; does not appear in the
+  // list of nonterminals or terminals for a grammar, but can be
+  // referenced by productions, etc.; the decision to explicitly have
+  // such a symbol, instead of letting it always be implicit, is
+  // motivated by things like the derivability relation, where it's
+  // nice to treat empty like any other symbol
+  Nonterminal emptyString;
+
+private:    // funcs
+  bool parseAnAction(char const *keyword, char const *insideBraces,
+                     Production *lastProduction);
+
+  bool declareToken(char const *symbolName, int code, char const *alias);
+
+public:     // funcs
+  Grammar();                            // set everything manually
+  ~Grammar();
+
+  // simple queries
+  int numTerminals() const;
+  int numNonterminals() const;
+
+
+  // ---- building a grammar ----
+  // add a new production; the rhs arg list must be terminated with a NULL
+  void addProduction(Nonterminal *lhs, Symbol *rhs, ...);
+
+  // add a pre-constructed production
+  void addProduction(Production *prod);
+
+  // print the current list of productions
+  void printProductions(ostream &os) const;
+
+  // ---- whole-grammar stuff ----
+  // after adding all rules, check that all nonterminals have
+  // at least one rule
+  void checkWellFormed() const;
+
+  // output grammar in Bison's syntax
+  // (coincidentally, when bison dumps its table with '-v', its table
+  // dump syntax is identical to my (current) input syntax!)
+  void printAsBison(ostream &os) const;
+
+  // ---- grammar parsing ----
+  void readFile(char const *fname);
+
+  // parse a line like "LHS -> R1 R2 R3", return false on parse error
+  bool parseLine(char const *grammarLine);
+  bool parseLine(char const *preLine, SObjList<Production> &lastProductions);
+
+
+  // ---- symbol access ----
+  #define SYMBOL_ACCESS(Thing)                              \
+    /* retrieve, return NULL if not there */                \
+    Thing const *find##Thing##C(char const *name) const;    \
+    Thing *find##Thing(char const *name)                    \
+      { return const_cast<Thing*>(find##Thing##C(name)); }  \
+                                                            \
+    /* retrieve, or create it if not already there */       \
+    Thing *getOrMake##Thing(char const *name) /* user ; */
+
+  SYMBOL_ACCESS(Symbol);       // findSymbolC, findSymbol, getOrMakeSymbol
+  SYMBOL_ACCESS(Terminal);     //   likewise
+  SYMBOL_ACCESS(Nonterminal);  //   ..
+  #undef SYMBOL_ACCESS
+
+  // the inverse of transition: map a target state to the symbol that
+  // would transition to that state (from the given source state)
+  Symbol const *inverseTransitionC(ItemSet const *source,
+                                   ItemSet const *target) const;
+};
+
+
+#endif // __GRAMMAR_H
+

Added: vendor/elsa/current/elkhound/in/cc.in5
===================================================================
--- vendor/elsa/current/elkhound/in/cc.in5	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cc.in5	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1032 @@
+// glr.cc
+// code for glr.h
+
+/* Implementation Notes
+ *
+ * A design point: [GLR] uses more 'global's than I do.  My criteria
+ * here is that something should be global (stored in class GLR) if
+ * it has meaning between processing of tokens.  If something is only
+ * used during the processing of a single token, then I make it a
+ * parameter where necessary.
+ *
+ * Update: I've decided to make 'currentToken' and 'parserWorklist'
+ * global because they are needed deep inside of 'glrShiftNonterminal',
+ * though they are not needed by the intervening levels, and their
+ * presence in the argument lists would therefore only clutter them.
+ *
+ * It should be clear that many factors contribute to this
+ * implementation being slow, and I'm going to refrain from any
+ * optimization for a bit.
+ *
+ * Description of the various lists in play here:
+ *
+ *   activeParsers
+ *   -------------
+ *   The active parsers are at the frontier of the parse tree
+ *   space.  It *never* contains more than one stack node with
+ *   a given parse state; I call this the unique-state property
+ *   (USP).  If we're about to add a stack node with the same
+ *   state as an existing node, we merge them (if it's a shift,
+ *   we add another leftAdjState; if it's a reduction, we add a
+ *   rule node *and* another leftAdjState).
+ *
+ *   Before a token is processed, activeParsers contains those
+ *   parsers that successfully shifted the previous token.  This
+ *   list is then copied to the parserWorklist (described below).
+ *
+ *   As reductions are processed, new parsers are generated and
+ *   added to activeParsers (modulo USP).
+ *
+ *   Before the accumulated shifts are processed, the activeParsers
+ *   list is cleared.  As each shift is processed, the resulting
+ *   parser is added to activeParsers (modulo USP).
+ *
+ *   [GLR] calls this "active-parsers"
+ *
+ *
+ *   parserWorklist
+ *   --------------
+ *   The worklist contains all parsers we have not yet been considered
+ *   for advancement (shifting or reducing).  Initially, it is the
+ *   same as the activeParsers, but we take a parser from it on
+ *   each iteration of the inner loop in 'glrParse'.
+ *
+ *   Whenever, during processing of reductions, we add a parser to
+ *   activeParsers, we also add it to parserWorklist.  This ensures
+ *   the just-reduced parser gets a chance to reduce or shift.
+ *
+ *   [GLR] calls this "for-actor"
+ *
+ *
+ *   pendingShifts
+ *   -------------
+ *   The GLR parser alternates between reducing and shifting.
+ *   During the processing of a given token, shifting happens last.
+ *   This keeps the parsers synchronized, since every token is
+ *   shifted by every parser at the same time.  This synchronization
+ *   is important because it makes merging parsers possible.
+ *
+ *   [GLR] calls this "for-shifter"
+ *
+ * 
+ * Discussion of path re-examination, called do-limited-reductions by
+ * [GLR]:
+ *
+ * After thinking about this for some time, I have reached the conclusion
+ * that the only way to handle the above problem is to separate the
+ * collection of paths from the iteration over them.
+ *
+ * Here are several alternative schemes, and the reasons they don't
+ * work:
+ *
+ *   1. [GLR]'s approach of limiting re-examination to those involving
+ *      the new link
+ *
+ *      This fails because it does not prevent re-examined paths
+ *      from appearing in the normal iteration also.
+ *
+ *   2. Modify [GLR] so the new link can't be used after the re-examination
+ *      is complete
+ *
+ *      Then if *another* new link is added, paths involving both new
+ *      links wouldn't be processed.
+ *
+ *   3. Further schemes involving controlling which re-examination stage can
+ *      use which links
+ *
+ *      Difficult to reason about, unclear a correct scheme exists, short
+ *      of the full-blown path-listing approach I'm going to take.
+ *
+ *   4. My first "fix" which assumes there is never more than one path to
+ *      a given parser
+ *
+ *      This is WRONG.  There can be more than one path, even as all such
+ *      paths are labelled the same (namely, with the RHS symbols).  Consider
+ *      grammar "E -> x | E + E" parsing "x+x+x": both toplevel parses use
+ *      the "E -> E + E" rule, and both arrive at the root parser
+ *
+ * So, the solution I will implement is to collect all paths into a list
+ * before processing any of them.  During path re-examination, I also will
+ * collect paths into a list, this time only those that involve the new
+ * link.
+ *
+ * This scheme is clearly correct, since path collection cannot be disrupted
+ * by the process of adding links, and when links are added, exactly the new
+ * paths are collected and processed.  It's easy to see that every path is
+ * considered exactly once.
+ */
+
+
+#include "glr.h"         // this module
+#include "strtokp.h"     // StrtokParse
+#include "syserr.h"      // xsyserror
+#include "trace.h"       // tracing system
+#include "strutil.h"     // replace
+#include "lexer1.h"      // Lexer1
+#include "lexer2.h"      // Lexer2
+
+#include <stdio.h>       // FILE
+#include <fstream.h>     // ofstream
+
+
+// ----------------------- StackNode -----------------------
+StackNode::StackNode(int id, int col, ItemSet const *st)
+  : stackNodeId(id),
+    tokenColumn(col),
+    state(st)
+{}
+
+StackNode::~StackNode()
+{}
+
+
+Symbol const *StackNode::getSymbolC() const
+{
+  return state->getStateSymbolC();
+}
+
+
+// add a new sibling by creating a new link
+SiblingLink *StackNode::
+  addSiblingLink(StackNode *leftSib, TreeNode *treeNode)
+{
+  SiblingLink *link = new SiblingLink(leftSib, treeNode);
+  leftSiblings.append(link);
+  return link;
+}
+
+
+SiblingLink *StackNode::
+  findSiblingLink(StackNode *leftSib)
+{
+  MUTATE_EACH_OBJLIST(SiblingLink, leftSiblings, sib) {
+    if (sib.data()->sib == leftSib) {
+      return sib.data();
+    }
+  }
+  return NULL;
+}
+
+
+// ------------------ PathCollectionState -----------------
+PathCollectionState::~PathCollectionState()
+{}
+
+PathCollectionState::ReductionPath::~ReductionPath()
+{
+  if (reduction) {
+    // should only be executed under exceptional circumstances;
+    // normally, this object owns the reduction only temporarily
+    delete reduction;
+  }
+}
+
+
+// ------------------------- GLR ---------------------------
+GLR::GLR()
+  : currentToken(NULL),
+    currentTokenClass(NULL)
+  // some fields initialized by 'clearAllStackNodes'
+{}
+
+GLR::~GLR()
+{}
+
+
+void GLR::clearAllStackNodes()
+{
+  // throw away any parse nodes leftover from previous parses
+  allStackNodes.deleteAll();
+  treeNodes.deleteAll();
+  nextStackNodeId = initialStackNodeId;
+  currentTokenColumn = 0;
+}
+
+
+// process the input string, and yield a parse graph
+void GLR::glrParse(char const *inputFname)
+{
+  // do first phase lexer
+  trace("progress") << "lexical analysis stage 1...\n";
+  Lexer1 lexer1;
+  {
+    FILE *input = fopen(inputFname, "r");
+    if (!input) {
+      xsyserror("fopen", inputFname);
+    }
+
+    lexer1_lex(lexer1, input);
+    fclose(input);
+
+    if (lexer1.errors > 0) {
+      printf("L1: %d error(s)\n", lexer1.errors);
+      return;
+    }
+  }
+
+  // do second phase lexer
+  trace("progress") << "lexical analysis stage 2...\n";
+  Lexer2 lexer2;
+  lexer2_lex(lexer2, lexer1);
+
+
+  // get ready..
+  trace("progress") << "parsing...\n";
+  clearAllStackNodes();
+
+  // create an initial ParseTop with grammar-initial-state,
+  // set active-parsers to contain just this
+  StackNode *first = makeStackNode(itemSets.first());
+  activeParsers.append(first);
+
+  // for each input symbol
+  int tokenNumber = 0;
+  for (ObjListIter<Lexer2Token> tokIter(lexer2.tokens);
+       !tokIter.isDone(); tokIter.adv(), tokenNumber++) {
+    currentToken = tokIter.data();
+
+    // debugging
+    trace("parse")
+      << "---------- "
+      << "processing token " << currentToken->toString()
+      << ", " << activeParsers.count() << " active parsers"
+      << " ----------"
+      << endl;
+
+    // convert the token to a symbol
+    xassert(currentToken->type < numTerms);
+    currentTokenClass = indexedTerms[currentToken->type];
+    currentTokenColumn = tokenNumber;
+
+
+    // ([GLR] called the code from here to the end of
+    // the loop 'parseword')
+
+    // we will queue up shifts and process them all
+    // at the end
+    ObjList<PendingShift> pendingShifts;                  // starts empty
+
+    // put active parser tops into a worklist
+    parserWorklist = activeParsers;
+
+    // work through the worklist
+    StackNode *lastToDie = NULL;
+    while (parserWorklist.isNotEmpty()) {
+      StackNode *parser = parserWorklist.removeAt(0);     // dequeue
+      int actions = glrParseAction(parser, pendingShifts);
+
+      if (actions == 0) {
+        trace("parse") << "parser in state " << parser->state->id
+                       << " died\n";
+        lastToDie = parser;          // for reporting the error later if necessary
+      }
+      else if (actions > 1) {
+        trace("parse") << "parser in state " << parser->state->id
+                       << " split into " << actions << " parsers\n";
+      }
+    }
+
+    // process all pending shifts
+    glrShiftTerminals(pendingShifts);
+
+    // if all active parsers have died, there was an error
+    if (activeParsers.isEmpty()) {
+      cout << "Line " << currentToken->loc.line
+           << ", col " << currentToken->loc.col
+           << ": Parse error at " << currentToken->toString() << endl;
+           
+      if (lastToDie == NULL) {                     
+        // I'm not entirely confident it has to be nonnull..
+        cout << "what the?  lastToDie is NULL??\n";         
+      }
+      else {
+        // print out the context of that parser
+        cout << "last parser to die had:\n"
+                "  sample input: " << sampleInput(lastToDie->state) << "\n"
+                "  left context: " << leftContextString(lastToDie->state) << "\n";
+      }
+
+      return;
+    }
+  }
+
+
+  trace("parse") << "Parse succeeded!\n";
+
+
+  // print the parse as a graph for my graph viewer
+  // (the slight advantage to printing the graph first is that
+  // if there is circularity in the parse tree, the graph
+  // printer will handle it ok, whereas thet tree printer will
+  // get into an infinite loop (so at least the graph will be
+  // available in a file after I kill the process))
+  if (tracingSys("parse-graph")) {      // profiling says this is slow
+    trace("progress") << "writing parse graph...\n";
+    writeParseGraph("parse.g");
+  }
+
+
+  // print parse tree in ascii; the final activeParser is the one
+  // that shifted the end-of-stream marker, so we want its left
+  // sibling, since that will be the reduction(s) to the start
+  // symbol
+  TreeNode const *tn =
+    activeParsers.firstC()->                    // parser that shifted end-of-stream
+      leftSiblings.firstC()->sib->              // parser that shifted start symbol
+      leftSiblings.firstC()->                   // sibling link with start symbol
+      treeNode;                                 // start symbol tree node
+
+  // had broken this into pieces while tracking down a problem, and
+  // I've decided to leave it this way
+  xassert(tn);
+  if (tracingSys("parse-tree")) {
+    tn->printParseTree(trace("parse-tree") << endl, 2 /*indent*/);
+  }
+
+
+  // generate an ambiguity report
+  if (tracingSys("ambiguities")) {
+    tn->ambiguityReport(trace("ambiguities") << endl);
+  }
+}
+
+
+// do the actions for this parser, on input 'token'; if a shift
+// is required, we postpone it by adding the necessary state
+// to 'pendingShifts'; returns number of actions performed
+// ([GLR] called this 'actor')
+int GLR::glrParseAction(StackNode *parser,
+                        ObjList<PendingShift> &pendingShifts)
+{
+  int actions = 
+    postponeShift(parser, pendingShifts);
+
+  actions += 
+    doAllPossibleReductions(parser, NULL /*no link restrictions*/);
+
+  return actions;
+}
+
+
+int GLR::postponeShift(StackNode *parser,
+                        ObjList<PendingShift> &pendingShifts)
+{
+  // see where a shift would go
+  ItemSet const *shiftDest = parser->state->transitionC(currentTokenClass);
+  if (shiftDest != NULL) {
+    // postpone until later; save necessary state (the
+    // parser and the state to transition to)
+
+    // add (parser, shiftDest) to pending-shifts
+    pendingShifts.append(new PendingShift(parser, shiftDest));
+    
+    return 1;   // 1 action
+  }                        
+  else {
+    return 0;
+  }
+}
+
+
+// mustUseLink: if non-NULL, then we only want to consider
+// reductions that use that link
+int GLR::doAllPossibleReductions(StackNode *parser,
+                                 SiblingLink *mustUseLink)
+{
+  int actions = 0;
+
+  // get all possible reductions where 'currentToken' is in Follow(LHS)
+  ProductionList reductions;
+  parser->state->getPossibleReductions(reductions, currentTokenClass,
+                                       true /*parsing*/);
+
+  // for each possible reduction, do it
+  SFOREACH_PRODUCTION(reductions, prod) {
+    actions++;
+    int rhsLen = prod.data()->rhsLength();
+    xassert(rhsLen >= 0);    // paranoia before using this to control recursion
+
+    // in ordinary LR parsing, at this point we would pop 'rhsLen'
+    // symbols off the stack, and push the LHS of this production.
+    // here, we search down the stack for the node 'sibling' that
+    // would be at the top after popping, and then tack on a new
+    // StackNode after 'sibling' as the new top of stack
+
+    // however, there might be more than one 'sibling' node, so we
+    // must process all candidates.  the strategy will be to do a
+    // simple depth-first search
+
+    // WRONG:
+      // (note that each such candidate defines a unique path -- all
+      // paths must be composed of the same symbol sequence (namely the
+      // RHS symbols), and if more than one such path existed it would
+      // indicate a failure to collapse and share somewhere)
+
+    // CORRECTION:
+      // there *can* be more than one path to a given candidate; see
+      // the comments at the top
+
+    // step 1: collect all paths of length 'rhsLen' that start at
+    // 'parser', via DFS
+    PathCollectionState pcs(prod.data());
+    collectReductionPaths(pcs, rhsLen, parser, mustUseLink);
+
+    // invariant: poppedSymbols' length is equal to the recursion
+    // depth in 'popStackSearch'; thus, should be empty now
+    xassert(pcs.poppedSymbols.isEmpty());
+
+    // terminology:
+    //   - a 'reduction' is a grammar rule plus the TreeNode children
+    //     that constitute the RHS
+    //	 - a 'path' is a reduction plus the parser (StackNode) that is
+    //     at the end of the sibling link path (which is essentially the
+    //     parser we're left with after "popping" the reduced symbols)
+
+    // step 2: process those paths
+    // ("mutate" because of ownership transfer)
+    MUTATE_EACH_OBJLIST(PathCollectionState::ReductionPath, pcs.paths, pathIter) {
+      PathCollectionState::ReductionPath *rpath = pathIter.data();
+
+      if (tracingSys("parse")) {
+        // profiling reported this used significant time even when not tracing
+        trace("parse")
+          << "in state " << parser->state->id
+          << ", reducing by " << *(prod.data())
+          << ", back to state " << rpath->finalState->state->id
+          << endl;
+      }
+
+      // this is like shifting the reduction's LHS onto 'finalParser'
+      glrShiftNonterminal(rpath->finalState, transferOwnership(rpath->reduction));
+    }
+  }
+  
+  return actions;
+}
+
+
+/*
+ * collectReductionPaths():
+ *   this function searches for all paths (over the
+ *   sibling links) of a particular length, starting
+ *   at currentNode
+ *
+ * pcs:
+ *   various search state elements; see glr.h
+ *
+ * popsRemaining:
+ *   number of links left to traverse before we've popped
+ *   the correct number
+ *
+ * currentNode:
+ *   where we are in the search; this call will consider the
+ *   siblings of currentNode
+ *
+ * mustUseLink:
+ *   a particular sibling link that must appear on all collected
+ *   paths; it is NULL if we have no such requirement
+ *
+ * ([GLR] called this 'do-reductions' and 'do-limited-reductions')
+ */
+void GLR::collectReductionPaths(PathCollectionState &pcs, int popsRemaining,
+                                StackNode *currentNode, SiblingLink *mustUseLink)
+{
+  // inefficiency: all this mechanism is somewhat overkill, given that
+  // most of the time the reductions are unambiguous and unrestricted
+
+  if (popsRemaining == 0) {
+    // we've found a path of the required length
+
+    // if we have failed to use the required link, ignore this path
+    if (mustUseLink != NULL) {
+      return;
+    }
+
+    // we've popped the required number of symbols; collect the
+    // popped symbols into a Reduction
+    Reduction *rn = new Reduction(pcs.production);        // (owner)
+    rn->children = pcs.poppedSymbols;       // profiling: majority of time spent here
+
+    // previously, I had been reversing the children here; that
+    // is wrong!  since the most recent symbol prepended is the
+    // leftmost one in the input, the list is in the correct order
+
+    // and just collect this reduction, and the final state, in our
+    // running list
+    pcs.paths.append(new PathCollectionState::
+      ReductionPath(currentNode, transferOwnership(rn)));
+  }
+
+  else {
+    // explore currentNode's siblings
+    MUTATE_EACH_OBJLIST(SiblingLink, currentNode->leftSiblings, sibling) {
+      // the symbol on the sibling link is being popped
+      pcs.poppedSymbols.prepend(sibling.data()->treeNode);
+
+      // recurse one level deeper, having traversed this link
+      if (sibling.data() == mustUseLink) {
+        // consumed the mustUseLink requirement
+        collectReductionPaths(pcs, popsRemaining-1, sibling.data()->sib,
+                              NULL /*mustUseLink*/);
+      }
+      else {
+        // either no requirement, or we didn't consume it; just
+        // propagate current requirement state
+        collectReductionPaths(pcs, popsRemaining-1, sibling.data()->sib,
+                              mustUseLink);
+      }
+
+      // un-pop the tree node, so exploring another path will work
+      pcs.poppedSymbols.removeAt(0);
+    }
+  }
+}
+
+
+// shift reduction onto 'leftSibling' parser
+// ([GLR] calls this 'reducer')
+void GLR::glrShiftNonterminal(StackNode *leftSibling,
+                              Reduction * /*(owner)*/ reduction)
+{
+  // package some things up
+  Attributes parentAttr;       // attributes for parent of reduction's children
+  Production const *prod = reduction->production;
+  AttrContext actx(parentAttr, transferOwnership(reduction));
+
+  // apply the actions and conditions for this production
+  prod->actions.fire(actx);
+  if (!prod->conditions.test(actx)) {
+    // failed to satisfy conditions
+    return;
+  }
+
+  // this is like a shift -- we need to know where to go
+  ItemSet const *rightSiblingState =
+    leftSibling->state->transitionC(prod->left);
+
+  // debugging
+  if (tracingSys("parse")) {
+    trace("parse")
+      << "from state " << leftSibling->state->id
+      << ", shifting production " << *(prod)
+      << ", transitioning to state " << rightSiblingState->id
+      << endl;
+  }
+
+  // is there already an active parser with this state?
+  StackNode *rightSibling = findActiveParser(rightSiblingState);
+  if (rightSibling) {
+    // does it already have a sibling link to 'leftSibling'?
+    SiblingLink *sibLink = rightSibling->findSiblingLink(leftSibling);
+    if (sibLink != NULL) {
+      // yes; don't need to add a sibling link
+
+      // +--------------------------------------------------+
+      // | it is here that we are bringing the tops of two  |
+      // | alternative parses together 	       	       	    |
+      // +--------------------------------------------------+
+      mergeAlternativeParses(sibLink->treeNode->asNonterm(), actx);
+
+      // and since we didn't add a link, there is no potential for new
+      // paths
+    }
+
+    else {
+      // no, so add the link (and keep the ptr for below)
+      sibLink =
+        rightSibling->addSiblingLink(leftSibling,
+                                     makeNonterminalNode(actx));
+
+      // adding a new sibling link may have introduced additional
+      // opportunties to do reductions from parsers we thought
+      // we were finished with.
+      //
+      // what's more, it's not just the parser ('rightSibling') we
+      // added the link to -- if rightSibling's itemSet contains 'A ->
+      // alpha . B beta' and B ->* empty (so A's itemSet also has 'B
+      // -> .'), then we reduced it (if lookahead ok), so
+      // 'rightSibling' now has another left sibling with 'A -> alpha
+      // B . beta'.  We need to let this sibling re-try its reductions
+      // also.
+      //
+      // so, the strategy is to let all 'finished' parsers re-try
+      // reductions, and process those that actually use the just-
+      // added link
+
+      // for each 'finished' parser (i.e. those not still on
+      // the worklist)
+      SMUTATE_EACH_OBJLIST(StackNode, activeParsers, parser) {
+        if (parserWorklist.contains(parser.data())) continue;
+
+        // do any reduce actions that are now enabled
+        doAllPossibleReductions(parser.data(), sibLink);
+      }
+    }
+  }
+
+  else {
+    // no, there is not already an active parser with this
+    // state.  we must create one; it will become the right
+    // sibling of 'leftSibling'
+    rightSibling = makeStackNode(rightSiblingState);
+
+    // add the sibling link (and keep ptr for tree stuff)
+    rightSibling->addSiblingLink(leftSibling,
+                                 makeNonterminalNode(actx));
+
+    // since this is a new parser top, it needs to become a
+    // member of the frontier
+    activeParsers.append(rightSibling);
+    parserWorklist.append(rightSibling);
+
+    // no need for the elaborate re-checking above, since we
+    // just created rightSibling, so no new opportunities
+    // for reduction could have arisen
+  }
+}
+
+
+void GLR::mergeAlternativeParses(NonterminalNode &node, AttrContext &actx)
+{
+  // we only get here if the single-tree tests have passed, but we
+  // haven't applied the multi-tree comparisons; so do that now
+  // TODO: figure out interface and specification for multi-tree
+  // comparisons
+
+  // at this point, we still have multiple trees; we require of
+  // the parser that the parent attributes MUST match exactly
+  if (actx.parentAttr() != node.attr) {
+    // there is a bug in the parser
+    cout << "PARSER GRAMMAR BUG: alternative parses have different attributes\n";
+    cout << "  existing parse(s) and attributes:\n";
+    node.printParseTree(cout, 4 /*indent*/);
+
+    cout << "  new parse and attributes:\n";
+    actx.reduction().printParseTree(actx.parentAttr(), cout, 4 /*indent*/);
+
+    xfailure("parser bug: alternative parses with different attributes");
+  }
+
+  // ok, they match; just add the reduction to the existing node
+  // (and let 'parentAttr' drop on the floor since it was the same anyway)
+  node.addReduction(actx.grabReduction());
+}
+
+
+void GLR::glrShiftTerminals(ObjList<PendingShift> &pendingShifts)
+{
+  // clear the active-parsers list; we rebuild it in this fn
+  activeParsers.removeAll();
+
+  // foreach (leftSibling, newState) in pendingShifts
+  FOREACH_OBJLIST(PendingShift, pendingShifts, pshift) {
+    StackNode *leftSibling = pshift.data()->parser;
+    ItemSet const *newState = pshift.data()->shiftDest;
+
+    // debugging
+    trace("parse")
+      << "from state " << leftSibling->state->id
+      << ", shifting terminal " << currentToken->toString()
+      << ", transitioning to state " << newState->id
+      << endl;
+
+    // if there's already a parser with this state
+    StackNode *rightSibling = findActiveParser(newState);
+    if (rightSibling != NULL) {
+      // no need to create the node
+    }
+
+    else {
+      // must make a new stack node
+      rightSibling = makeStackNode(newState);
+
+      // and add it to the active parsers
+      activeParsers.append(rightSibling);
+    }
+
+    // either way, add the sibling link now
+    rightSibling->addSiblingLink(
+      leftSibling, makeTerminalNode(currentToken, currentTokenClass));
+  }
+}
+
+
+// if an active parser is at 'state', return it; otherwise
+// return NULL
+StackNode *GLR::findActiveParser(ItemSet const *state)
+{
+  SMUTATE_EACH_OBJLIST(StackNode, activeParsers, parser) {
+    if (parser.data()->state == state) {
+      return parser.data();
+    }
+  }
+  return NULL;
+}
+
+
+StackNode *GLR::makeStackNode(ItemSet const *state)
+{
+  StackNode *sn = new StackNode(nextStackNodeId++, currentTokenColumn,
+                                state);
+  allStackNodes.prepend(sn);
+  return sn;
+}
+
+
+TerminalNode *GLR::makeTerminalNode(Lexer2Token const *tk, Terminal const *tc)
+{
+  TerminalNode *ret = new TerminalNode(tk, tc);
+  treeNodes.prepend(ret);
+  return ret;
+}
+
+NonterminalNode *GLR::makeNonterminalNode(AttrContext &actx)
+{
+  NonterminalNode *ret = new NonterminalNode(actx.grabReduction());
+  ret->attr.destructiveEquals(actx.parentAttr());   // effect: ret->attr = parentAttr
+  treeNodes.prepend(ret);
+  return ret;
+}
+
+
+// ------------------ stuff for outputting raw graphs ------------------
+// name for graphs (can't have any spaces in the name)
+string stackNodeName(StackNode const *sn)
+{     
+  Symbol const *s = sn->getSymbolC();
+  char const *symName = (s? s->name.pcharc() : "(null)");
+  return stringb(sn->stackNodeId
+              << ":col="  << sn->tokenColumn
+              << ",st=" << sn->state->id
+              << ",sym=" << symName);
+}
+
+// name for rules; 'rn' is the 'ruleNo'-th rule in 'sn'
+// (again, no spaces allowed)
+string reductionName(StackNode const *sn, int ruleNo, Reduction const *red)
+{
+  return stringb(sn->stackNodeId << "/" << ruleNo << ":"
+              << replace(red->production->toString(), " ", "_"));
+}							     
+
+
+// this prints the graph in my java graph applet format, where
+// nodes lines look like
+//   n <name> <optional-desc>
+// and edges look like
+//   e <from> <to>
+// unfortunately, the graph applet needs a bit of work before it
+// is worthwhile to use this routinely (though it's great for
+// quickly verifying a single (small) parse)
+//
+// however, it's worth noting that the text output is not entirely
+// unreadable...
+void GLR::writeParseGraph(char const *fname) const
+{
+  FILE *out = fopen(stringb("graphs/" << fname), "w");
+  if (!out) {
+    xsyserror("fopen", stringb("opening file `graphs/" << fname << "'"));
+  }
+
+  // header info
+  fprintf(out, "# parse graph file: %s\n", fname);
+  fprintf(out, "# automatically generated\n"
+               "\n");
+
+  // for each stack node
+  FOREACH_OBJLIST(StackNode, allStackNodes, stackNodeIter) {
+    StackNode const *stackNode = stackNodeIter.data();
+    string myName = stackNodeName(stackNode);
+
+    // visual delimiter
+    fputs(stringb("\n# ------ node: " << myName << " ------\n"), out);
+
+    // write info for the node itself
+    fputs(stringb("n " << myName << "\n\n"), out);
+
+    // for all sibling links
+    int ruleNo=0;
+    FOREACH_OBJLIST(SiblingLink, stackNode->leftSiblings, sibIter) {
+      SiblingLink const *link = sibIter.data();
+
+      // write the sibling link
+      fputs(stringb("e " << myName << " "
+                         << stackNodeName(link->sib) << "\n"), out);
+
+      // ideally, we'd attach the reduction nodes directly to the
+      // sibling edge.  however, since I haven't developed the
+      // graph applet far enough for that, I'll instead attach it
+      // to the stack node directly..
+
+      if (link->treeNode->isNonterm()) {
+        // for each reduction node
+        FOREACH_OBJLIST(Reduction, link->treeNode->asNonterm().reductions,
+                        redIter) {
+          Reduction const *red = redIter.data();
+          ruleNo++;
+
+          string ruleName = reductionName(stackNode, ruleNo, red);
+
+          // write info for the rule node
+          fputs(stringb("n " << ruleName << "\n"), out);
+
+          // put the link from the stack node to the rule node
+          fputs(stringb("e " << myName << " " << ruleName << "\n"), out);
+
+          // write all child links
+          // ACK!  until my graph format is better, this is almost impossible
+          #if 0
+          SFOREACH_OBJLIST(StackNode, rule->children, child) {
+            fputs(stringb("e " << ruleName << " "
+                               << stackNodeName(child.data()) << "\n"), out);
+          }
+          #endif // 0
+
+          // blank line for visual separation
+          fputs("\n", out);
+        } // for each reduction
+      } // if is nonterminal
+    } // for each sibling
+  } // for each stack node
+
+  // done
+  if (fclose(out) != 0) {
+    xsyserror("fclose");
+  }
+}
+
+
+// --------------------- testing ------------------------
+// read an entire file into a single string
+// currenty is *not* pipe-friendly because it must seek
+// (candidate for adding to 'str' module)
+string readFileIntoString(char const *fname)
+{
+  // open file
+  FILE *fp = fopen(fname, "r");
+  if (!fp) {
+    xsyserror("fopen", stringb("opening `" << fname << "' for reading"));
+  }
+
+  // determine file's length
+  if (fseek(fp, 0, SEEK_END) < 0) {
+    xsyserror("fseek");
+  }
+  int len = (int)ftell(fp);      // conceivably problematic cast..
+  if (len < 0) {
+    xsyserror("ftell");
+  }
+  if (fseek(fp, 0, SEEK_SET) < 0) {
+    xsyserror("fseek");
+  }
+
+  // allocate a sufficiently large buffer
+  string ret(len);
+  
+  // read the file into that buffer
+  if (fread(ret.pchar(), 1, len, fp) < (size_t)len) {
+    xsyserror("fread");
+  }
+
+  // close file
+  if (fclose(fp) < 0) {
+    xsyserror("fclose");
+  }
+
+  // return the new string
+  return ret;
+}
+
+
+void GLR::glrTest(char const *grammarFname, char const *inputFname,
+                  char const *symOfInterestName)
+{
+  #if 0
+    // [ASU] grammar 4.19, p.222: demonstrating LR sets-of-items construction
+    parseLine("E' ->  E $                ");
+    parseLine("E  ->  E + T  |  T        ");
+    parseLine("T  ->  T * F  |  F        ");
+    parseLine("F  ->  ( E )  |  id       ");
+
+    char const *input[] = {
+      " id                 $",
+      " id + id            $",
+      " id * id            $",
+      " id + id * id       $",
+      " id * id + id       $",
+      " ( id + id ) * id   $",
+      " id + id + id       $",
+      " id + ( id + id )   $"
+    };
+  #endif // 0/1
+
+ #if 0
+    // a simple ambiguous expression grammar
+    parseLine("S  ->  E  $                  ");
+    parseLine("E  ->  x  |  E + E  | E * E  ");
+
+    char const *input[] = {
+      "x + x * x $",
+    };
+  #endif // 0/1
+
+  #if 0
+    // my cast-problem grammar
+    parseLine("Start -> Expr $");
+    parseLine("Expr -> CastExpr");
+    parseLine("Expr -> Expr + CastExpr");
+    parseLine("CastExpr -> AtomExpr");
+    parseLine("CastExpr -> ( Type ) CastExpr");
+    parseLine("AtomExpr -> 3");
+    parseLine("AtomExpr -> x");
+    parseLine("AtomExpr -> ( Expr )");
+    parseLine("AtomExpr -> AtomExpr ( Expr )");
+    parseLine("Type -> int");
+    parseLine("Type -> x");
+
+    char const *input[] = {
+      "( x ) ( x ) $",
+    };
+
+    printProductions(cout);
+    runAnalyses();
+
+    INTLOOP(i, 0, (int)TABLESIZE(input)) {
+      cout << "------ parsing: `" << input[i] << "' -------\n";
+      glrParse(input[i]);
+    }
+  #endif // 0/1
+
+  #if 1
+    // read grammar
+    readFile(grammarFname);
+
+    // spit grammar out as something bison might be able to parse
+    {
+      ofstream bisonOut("bisongr.y");
+      printAsBison(bisonOut);
+    }
+
+    // prepare for symbol of interest
+    if (symOfInterestName != NULL) {
+      symOfInterest = findSymbolC(symOfInterestName);
+      if (!symOfInterest) {
+        cout << "warning: " << symOfInterestName << " isn't in the grammar\n";
+      }
+    }
+
+    printProductions(trace("grammar") << endl);
+    runAnalyses();
+
+
+    // parse input
+    glrParse(inputFname);
+
+  #endif // 0/1
+}
+
+
+#ifdef GLR_MAIN
+//#include <fstream.h>    // ofstream
+
+int main(int argc, char **argv)
+{
+  // skip program name
+  char const *progName = argv[0];
+  argc--;
+  argv++;
+
+  // parameters
+  char const *symOfInterestName = NULL;
+
+  // process args
+  while (argc >= 1) {
+    if (0==strcmp(argv[0], "-tr") && argc >= 2) {
+      traceAddMultiSys(argv[1]);
+      argc -= 2;
+      argv += 2;
+    }
+    else if (0==strcmp(argv[0], "-sym") && argc >= 2) {
+      symOfInterestName = argv[1];
+      argc -= 2;
+      argv += 2;
+    }
+    else {
+      break;     // didn't find any more options
+    }
+  }
+
+  if (argc != 2) {
+    cout << "usage: " << progName << " [options] grammar-file input-file\n"
+            "  options:\n"
+            "    -tr <sys>:  turn on tracing for the named subsystem\n"
+            "    -sym <sym>: name the \"symbol of interest\"\n"
+            ;
+    return 0;
+  }
+
+  GLR g;
+  g.glrTest(argv[0], argv[1], symOfInterestName);
+  return 0;
+}
+#endif // GLR_MAIN

Added: vendor/elsa/current/elkhound/in/cc.in6
===================================================================
--- vendor/elsa/current/elkhound/in/cc.in6	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cc.in6	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1639 @@
+// gramanl.cc
+// code for gramanl.h
+
+#include "gramanl.h"     // this module
+
+#include "bit2d.h"       // Bit2d
+#include "strtokp.h"     // StrtokParse
+#include "syserr.h"      // xsyserror
+#include "trace.h"       // tracing system
+#include "nonport.h"     // getMilliseconds
+
+#include <fstream.h>     // ofstream
+
+
+#if 0    // not used anymore; gprof is much better
+// should make a new module for this
+class Timer {
+  long start;
+  long &accumulator;
+
+public:
+  Timer(long &acc) : accumulator(acc)
+    { start = getMilliseconds(); }
+  ~Timer()
+    { accumulator += getMilliseconds() - start; }
+};
+#endif // 0
+
+
+GrammarAnalysis::GrammarAnalysis()
+  : derivable(NULL),
+    indexedNonterms(NULL),
+    indexedTerms(NULL),
+    numNonterms(0),
+    numTerms(0),
+    productionsByLHS(NULL),
+    initialized(false),
+    nextItemSetId(0),    // [ASU] starts at 0 too
+    startState(NULL),
+    cyclic(false),
+    symOfInterest(NULL)
+{}
+
+
+GrammarAnalysis::~GrammarAnalysis()
+{
+  if (indexedNonterms != NULL) {
+    delete indexedNonterms;
+  }
+
+  if (indexedTerms != NULL) {
+    delete indexedTerms;
+  }
+
+  if (productionsByLHS != NULL) {
+    // empties all lists automatically because of "[]"
+    delete[] productionsByLHS;
+  }
+
+  if (derivable != NULL) {
+    delete derivable;
+  }
+}
+
+
+void GrammarAnalysis::printProductions(ostream &os) const
+{
+  if (cyclic) {
+    os << "(cyclic!) ";
+  }
+  Grammar::printProductions(os);
+}
+
+
+void printSymbols(ostream &os, ObjList<Symbol> const &list)
+{
+  for (ObjListIter<Symbol> iter(list);
+       !iter.isDone(); iter.adv()) {
+    os << "  " << *(iter.data()) << endl;
+  }
+}
+
+
+bool GrammarAnalysis::addDerivable(Nonterminal const *left, Nonterminal const *right)
+{
+  return addDerivable(left->ntIndex, right->ntIndex);
+}
+
+bool GrammarAnalysis::addDerivable(int left, int right)
+{
+  // Almost as an aside, I'd like to track cyclicity in grammars.
+  // It's always true that N ->* N, because 0 steps are allowed.
+  // A grammar is cyclic if N ->+ N, i.e. it derives itself in
+  // 1 or more steps.
+  //
+  // We can detect that fairly easily by tracking calls to
+  // this fn with left==right.  Since N ->* N in 0 steps is
+  // recorded during init (and *not* by calling this fn), the
+  // only calls to this with left==right will be when the
+  // derivability code detects a nonzero-length path.
+
+  if (left==right) {
+    Nonterminal *NT = indexedNonterms[left];    // ==right
+    if (!NT->cyclic) {
+      trace("derivable")
+        << "discovered that " << NT->name << " ->+ "
+        << NT->name << " (i.e. is cyclic)\n";
+      NT->cyclic = true;
+      cyclic = true;     // for grammar as a whole
+
+      // Even though we didn't know this already, it doesn't
+      // constitute a change in the ->* relation (which is what the
+      // derivability code cares about), so we do *not* report a
+      // change for the cyclicty detection.
+    }
+  }
+
+  // we only made a change, and hence should return true,
+  // if there was a 0 here before
+  return 0 == derivable->testAndSet(point(left, right));
+}
+
+
+bool GrammarAnalysis::canDerive(Nonterminal const *left, Nonterminal const *right) const
+{
+  return canDerive(left->ntIndex, right->ntIndex);
+}
+
+bool GrammarAnalysis::canDerive(int left, int right) const
+{
+  return 1 == derivable->get(point(left, right));
+}
+
+
+void GrammarAnalysis::initDerivableRelation()
+{
+  // two-dimensional matrix to represent token derivabilities
+  int numNonterms = numNonterminals();
+  derivable = new Bit2d(point(numNonterms, numNonterms));
+
+  // initialize it
+  derivable->setall(0);
+  loopi(numNonterms) {
+    derivable->set(point(i,i));
+      // every nonterminal can derive itself in 0 or more steps
+      // (specifically, in 0 steps, at least)
+      //
+      // NOTE: we do *not* call addDerivable because that would
+      // mess up the cyclicity detection logic
+  }
+}
+
+
+bool GrammarAnalysis::canDeriveEmpty(Nonterminal const *nonterm) const
+{
+  return canDerive(nonterm, &emptyString);
+}
+
+
+bool GrammarAnalysis::sequenceCanDeriveEmpty(SymbolList const &list) const
+{
+  SymbolListIter iter(list);
+  return iterSeqCanDeriveEmpty(iter);
+}
+
+bool GrammarAnalysis::iterSeqCanDeriveEmpty(SymbolListIter iter) const
+{
+  // look through the sequence beginning with 'iter'; if any members cannot
+  // derive emptyString, fail
+  for (; !iter.isDone(); iter.adv()) {
+    if (iter.data()->isTerminal()) {
+      return false;    // terminals can't derive emptyString
+    }
+
+    if (!canDeriveEmpty(&( iter.data()->asNonterminalC() ))) {
+      return false;    // nonterminal that can't derive emptyString
+    }
+  }
+
+  return true;
+}
+
+
+bool GrammarAnalysis::firstIncludes(Nonterminal const *NT, Terminal const *term) const
+{
+  return NT->first.contains(term);
+}
+
+bool GrammarAnalysis::addFirst(Nonterminal *NT, Terminal *term)
+{
+  return NT->first.prependUnique(term);
+
+  // regarding non-constness of 'term':
+  // highly nonideal.. the problem is that by using annotations in
+  // the structures themselves, I have a hard time saying that I
+  // intend to modify the annotations but not the "key" data...
+  // this cast is really a symptom of that too.. (and, perhaps, also
+  // that I don't have a List class that promises to never permit
+  // modification of the pointed-to data.. but it's not clear I'd
+  // be better of using it here even if I had it)
+}
+
+
+bool GrammarAnalysis::followIncludes(Nonterminal const *NT, Terminal const *term) const
+{
+  return NT->follow.contains(term);
+}
+
+// returns true if Follow(NT) is changed by adding 'term' to it
+bool GrammarAnalysis::addFollow(Nonterminal *NT, Terminal *term)
+{
+  return NT->follow.prependUnique(term);
+}
+
+
+// ----------------- Grammar algorithms --------------------------
+void GrammarAnalysis::initializeAuxData()
+{
+  // at the moment, calling this twice leaks memory
+  xassert(!initialized);
+
+
+  // map: ntIndex -> Nonterminal*
+  numNonterms = numNonterminals();
+  indexedNonterms = new Nonterminal* [numNonterms];
+
+  // fill it
+  indexedNonterms[emptyStringIndex] = &emptyString;
+  int index = emptyStringIndex;
+  emptyString.ntIndex = index++;
+
+  for (ObjListMutator<Nonterminal> sym(nonterminals);
+       !sym.isDone(); index++, sym.adv()) {
+    indexedNonterms[index] = sym.data();    // map: index to symbol
+    sym.data()->ntIndex = index;            // map: symbol to index
+  }
+
+
+  // map: termIndex -> Terminal*
+  // the ids have already been assigned; but I'm going to continue
+  // to insist on a contiguous space starting at 0
+  numTerms = numTerminals();
+  indexedTerms = new Terminal* [numTerms];
+  loopi(numTerminals()) {
+    indexedTerms[i] = NULL;      // used to track id duplication
+  }
+  for (ObjListMutator<Terminal> sym(terminals);
+       !sym.isDone(); sym.adv()) {
+    int index = sym.data()->termIndex;   // map: symbol to index
+    if (indexedTerms[index] != NULL) {
+      xfailure(stringc << "terminal index collision at index " << index);
+    }
+    indexedTerms[index] = sym.data();    // map: index to symbol
+  }
+
+
+  #if 0     // old: this was when class ids were assigned automatically
+  indexedTerms = new Terminal* [numTerminals()];
+  index = 0;
+  for (ObjListMutator<Terminal> sym(terminals);
+       !sym.isDone(); index++, sym.adv()) {
+    indexedTerms[index] = sym.data();    // map: index to symbol
+    sym.data()->termIndex = index;       // map: symbol to index
+  }
+  #endif
+
+  
+  // map: nonterminal -> productions with that nonterm on LHS
+  productionsByLHS = new SObjList<Production> [numNonterms];
+  {
+    MUTATE_EACH_PRODUCTION(productions, prod) {        // (constness)
+      int LHSindex = prod.data()->left->ntIndex;
+      xassert(LHSindex < numNonterms);
+
+      productionsByLHS[LHSindex].append(prod.data());
+    }
+  }
+
+
+  // initialize the derivable relation
+  initDerivableRelation();
+
+  
+  // dotted productions
+  MUTATE_EACH_PRODUCTION(productions, prod) {
+    prod.data()->finished();
+  }
+
+
+  // mark the grammar as initialized
+  initialized = true;
+}
+
+
+void GrammarAnalysis::computeWhatCanDeriveWhat()
+{
+  xassert(initialized);
+
+
+  // iterate: propagate 'true' bits across the derivability matrix
+  // (i.e. compute transitive closure on the canDerive relation)
+  for (;;) {
+    int changes = 0;       // for this iter, # of times we set a matrix bit
+
+    // --------- first part: add new canDerive relations --------
+    // loop over all productions
+    for (ObjListIter<Production> prodIter(productions);
+         !prodIter.isDone(); prodIter.adv()) {
+      // convenient alias
+      Production const *prod = prodIter.data();
+
+      // since I don't include 'empty' explicitly in my rules, I won't
+      // conclude that anything can derive empty, which is a problem;
+      // so I special-case it here
+      if (prod->right.isEmpty()) {
+	addDerivable(prod->left, &emptyString);
+        continue;      	// no point in looping over RHS symbols since there are none
+      }
+
+      // iterate over RHS symbols, seeing if the LHS can derive that
+      // RHS symbol (by itself)
+      for (SymbolListIter rightSym(prod->right);
+           !rightSym.isDone(); rightSym.adv()) {
+
+        if (rightSym.data()->isTerminal()) {
+          // if prod->left derives a string containing a terminal,
+          // then it can't derive any nontermial alone (using this
+          // production, at least) -- empty is considered a nonterminal
+          break;
+        }
+
+        // otherwise, it's a nonterminal
+        Nonterminal const &rightNT = rightSym.data()->asNonterminalC();
+
+        // check if we already know that LHS derives rightNT
+        if (canDerive(prod->left, &rightNT)) {
+          // we already know that prod->left derives rightSym,
+          // so let's not check it again
+        }
+
+        else {
+          // we are wondering if prod->left can derive rightSym.. for
+          // this to be true, every symbol that comes after rightSym
+          // must be able to derive emptySymbol (we've already verified
+          // by now that every symbol to the *left* can derive empty)
+          SymbolListIter afterRightSym(rightSym);
+          bool restDeriveEmpty = true;
+          for (afterRightSym.adv();    // *after* right symbol
+               !afterRightSym.isDone(); afterRightSym.adv()) {
+
+            if (afterRightSym.data()->isTerminal()  ||
+                  // if it's a terminal, it can't derive emptyString
+                !canDeriveEmpty(&( afterRightSym.data()->asNonterminalC() ))) {
+                  // this symbol can't derive empty string (or, we don't
+                  // yet know that it can), so we conclude that prod->left
+                  // can't derive rightSym
+              restDeriveEmpty = false;
+              break;
+            }
+          }
+
+          if (restDeriveEmpty) {
+            // we have discovered that prod->left can derive rightSym
+            bool chgd = addDerivable(prod->left, &rightNT);
+            xassert(chgd);    // above, we verified we didn't already know this
+
+            changes++;
+
+            trace("derivable") 
+              << "discovered (by production): " << prod->left->name
+              << " ->* " << rightNT.name << "\n";
+          }
+        }
+
+        // ok, we've considered prod->left deriving rightSym.  now, we
+        // want to consider whether prod->left can derive any of the
+        // symbols that follow rightSym in this production.  for this
+        // to be true, rightSym itself must derive the emptyString
+        if (!canDeriveEmpty(&rightNT)) {
+          // it doesn't -- no point in further consideration of
+          // this production
+          break;
+        }
+      } // end of loop over RHS symbols
+    } // end of loop over productions
+
+
+    // -------- second part: compute closure over existing relations ------
+    // I'll do this by computing R + R^2 -- that is, I'll find all
+    // paths of length 2 and add an edge between their endpoints.
+    // I do this, rather than computing the entire closure now, since
+    // on the next iter I will add more relations and have to re-do
+    // a full closure; iterative progress seems a better way.
+
+    // I don't consider edges (u,u) because it messes up my cyclicty
+    // detection logic.  (But (u,v) and (v,u) is ok, and in fact is
+    // what I want, for detecting cycles.)
+
+    // for each node u (except empty)
+    int numNonterms = numNonterminals();
+    for (int u=1; u<numNonterms; u++) {
+      // for each edge (u,v) where u != v
+      for (int v=0; v<numNonterms; v++) {
+        if (u==v || !canDerive(u,v)) continue;
+
+        // for each edge (v,w) where v != w
+        for (int w=0; w<numNonterms; w++) {
+          if (v==w || !canDerive(v,w)) continue;
+
+          // add an edge (u,w), if there isn't one already
+          if (addDerivable(u,w)) {
+            changes++;
+            trace("derivable") 
+              << "discovered (by closure step): "
+              << indexedNonterms[u]->name << " ->* "
+              << indexedNonterms[w]->name << "\n";
+          }
+        }
+      }
+    }
+
+
+    // ------ finally: iterate until no changes -------
+    if (changes == 0) {
+      // didn't make any changes during the last iter, so
+      // everything has settled
+      break;
+    }
+  } // end of loop until settles
+
+
+  // I used to do all closure here and no closure in the loop.
+  // But that fails in cases where closure (when it reveals
+  // more things that derive emptyString) yields new opportunities
+  // for derives-relation discovery.  Therefore I now alternate
+  // between them, and at the end, no closure is necessary.
+}
+
+
+// Compute, for each nonterminal, the "First" set, defined as:
+//
+//   First(N) = { x | N ->* x alpha }, where alpha is any sequence
+//                                     of terminals and nonterminals
+//
+// If N can derive emptyString, I'm going to say that empty is
+// *not* in First, despite what Aho/Sethi/Ullman says.  I do this
+// because I have that information readily as my derivable relation,
+// and because it violates the type system I've devised.
+//
+// I also don't "compute" First for terminals, since they are trivial
+// (First(x) = {x}).
+void GrammarAnalysis::computeFirst()
+{
+  // iterate, looking for new First members, until no changes
+  int changes = 1;   // so the loop begins
+  while (changes > 0) {
+    changes = 0;
+
+    // for each production
+    for (ObjListMutator<Production> prodIter(productions);
+         !prodIter.isDone(); prodIter.adv()) {
+      // convenient aliases
+      Production *prod = prodIter.data();
+      Nonterminal *LHS = prod->left;
+        // the list iter is mutating because I modify LHS's First list
+
+      // compute First(RHS-sequence)
+      TerminalList firstOfRHS;
+      firstOfSequence(firstOfRHS, prod->right);
+
+      // add everything in First(RHS-sequence) to First(LHS)
+      SMUTATE_EACH_TERMINAL(firstOfRHS, iter) {
+        changes += true==addFirst(LHS, iter.data());
+      }
+    } // for (productions)
+  } // while (changes)
+}
+
+
+// 'sequence' isn't const because we need to hand pointers over to
+// the 'destList', which isn't const; similarly for 'this'
+// (what I'd like here is to say that 'sequence' and 'this' are const
+// if 'destList' can't modify the things it contains)
+void GrammarAnalysis::firstOfSequence(TerminalList &destList, SymbolList &sequence)
+{
+  SymbolListMutator iter(sequence);
+  firstOfIterSeq(destList, iter);
+}
+
+// similar to above, 'sym' needs to be a mutator
+void GrammarAnalysis::firstOfIterSeq(TerminalList &destList, SymbolListMutator sym)
+{
+  int numTerms = numTerminals();     // loop invariant
+
+  // for each sequence member such that all
+  // preceeding members can derive emptyString
+  for (; !sym.isDone(); sym.adv()) {
+    // LHS -> x alpha   means x is in First(LHS)
+    if (sym.data()->isTerminal()) {
+      destList.append(&( sym.data()->asTerminal() ));
+      break;    // stop considering RHS members since a terminal
+                // effectively "hides" all further symbols from First
+    }
+
+    // sym must be a nonterminal
+    Nonterminal const &nt = sym.data()->asNonterminalC();
+
+    // anything already in nt's First should be added to destList:
+    // for each element in First(nt)
+    for (int t=0; t<numTerms; t++) {
+      if (firstIncludes(&nt, indexedTerms[t])) {
+        destList.append(indexedTerms[t]);
+      }
+    }
+
+    // if nt can't derive emptyString, then it blocks further
+    // consideration of right-hand side members
+    if (!canDeriveEmpty(&nt)) {
+      break;
+    }
+  } // for (RHS members)
+}
+
+
+void GrammarAnalysis::computeFollow()
+{
+  int numTerms = numTerminals();     // loop invariant
+
+  // loop until no changes
+  int changes = 1;
+  while (changes > 0) {
+    changes = 0;
+
+    // 'mutate' is needed because adding 'term' to the follow of 'nt'
+    // needs a mutable 'term' and 'nt'
+
+    // for each production
+    MUTATE_EACH_PRODUCTION(productions, prodIter) {
+      Production *prod = prodIter.data();
+
+      // for each RHS nonterminal member
+      SMUTATE_EACH_SYMBOL(prod->right, rightSym) {
+        if (rightSym.data()->isTerminal()) continue;
+
+        // convenient alias
+        Nonterminal &rightNT = rightSym.data()->asNonterminal();
+
+        // I'm not sure what it means to compute Follow(emptyString),
+        // so let's just not do so
+        if (&rightNT == &emptyString) {
+          continue;
+        }
+
+        // an iterator pointing to the symbol just after
+        // 'rightSym' will be useful below
+        SymbolListMutator afterRightSym(rightSym);
+        afterRightSym.adv();    // NOTE: 'isDone()' may be true now
+
+        // rule 1:
+        // if there is a production A -> alpha B beta, then
+        // everything in First(beta) is in Follow(B)
+        {
+          // compute First(beta)
+          TerminalList firstOfBeta;
+          firstOfIterSeq(firstOfBeta, afterRightSym);
+
+          // put those into Follow(rightNT)
+          SMUTATE_EACH_TERMINAL(firstOfBeta, term) {
+            if (addFollow(&rightNT, term.data())) {
+              changes++;
+              if (&rightNT == symOfInterest) {
+                trace("follow-sym")
+                  << "Follow(" << rightNT.name
+                  << "): adding " << term.data()->name
+                  << " by first(RHS-tail) of " << *prod
+                  << endl;
+              }
+            }
+          }
+        }
+
+        // rule 2:
+        // if there is a production A -> alpha B, or a
+        // production A -> alpha B beta where beta ->* empty,
+        // then everything in Follow(A) is in Follow(B)
+        if (iterSeqCanDeriveEmpty(afterRightSym)) {
+          // for each element in Follow(LHS)
+          for (int t=0; t<numTerms; t++) {
+            if (followIncludes(prod->left, indexedTerms[t])) {
+              if (addFollow(&rightNT, indexedTerms[t])) {
+                changes++;
+                if (&rightNT == symOfInterest) {
+                  trace("follow-sym")
+                    << "Follow(" << rightNT.name
+                    << "): adding " << indexedTerms[t]->name
+                    << " by follow(LHS) of " << *prod
+                    << endl;
+                }
+              }
+            }
+          } // for each in Follow(LHS)
+        }
+
+      } // for each RHS nonterminal member
+    } // for each production
+  } // until no changes
+}
+
+
+// [ASU] alg 4.4, p.190
+void GrammarAnalysis::computePredictiveParsingTable()
+{
+  int numTerms = numTerminals();
+  int numNonterms = numNonterminals();
+
+  // the table will be a 2d array of lists of productions
+  ProductionList *table = new ProductionList[numTerms * numNonterms];     // (owner)
+  #define TABLE(term,nt) table[(term) + (nt)*numNonterms]
+
+  // for each production 'prod' (non-const iter because adding them
+  // to ProductionList, which doesn't promise to not change them)
+  MUTATE_EACH_PRODUCTION(productions, prodIter) {
+    Production *prod = prodIter.data();
+
+    // for each terminal 'term' in First(RHS)
+    TerminalList firsts;
+    firstOfSequence(firsts, prod->right);
+    SFOREACH_TERMINAL(firsts, term) {
+      // add 'prod' to table[LHS,term]
+      TABLE(prod->left->ntIndex,
+            term.data()->termIndex).prependUnique(prod);
+    }
+
+    // if RHS ->* emptyString, ...
+    if (sequenceCanDeriveEmpty(prod->right)) {
+      // ... then for each terminal 'term' in Follow(LHS), ...
+      SFOREACH_TERMINAL(prod->left->follow, term) {
+        // ... add 'prod' to table[LHS,term]
+        TABLE(prod->left->ntIndex,
+              term.data()->termIndex).prependUnique(prod);
+      }
+    }
+  }
+
+
+  // print the resulting table
+  ostream &os = trace("pred-table") << endl;
+
+  // for each nonterminal
+  INTLOOP(nonterm, 0, numNonterms) {
+    os << "Row " << indexedNonterms[nonterm]->name << ":\n";
+
+    // for each terminal
+    INTLOOP(term, 0, numTerms) {
+      os << "  Column " << indexedTerms[term]->name << ":";
+
+      // for each production in table[nonterm,term]
+      SFOREACH_PRODUCTION(TABLE(nonterm,term), prod) {
+        os << "   ";
+        prod.data()->print(os);
+      }
+
+      os << endl;
+    }
+  }
+
+  // cleanup
+  #undef TABLE
+  delete[] table;
+}
+
+
+// [ASU] figure 4.33, p.223
+void GrammarAnalysis::itemSetClosure(ItemSet &itemSet)
+{
+  // while no changes
+  int changes = 1;
+  while (changes > 0) {
+    changes = 0;
+
+    // a place to store the items we plan to add
+    DProductionList newItems;
+
+    // grab the current set of items
+    DProductionList items;
+    itemSet.getAllItems(items);
+
+    // for each item A -> alpha . B beta in itemSet
+    SFOREACH_DOTTEDPRODUCTION(items, itemIter) {            // (constness ok)
+      DottedProduction const *item = itemIter.data();
+
+      // get the symbol B (the one right after the dot)
+      if (item->isDotAtEnd()) continue;
+      Symbol const *B = item->symbolAfterDotC();
+      if (B->isTerminal()) continue;
+      int nontermIndex = B->asNonterminalC().ntIndex;
+
+      // for each production B -> gamma
+      SMUTATE_EACH_PRODUCTION(productionsByLHS[nontermIndex], prod) {           // (constness)
+        // invariant of the indexed productions list
+        xassert(prod.data()->left == B);
+
+        // plan to add B -> . gamma to the itemSet, if not already there
+        DottedProduction *dp = prod.data()->getDProd(0 /*dot placement*/);     // (constness)
+        if (!items.contains(dp)) {
+          newItems.append(dp);
+        }
+      } // for each production
+    } // for each item
+
+    // add the new items (we don't do this while iterating because my
+    // iterator interface says not to, even though it would work with
+    // my current implementation)
+    SMUTATE_EACH_DOTTEDPRODUCTION(newItems, item) {
+      itemSet.addNonkernelItem(item.data());	            // (constness)
+      changes++;
+    }
+  } // while changes
+}
+
+
+// -------------- START of construct LR item sets -------------------
+ItemSet *GrammarAnalysis::makeItemSet()
+{
+  return new ItemSet(nextItemSetId++, numTerminals(), numNonterminals());
+}
+
+void GrammarAnalysis::disposeItemSet(ItemSet *is)
+{
+  // we assume we're only doing this right after making it, as the
+  // point of this exercise is to avoid fragmenting the id space
+  nextItemSetId--;
+  xassert(is->id == nextItemSetId);
+  delete is;
+}
+
+
+// yield a new itemset by moving the dot across the productions
+// in 'source' that have 'symbol' to the right of the dot; do *not*
+// compute the closure
+ItemSet *GrammarAnalysis::moveDotNoClosure(ItemSet const *source, Symbol const *symbol)
+{
+  ItemSet *ret = makeItemSet();
+
+  DProductionList items;
+  source->getAllItems(items);
+
+  // for each item
+  int appendCt=0;
+  SFOREACH_DOTTEDPRODUCTION(items, dprodi) {
+    DottedProduction const *dprod = dprodi.data();
+
+    if (dprod->isDotAtEnd() ||
+        dprod->symbolAfterDotC() != symbol) {
+      continue;    // can't move dot
+    }
+
+    // move the dot
+    DottedProduction *dotMoved =
+      dprod->prod->getDProd(dprod->dot + 1);      // (constness!)
+
+    // add the new item to the itemset I'm building
+    ret->addKernelItem(dotMoved);
+    appendCt++;
+  }
+
+  // for now, verify we actually got something; though it would
+  // be easy to simply return null (after dealloc'ing ret)
+  xassert(appendCt > 0);
+
+  // return built itemset
+  return ret;
+}
+
+
+// if 'list' contains 'itemSet', return the equivalent copy
+// in 'list'; otherwise, return NULL
+// 'list' is non-const because might return an element of it
+ItemSet *GrammarAnalysis::findItemSetInList(ObjList<ItemSet> &list,
+                                            ItemSet const *itemSet)
+{
+  // inefficiency: using iteration to check set membership
+
+  MUTATE_EACH_OBJLIST(ItemSet, list, iter) {
+    if (itemSetsEqual(iter.data(), itemSet)) {
+      return iter.data();
+    }
+  }
+  return NULL;
+}
+
+
+/*STATICDEF*/ bool GrammarAnalysis::itemSetsEqual(ItemSet const *is1, ItemSet const *is2)
+{
+  return *is1 == *is2;
+}
+
+
+// [ASU] fig 4.34, p.224
+// puts the finished parse tables into 'itemSetsDone'
+void GrammarAnalysis::constructLRItemSets()
+{
+  // sets of item sets
+  ObjList<ItemSet> itemSetsPending;            // yet to be processed
+
+  ObjList<ItemSet> &itemSetsDone = itemSets;   // all outgoing links processed
+    // (renamed-by-reference to make role clearer here)
+
+  // start by constructing closure of first production
+  // (basically assumes first production has start symbol
+  // on LHS, and no other productions have the start symbol
+  // on LHS)
+  {
+    ItemSet *is = makeItemSet();              // (owner)
+    startState = is;
+    is->addKernelItem(productions.nth(0)->    // first production's ..
+                        getDProd(0));         //   .. first dot placement
+    itemSetClosure(*is);
+
+    // this makes the initial pending itemSet
+    itemSetsPending.append(is);              // (ownership transfer)
+  }
+
+  // for each pending item set
+  while (!itemSetsPending.isEmpty()) {
+    ItemSet *itemSet = itemSetsPending.removeAt(0);    // dequeue   (owner; ownership transfer)
+
+    // put it in the done set; note that we must do this *before*
+    // the processing below, to properly handle self-loops
+    itemSetsDone.append(itemSet);                      // (ownership transfer; 'itemSet' becomes serf)
+
+    DProductionList items;
+    itemSet->getAllItems(items);
+
+    // for each production in the item set where the
+    // dot is not at the right end
+    SFOREACH_DOTTEDPRODUCTION(items, dprodIter) {
+      DottedProduction const *dprod = dprodIter.data();
+      if (dprod->isDotAtEnd()) continue;
+
+      // get the symbol 'sym' after the dot (next to be shifted)
+      Symbol const *sym = dprod->symbolAfterDotC();
+
+      // if we already have a transition for this symbol,
+      // there's nothing more to be done
+      if (itemSet->transitionC(sym) != NULL) {
+        continue;
+      }
+
+      // fixed: adding transition functions fixes this:
+	// inefficiency: if several productions have X to the
+	// left of the dot, then we will 'moveDot' each time
+
+      // compute the itemSet produced by moving the dot
+      // across 'sym'; but don't take closure yet since
+      // we first want to check whether it is already present
+      ItemSet *withDotMoved = moveDotNoClosure(itemSet, sym);
+
+      // see if we already have it, in either set
+      ItemSet *already = findItemSetInList(itemSetsPending, withDotMoved);
+      if (already == NULL) {
+        already = findItemSetInList(itemSetsDone, withDotMoved);
+      }
+
+      // have it?
+      if (already != NULL) {
+        // we already have it, so throw away one we made
+        disposeItemSet(withDotMoved);     // deletes 'withDotMoved'
+
+        // and use existing one for setting the transition function
+        withDotMoved = already;
+      }
+      else {
+        // we don't already have it; finish it by computing its closure
+        itemSetClosure(*withDotMoved);
+
+        // then add it to 'pending'
+        itemSetsPending.append(withDotMoved);
+      }
+
+      // setup the transition function
+      itemSet->setTransition(sym, withDotMoved);
+
+    } // for each item
+  } // for each item set
+
+
+  // do the BFS now, since we want to print the sample inputs
+  // in the loop that follows
+  trace("progress") << "BFS tree on transition graph...\n";
+  computeBFSTree();
+
+
+  if (tracingSys("item-sets")) {
+    // print each item set
+    FOREACH_OBJLIST(ItemSet, itemSetsDone, itemSet) {
+      ostream &os = trace("item-sets")
+        << "State " << itemSet.data()->id
+        << ", sample input: " << sampleInput(itemSet.data())
+        << endl
+        << "  and left context: " << leftContextString(itemSet.data())
+        << endl
+        ;
+
+      itemSet.data()->print(os);
+    }
+  }
+
+
+  // write this info to a graph applet file
+  ofstream out("lrsets.g");
+  if (!out) {
+    xsyserror("ofstream open");
+  }
+  out << "# lr sets in graph form\n";
+
+  FOREACH_OBJLIST(ItemSet, itemSetsDone, itemSet) {
+    itemSet.data()->writeGraph(out);
+  }
+}
+
+// --------------- END of construct LR item sets -------------------
+
+// --------------- LR support -------------------
+// find and print all the conflicts that would be reported by
+// an SLR(1) parser; this is a superset of the conflicts reported
+// by bison, which is LALR(1); found conflicts are printed with
+// trace("conflict")
+void GrammarAnalysis::findSLRConflicts() const
+{
+  // for every item set..
+  FOREACH_OBJLIST(ItemSet, itemSets, itemSet) {
+  
+    // we want to print something special for the first conflict
+    // in a state, so track which is first
+    bool conflictAlready = false;
+
+    // for every input symbol..
+    FOREACH_TERMINAL(terminals, t) {
+      // check it
+      bool con = checkSLRConflicts(itemSet.data(), t.data(), conflictAlready);
+      conflictAlready = conflictAlready || con;
+    }
+  }
+}
+
+
+// given a parser state and an input symbol determine if we will fork
+// the parse stack; return true if there is a conflict
+bool GrammarAnalysis::checkSLRConflicts(ItemSet const *state, Terminal const *sym,
+                                        bool conflictAlready) const
+{
+  // see where a shift would go
+  ItemSet const *shiftDest = state->transitionC(sym);
+
+  // get all possible reductions where 'sym' is in Follow(LHS)
+  ProductionList reductions;
+  state->getPossibleReductions(reductions, sym, false /*parsing*/);
+
+  // case analysis
+  if (shiftDest != NULL &&
+      reductions.isEmpty()) {
+    // unambiguous shift; ok
+  }
+
+  else if (shiftDest == NULL &&
+           reductions.count() == 1) {
+    // unambiguous reduction; ok
+  }
+
+  else if (shiftDest == NULL &&
+           reductions.isEmpty()) {
+    // no transition: syntax error
+    // presumably it's really an input error, not a grammar issue,
+    // so I'd rather not see these
+  }
+
+  else {
+    // local ambiguity
+    if (!conflictAlready) {
+      trace("conflict")
+        << "--------- state " << state->id << " ----------\n"
+        << "left context: " << leftContextString(state)
+        << endl
+        << "sample input: " << sampleInput(state)
+        << endl
+        ;
+    }
+
+    trace("conflict")
+      << "conflict for symbol " << sym->name
+      << endl;
+
+    if (shiftDest) {
+      trace("conflict") << "  shift, and move to state " << shiftDest->id << endl;
+    }
+
+    SFOREACH_PRODUCTION(reductions, prod) {
+      trace("conflict") << "  reduce by rule " << *(prod.data()) << endl;
+    }
+
+    return true;    // found conflict
+  }
+  
+  return false;     // no conflict
+}
+
+
+// given an LR transition graph, compute the BFS tree on top of it
+// and set the parent links to record the tree
+void GrammarAnalysis::computeBFSTree()
+{
+  // for the BFS, we need a queue of states yet to be processed, and a
+  // pile of 'done' states
+  SObjList<ItemSet> queue;
+  SObjList<ItemSet> done;
+
+  // initial entry in queue is root of BFS tree
+  queue.append(startState);
+
+  // it will be convenient to have all the symbols in a single list
+  // for iteration purposes
+  SymbolList allSymbols;       	  // (const list)
+  {
+    FOREACH_TERMINAL(terminals, t) {
+      allSymbols.append(const_cast<Terminal*>(t.data()));
+    }
+    FOREACH_NONTERMINAL(nonterminals, nt) {
+      allSymbols.append(const_cast<Nonterminal*>(nt.data()));
+    }
+  }
+
+  // loop until the queue is exhausted
+  while (queue.isNotEmpty()) {
+    // dequeue first element
+    ItemSet *source = queue.removeAt(0);
+
+    // mark it as done so we won't consider any more transitions to it
+    done.append(source);
+
+    // for each symbol...
+    SFOREACH_SYMBOL(allSymbols, sym) {
+      // get the transition on this symbol
+      ItemSet *target = source->transition(sym.data());
+
+      // if the target is done or already enqueued, or there is no
+      // transition on this symbol, we don't need to consider it
+      // further
+      if (target == NULL ||
+          done.contains(target) || 
+          queue.contains(target)) {
+        continue;
+      }
+
+      // the source->target link just examined is the first time
+      // we've encounted 'target', so that link becomes the BFS
+      // parent link
+      target->BFSparent = source;
+
+      // finally, enqueue the target so we'll explore its targets too
+      queue.append(target);
+    }
+  }
+}
+
+// --------------- END of LR support -------------------
+
+
+// --------------- sample inputs -------------------
+// yield a sequence of names of symbols (terminals and nonterminals) that
+// will lead to the given state, from the start state
+string GrammarAnalysis::leftContextString(ItemSet const *state) const
+{
+  SymbolList ctx;
+  leftContext(ctx, state);                // get as list
+  return symbolSequenceToString(ctx);	  // convert to string
+}
+
+
+// yield the left-context as a sequence of symbols
+// CONSTNESS: want output as list of const pointers
+void GrammarAnalysis::leftContext(SymbolList &output,
+                                  ItemSet const *state) const
+{
+  // since we have the BFS tree, generating sample input (at least, if
+  // it's allowed to contain nonterminals) is a simple matter of walking
+  // the tree towards the root
+
+  // for each parent..
+  while (state->BFSparent) {
+    // get that parent
+    ItemSet *parent = state->BFSparent;
+
+    // find a symbol on which we would transition from the parent
+    // to the current state
+    Symbol const *sym = inverseTransitionC(parent, state);
+
+    // prepend that symbol's name to our current context
+    output.prepend(const_cast<Symbol*>(sym));
+
+    // move to our parent and repeat
+    state = parent;
+  }
+}
+
+
+// compare two-element quantities where one dominates and the other
+// is only for tie-breaking; return true if a's quantities are fewer
+// (candidate for adding to a library somewhere)
+int priorityFewer(int a_dominant, int b_dominant,
+                  int a_recessive, int b_recessive)
+{
+  return (a_dominant < b_dominant) ||
+       	 ((a_dominant == b_dominant) && (a_recessive < b_recessive));
+}
+
+
+// sample input (terminals only) that can lead to a state
+string GrammarAnalysis::sampleInput(ItemSet const *state) const
+{
+  // get left-context as terminals and nonterminals
+  SymbolList symbols;
+  leftContext(symbols, state);
+
+  // reduce the nonterminals to terminals
+  TerminalList terminals;
+  if (!rewriteAsTerminals(terminals, symbols)) {
+    return string("(failed to reduce!!)");
+  }
+  
+  // convert to a string
+  return terminalSequenceToString(terminals);
+}
+
+
+// given a sequence of symbols (terminals and nonterminals), use the
+// productions to rewrite it as a (hopefully minimal) sequence of
+// terminals only; return true if it works, false if we get stuck
+// in an infinite loop
+// CONSTNESS: ideally, 'output' would contain const ptrs to terminals
+bool GrammarAnalysis::rewriteAsTerminals(TerminalList &output, SymbolList const &input) const
+{
+  // we detect looping by noticing if we ever reduce the same
+  // nonterminal more than once in a single vertical recursive slice
+  // (which is necessary and sufficient for looping, since we have a
+  // context-*free* grammar)
+  NonterminalList reducedStack;      // starts empty
+
+  // start the recursive version
+  return rewriteAsTerminalsHelper(output, input, reducedStack);
+}
+
+
+// (nonterminals and terminals) -> terminals
+bool GrammarAnalysis::
+  rewriteAsTerminalsHelper(TerminalList &output, SymbolList const &input,
+                           NonterminalList &reducedStack) const
+{
+  // walk down the input list, creating the output list by copying
+  // terminals and reducing nonterminals
+  SFOREACH_SYMBOL(input, symIter) {
+    Symbol const *sym = symIter.data();
+
+    if (sym->isEmptyString) {
+      // easy; no-op
+    }
+
+    else if (sym->isTerminal()) {
+      // no sweat, just copy it (er, copy the pointer)
+      output.append(const_cast<Terminal*>(&sym->asTerminalC()));
+    }
+
+    else {
+      // not too bad either, just reduce it, sticking the result
+      // directly into our output list
+      if (!rewriteSingleNTAsTerminals(output, &sym->asNonterminalC(),
+                                      reducedStack)) {
+        // oops..
+        return false;
+      }
+    }
+  }
+
+  // ok!
+  return true;
+}
+
+
+// nonterminal -> terminals
+// CONSTNESS: want 'reducedStack' to be list of const ptrs
+bool GrammarAnalysis::
+  rewriteSingleNTAsTerminals(TerminalList &output, Nonterminal const *nonterminal,
+                             NonterminalList &reducedStack) const
+{
+  // have I already reduced this?
+  if (reducedStack.contains(nonterminal)) {
+    // we'd loop if we continued
+    trace("rewrite") << "aborting rewrite of " << nonterminal->name
+                     << " because of looping\n";
+    return false;
+  }
+
+  // add myself to the stack
+  reducedStack.prepend(const_cast<Nonterminal*>(nonterminal));
+
+  // look for best rule to use
+  Production const *best = NULL;
+
+  // for each rule with 'nonterminal' on LHS ...
+  FOREACH_PRODUCTION(productions, prodIter) {
+    Production const *prod = prodIter.data();
+    if (prod->left != nonterminal) continue;
+
+    // if 'prod' has 'nonterminal' on RHS, that would certainly
+    // lead to looping (though it's not the only way -- consider
+    // mutual recursion), so don't even consider it
+    if (prod->right.contains(nonterminal)) {
+      continue;
+    }
+
+    // no champ yet?
+    if (best == NULL) {
+      best = prod;
+      continue;
+    }
+
+    // compare new guy to existing champ
+    if (priorityFewer(prod->numRHSNonterminals(), best->numRHSNonterminals(),
+		      prod->rhsLength(), best->rhsLength())) {
+      // 'prod' is better
+      best = prod;
+    }
+  }
+
+  // I don't expect this... either the NT doesn't have any rules,
+  // or all of them are recursive (which means the language doesn't
+  // have any finite sentences)
+  if (best == NULL) {
+    trace("rewrite") << "couldn't find suitable rule to reduce "
+		     << nonterminal->name << "!!\n";
+    return false;
+  }
+
+  // now, the chosen rule provides a RHS, which is a sequence of
+  // terminals and nonterminals; recursively reduce that sequence
+  bool retval = rewriteAsTerminalsHelper(output, best->right, reducedStack);
+
+  // remove myself from stack
+  Nonterminal *temp = reducedStack.removeAt(0);
+  xassert((temp == nonterminal) || !retval);
+    // make sure pushes are paired with pops properly (unless we're just
+    // bailing out of a failed attempt, in which case some things might
+    // not get popped)
+
+  // and we succeed only if the recursive call succeeded
+  return retval;
+}
+
+// --------------- END of sample inputs -------------------
+
+
+// this is mostly [ASU] algorithm 4.7, p.218-219.  however,
+// I've modified it to store one less item on the state stack
+// (not really as optimization, just it made more sense to
+// me that way)
+void GrammarAnalysis::lrParse(char const *input)
+{
+  // tokenize the input
+  StrtokParse tok(input, " \t");
+
+  // parser state
+  int currentToken = 0;               // index of current token
+  ItemSet *state = startState;        // current parser state
+  SObjList<ItemSet> stateStack;       // stack of parser states
+  SObjList<Symbol> symbolStack;       // stack of shifted symbols
+
+  // for each token of input
+  while (currentToken < tok) {
+    // map the token text to a symbol
+    Terminal *symbol = findTerminal(tok[currentToken]);     // (constness)
+
+    // see where a shift would go
+    ItemSet *shiftDest = state->transition(symbol);
+
+    // get all possible reductions where 'sym' is in Follow(LHS)
+    ProductionList reductions;
+    state->getPossibleReductions(reductions, symbol, true /*parsing*/);
+
+    // case analysis
+    if (shiftDest != NULL &&
+        reductions.isEmpty()) {            // unambiguous shift
+      // push current state and symbol
+      stateStack.prepend(state);
+      symbolStack.prepend(symbol);
+
+      // move to new state
+      state = shiftDest;
+
+      // and to next input symbol
+      currentToken++;
+
+      // debugging
+      trace("parse")
+        << "moving to state " << state->id
+        << " after shifting symbol " << symbol->name << endl;
+    }
+
+    else if (shiftDest == NULL &&
+             reductions.count() == 1) {    // unambiguous reduction
+      // get the production we're reducing by
+      Production *prod = reductions.nth(0);
+
+      // it is here that an action or tree-building step would
+      // take place
+
+      // pop as many symbols off stack as there are symbols on
+      // the right-hand side of 'prod'; and pop one less as many
+      // states off state stack
+      INTLOOP(i, 1, prod->rhsLength()) {
+        stateStack.removeAt(0);
+        symbolStack.removeAt(0);
+      }
+      symbolStack.removeAt(0);
+
+      // in [ASU] terms, the act of forgetting 'state' is the
+      // "extra" state pop I didn't do above
+
+      // get state now on stack top
+      state = stateStack.nth(0);
+
+      // get state we're going to move to (it's like a shift
+      // on prod's LHS)
+      ItemSet *gotoDest = state->transition(prod->left);
+
+      // push prod's LHS (as in a shift)
+      symbolStack.prepend(prod->left);
+
+      // move to new state
+      state = gotoDest;
+                          
+      // again, setting 'state' is what [ASU] accomplishes with
+      // a push
+
+      // debugging
+      trace("parse")
+        << "moving to state " << state->id
+        << " after reducing by rule " << *prod << endl;
+    }
+
+    else if (shiftDest == NULL &&
+             reductions.isEmpty()) {       // no transition: syntax error
+      trace("parse")
+        << "no actions defined for symbol " << symbol->name
+        << " in state " << state->id << endl;
+      break;       // stop parsing
+    }
+
+    else {                                 // local ambiguity
+      trace("parse")
+        << "conflict for symbol " << symbol->name
+        << " in state " << state->id
+        << "; possible actions:\n";
+
+      if (shiftDest) {
+        trace("parse") << "  shift, and move to state " << shiftDest->id << endl;
+      }
+
+      SFOREACH_PRODUCTION(reductions, prod) {
+        trace("parse") << "  reduce by rule " << *(prod.data()) << endl;
+      }
+
+      break;       // stop parsing
+    }
+  }
+
+  // print final contents of stack; if the parse was successful,
+  // I want to see what remains; if not, it's interesting anyway
+  trace("parse") << "final contents of stacks (right is top):\n";
+  stateStack.reverse();    // more convenient for printing
+  symbolStack.reverse();
+
+  ostream &os = trace("parse") << "  state stack:";
+  SFOREACH_OBJLIST(ItemSet, stateStack, stateIter) {
+    os << " " << stateIter.data()->id;
+  }
+  os << " current=" << state->id;   // print current state too
+  os << endl;
+
+  trace("parse") << "  symbol stack:";
+  SFOREACH_SYMBOL(symbolStack, sym) {
+    os << " " << sym.data()->name;
+  }
+  os << endl;
+}
+
+
+// ---------------------------- main --------------------------------
+void pretendUsed(...)
+{}
+
+
+void GrammarAnalysis::exampleGrammar()
+{
+  // for now, let's use a hardcoded grammar
+
+
+
+  #if 0
+    // grammar 4.13 of [ASU] (p.191)
+    parseLine("Start  ->  S $                ");
+    parseLine("S  ->  i E t S S'   |  a      ");
+    parseLine("S' ->  e S          |  empty  ");
+    parseLine("E  ->  b                      ");
+  #endif // 0
+
+
+  #if 0
+    // grammar 4.11 of [ASU] (p.189), designed to show First and Follow
+    parseLine("S  ->  E $                ");
+    parseLine("E  ->  T E'               ");
+    parseLine("E' ->  + T E'  | empty    ");
+    parseLine("T  ->  F T'               ");
+    parseLine("T' ->  * F T'  | empty    ");
+    parseLine("F  ->  ( E )   | id       ");
+  #endif // 0
+
+
+  #if 0
+    // terminals: "a", "b", .. "e"
+    char const termLetters[] = "abcde";
+    Terminal *terms[5];
+    loopi(5) {
+      char s[2];          // will be e.g. "b\0"
+      s[0] = termLetters[i];
+      s[1] = 0;
+      terms[i] = new Terminal(s);
+      terminals.append(terms[i]);
+    }
+
+    // give then convenient names
+    Terminal *a = terms[0];
+    Terminal *b = terms[1];
+    Terminal *c = terms[2];
+    Terminal *d = terms[3];
+    Terminal *e = terms[4];
+
+    // nonterminals
+    char const * const nontermNames[] = {
+      "Start", "A", "B", "C", "D"
+    };
+    Nonterminal *nonterms[5];
+    loopi(5) {
+      nonterms[i] = new Nonterminal(nontermNames[i]);
+      nonterminals.append(nonterms[i]);
+    }
+
+    // give them convenient names
+    Nonterminal *S = nonterms[0];
+    Nonterminal *A = nonterms[1];
+    Nonterminal *B = nonterms[2];
+    Nonterminal *C = nonterms[3];
+    Nonterminal *D = nonterms[4];
+
+    // start symbol
+    startSymbol = S;
+
+    // productions
+    #define E  S
+    #define Ep A
+    #define T  B
+    #define Tp C
+    #define F  D
+    #define plus a
+    #define times b
+    #define lparen c
+    #define rparen d
+    #define id e
+    addProduction(E,  /* -> */   T, Ep,               NULL);
+    addProduction(Ep, /* -> */   plus, T, Ep,         NULL);
+    addProduction(Ep, /* -> */   &emptyString,        NULL);
+    addProduction(T,  /* -> */   F, Tp,               NULL);
+    addProduction(Tp, /* -> */   times, F, Tp,        NULL);
+    addProduction(Tp, /* -> */   &emptyString,        NULL);
+    addProduction(F,  /* -> */   lparen, E, rparen,   NULL);
+    addProduction(F,  /* -> */   id,                  NULL);
+  #endif // 0
+
+  #if 0
+    addProduction(S,  /* -> */   A, B, A, C,    NULL);
+    addProduction(A,  /* -> */   B,             NULL);
+    addProduction(B,  /* -> */   &emptyString,  NULL);
+    addProduction(C,  /* -> */   A, D,          NULL);
+    addProduction(D,  /* -> */   a,             NULL);
+  #endif // 0
+
+  #if 0
+    addProduction(S,  /* -> */   A, B, A, C,    NULL);
+    addProduction(A,  /* -> */   &emptyString,  NULL);
+    addProduction(B,  /* -> */   C, D, C,       NULL);
+    addProduction(C,  /* -> */   &emptyString,  NULL);
+    addProduction(D,  /* -> */   a,             NULL);
+  #endif // 0
+
+  #if 1
+    // [ASU] grammar 4.19, p.222: demonstrating LR sets-of-items construction
+    parseLine("E' ->  E $                ");
+    parseLine("E  ->  E + T  |  T        ");
+    parseLine("T  ->  T * F  |  F        ");
+    parseLine("F  ->  ( E )  |  id       ");
+
+    char const *input[] = {
+      " id                 $",
+      " id + id            $",
+      " id * id            $",
+      " id + id * id       $",
+      " id * id + id       $",
+      " ( id + id ) * id   $",
+      " id + id + id       $",
+      " id + ( id + id )   $"
+    };
+  #endif // 0/1
+
+  #if 0
+    // [ASU] grammar 4.20, p.229: more sets-of-items
+    parseLine("S' ->  S $                 ");
+    parseLine("S  ->  L = R               ");
+    parseLine("S  ->  R                   ");
+    parseLine("L  ->  * R                 ");
+    parseLine("L  ->  id                  ");
+    parseLine("R  ->  L                   ");
+
+    char const *input[] = {
+      " id                 $",
+      " id = id            $",
+      " * id = id          $",
+      " id = * id          $",
+      " * id = * id        $",
+      " * * id = * * id    $"
+    };
+  #endif // 0
+
+
+  // verify we got what we expected
+  printProductions(trace("grammar") << endl);
+
+
+  // run analyses
+  runAnalyses();
+
+
+  // do some test parses
+  INTLOOP(i, 0, (int)TABLESIZE(input)) {
+    trace("parse") << "------ parsing: `" << input[i] << "' -------\n";
+    lrParse(input[i]);
+  }
+}
+
+
+void GrammarAnalysis::runAnalyses()
+{
+  checkWellFormed();
+
+  // precomputations
+  trace("progress") << "init...\n";
+  initializeAuxData();
+
+  trace("progress") << "derivability relation...\n";
+  computeWhatCanDeriveWhat();
+
+  trace("progress") << "first...\n";
+  computeFirst();
+
+  trace("progress") << "follow...\n";
+  computeFollow();
+
+  // print results
+  {
+    ostream &tracer = trace("terminals") << "Terminals:\n";
+    printSymbols(tracer, toObjList(terminals));
+  }
+  {
+    ostream &tracer = trace("nonterminals") << "Nonterminals:\n";
+    tracer << "  " << emptyString << endl;
+    printSymbols(tracer, toObjList(nonterminals));
+  }
+
+  if (tracingSys("derivable")) {
+    derivable->print();
+  }
+    
+  // testing closure
+  #if 0
+  {
+    // make a singleton set out of the first production, and
+    // with the dot at the start
+    DProductionList itemSet;
+    DottedProduction *kernel = productions.nth(0)->getDProd(0);  // (serf)
+    itemSet.append(kernel);
+
+    // compute its closure
+    itemSetClosure(itemSet);
+
+    // print it
+    cout << "Closure of: ";
+    kernel->print(cout);
+    cout << endl;
+
+    SFOREACH_DOTTEDPRODUCTION(itemSet, dprod) {
+      cout << "  ";
+      dprod.data()->print(cout);
+      cout << endl;
+    }
+  }
+  #endif // 0
+
+
+  // LR stuff
+  trace("progress") << "LR item sets...\n";
+  constructLRItemSets();
+
+  trace("progress") << "SLR conflicts...\n";
+  findSLRConflicts();
+
+  // another analysis
+  //computePredictiveParsingTable();
+
+  // silence warnings
+  //pretendUsed(a,b,c,d,e, S,A,B,C,D);
+}
+
+
+#ifdef GRAMANL_MAIN
+int main()
+{
+  GrammarAnalysis g;
+  g.exampleGrammar();
+  return 0;
+}
+#endif // GRAMANL_MAIN

Added: vendor/elsa/current/elkhound/in/cdecl.in1
===================================================================
--- vendor/elsa/current/elkhound/in/cdecl.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cdecl.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+
+int(x);
+foo(y);
+
+{
+  int(x);
+  typedef int integer;
+  integer(y);
+  integer(q);
+}
+
+integer(z);
+integer(w);
+

Added: vendor/elsa/current/elkhound/in/cexp.in1
===================================================================
--- vendor/elsa/current/elkhound/in/cexp.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cexp.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// cexp.in1
+// simple test of cexp2.gr
+
+x=3; x + x * x + x
+

Added: vendor/elsa/current/elkhound/in/cexp2.in2
===================================================================
--- vendor/elsa/current/elkhound/in/cexp2.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cexp2.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// cexp2.in2
+// more complicated example
+
+x=4, y=8, z=0-1; x * y + y / x - 17 + z * y
+
+//               ^^^^^   ^^^^^        ^^^^^
+//                32       2            -8
+//                ^^^^^^^^^^
+//                     34
+//                     ^^^^^^^^^^^^
+//                          17
+//                          ^^^^^^^^^^^^^^
+//                                9

Added: vendor/elsa/current/elkhound/in/cexp3.in1
===================================================================
--- vendor/elsa/current/elkhound/in/cexp3.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cexp3.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+// cexp3.in1
+
+1+2*3

Added: vendor/elsa/current/elkhound/in/cexp3.in2
===================================================================
--- vendor/elsa/current/elkhound/in/cexp3.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/cexp3.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+// cexp3.in2
+
+1+2*3+4

Added: vendor/elsa/current/elkhound/in/expr.in1
===================================================================
--- vendor/elsa/current/elkhound/in/expr.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/expr.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2 @@
+x + x * x + x $
+

Added: vendor/elsa/current/elkhound/in/ffollow.in1
===================================================================
--- vendor/elsa/current/elkhound/in/ffollow.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/ffollow.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+id $

Added: vendor/elsa/current/elkhound/in/gramlex.in1
===================================================================
--- vendor/elsa/current/elkhound/in/gramlex.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/gramlex.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// gramlex.in1
+// test input for grammar lexer
+
+foo bar(5);
+
+include("a filename")
+
+include("something unterminated
+
+!    // illegal character
+
+67 {}
+
+/* unterminated comment
+   2nd line, last of file

Added: vendor/elsa/current/elkhound/in/gramlex.in2
===================================================================
--- vendor/elsa/current/elkhound/in/gramlex.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/gramlex.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// gramlex.in2
+// test file inclusion
+
+some stuff
+
+3+4
+
+{ include("gramlex.in3") }
+
+fundecl int foo();
+
+fun foo { 
+  return 4; 
+}
+fun bar = 5;
+
+end of gramlex.in2

Added: vendor/elsa/current/elkhound/in/gramlex.in3
===================================================================
--- vendor/elsa/current/elkhound/in/gramlex.in3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/gramlex.in3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+
+this is gramlex.in3
+

Added: vendor/elsa/current/elkhound/in/lexer2.in1
===================================================================
--- vendor/elsa/current/elkhound/in/lexer2.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/lexer2.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// some junk
+   
+bar
+"a" "b" "c\
+d"
+foo

Added: vendor/elsa/current/elkhound/in/mem.in1
===================================================================
--- vendor/elsa/current/elkhound/in/mem.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/mem.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,54 @@
+// mem.in1
+// simple functions that manage memory
+
+int * owner malloc();
+void free(int * owner p);
+void do_stuff(int *p, int *q);
+
+void ok()
+{
+  int * owner p;
+  p = malloc();
+  if (p) {
+    *p = 5;
+    free(p);
+  }
+}
+
+void leaks()
+{
+  int * owner p;
+  p = malloc();
+  p = malloc();           // LEAK of p
+}                         // LEAK of p
+
+void bad_derefs()
+{
+  int * owner p;
+  *p = 6;                 // BAD DEREF
+  p = 0;
+  *p = 7;                 // BAD DEREF
+}
+
+void more_complicated()
+{
+  int * owner p, * owner q;
+  p = malloc();
+  if (p) {
+    q = malloc();
+    if (q) {
+      do_stuff(p, q);
+      free(q);
+    }
+    free(p);
+  }
+}
+
+/*
+void bad()
+{
+  int * q;
+  q = malloc();
+  free(q);
+}
+*/

Added: vendor/elsa/current/elkhound/in/mem.in2
===================================================================
--- vendor/elsa/current/elkhound/in/mem.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/mem.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+// mem.in2
+// experimenting with arrays of owner pointers
+
+int * owner malloc();
+void free(int * owner p);
+
+void f1()
+{
+  int * owner p[5];    // (auto) array of 5 owner pointers
+  int i;
+
+  // here, 'p' is <uninit>
+
+  INTLOOP(i,5) {       // for(i=0; i<5; i++)
+
+    // invariant: 'p' is <i:init,uninit,uninit>
+
+    p[i] = malloc();
+
+    // here, 'p' is <i:init,init?,uninit>
+
+    if (!p[i]) {
+
+      // 'p' is <i:init,null,uninit>
+
+      abort();
+
+      // 'p' is top
+
+      /*
+      for (j=0; j<i; j++) {
+        free(p[j]);
+      }
+      break;
+      */
+    }
+
+    // 'p' is <i:init,init,uninit>
+
+  }
+
+  // here, 'p' is <init>
+
+}
+

Added: vendor/elsa/current/elkhound/in/mem.in3
===================================================================
--- vendor/elsa/current/elkhound/in/mem.in3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/mem.in3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// mem.in3
+// some array code
+
+struct List {
+  List * owner next;
+};
+
+List * owner append(List owner *head, List owner *tail)
+{
+  if (!head) {
+    return tail;
+  }
+  else {
+    List /*serf*/ *tmp;
+    tmp = head;
+    while (tmp->next) {
+      tmp = tmp->next;
+    }
+    tmp->next = tail;            // swap(tmp->next, tail);
+    return head;
+  }
+}

Added: vendor/elsa/current/elkhound/in/pc_keyb.i
===================================================================
--- vendor/elsa/current/elkhound/in/pc_keyb.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/pc_keyb.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19247 @@
+# 1 "pc_keyb.c"
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/config.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/autoconf.h" 1
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+# 4 "/usr/src/linux/include/linux/config.h" 2
+
+
+
+# 18 "pc_keyb.c" 2
+
+
+# 1 "/usr/src/linux/include/asm/spinlock.h" 1
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+  typedef struct { } spinlock_t;
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 80 "/usr/src/linux/include/asm/spinlock.h"
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+  typedef struct { } rwlock_t;
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 253 "/usr/src/linux/include/asm/spinlock.h"
+
+
+# 20 "pc_keyb.c" 2
+
+# 1 "/usr/src/linux/include/linux/sched.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/param.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 4 "/usr/src/linux/include/linux/sched.h" 2
+
+
+extern unsigned long global_event;
+
+# 1 "/usr/src/linux/include/linux/binfmts.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/ptrace.h" 1
+
+
+ 
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/ptrace.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+struct pt_regs {
+	long ebx;
+	long ecx;
+	long edx;
+	long esi;
+	long edi;
+	long ebp;
+	long eax;
+	int  xds;
+	int  xes;
+	long orig_eax;
+	long eip;
+	int  xcs;
+	long eflags;
+	long esp;
+	int  xss;
+};
+
+ 
+
+
+
+
+
+
+
+
+extern void show_regs(struct pt_regs *);
+
+
+
+# 24 "/usr/src/linux/include/linux/ptrace.h" 2
+
+
+
+# 4 "/usr/src/linux/include/linux/binfmts.h" 2
+
+# 1 "/usr/src/linux/include/linux/capability.h" 1
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+# 1 "/usr/src/linux/include/linux/types.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/posix_types.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/stddef.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 4 "/usr/src/linux/include/linux/posix_types.h" 2
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct {
+	unsigned long fds_bits [(1024 / (8 * sizeof(unsigned long)) ) ];
+} __kernel_fd_set;
+
+ 
+typedef void (*__kernel_sighandler_t)(int);
+
+ 
+typedef int __kernel_key_t;
+
+# 1 "/usr/src/linux/include/asm/posix_types.h" 1
+
+
+
+ 
+
+
+
+
+
+typedef unsigned short	__kernel_dev_t;
+typedef unsigned long	__kernel_ino_t;
+typedef unsigned short	__kernel_mode_t;
+typedef unsigned short	__kernel_nlink_t;
+typedef long		__kernel_off_t;
+typedef int		__kernel_pid_t;
+typedef unsigned short	__kernel_ipc_pid_t;
+typedef unsigned short	__kernel_uid_t;
+typedef unsigned short	__kernel_gid_t;
+typedef unsigned int	__kernel_size_t;
+typedef int		__kernel_ssize_t;
+typedef int		__kernel_ptrdiff_t;
+typedef long		__kernel_time_t;
+typedef long		__kernel_suseconds_t;
+typedef long		__kernel_clock_t;
+typedef int		__kernel_daddr_t;
+typedef char *		__kernel_caddr_t;
+
+
+typedef long long	__kernel_loff_t;
+
+
+typedef struct {
+
+	int	val[2];
+
+
+
+} __kernel_fsid_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 70 "/usr/src/linux/include/asm/posix_types.h"
+
+
+
+
+# 46 "/usr/src/linux/include/linux/posix_types.h" 2
+
+
+
+# 4 "/usr/src/linux/include/linux/types.h" 2
+
+# 1 "/usr/src/linux/include/asm/types.h" 1
+
+
+
+typedef unsigned short umode_t;
+
+ 
+
+
+
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+
+
+ 
+
+
+
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+
+
+
+
+
+# 5 "/usr/src/linux/include/linux/types.h" 2
+
+
+
+
+typedef __kernel_fd_set		fd_set;
+typedef __kernel_dev_t		dev_t;
+typedef __kernel_ino_t		ino_t;
+typedef __kernel_mode_t		mode_t;
+typedef __kernel_nlink_t	nlink_t;
+typedef __kernel_off_t		off_t;
+typedef __kernel_pid_t		pid_t;
+typedef __kernel_uid_t		uid_t;
+typedef __kernel_gid_t		gid_t;
+typedef __kernel_daddr_t	daddr_t;
+typedef __kernel_key_t		key_t;
+typedef __kernel_suseconds_t	suseconds_t;
+
+
+typedef __kernel_loff_t		loff_t;
+
+
+ 
+
+
+
+
+
+typedef __kernel_size_t		size_t;
+
+
+
+
+typedef __kernel_ssize_t	ssize_t;
+
+
+
+
+typedef __kernel_ptrdiff_t	ptrdiff_t;
+
+
+
+
+typedef __kernel_time_t		time_t;
+
+
+
+
+typedef __kernel_clock_t	clock_t;
+
+
+
+
+typedef __kernel_caddr_t	caddr_t;
+
+
+ 
+typedef unsigned char		u_char;
+typedef unsigned short		u_short;
+typedef unsigned int		u_int;
+typedef unsigned long		u_long;
+
+ 
+typedef unsigned char		unchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+
+
+
+
+typedef		__u8		u_int8_t;
+typedef		__s8		int8_t;
+typedef		__u16		u_int16_t;
+typedef		__s16		int16_t;
+typedef		__u32		u_int32_t;
+typedef		__s32		int32_t;
+
+
+
+typedef		__u8		uint8_t;
+typedef		__u16		uint16_t;
+typedef		__u32		uint32_t;
+
+
+typedef		__u64		uint64_t;
+typedef		__u64		u_int64_t;
+typedef		__s64		int64_t;
+
+
+
+
+ 
+
+
+
+
+struct ustat {
+	__kernel_daddr_t	f_tfree;
+	__kernel_ino_t		f_tinode;
+	char			f_fname[6];
+	char			f_fpack[6];
+};
+
+
+# 16 "/usr/src/linux/include/linux/capability.h" 2
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+typedef struct __user_cap_header_struct {
+	__u32 version;
+	int pid;
+} *cap_user_header_t;
+ 
+typedef struct __user_cap_data_struct {
+        __u32 effective;
+        __u32 permitted;
+        __u32 inheritable;
+} *cap_user_data_t;
+  
+
+
+ 
+
+
+
+
+
+
+
+
+
+typedef __u32 kernel_cap_t;
+
+
+  
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+    
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+ 
+ 
+ 
+
+
+
+ 
+ 
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+ 
+
+
+
+ 
+ 
+ 
+ 
+ 
+
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+
+ 
+ 
+
+
+
+ 
+ 
+
+
+
+
+ 
+
+
+
+ 
+ 
+
+
+ 
+
+
+
+ 
+
+
+
+ 
+
+
+
+ 
+
+
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+ 
+
+
+
+ 
+
+
+
+ 
+
+ 
+
+
+
+
+
+ 
+ 
+ 
+ 
+
+ 
+ 
+ 
+ 
+
+
+
+ 
+ 
+ 
+
+
+
+ 
+ 
+
+
+
+
+ 
+
+
+extern kernel_cap_t cap_bset;
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b)
+{
+     kernel_cap_t dest;
+     ( dest )  = ( a )  | ( b ) ;
+     return dest;
+}
+
+static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b)
+{
+     kernel_cap_t dest;
+     ( dest )  = ( a )  & ( b ) ;     // AMBIGUOUS
+     return dest;
+}
+
+static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop)
+{
+     kernel_cap_t dest;
+     ( dest )  = ( a )  & ~( drop ) ;     // AMBIGUOUS
+     return dest;
+}
+
+static inline kernel_cap_t cap_invert(kernel_cap_t c)
+{
+     kernel_cap_t dest;
+     ( dest )  = ~( c ) ;
+     return dest;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 5 "/usr/src/linux/include/linux/binfmts.h" 2
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+struct linux_binprm{
+	char buf[128];
+	unsigned long page[32 ];
+	unsigned long p;
+	int sh_bang;
+	int java;		 
+	struct dentry * dentry;
+	int e_uid, e_gid;
+	kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
+	int argc, envc;
+	char * filename;	 
+	unsigned long loader, exec;
+};
+
+ 
+
+
+
+struct linux_binfmt {
+	struct linux_binfmt * next;
+	struct module *module;
+	int (*load_binary)(struct linux_binprm *, struct  pt_regs * regs);
+	int (*load_shlib)(int fd);
+	int (*core_dump)(long signr, struct pt_regs * regs);
+};
+
+extern int register_binfmt(struct linux_binfmt *);
+extern int unregister_binfmt(struct linux_binfmt *);
+
+extern int read_exec(struct dentry *, unsigned long offset,
+	char * addr, unsigned long count, int to_kmem);
+
+extern int open_dentry(struct dentry *, int mode);
+
+extern int init_elf_binfmt(void);
+extern int init_elf32_binfmt(void);
+extern int init_irix_binfmt(void);
+extern int init_aout_binfmt(void);
+extern int init_aout32_binfmt(void);
+extern int init_script_binfmt(void);
+extern int init_java_binfmt(void);
+extern int init_em86_binfmt(void);
+extern int init_misc_binfmt(void);
+
+extern int prepare_binprm(struct linux_binprm *);
+extern void remove_arg_zero(struct linux_binprm *);
+extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
+extern int flush_old_exec(struct linux_binprm * bprm);
+extern unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm);
+extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
+		unsigned long p, int from_kmem);
+
+extern void compute_creds(struct linux_binprm *binprm);
+
+ 
+
+
+
+
+# 8 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/personality.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/linkage.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 52 "/usr/src/linux/include/linux/linkage.h"
+
+
+
+# 4 "/usr/src/linux/include/linux/personality.h" 2
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+typedef void (*lcall7_func)(struct pt_regs *);
+
+
+ 
+
+
+
+
+struct exec_domain {
+	const char *name;
+	lcall7_func handler;
+	unsigned char pers_low, pers_high;
+	unsigned long * signal_map;
+	unsigned long * signal_invmap;
+	struct module * module;
+	struct exec_domain *next;
+};
+
+extern struct exec_domain default_exec_domain;
+
+extern struct exec_domain *lookup_exec_domain(unsigned long personality);
+extern int register_exec_domain(struct exec_domain *it);
+extern int unregister_exec_domain(struct exec_domain *it);
+  __attribute__((regparm(0)))  int sys_personality(unsigned long personality);
+
+
+# 9 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/tasks.h" 1
+
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+# 10 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/kernel.h" 1
+
+
+
+ 
+
+
+
+
+
+# 1 "/usr/lib/gcc-lib/i386-slackware-linux/egcs-2.91.66/include/stdarg.h" 1 3
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+typedef void *__gnuc_va_list;
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void va_end (__gnuc_va_list);		 
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 168 "/usr/lib/gcc-lib/i386-slackware-linux/egcs-2.91.66/include/stdarg.h" 3
+
+
+ 
+
+
+
+
+ 
+
+ 
+
+ 
+
+typedef __gnuc_va_list va_list;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 10 "/usr/src/linux/include/linux/kernel.h" 2
+
+
+
+ 
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern void math_error(void);
+extern struct notifier_block *panic_notifier_list;
+  void panic(const char * fmt, ...)
+	__attribute__ ((noreturn,  format (printf, 1, 2)));
+  void do_exit(long error_code)
+	__attribute__((noreturn)) ;
+extern unsigned long simple_strtoul(const char *,char **,unsigned int);
+extern long simple_strtol(const char *,char **,unsigned int);
+extern int sprintf(char * buf, const char * fmt, ...);
+extern int vsprintf(char *buf, const char *, va_list);
+
+extern int session_of_pgrp(int pgrp);
+
+  __attribute__((regparm(0)))  int printk(const char * fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+struct sysinfo {
+	long uptime;			 
+	unsigned long loads[3];		 
+	unsigned long totalram;		 
+	unsigned long freeram;		 
+	unsigned long sharedram;	 
+	unsigned long bufferram;	 
+	unsigned long totalswap;	 
+	unsigned long freeswap;		 
+	unsigned short procs;		 
+	char _f[22];			 
+};
+
+
+# 11 "/usr/src/linux/include/linux/sched.h" 2
+
+
+# 1 "/usr/src/linux/include/linux/times.h" 1
+
+
+
+struct tms {
+	clock_t tms_utime;
+	clock_t tms_stime;
+	clock_t tms_cutime;
+	clock_t tms_cstime;
+};
+
+
+# 13 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/timex.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+# 1 "/usr/src/linux/include/asm/timex.h" 1
+ 
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/msr.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 10 "/usr/src/linux/include/asm/timex.h" 2
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned long cycles_t;
+
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles (void)
+{
+
+
+
+	unsigned long eax, edx;
+
+	__asm__ __volatile__("rdtsc" : "=a" ( eax ), "=d" ( edx )) ;
+	return eax;
+
+}
+
+
+# 138 "/usr/src/linux/include/linux/timex.h" 2
+
+ 
+
+
+# 1 "/usr/src/linux/include/linux/time.h" 1
+
+
+
+
+
+
+
+
+struct timespec {
+	time_t	tv_sec;		 
+	long	tv_nsec;	 
+};
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+static __inline__ unsigned long
+timespec_to_jiffies(struct timespec *value)
+{
+	unsigned long sec = value->tv_sec;
+	long nsec = value->tv_nsec;
+
+	if (sec >= (((~0UL >> 1)-1)  / 100 ))
+		return ((~0UL >> 1)-1) ;
+	nsec += 1000000000L / 100  - 1;
+	nsec /= 1000000000L / 100 ;
+	return 100  * sec + nsec;
+}
+
+static __inline__ void
+jiffies_to_timespec(unsigned long jiffies, struct timespec *value)
+{
+	value->tv_nsec = (jiffies % 100 ) * (1000000000L / 100 );
+	value->tv_sec = jiffies / 100 ;
+}
+ 
+struct timeval {
+	time_t		tv_sec;		 
+	suseconds_t	tv_usec;	 
+};
+
+struct timezone {
+	int	tz_minuteswest;	 
+	int	tz_dsttime;	 
+};
+
+
+
+
+extern void do_gettimeofday(struct timeval *tv);
+extern void do_settimeofday(struct timeval *tv);
+extern void get_fast_time(struct timeval *tv);
+extern void (*do_get_fast_time)(struct timeval *);
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+struct  itimerspec {
+        struct  timespec it_interval;     
+        struct  timespec it_value;        
+};
+
+struct	itimerval {
+	struct	timeval it_interval;	 
+	struct	timeval it_value;	 
+};
+
+
+# 142 "/usr/src/linux/include/linux/timex.h" 2
+
+
+ 
+
+
+ 
+
+
+
+struct timex {
+	unsigned int modes;	 
+	long offset;		 
+	long freq;		 
+	long maxerror;		 
+	long esterror;		 
+	int status;		 
+	long constant;		 
+	long precision;		 
+	long tolerance;		 
+
+
+	struct timeval time;	 
+	long tick;		 
+
+	long ppsfreq;            
+	long jitter;             
+	int shift;               
+	long stabil;             
+	long jitcnt;             
+	long calcnt;             
+	long errcnt;             
+	long stbcnt;             
+
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+extern long tick;                       
+extern int tickadj;			 
+
+ 
+
+
+extern int time_state;		 
+extern int time_status;		 
+extern long time_offset;	 
+extern long time_constant;	 
+extern long time_tolerance;	 
+extern long time_precision;	 
+extern long time_maxerror;	 
+extern long time_esterror;	 
+
+extern long time_phase;		 
+extern long time_freq;		 
+extern long time_adj;		 
+extern long time_reftime;	 
+
+extern long time_adjust;	 
+
+ 
+extern long pps_offset;		 
+extern long pps_jitter;		 
+extern long pps_freq;		 
+extern long pps_stabil;		 
+extern long pps_valid;		 
+
+ 
+extern int pps_shift;		 
+extern long pps_jitcnt;		 
+extern long pps_calcnt;		 
+extern long pps_errcnt;		 
+extern long pps_stbcnt;		 
+
+
+
+
+# 14 "/usr/src/linux/include/linux/sched.h" 2
+
+
+# 1 "/usr/src/linux/include/asm/system.h" 1
+
+
+
+
+# 1 "/usr/src/linux/include/asm/segment.h" 1
+
+
+
+
+
+
+
+
+
+
+# 5 "/usr/src/linux/include/asm/system.h" 2
+
+
+
+
+struct task_struct;	 
+extern void  __switch_to(struct task_struct *prev, struct task_struct *next)  __attribute__((regparm(3))) ;
+
+
+# 31 "/usr/src/linux/include/asm/system.h"
+
+
+# 43 "/usr/src/linux/include/asm/system.h"
+
+
+# 56 "/usr/src/linux/include/asm/system.h"
+
+
+
+
+static inline unsigned long _get_base(char * addr)
+{
+	unsigned long __base;
+	__asm__("movb %3,%%dh\n\t"
+		"movb %2,%%dl\n\t"
+		"shll $16,%%edx\n\t"
+		"movw %1,%%dx"
+		:"=&d" (__base)
+		:"m" (*((addr)+2)),
+		 "m" (*((addr)+4)),
+		 "m" (*((addr)+7)));
+	return __base;
+}
+
+
+
+ 
+
+
+
+
+# 96 "/usr/src/linux/include/asm/system.h"
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static inline unsigned long get_limit(unsigned long segment)
+{
+	unsigned long __limit;
+	__asm__("lsll %1,%0"
+		:"=r" (__limit):"r" (segment));
+	return __limit+1;
+}
+
+
+
+
+
+
+struct __xchg_dummy { unsigned long a[100]; };
+
+
+ 
+
+
+static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
+{
+	switch (size) {
+		case 1:
+			__asm__("xchgb %b0,%1"
+				:"=q" (x)
+				:"m" (* ((struct __xchg_dummy *)( ptr )) ), "0" (x)
+				:"memory");
+			break;
+		case 2:
+			__asm__("xchgw %w0,%1"
+				:"=r" (x)
+				:"m" (* ((struct __xchg_dummy *)( ptr )) ), "0" (x)
+				:"memory");
+			break;
+		case 4:
+			__asm__("xchgl %0,%1"
+				:"=r" (x)
+				:"m" (* ((struct __xchg_dummy *)( ptr )) ), "0" (x)
+				:"memory");
+			break;
+	}
+	return x;
+}
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+# 196 "/usr/src/linux/include/asm/system.h"
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+void disable_hlt(void);
+void enable_hlt(void);
+
+
+# 16 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/asm/semaphore.h" 1
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/atomic.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+typedef struct { int counter; } atomic_t;
+
+
+
+
+
+
+
+static __inline__ void atomic_add(int i, volatile atomic_t *v)
+{
+	__asm__ __volatile__(
+		""  "addl %1,%0"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) )
+		:"ir" (i), "m" ((*(volatile struct { int a[100]; } *) v ) ));
+}
+
+static __inline__ void atomic_sub(int i, volatile atomic_t *v)
+{
+	__asm__ __volatile__(
+		""  "subl %1,%0"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) )
+		:"ir" (i), "m" ((*(volatile struct { int a[100]; } *) v ) ));
+}
+
+static __inline__ void atomic_inc(volatile atomic_t *v)
+{
+	__asm__ __volatile__(
+		""  "incl %0"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) )
+		:"m" ((*(volatile struct { int a[100]; } *) v ) ));
+}
+
+static __inline__ void atomic_dec(volatile atomic_t *v)
+{
+	__asm__ __volatile__(
+		""  "decl %0"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) )
+		:"m" ((*(volatile struct { int a[100]; } *) v ) ));
+}
+
+static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		""  "decl %0; sete %1"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) ), "=qm" (c)
+		:"m" ((*(volatile struct { int a[100]; } *) v ) ));
+	return c != 0;
+}
+
+extern __inline__ int atomic_inc_and_test_greater_zero(volatile atomic_t *v)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		""  "incl %0; setg %1"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) ), "=qm" (c)
+		:"m" ((*(volatile struct { int a[100]; } *) v ) ));
+	return c;  
+}
+
+ 
+
+
+
+
+
+
+
+
+
+# 32 "/usr/src/linux/include/asm/semaphore.h" 2
+
+
+
+struct semaphore {
+	atomic_t count;
+	int waking;
+	struct wait_queue * wait;
+};
+
+
+
+
+  __attribute__((regparm(0)))  void __down_failed(void  );
+  __attribute__((regparm(0)))  int  __down_failed_interruptible(void   );
+  __attribute__((regparm(0)))  int  __down_failed_trylock(void   );
+  __attribute__((regparm(0)))  void __up_wakeup(void  );
+
+  __attribute__((regparm(0)))  void __down(struct semaphore * sem);
+  __attribute__((regparm(0)))  int  __down_interruptible(struct semaphore * sem);
+  __attribute__((regparm(0)))  int  __down_trylock(struct semaphore * sem);
+  __attribute__((regparm(0)))  void __up(struct semaphore * sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+
+
+ 
+
+
+
+
+extern inline void down(struct semaphore * sem)
+{
+	__asm__ __volatile__(
+		"# atomic down operation\n\t"
+
+
+
+		"decl (%0)\n\t"      
+		"js 2f\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		"2:\tcall __down_failed\n\t"
+		"jmp 1b\n"
+		".previous"
+		: 
+		:"c" (sem)
+		:"memory");
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+	int result;
+
+	__asm__ __volatile__(
+		"# atomic interruptible down operation\n\t"
+
+
+
+		"decl (%1)\n\t"      
+		"js 2f\n\t"
+		"xorl %0,%0\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		"2:\tcall __down_failed_interruptible\n\t"
+		"jmp 1b\n"
+		".previous"
+		:"=a" (result)
+		:"c" (sem)
+		:"memory");
+	return result;
+}
+
+extern inline int down_trylock(struct semaphore * sem)
+{
+	int result;
+
+	__asm__ __volatile__(
+		"# atomic interruptible down operation\n\t"
+
+
+
+		"decl (%1)\n\t"      
+		"js 2f\n\t"
+		"xorl %0,%0\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		"2:\tcall __down_failed_trylock\n\t"
+		"jmp 1b\n"
+		".previous"
+		:"=a" (result)
+		:"c" (sem)
+		:"memory");
+	return result;
+}
+
+ 
+
+
+
+
+
+extern inline void up(struct semaphore * sem)
+{
+	__asm__ __volatile__(
+		"# atomic up operation\n\t"
+
+
+
+		"incl (%0)\n\t"      
+		"jle 2f\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		"2:\tcall __up_wakeup\n\t"
+		"jmp 1b\n"
+		".previous"
+		: 
+		:"c" (sem)
+		:"memory");
+}
+
+
+# 17 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/asm/page.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+
+
+
+
+
+
+
+
+
+
+# 55 "/usr/src/linux/include/asm/page.h"
+
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/page_offset.h" 1
+
+
+
+
+
+
+
+
+# 83 "/usr/src/linux/include/asm/page.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+# 18 "/usr/src/linux/include/linux/sched.h" 2
+
+
+# 1 "/usr/src/linux/include/linux/smp.h" 1
+
+
+
+ 
+
+
+
+
+# 71 "/usr/src/linux/include/linux/smp.h"
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+# 20 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/tty.h" 1
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+		 
+
+
+
+
+# 1 "/usr/src/linux/include/linux/fs.h" 1
+
+
+
+ 
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/limits.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 11 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/wait.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+struct wait_queue {
+	struct task_struct * task;
+	struct wait_queue * next;
+};
+
+
+
+static inline void init_waitqueue(struct wait_queue **q)
+{
+	*q = ((struct wait_queue *)(( q )-1)) ;   // AMBIGUOUS
+}
+
+static inline int waitqueue_active(struct wait_queue **q)
+{
+	struct wait_queue *head = *q;
+	return head && head != ((struct wait_queue *)(( q )-1)) ;   // AMBIGUOUS
+}
+
+
+
+
+# 12 "/usr/src/linux/include/linux/fs.h" 2
+
+
+# 1 "/usr/src/linux/include/linux/vfs.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/statfs.h" 1
+
+
+
+
+
+
+
+typedef __kernel_fsid_t	fsid_t;
+
+
+
+struct statfs {
+	long f_type;
+	long f_bsize;
+	long f_blocks;
+	long f_bfree;
+	long f_bavail;
+	long f_files;
+	long f_ffree;
+	__kernel_fsid_t f_fsid;
+	long f_namelen;
+	long f_spare[6];
+};
+
+
+# 4 "/usr/src/linux/include/linux/vfs.h" 2
+
+
+
+# 14 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/net.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/socket.h" 1
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/socket.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/sockios.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+# 4 "/usr/src/linux/include/asm/socket.h" 2
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+ 
+
+
+
+
+
+
+					 
+					 
+					 
+					 
+
+
+
+# 6 "/usr/src/linux/include/linux/socket.h" 2
+
+# 1 "/usr/src/linux/include/linux/sockios.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+		     
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+ 
+
+
+
+
+
+ 
+
+
+ 
+
+
+ 
+
+
+# 7 "/usr/src/linux/include/linux/socket.h" 2
+
+# 1 "/usr/src/linux/include/linux/uio.h" 1
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+struct iovec
+{
+	void *iov_base;		 
+	__kernel_size_t iov_len;  
+};
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+# 8 "/usr/src/linux/include/linux/socket.h" 2
+
+
+
+typedef unsigned short	sa_family_t;
+
+ 
+
+
+ 
+struct sockaddr {
+	sa_family_t	sa_family;	 
+	char		sa_data[14];	 
+};
+
+struct linger {
+	int		l_onoff;	 
+	int		l_linger;	 
+};
+
+ 
+
+
+
+
+ 
+struct msghdr {
+	void	*	msg_name;	 
+	int		msg_namelen;	 
+	struct iovec *	msg_iov;	 
+	__kernel_size_t	msg_iovlen;	 
+	void 	*	msg_control;	 
+	__kernel_size_t	msg_controllen;	 
+	unsigned	msg_flags;
+};
+
+ 
+
+
+
+
+
+struct cmsghdr {
+	__kernel_size_t	cmsg_len;	 
+        int		cmsg_level;	 
+        int		cmsg_type;	 
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+extern __inline__  struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
+					       struct cmsghdr *__cmsg)
+{
+	struct cmsghdr * __ptr;
+
+	__ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) +  ( (( __cmsg->cmsg_len )+sizeof(long)-1) & ~(sizeof(long)-1) ) );
+	if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+		return (struct cmsghdr*)0;
+
+	return __ptr;
+}
+
+extern __inline__  struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
+{
+	return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
+}
+
+ 
+
+
+
+
+
+struct ucred {
+	__u32	pid;
+	__u32	uid;
+	__u32	gid;
+};
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+
+
+
+extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
+extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, 
+				int offset, int len);
+extern int csum_partial_copy_fromiovecend(unsigned char *kdata, 
+					  struct iovec *iov, 
+					  int offset, 
+					  unsigned int len, int *csump);
+
+extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode);
+extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
+extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len);
+extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
+extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
+extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
+
+
+
+# 279 "/usr/src/linux/include/linux/socket.h"
+
+
+# 21 "/usr/src/linux/include/linux/net.h" 2
+
+
+struct poll_table_struct;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef enum {
+  SS_FREE = 0,				 
+  SS_UNCONNECTED,			 
+  SS_CONNECTING,			 
+  SS_CONNECTED,				 
+  SS_DISCONNECTING			 
+} socket_state;
+
+
+
+
+
+
+
+struct socket
+{
+	socket_state		state;
+
+	unsigned long		flags;
+	struct proto_ops	*ops;
+	struct inode		*inode;
+	struct fasync_struct	*fasync_list;	 
+	struct file		*file;		 
+	struct sock		*sk;
+	struct wait_queue	*wait;
+
+	short			type;
+	unsigned char		passcred;
+	unsigned char		tli;
+};
+
+
+
+struct scm_cookie;
+
+struct proto_ops {
+  int	family;
+
+  int	(*dup)		(struct socket *newsock, struct socket *oldsock);
+  int	(*release)	(struct socket *sock, struct socket *peer);
+  int	(*bind)		(struct socket *sock, struct sockaddr *umyaddr,
+			 int sockaddr_len);
+  int	(*connect)	(struct socket *sock, struct sockaddr *uservaddr,
+			 int sockaddr_len, int flags);
+  int	(*socketpair)	(struct socket *sock1, struct socket *sock2);
+  int	(*accept)	(struct socket *sock, struct socket *newsock,
+			 int flags);
+  int	(*getname)	(struct socket *sock, struct sockaddr *uaddr,
+			 int *usockaddr_len, int peer);
+  unsigned int (*poll)	(struct file *file, struct socket *sock, struct poll_table_struct *wait);
+  int	(*ioctl)	(struct socket *sock, unsigned int cmd,
+			 unsigned long arg);
+  int	(*listen)	(struct socket *sock, int len);
+  int	(*shutdown)	(struct socket *sock, int flags);
+  int	(*setsockopt)	(struct socket *sock, int level, int optname,
+			 char *optval, int optlen);
+  int	(*getsockopt)	(struct socket *sock, int level, int optname,
+			 char *optval, int *optlen);
+  int	(*fcntl)	(struct socket *sock, unsigned int cmd,
+			 unsigned long arg);	
+  int   (*sendmsg)	(struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm);
+  int   (*recvmsg)	(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm);
+};
+
+struct net_proto_family 
+{
+	int	family;
+	int	(*create)(struct socket *sock, int protocol);
+	 
+
+	short	authentication;
+	short	encryption;
+	short	encrypt_net;
+};
+
+struct net_proto 
+{
+	const char *name;		 
+	void (*init_func)(struct net_proto *);	 
+};
+
+extern struct net_proto_family *net_families[];
+extern int	sock_wake_async(struct socket *sk, int how);
+extern int	sock_register(struct net_proto_family *fam);
+extern int	sock_unregister(int family);
+extern struct socket *sock_alloc(void);
+extern int	sock_create(int family, int type, int proto, struct socket **);
+extern void	sock_release(struct socket *);
+extern int   	sock_sendmsg(struct socket *, struct msghdr *m, int len);
+extern int	sock_recvmsg(struct socket *, struct msghdr *m, int len, int flags);
+extern int	sock_readv_writev(int type, struct inode * inode, struct file * file,
+				  const struct iovec * iov, long count, long size);
+
+extern int	net_ratelimit(void);
+extern unsigned long net_random(void);
+extern void net_srandom(unsigned long);
+
+
+
+# 15 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/kdev_t.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+typedef unsigned short kdev_t;
+
+
+
+
+
+
+
+
+extern char * kdevname(kdev_t);	 
+
+ 
+
+
+
+
+static inline unsigned int kdev_t_to_nr(kdev_t dev) {
+   return (((unsigned int) (( dev ) >> 8 )) <<8) | ((unsigned int) (( dev ) & ((1U << 8 ) - 1) )) ;   // AMBIGUOUS
+}
+
+static inline kdev_t to_kdev_t(int dev)
+{
+	int major, minor;
+
+
+
+
+
+
+
+
+	major = (dev >> 8);
+	minor = (dev & 0xff);
+
+	return ((( major ) << 8 ) | (  minor )) ;
+}
+
+# 113 "/usr/src/linux/include/linux/kdev_t.h"
+
+
+# 16 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/ioctl.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/ioctl.h" 1
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+# 4 "/usr/src/linux/include/linux/ioctl.h" 2
+
+
+
+
+# 17 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/list.h" 1
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+static __inline__ void __list_add(struct list_head * new,
+	struct list_head * prev,
+	struct list_head * next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+ 
+
+
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+ 
+
+
+
+
+
+
+static __inline__ void __list_del(struct list_head * prev,
+				  struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static __inline__ void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+static __inline__ int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+ 
+
+
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+	struct list_head *first = list->next;
+
+	if (first != list) {
+		struct list_head *last = list->prev;
+		struct list_head *at = head->next;
+
+		first->prev = head;
+		head->next = first;
+
+		last->next = at;
+		at->prev = last;
+	}
+}
+
+
+
+
+
+
+
+# 18 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/dcache.h" 1
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+struct qstr {
+	const unsigned char * name;
+	unsigned int len;
+	unsigned int hash;
+};
+
+ 
+
+
+ 
+static __inline__ unsigned long partial_name_hash(unsigned long c, unsigned long prevhash)
+{
+	prevhash = (prevhash << 4) | (prevhash >> (8*sizeof(unsigned long)-4));
+	return prevhash ^ c;
+}
+
+ 
+static __inline__ unsigned long end_name_hash(unsigned long hash)
+{
+	if (sizeof(hash) > sizeof(unsigned int))
+		hash += hash >> 4*sizeof(hash);
+	return (unsigned int) hash;
+}
+
+ 
+static __inline__ unsigned int full_name_hash(const unsigned char * name, unsigned int len)
+{
+	unsigned long hash = 0 ;
+	while (len--)
+		hash = partial_name_hash(*name++, hash);
+	return end_name_hash(hash);
+}
+
+
+
+struct dentry {
+	int d_count;
+	unsigned int d_flags;
+	struct inode  * d_inode;	 
+	struct dentry * d_parent;	 
+	struct dentry * d_mounts;	 
+	struct dentry * d_covers;
+	struct list_head d_hash;	 
+	struct list_head d_lru;		 
+	struct list_head d_child;	 
+	struct list_head d_subdirs;	 
+	struct list_head d_alias;	 
+	struct qstr d_name;
+	unsigned long d_time;		 
+	struct dentry_operations  *d_op;
+	struct super_block * d_sb;	 
+	unsigned long d_reftime;	 
+	void * d_fsdata;		 
+	unsigned char d_iname[16 ];  
+};
+
+struct dentry_operations {
+	int (*d_revalidate)(struct dentry *, int);
+	int (*d_hash) (struct dentry *, struct qstr *);
+	int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
+	void (*d_delete)(struct dentry *);
+	void (*d_release)(struct dentry *);
+	void (*d_iput)(struct dentry *, struct inode *);
+};
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+static __inline__ void d_drop(struct dentry * dentry)
+{
+	list_del(&dentry->d_hash);
+	do { ( &dentry->d_hash )->next = ( &dentry->d_hash ); ( &dentry->d_hash )->prev = ( &dentry->d_hash ); } while (0) ;
+}
+
+static __inline__ int dname_external(struct dentry *d)
+{
+	return d->d_name.name != d->d_iname; 
+}
+
+ 
+
+
+extern void d_instantiate(struct dentry *, struct inode *);
+extern void d_delete(struct dentry *);
+
+ 
+extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
+extern int prune_dcache(int, int);
+extern void shrink_dcache_sb(struct super_block *);
+extern void shrink_dcache_parent(struct dentry *);
+extern int d_invalidate(struct dentry *);
+
+
+
+ 
+extern void shrink_dcache_memory(int, unsigned int);
+extern void check_dcache_memory(void);
+extern void free_inode_memory(int);	 
+
+ 
+extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root);
+
+ 
+extern int is_root_busy(struct dentry *);
+
+ 
+extern int have_submounts(struct dentry *);
+
+ 
+
+
+extern void d_rehash(struct dentry * entry);
+ 
+
+
+
+static __inline__ void d_add(struct dentry * entry, struct inode * inode)
+{
+	d_rehash(entry);
+	d_instantiate(entry, inode);
+}
+
+ 
+extern void d_move(struct dentry * entry, struct dentry * newdentry);
+
+ 
+extern struct dentry * d_lookup(struct dentry * dir, struct qstr * name);
+
+ 
+extern int d_validate(struct dentry *dentry, struct dentry *dparent,
+		      unsigned int hash, unsigned int len);
+
+ 
+extern char * d_path(struct dentry * entry, char * buf, int buflen);
+
+ 
+static __inline__ struct dentry * dget(struct dentry *dentry)
+{
+	if (dentry)
+		dentry->d_count++;
+	return dentry;
+}
+
+extern void dput(struct dentry *);
+
+
+
+
+# 19 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/stat.h" 1
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/stat.h" 1
+
+
+
+struct __old_kernel_stat {
+	unsigned short st_dev;
+	unsigned short st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned long  st_size;
+	unsigned long  st_atime;
+	unsigned long  st_mtime;
+	unsigned long  st_ctime;
+};
+
+struct stat {
+	unsigned short st_dev;
+	unsigned short __pad1;
+	unsigned long st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned short __pad2;
+	unsigned long  st_size;
+	unsigned long  st_blksize;
+	unsigned long  st_blocks;
+	unsigned long  st_atime;
+	unsigned long  __unused1;
+	unsigned long  st_mtime;
+	unsigned long  __unused2;
+	unsigned long  st_ctime;
+	unsigned long  __unused3;
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+
+# 6 "/usr/src/linux/include/linux/stat.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 20 "/usr/src/linux/include/linux/fs.h" 2
+
+
+
+# 1 "/usr/src/linux/include/linux/bitops.h" 1
+
+
+
+
+ 
+
+
+
+
+
+extern __inline__ int generic_ffs(int x)
+{
+	int r = 1;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff)) {
+		x >>= 16;
+		r += 16;
+	}
+	if (!(x & 0xff)) {
+		x >>= 8;
+		r += 8;
+	}
+	if (!(x & 0xf)) {
+		x >>= 4;
+		r += 4;
+	}
+	if (!(x & 3)) {
+		x >>= 2;
+		r += 2;
+	}
+	if (!(x & 1)) {
+		x >>= 1;
+		r += 1;
+	}
+	return r;
+}
+
+ 
+
+
+
+
+extern __inline__ unsigned int generic_hweight32(unsigned int w)
+{
+        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+extern __inline__ unsigned int generic_hweight16(unsigned int w)
+{
+        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+        res = (res & 0x3333) + ((res >> 2) & 0x3333);
+        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+        return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+
+extern __inline__ unsigned int generic_hweight8(unsigned int w)
+{
+        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+        res = (res & 0x33) + ((res >> 2) & 0x33);
+        return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+
+# 1 "/usr/src/linux/include/asm/bitops.h" 1
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+extern void set_bit(int nr, volatile void * addr);
+extern void clear_bit(int nr, volatile void * addr);
+extern void change_bit(int nr, volatile void * addr);
+extern int test_and_set_bit(int nr, volatile void * addr);
+extern int test_and_clear_bit(int nr, volatile void * addr);
+extern int test_and_change_bit(int nr, volatile void * addr);
+extern int __constant_test_bit(int nr, const volatile void * addr);
+extern int __test_bit(int nr, volatile void * addr);
+extern int find_first_zero_bit(void * addr, unsigned size);
+extern int find_next_zero_bit (void * addr, int size, int offset);
+extern unsigned long ffz(unsigned long word);
+
+ 
+
+
+struct __dummy { unsigned long a[100]; };
+
+
+
+extern __inline__ void set_bit(int nr, volatile void * addr)
+{
+	__asm__ __volatile__( "" 
+		"btsl %1,%0"
+		:"=m" ((*(volatile struct __dummy *) addr) )
+		:"Ir" (nr));
+}
+
+extern __inline__ void clear_bit(int nr, volatile void * addr)
+{
+	__asm__ __volatile__( "" 
+		"btrl %1,%0"
+		:"=m" ((*(volatile struct __dummy *) addr) )
+		:"Ir" (nr));
+}
+
+extern __inline__ void change_bit(int nr, volatile void * addr)
+{
+	__asm__ __volatile__( "" 
+		"btcl %1,%0"
+		:"=m" ((*(volatile struct __dummy *) addr) )
+		:"Ir" (nr));
+}
+
+extern __inline__ int test_and_set_bit(int nr, volatile void * addr)
+{
+	int oldbit;
+
+	__asm__ __volatile__( "" 
+		"btsl %2,%1\n\tsbbl %0,%0"
+		:"=r" (oldbit),"=m" ((*(volatile struct __dummy *) addr) )
+		:"Ir" (nr));
+	return oldbit;
+}
+
+extern __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+{
+	int oldbit;
+
+	__asm__ __volatile__( "" 
+		"btrl %2,%1\n\tsbbl %0,%0"
+		:"=r" (oldbit),"=m" ((*(volatile struct __dummy *) addr) )
+		:"Ir" (nr));
+	return oldbit;
+}
+
+extern __inline__ int test_and_change_bit(int nr, volatile void * addr)
+{
+	int oldbit;
+
+	__asm__ __volatile__( "" 
+		"btcl %2,%1\n\tsbbl %0,%0"
+		:"=r" (oldbit),"=m" ((*(volatile struct __dummy *) addr) )
+		:"Ir" (nr));
+	return oldbit;
+}
+
+ 
+
+
+extern __inline__ int __constant_test_bit(int nr, const volatile void * addr)
+{
+	return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
+}
+
+extern __inline__ int __test_bit(int nr, volatile void * addr)
+{
+	int oldbit;
+
+	__asm__ __volatile__(
+		"btl %2,%1\n\tsbbl %0,%0"
+		:"=r" (oldbit)
+		:"m" ((*(volatile struct __dummy *) addr) ),"Ir" (nr));
+	return oldbit;
+}
+
+
+
+
+
+
+ 
+
+
+extern __inline__ int find_first_zero_bit(void * addr, unsigned size)
+{
+	int d0, d1, d2;
+	int res;
+
+	if (!size)
+		return 0;
+	__asm__("cld\n\t"
+		"movl $-1,%%eax\n\t"
+		"xorl %%edx,%%edx\n\t"
+		"repe; scasl\n\t"
+		"je 1f\n\t"
+		"xorl -4(%%edi),%%eax\n\t"
+		"subl $4,%%edi\n\t"
+		"bsfl %%eax,%%edx\n"
+		"1:\tsubl %%ebx,%%edi\n\t"
+		"shll $3,%%edi\n\t"
+		"addl %%edi,%%edx"
+		:"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+		:"1" ((size + 31) >> 5), "2" (addr), "b" (addr));
+	return res;
+}
+
+extern __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+{
+	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+	int set = 0, bit = offset & 31, res;
+	
+	if (bit) {
+		 
+
+
+		__asm__("bsfl %1,%0\n\t"
+			"jne 1f\n\t"
+			"movl $32, %0\n"
+			"1:"
+			: "=r" (set)
+			: "r" (~(*p >> bit)));
+		if (set < (32 - bit))
+			return set + offset;
+		set = 32 - bit;
+		p++;
+	}
+	 
+
+
+	res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
+	return (offset + set + res);
+}
+
+ 
+
+
+
+extern __inline__ unsigned long ffz(unsigned long word)
+{
+	__asm__("bsfl %1,%0"
+		:"=r" (word)
+		:"r" (~word));
+	return word;
+}
+
+
+
+ 
+
+
+
+
+
+extern __inline__ int ffs(int x)
+{
+	int r;
+
+	__asm__("bsfl %1,%0\n\t"
+		"jnz 1f\n\t"
+		"movl $-1,%0\n"
+		"1:" : "=r" (r) : "g" (x));
+	return r+1;
+}
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+# 69 "/usr/src/linux/include/linux/bitops.h" 2
+
+
+
+
+# 23 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/asm/cache.h" 1
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+# 24 "/usr/src/linux/include/linux/fs.h" 2
+
+
+
+struct poll_table_struct;
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+extern int max_inodes;
+extern int max_files, nr_files, nr_free_files;
+extern int max_super_blocks, nr_super_blocks;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/byteorder.h" 1
+
+
+
+
+
+
+
+ 
+
+
+
+
+static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+{
+
+	__asm__("bswap %0" : "=r" (x) : "0" (x));
+
+
+
+
+
+
+
+	return x;
+}
+
+static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+{
+	__asm__("xchgb %b0,%h0"		  		: "=q" (x) 		:  "0" (x)); 		return x;
+
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/byteorder/little_endian.h" 1
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/byteorder/swab.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 41 "/usr/src/linux/include/linux/byteorder/swab.h"
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern __inline__ __const__ __u16 __fswab16(__u16 x)
+{
+	return ___arch__swab16( x ) ;
+}
+extern __inline__ __u16 __swab16p(__u16 *x)
+{
+	return (__builtin_constant_p((__u16)( *( x ) )) ? ((__u16)( (((__u16)( ( *( x ) ) ) & (__u16)0x00ffU) << 8) | (((__u16)( ( *( x ) ) ) & (__u16)0xff00U) >> 8) ))  : __fswab16(( *( x ) )))  ;
+}
+extern __inline__ void __swab16s(__u16 *addr)
+{
+	do { *( addr ) = __swab16p(( addr )); } while (0) ;
+}
+
+extern __inline__ __const__ __u32 __fswab32(__u32 x)
+{
+	return ___arch__swab32( x ) ;
+}
+extern __inline__ __u32 __swab32p(__u32 *x)
+{
+	return (__builtin_constant_p((__u32)( *( x ) )) ? ((__u32)( (((__u32)( ( *( x ) ) ) & (__u32)0x000000ffUL) << 24) | (((__u32)( ( *( x ) ) ) & (__u32)0x0000ff00UL) <<  8) | (((__u32)( ( *( x ) ) ) & (__u32)0x00ff0000UL) >>  8) | (((__u32)( ( *( x ) ) ) & (__u32)0xff000000UL) >> 24) ))  : __fswab32(( *( x ) )))  ;
+}
+extern __inline__ void __swab32s(__u32 *addr)
+{
+	do { *( addr ) = __swab32p(( addr )); } while (0) ;
+}
+
+
+extern __inline__ __const__ __u64 __fswab64(__u64 x)
+{
+
+	__u32 h = x >> 32;
+        __u32 l = x & ((1ULL<<32)-1);
+        return (((__u64)(__builtin_constant_p((__u32)( l )) ? ((__u32)( (((__u32)( ( l ) ) & (__u32)0x000000ffUL) << 24) | (((__u32)( ( l ) ) & (__u32)0x0000ff00UL) <<  8) | (((__u32)( ( l ) ) & (__u32)0x00ff0000UL) >>  8) | (((__u32)( ( l ) ) & (__u32)0xff000000UL) >> 24) ))  : __fswab32(( l ))) ) << 32) | ((__u64)((__builtin_constant_p((__u32)( h )) ? ((__u32)( (((__u32)( ( h ) ) & (__u32)0x000000ffUL) << 24) | (((__u32)( ( h ) ) & (__u32)0x0000ff00UL) <<  8) | (((__u32)( ( h ) ) & (__u32)0x00ff0000UL) >>  8) | (((__u32)( ( h ) ) & (__u32)0xff000000UL) >> 24) ))  : __fswab32(( h ))) ));
+
+
+
+}
+extern __inline__ __u64 __swab64p(__u64 *x)
+{
+	return (__builtin_constant_p((__u64)( *( x ) )) ? ((__u64)( (__u64)(((__u64)( ( *( x ) ) ) & (__u64)0x00000000000000ffULL) << 56) | (__u64)(((__u64)( ( *( x ) ) ) & (__u64)0x000000000000ff00ULL) << 40) | (__u64)(((__u64)( ( *( x ) ) ) & (__u64)0x0000000000ff0000ULL) << 24) | (__u64)(((__u64)( ( *( x ) ) ) & (__u64)0x00000000ff000000ULL) <<  8) | (__u64)(((__u64)( ( *( x ) ) ) & (__u64)0x000000ff00000000ULL) >>  8) | (__u64)(((__u64)( ( *( x ) ) ) & (__u64)0x0000ff0000000000ULL) >> 24) | (__u64)(((__u64)( ( *( x ) ) ) & (__u64)0x00ff000000000000ULL) >> 40) | (__u64)(((__u64)( ( *( x ) ) ) & (__u64)0xff00000000000000ULL) >> 56) ))  : __fswab64(( *( x ) )))  ;
+}
+extern __inline__ void __swab64s(__u64 *addr)
+{
+	do { *( addr ) = __swab64p(( addr )); } while (0) ;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 11 "/usr/src/linux/include/linux/byteorder/little_endian.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/byteorder/generic.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+extern __u32			ntohl(__u32);
+extern __u32			htonl(__u32);
+
+
+
+
+extern unsigned short int	ntohs(unsigned short int);
+extern unsigned short int	htons(unsigned short int);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 54 "/usr/src/linux/include/linux/byteorder/little_endian.h" 2
+
+
+
+# 45 "/usr/src/linux/include/asm/byteorder.h" 2
+
+
+
+# 169 "/usr/src/linux/include/linux/fs.h" 2
+
+
+
+extern void update_atime (struct inode *inode);
+
+
+extern void buffer_init(unsigned long);
+extern void inode_init(void);
+extern void file_table_init(void);
+extern void dcache_init(void);
+
+typedef char buffer_block[(1<< 10 ) ];
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+struct buffer_head {
+	 
+	struct buffer_head * b_next;	 
+	unsigned long b_blocknr;	 
+	unsigned long b_size;		 
+	kdev_t b_dev;			 
+	kdev_t b_rdev;			 
+	unsigned long b_rsector;	 
+	struct buffer_head * b_this_page;	 
+	unsigned long b_state;		 
+	struct buffer_head * b_next_free;
+	unsigned int b_count;		 
+
+	 
+	char * b_data;			 
+	unsigned int b_list;		 
+	unsigned long b_flushtime;       
+
+	struct wait_queue * b_wait;
+	struct buffer_head ** b_pprev;		 
+	struct buffer_head * b_prev_free;	 
+	struct buffer_head * b_reqnext;		 
+
+	 
+
+
+	void (*b_end_io)(struct buffer_head *bh, int uptodate);
+	void *b_dev_id;
+};
+
+typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
+void init_buffer(struct buffer_head *bh, kdev_t dev, int block,
+		 bh_end_io_t *handler, void *dev_id);
+
+static inline int buffer_uptodate(struct buffer_head * bh)
+{
+	return (__builtin_constant_p( 0  ) ? __constant_test_bit(( 0  ),(  &bh->b_state )) : __test_bit(( 0  ),(  &bh->b_state ))) ;
+}	
+
+static inline int buffer_dirty(struct buffer_head * bh)
+{
+	return (__builtin_constant_p( 1  ) ? __constant_test_bit(( 1  ),(  &bh->b_state )) : __test_bit(( 1  ),(  &bh->b_state ))) ;
+}
+
+static inline int buffer_locked(struct buffer_head * bh)
+{
+	return (__builtin_constant_p( 2  ) ? __constant_test_bit(( 2  ),(  &bh->b_state )) : __test_bit(( 2  ),(  &bh->b_state ))) ;
+}
+
+static inline int buffer_req(struct buffer_head * bh)
+{
+	return (__builtin_constant_p( 3  ) ? __constant_test_bit(( 3  ),(  &bh->b_state )) : __test_bit(( 3  ),(  &bh->b_state ))) ;
+}
+
+static inline int buffer_protected(struct buffer_head * bh)
+{
+	return (__builtin_constant_p( 6  ) ? __constant_test_bit(( 6  ),(  &bh->b_state )) : __test_bit(( 6  ),(  &bh->b_state ))) ;
+}
+
+
+
+
+# 1 "/usr/src/linux/include/linux/pipe_fs_i.h" 1
+
+
+
+struct pipe_inode_info {
+	struct wait_queue * wait;
+	char * base;
+	unsigned int start;
+	unsigned int lock;
+	unsigned int rd_openers;
+	unsigned int wr_openers;
+	unsigned int readers;
+	unsigned int writers;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 263 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/minix_fs_i.h" 1
+
+
+
+ 
+
+
+struct minix_inode_info {
+	union {
+		__u16 i1_data[16];
+		__u32 i2_data[16];
+	} u;
+};
+
+
+# 264 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/ext2_fs_i.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+struct ext2_inode_info {
+	__u32	i_data[15];
+	__u32	i_flags;
+	__u32	i_faddr;
+	__u8	i_frag_no;
+	__u8	i_frag_size;
+	__u16	i_osync;
+	__u32	i_file_acl;
+	__u32	i_dir_acl;
+	__u32	i_dtime;
+	__u32	i_version;
+	__u32	i_block_group;
+	__u32	i_next_alloc_block;
+	__u32	i_next_alloc_goal;
+	__u32	i_prealloc_block;
+	__u32	i_prealloc_count;
+	__u32	i_high_size;
+	int	i_new_inode:1;	 
+};
+
+
+# 265 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/hpfs_fs_i.h" 1
+
+
+
+struct hpfs_inode_info {
+	ino_t i_parent_dir;	 
+	unsigned i_dno;		 
+	unsigned i_dpos;	 
+	unsigned i_dsubdno;	 
+	unsigned i_file_sec;	 
+	unsigned i_disk_sec;	 
+	unsigned i_n_secs;	 
+	unsigned i_conv : 2;	 
+};
+
+
+
+
+
+
+
+
+
+
+
+# 266 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/ntfs_fs_i.h" 1
+
+
+
+ 
+struct ntfs_attribute;
+struct ntfs_sb_info;
+
+ 
+
+
+typedef u8  ntfs_u8;
+typedef u16 ntfs_u16;
+typedef u32 ntfs_u32;
+typedef u64 ntfs_u64;
+typedef s8  ntfs_s8;
+typedef s16 ntfs_s16;
+typedef s32 ntfs_s32;
+typedef s64 ntfs_s64;
+
+
+
+
+typedef __kernel_mode_t ntmode_t;
+
+
+
+typedef __kernel_uid_t ntfs_uid_t;
+
+
+
+typedef __kernel_gid_t ntfs_gid_t;
+
+
+
+typedef __kernel_size_t ntfs_size_t;
+
+
+
+typedef __kernel_time_t ntfs_time_t;
+
+
+ 
+
+
+typedef unsigned short     ntfs_wchar_t;
+
+ 
+
+
+typedef unsigned long long ntfs_offset_t;
+
+ 
+
+
+typedef unsigned long long ntfs_time64_t;
+
+ 
+
+
+typedef unsigned int ntfs_cluster_t;
+
+
+ 
+struct ntfs_inode_info{
+	struct ntfs_sb_info *vol;
+	int i_number;                 
+	unsigned sequence_number;
+	unsigned char* attr;          
+	int attr_count;               
+	struct ntfs_attribute *attrs;
+	int record_count;             
+	 
+
+	int *records;
+	union{
+		struct{
+			int recordsize;
+			int clusters_per_record;
+		}index;
+	} u;	
+};
+
+
+# 267 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/msdos_fs_i.h" 1
+
+
+
+
+
+
+
+ 
+
+
+
+struct msdos_inode_info {
+	 
+
+
+
+
+
+
+
+
+
+
+
+
+
+	struct pipe_inode_info reserved;
+	int i_start;	 
+	int i_logstart;	 
+	int i_attrs;	 
+	int i_ctime_ms;	 
+	int i_binary;	 
+	int i_location;	 
+	struct inode *i_fat_inode;	 
+	struct list_head i_fat_hash;	 
+	off_t i_last_pos; 
+};
+
+
+# 268 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/umsdos_fs_i.h" 1
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct dir_locking_info {
+	struct wait_queue *p;
+	short int looking;	 
+	short int creating;	 
+
+
+
+	long pid;		 
+	 
+};
+
+struct umsdos_inode_info {
+	union {
+		struct msdos_inode_info msdos_info;
+		struct pipe_inode_info pipe_info;
+		struct dir_locking_info dir_info;
+	} u;
+	int i_patched;			 
+	int i_is_hlink;			 
+	unsigned long i_emd_owner;	 
+	off_t pos;			 
+	 
+	struct dentry *i_emd_dentry;	 
+	unsigned long i_emd_dir;	 
+};
+
+
+# 269 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/iso_fs_i.h" 1
+
+
+
+ 
+
+
+struct iso_inode_info {
+	unsigned int i_first_extent;
+	unsigned char i_file_format;
+	unsigned long i_next_section_ino;
+	off_t i_section_size;
+};
+
+
+# 270 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/nfs_fs_i.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/nfs.h" 1
+ 
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/sunrpc/msg_prot.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+enum rpc_auth_flavor {
+	RPC_AUTH_NULL  = 0,
+	RPC_AUTH_UNIX  = 1,
+	RPC_AUTH_SHORT = 2,
+	RPC_AUTH_DES   = 3,
+	RPC_AUTH_KRB   = 4,
+};
+
+enum rpc_msg_type {
+	RPC_CALL = 0,
+	RPC_REPLY = 1
+};
+
+enum rpc_reply_stat {
+	RPC_MSG_ACCEPTED = 0,
+	RPC_MSG_DENIED = 1
+};
+
+enum rpc_accept_stat {
+	RPC_SUCCESS = 0,
+	RPC_PROG_UNAVAIL = 1,
+	RPC_PROG_MISMATCH = 2,
+	RPC_PROC_UNAVAIL = 3,
+	RPC_GARBAGE_ARGS = 4,
+	RPC_SYSTEM_ERR = 5
+};
+
+enum rpc_reject_stat {
+	RPC_MISMATCH = 0,
+	RPC_AUTH_ERROR = 1
+};
+
+enum rpc_auth_stat {
+	RPC_AUTH_OK = 0,
+	RPC_AUTH_BADCRED = 1,
+	RPC_AUTH_REJECTEDCRED = 2,
+	RPC_AUTH_BADVERF = 3,
+	RPC_AUTH_REJECTEDVERF = 4,
+	RPC_AUTH_TOOWEAK = 5
+};
+
+
+
+
+
+
+
+
+
+# 7 "/usr/src/linux/include/linux/nfs.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+enum nfs_stat {
+	NFS_OK = 0,
+	NFSERR_PERM = 1,
+	NFSERR_NOENT = 2,
+	NFSERR_IO = 5,
+	NFSERR_NXIO = 6,
+	NFSERR_EAGAIN = 11,
+	NFSERR_ACCES = 13,
+	NFSERR_EXIST = 17,
+	NFSERR_XDEV = 18,
+	NFSERR_NODEV = 19,
+	NFSERR_NOTDIR = 20,
+	NFSERR_ISDIR = 21,
+	NFSERR_INVAL = 22,	 
+	NFSERR_FBIG = 27,
+	NFSERR_NOSPC = 28,
+	NFSERR_ROFS = 30,
+	NFSERR_OPNOTSUPP = 45,
+	NFSERR_NAMETOOLONG = 63,
+	NFSERR_NOTEMPTY = 66,
+	NFSERR_DQUOT = 69,
+	NFSERR_STALE = 70,
+	NFSERR_WFLUSH = 99
+};
+
+enum nfs_ftype {
+	NFNON = 0,
+	NFREG = 1,
+	NFDIR = 2,
+	NFBLK = 3,
+	NFCHR = 4,
+	NFLNK = 5,
+	NFSOCK = 6,
+	NFBAD = 7,
+	NFFIFO = 8
+};
+
+struct nfs_fh {
+	char			data[32 ];
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+extern struct rpc_program	nfs_program;
+extern struct rpc_stat		nfs_rpcstat;
+
+struct nfs_time {
+	__u32			seconds;
+	__u32			useconds;
+};
+
+struct nfs_fattr {
+	enum nfs_ftype		type;
+	__u32			mode;
+	__u32			nlink;
+	__u32			uid;
+	__u32			gid;
+	__u32			size;
+	__u32			blocksize;
+	__u32			rdev;
+	__u32			blocks;
+	__u32			fsid;
+	__u32			fileid;
+	struct nfs_time		atime;
+	struct nfs_time		mtime;
+	struct nfs_time		ctime;
+};
+
+struct nfs_sattr {
+	__u32			mode;
+	__u32			uid;
+	__u32			gid;
+	__u32			size;
+	struct nfs_time		atime;
+	struct nfs_time		mtime;
+};
+
+struct nfs_fsinfo {
+	__u32			tsize;
+	__u32			bsize;
+	__u32			blocks;
+	__u32			bfree;
+	__u32			bavail;
+};
+
+struct nfs_writeargs {
+	struct nfs_fh *		fh;
+	__u32			offset;
+	__u32			count;
+	const void *		buffer;
+};
+
+# 223 "/usr/src/linux/include/linux/nfs.h"
+
+
+
+
+# 4 "/usr/src/linux/include/linux/nfs_fs_i.h" 2
+
+
+
+ 
+
+
+struct nfs_inode_info {
+	 
+
+
+
+
+	struct pipe_inode_info	pipeinfo;
+
+	 
+
+
+	unsigned short		flags;
+
+	 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	unsigned long		read_cache_jiffies;
+	unsigned long		read_cache_mtime;
+	unsigned long		attrtimeo;
+
+	 
+
+
+
+
+	struct nfs_wreq *	writeback;
+};
+
+ 
+
+
+
+
+
+ 
+
+
+struct nfs_lock_info {
+	u32		state;
+	u32		flags;
+};
+
+ 
+
+
+
+
+
+# 271 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/sysv_fs_i.h" 1
+
+
+
+ 
+
+
+struct sysv_inode_info {
+	u32 i_data[10+1+1+1];	 
+
+
+
+
+};
+
+
+
+# 272 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/affs_fs_i.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/a.out.h" 1
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/a.out.h" 1
+
+
+
+struct exec
+{
+  unsigned long a_info;		 
+  unsigned a_text;		 
+  unsigned a_data;		 
+  unsigned a_bss;		 
+  unsigned a_syms;		 
+  unsigned a_entry;		 
+  unsigned a_trsize;		 
+  unsigned a_drsize;		 
+};
+
+
+
+
+
+
+
+
+
+
+
+
+# 8 "/usr/src/linux/include/linux/a.out.h" 2
+
+
+
+
+ 
+enum machine_type {
+
+
+
+  M_OLDSUN2 = 0,
+
+
+
+
+  M_68010 = 1,
+
+
+
+
+  M_68020 = 2,
+
+
+
+
+  M_SPARC = 3,
+
+   
+  M_386 = 100,
+  M_MIPS1 = 151,	 
+  M_MIPS2 = 152		 
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+struct nlist {
+  union {
+    char *n_name;
+    struct nlist *n_next;
+    long n_strx;
+  } n_un;
+  unsigned char n_type;
+  char n_other;
+  short n_desc;
+  unsigned long n_value;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+struct relocation_info
+{
+   
+  int r_address;
+   
+  unsigned int r_symbolnum:24;
+   
+
+
+  unsigned int r_pcrel:1;
+   
+
+  unsigned int r_length:2;
+   
+
+
+
+
+
+  unsigned int r_extern:1;
+   
+
+
+
+
+
+
+  unsigned int r_pad:4;
+
+};
+
+
+
+
+# 4 "/usr/src/linux/include/linux/affs_fs_i.h" 2
+
+
+
+
+
+
+struct key_cache {
+	struct timeval	 kc_lru_time;	 
+	s32	 kc_first;		 
+	s32	 kc_last;		 
+	s32	 kc_this_key;		 
+	int	 kc_this_seq;		 
+	s32	 kc_next_key;		 
+	s32	 kc_keys[73 ];	 
+};
+
+
+
+struct ext_cache {
+	struct key_cache  kc[4];	 
+	s32	 ec[((1UL << 12 )  - 4 * sizeof(struct key_cache) - 4) / 4 ];		 
+	int	 max_ext;		 
+};
+
+ 
+
+
+struct affs_inode_info {
+	u32	 i_protect;			 
+	s32	 i_parent;			 
+	s32	 i_original;			 
+	s32	 i_data[16 ];	 
+	struct ext_cache *i_ec;			 
+	int	 i_cache_users;			 
+	int	 i_lastblock;			 
+	short	 i_pa_cnt;			 
+	short	 i_pa_next;			 
+	short	 i_pa_last;			 
+	short	 i_zone;			 
+	unsigned char i_hlink;			 
+	unsigned char i_pad;
+};
+
+
+# 273 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/ufs_fs_i.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct ufs_inode_info {
+	union {
+		__u32	i_data[15];
+		__u8	i_symlink[4*15];
+	} i_u1;
+	__u64	i_size;
+	__u32	i_flags;
+	__u32	i_gen;
+	__u32	i_shadow;
+	__u32	i_uid;
+	__u32	i_gid;
+	__u32	i_oeftflag;
+	__u16	i_osync;
+	__u32	i_lastfrag;
+};
+
+
+# 274 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/efs_fs_i.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+typedef	int32_t		efs_block_t;
+typedef uint32_t	efs_ino_t;
+
+
+
+ 
+
+
+typedef union extent_u {
+	unsigned char raw[8];
+	struct extent_s {
+		unsigned int	ex_magic:8;	 
+		unsigned int	ex_bn:24;	 
+		unsigned int	ex_length:8;	 
+		unsigned int	ex_offset:24;	 
+	} cooked;
+} efs_extent;
+
+typedef struct edevs {
+	short		odev;
+	short		dev_filler;	 
+	unsigned int	ndev;		 
+} efs_devs;
+
+ 
+
+
+
+struct	efs_dinode {
+	u_short		di_mode;	 
+	short		di_nlink;	 
+	u_short		di_uid;		 
+	u_short		di_gid;		 
+	int32_t		di_size;	 
+	int32_t		di_atime;	 
+	int32_t		di_mtime;	 
+	int32_t		di_ctime;	 
+	uint32_t	di_gen;		 
+	short		di_numextents;	 
+	u_char		di_version;	 
+	u_char		di_spare;	 
+	union di_addr {
+		efs_extent	di_extents[12 ];
+		efs_devs	di_dev;	 
+	} di_u;
+};
+
+ 
+struct efs_inode_info {
+	int		numextents;
+	int		lastextent;
+
+	efs_extent	extents[12 ];
+};
+
+
+
+# 275 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/coda_fs_i.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/coda.h" 1
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+# 98 "/usr/src/linux/include/linux/coda.h"
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned long long u_quad_t;
+
+
+
+
+
+
+
+
+
+
+
+
+# 130 "/usr/src/linux/include/linux/coda.h"
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+  
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+struct venus_dirent {
+        unsigned long	d_fileno;		 
+        unsigned short	d_reclen;		 
+        unsigned char 	d_type;			 
+        unsigned char	d_namlen;		 
+        char		d_name[255  + 1]; 
+};
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+typedef u_long VolumeId;
+typedef u_long VnodeId;
+typedef u_long Unique_t;
+typedef u_long FileVersion;
+
+
+
+
+typedef struct ViceFid {
+    VolumeId Volume;
+    VnodeId Vnode;
+    Unique_t Unique;
+} ViceFid;
+
+
+
+
+static __inline__ ino_t  coda_f2i(struct ViceFid *fid)
+{
+	if ( ! fid ) 
+		return 0; 
+	if (fid->Vnode == 0xfffffffe || fid->Vnode == 0xffffffff)
+		return ((fid->Volume << 20) | (fid->Unique & 0xfffff));
+	else
+		return (fid->Unique + (fid->Vnode<<10) + (fid->Volume<<20));
+}
+	
+
+
+
+
+
+
+
+
+typedef u_int32_t vuid_t;
+typedef u_int32_t vgid_t;
+
+
+
+
+struct coda_cred {
+    vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid;  
+    vgid_t cr_groupid,     cr_egid, cr_sgid, cr_fsgid;  
+};
+
+
+
+
+ 
+
+
+enum coda_vtype	{ C_VNON, C_VREG, C_VDIR, C_VBLK, C_VCHR, C_VLNK, C_VSOCK, C_VFIFO, C_VBAD };
+
+struct coda_vattr {
+	long     	va_type;	 
+	u_short		va_mode;	 
+	short		va_nlink;	 
+	vuid_t		va_uid;		 
+	vgid_t		va_gid;		 
+	long		va_fileid;	 
+	u_quad_t	va_size;	 
+	long		va_blocksize;	 
+	struct timespec	va_atime;	 
+	struct timespec	va_mtime;	 
+	struct timespec	va_ctime;	 
+	u_long		va_gen;		 
+	u_long		va_flags;	 
+	u_quad_t 	        va_rdev;	 
+	u_quad_t	va_bytes;	 
+	u_quad_t	va_filerev;	 
+};
+
+
+
+ 
+struct coda_statfs {
+    int32_t f_blocks;
+    int32_t f_bfree;
+    int32_t f_bavail;
+    int32_t f_files;
+    int32_t f_ffree;
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	 
+
+
+ 
+
+
+struct coda_in_hdr {
+    unsigned long opcode;
+    unsigned long unique;	     
+    u_short pid;		     
+    u_short pgid;		     
+    u_short sid;                     
+    struct coda_cred cred;	     
+};
+
+ 
+struct coda_out_hdr {
+    unsigned long opcode;
+    unsigned long unique;	
+    unsigned long result;
+};
+
+ 
+struct coda_root_out {
+    struct coda_out_hdr oh;
+    ViceFid VFid;
+};
+
+struct coda_root_in {
+    struct coda_in_hdr in;
+};
+
+ 
+ 
+
+ 
+struct coda_open_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int	flags;
+};
+
+struct coda_open_out {
+    struct coda_out_hdr oh;
+    u_quad_t 	dev;
+    ino_t	inode;
+};
+
+
+ 
+struct coda_close_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int	flags;
+};
+
+struct coda_close_out {
+    struct coda_out_hdr out;
+};
+
+ 
+struct coda_ioctl_in {
+    struct coda_in_hdr ih;
+    ViceFid VFid;
+    int	cmd;
+    int	len;
+    int	rwflag;
+    char *data;			 
+};
+
+struct coda_ioctl_out {
+    struct coda_out_hdr oh;
+    int	len;
+    caddr_t	data;		 
+};
+
+
+ 
+struct coda_getattr_in {
+    struct coda_in_hdr ih;
+    ViceFid VFid;
+};
+
+struct coda_getattr_out {
+    struct coda_out_hdr oh;
+    struct coda_vattr attr;
+};
+
+
+ 
+struct coda_setattr_in {
+    struct coda_in_hdr ih;
+    ViceFid VFid;
+    struct coda_vattr attr;
+};
+
+struct coda_setattr_out {
+    struct coda_out_hdr out;
+};
+
+ 
+struct coda_access_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int	flags;
+};
+
+struct coda_access_out {
+    struct coda_out_hdr out;
+};
+
+
+ 
+
+
+
+ 
+struct  coda_lookup_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int         name;		 
+    int         flags;	
+};
+
+struct coda_lookup_out {
+    struct coda_out_hdr oh;
+    ViceFid VFid;
+    int	vtype;
+};
+
+
+ 
+struct coda_create_in {
+    struct coda_in_hdr ih;
+    ViceFid VFid;
+    struct coda_vattr attr;
+    int excl;
+    int mode;
+    int 	name;		 
+};
+
+struct coda_create_out {
+    struct coda_out_hdr oh;
+    ViceFid VFid;
+    struct coda_vattr attr;
+};
+
+
+ 
+struct coda_remove_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int name;		 
+};
+
+struct coda_remove_out {
+    struct coda_out_hdr out;
+};
+
+ 
+struct coda_link_in {
+    struct coda_in_hdr ih;
+    ViceFid sourceFid;           
+    ViceFid destFid;             
+    int tname;		 
+};
+
+struct coda_link_out {
+    struct coda_out_hdr out;
+};
+
+
+ 
+struct coda_rename_in {
+    struct coda_in_hdr ih;
+    ViceFid	sourceFid;
+    int 	srcname;
+    ViceFid destFid;
+    int 	destname;
+};
+
+struct coda_rename_out {
+    struct coda_out_hdr out;
+};
+
+ 
+struct coda_mkdir_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    struct coda_vattr attr;
+    int	   name;		 
+};
+
+struct coda_mkdir_out {
+    struct coda_out_hdr oh;
+    ViceFid VFid;
+    struct coda_vattr attr;
+};
+
+
+ 
+struct coda_rmdir_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int name;		 
+};
+
+struct coda_rmdir_out {
+    struct coda_out_hdr out;
+};
+
+ 
+struct coda_readdir_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int	count;
+    int	offset;
+};
+
+struct coda_readdir_out {
+    struct coda_out_hdr oh;
+    int	size;
+    caddr_t	data;		 
+};
+
+ 
+struct coda_symlink_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;           
+    int srcname;
+    struct coda_vattr attr;
+    int tname;
+};
+
+struct coda_symlink_out {
+    struct coda_out_hdr out;
+};
+
+ 
+struct coda_readlink_in {
+    struct coda_in_hdr ih;
+    ViceFid VFid;
+};
+
+struct coda_readlink_out {
+    struct coda_out_hdr oh;
+    int	count;
+    caddr_t	data;		 
+};
+
+
+ 
+struct coda_fsync_in {
+    struct coda_in_hdr ih;
+    ViceFid VFid;
+};
+
+struct coda_fsync_out {
+    struct coda_out_hdr out;
+};
+
+ 
+struct coda_inactive_in {
+    struct coda_in_hdr ih;
+    ViceFid VFid;
+};
+
+ 
+struct coda_vget_in {
+    struct coda_in_hdr ih;
+    ViceFid VFid;
+};
+
+struct coda_vget_out {
+    struct coda_out_hdr oh;
+    ViceFid VFid;
+    int	vtype;
+};
+
+
+ 
+ 
+ 
+
+ 
+ 
+struct coda_purgeuser_out {
+    struct coda_out_hdr oh;
+    struct coda_cred cred;
+};
+
+ 
+ 
+struct coda_zapfile_out {  
+    struct coda_out_hdr oh;
+    ViceFid CodaFid;
+};
+
+ 
+ 	
+struct coda_zapdir_out {	  
+    struct coda_out_hdr oh;
+    ViceFid CodaFid;
+};
+
+ 
+ 	
+struct coda_zapvnode_out { 
+    struct coda_out_hdr oh;
+    struct coda_cred cred;
+    ViceFid VFid;
+};
+
+ 
+ 	
+struct coda_purgefid_out { 
+    struct coda_out_hdr oh;
+    ViceFid CodaFid;
+};
+
+ 
+struct coda_rdwr_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int	rwflag;
+    int	count;
+    int	offset;
+    int	ioflag;
+    caddr_t	data;		 	
+};
+
+struct coda_rdwr_out {
+    struct coda_out_hdr oh;
+    int	rwflag;
+    int	count;
+    caddr_t	data;	 
+};
+
+
+ 
+ 	
+struct coda_replace_out {  
+    struct coda_out_hdr oh;
+    ViceFid NewFid;
+    ViceFid OldFid;
+};
+
+ 
+struct coda_open_by_path_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int	flags;
+};
+
+struct coda_open_by_path_out {
+    struct coda_out_hdr oh;
+	int path;
+};
+
+ 
+struct coda_statfs_in {
+    struct coda_in_hdr in;
+};
+
+struct coda_statfs_out {
+    struct coda_out_hdr oh;
+    struct coda_statfs stat;
+};
+
+ 
+
+
+
+
+
+
+union inputArgs {
+    struct coda_in_hdr ih;		 
+    struct coda_open_in coda_open;
+    struct coda_close_in coda_close;
+    struct coda_ioctl_in coda_ioctl;
+    struct coda_getattr_in coda_getattr;
+    struct coda_setattr_in coda_setattr;
+    struct coda_access_in coda_access;
+    struct coda_lookup_in coda_lookup;
+    struct coda_create_in coda_create;
+    struct coda_remove_in coda_remove;
+    struct coda_link_in coda_link;
+    struct coda_rename_in coda_rename;
+    struct coda_mkdir_in coda_mkdir;
+    struct coda_rmdir_in coda_rmdir;
+    struct coda_readdir_in coda_readdir;
+    struct coda_symlink_in coda_symlink;
+    struct coda_readlink_in coda_readlink;
+    struct coda_fsync_in coda_fsync;
+    struct coda_inactive_in coda_inactive;
+    struct coda_vget_in coda_vget;
+    struct coda_rdwr_in coda_rdwr;
+    struct coda_open_by_path_in coda_open_by_path;
+    struct coda_statfs_in coda_statfs;
+};
+
+union outputArgs {
+    struct coda_out_hdr oh;		 
+    struct coda_root_out coda_root;
+    struct coda_open_out coda_open;
+    struct coda_ioctl_out coda_ioctl;
+    struct coda_getattr_out coda_getattr;
+    struct coda_lookup_out coda_lookup;
+    struct coda_create_out coda_create;
+    struct coda_mkdir_out coda_mkdir;
+    struct coda_readdir_out coda_readdir;
+    struct coda_readlink_out coda_readlink;
+    struct coda_vget_out coda_vget;
+    struct coda_purgeuser_out coda_purgeuser;
+    struct coda_zapfile_out coda_zapfile;
+    struct coda_zapdir_out coda_zapdir;
+    struct coda_zapvnode_out coda_zapvnode;
+    struct coda_purgefid_out coda_purgefid;
+    struct coda_rdwr_out coda_rdwr;
+    struct coda_replace_out coda_replace;
+    struct coda_open_by_path_out coda_open_by_path;
+    struct coda_statfs_out coda_statfs;
+};    
+
+union coda_downcalls {
+     
+     
+    struct coda_purgeuser_out purgeuser;
+    struct coda_zapfile_out zapfile;
+    struct coda_zapdir_out zapdir;
+    struct coda_zapvnode_out zapvnode;
+    struct coda_purgefid_out purgefid;
+    struct coda_replace_out replace;
+};
+
+
+ 
+
+
+
+
+struct ViceIoctl {
+        caddr_t in, out;         
+        short in_size;           
+        short out_size;          
+};
+
+struct PioctlData {
+        const char *path;
+        int follow;
+        struct ViceIoctl vi;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 14 "/usr/src/linux/include/linux/coda_fs_i.h" 2
+
+
+
+
+
+ 
+
+
+struct coda_inode_info {
+	 
+
+
+
+
+	struct pipe_inode_info  pipeinfo;
+
+        struct ViceFid     c_fid;	 
+        u_short	           c_flags;      
+        struct inode      *c_ovp;        
+        struct list_head   c_cnhead;     
+	struct list_head   c_volrootlist;  
+        struct inode      *c_vnode;      
+	unsigned int	   c_contcount;  
+        int                c_magic;      
+};
+
+ 
+
+
+
+
+int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *);
+int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
+struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb);
+void coda_replace_fid(struct inode *, ViceFid *, ViceFid *);
+
+
+
+# 276 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/romfs_fs_i.h" 1
+
+
+
+ 
+
+struct romfs_inode_info {
+	unsigned long i_metasize;	 
+	unsigned long i_dataoffset;	 
+};
+
+
+# 277 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/smb_fs_i.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+struct smb_inode_info {
+
+	 
+
+
+
+        unsigned int open;	 
+	__u16 fileid;		 
+	__u16 attr;		 
+
+	__u16 access;		 
+	__u16 cache_valid;	 
+	unsigned long oldmtime;	 
+	unsigned long closed;	 
+};
+
+
+
+# 278 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/hfs_fs_i.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+struct hfs_inode_info {
+	int				magic;      
+
+	struct hfs_cat_entry		*entry;
+
+	 
+	struct hfs_fork 		*fork;
+	int				convert;
+
+	 
+	ino_t				file_type;
+	char				dir_size;
+
+	 
+	const struct hfs_hdr_layout	*default_layout;
+	struct hfs_hdr_layout		*layout;
+
+	 
+	int                             tz_secondswest;
+
+         
+        void (*d_drop_op)(struct dentry *, const ino_t);
+};
+
+
+# 279 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/adfs_fs_i.h" 1
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+struct adfs_inode_info {
+	unsigned long	file_id;		 
+};
+
+
+# 280 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/qnx4_fs_i.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/qnxtypes.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef __u16 qnx4_nxtnt_t;
+typedef __u8  qnx4_ftype_t;
+
+typedef struct {
+	__u32 xtnt_blk;
+	__u32 xtnt_size;
+} qnx4_xtnt_t;
+
+typedef __u16 qnx4_mode_t;
+typedef __u16 qnx4_muid_t;
+typedef __u16 qnx4_mgid_t;
+typedef __u32 qnx4_off_t;
+typedef __u16 qnx4_nlink_t;
+
+
+# 14 "/usr/src/linux/include/linux/qnx4_fs_i.h" 2
+
+
+ 
+
+
+struct qnx4_inode_info {
+	char		i_reserved[16];	 
+	qnx4_off_t	i_size;		 
+	qnx4_xtnt_t	i_first_xtnt;	 
+	__u32		i_xblk;		 
+	__s32		i_ftime;	 
+	__s32		i_mtime;	 
+	__s32		i_atime;	 
+	__s32		i_ctime;	 
+	qnx4_nxtnt_t	i_num_xtnts;	 
+	qnx4_mode_t	i_mode;		 
+	qnx4_muid_t	i_uid;		 
+	qnx4_mgid_t	i_gid;		 
+	qnx4_nlink_t	i_nlink;	 
+	__u8		i_zero[4];	 
+	qnx4_ftype_t	i_type;		 
+	__u8		i_status;	 
+};
+
+
+# 281 "/usr/src/linux/include/linux/fs.h" 2
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+struct iattr {
+	unsigned int	ia_valid;
+	umode_t		ia_mode;
+	uid_t		ia_uid;
+	gid_t		ia_gid;
+	off_t		ia_size;
+	time_t		ia_atime;
+	time_t		ia_mtime;
+	time_t		ia_ctime;
+	unsigned int	ia_attr_flags;
+};
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+# 1 "/usr/src/linux/include/linux/quota.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/errno.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/errno.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 4 "/usr/src/linux/include/linux/errno.h" 2
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+# 42 "/usr/src/linux/include/linux/quota.h" 2
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+extern int nr_dquots, nr_free_dquots;
+extern int max_dquots;
+extern int dquot_root_squash;
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+struct dqblk {
+	__u32 dqb_bhardlimit;	 
+	__u32 dqb_bsoftlimit;	 
+	__u32 dqb_curblocks;	 
+	__u32 dqb_ihardlimit;	 
+	__u32 dqb_isoftlimit;	 
+	__u32 dqb_curinodes;	 
+	time_t dqb_btime;		 
+	time_t dqb_itime;		 
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct dqstats {
+	__u32 lookups;
+	__u32 drops;
+	__u32 reads;
+	__u32 writes;
+	__u32 cache_hits;
+	__u32 allocated_dquots;
+	__u32 free_dquots;
+	__u32 syncs;
+};
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+struct dquot {
+	struct dquot *dq_next;		 
+	struct dquot **dq_pprev;
+	struct list_head dq_free;	 
+	struct dquot *dq_hash_next;	 
+	struct dquot **dq_hash_pprev;	 
+	struct wait_queue *dq_wait;	 
+	int dq_count;			 
+
+	 
+	struct vfsmount *dq_mnt;	 
+	unsigned int dq_id;		 
+	kdev_t dq_dev;			 
+	short dq_type;			 
+	short dq_flags;			 
+	unsigned long dq_referenced;	 
+
+	struct dqblk dq_dqb;		 
+};
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+# 208 "/usr/src/linux/include/linux/quota.h"
+
+
+# 332 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/mount.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct quota_mount_options
+{
+	unsigned int flags;			 
+	struct semaphore dqio_sem;		 
+	struct semaphore dqoff_sem;		 
+	struct file *files[2 ];		 
+	time_t inode_expire[2 ];		 
+	time_t block_expire[2 ];		 
+	char rsquash[2 ];		 
+};
+
+struct vfsmount
+{
+  kdev_t mnt_dev;			 
+  char *mnt_devname;			 
+  char *mnt_dirname;			 
+  unsigned int mnt_flags;		 
+  struct super_block *mnt_sb;		 
+  struct quota_mount_options mnt_dquot;	 
+  struct vfsmount *mnt_next;		 
+};
+
+struct vfsmount *lookup_vfsmnt(kdev_t dev);
+
+ 
+
+
+ 
+
+
+
+# 333 "/usr/src/linux/include/linux/fs.h" 2
+
+
+struct inode {
+	struct list_head	i_hash;
+	struct list_head	i_list;
+	struct list_head	i_dentry;
+
+	unsigned long		i_ino;
+	unsigned int		i_count;
+	kdev_t			i_dev;
+	umode_t			i_mode;
+	nlink_t			i_nlink;
+	uid_t			i_uid;
+	gid_t			i_gid;
+	kdev_t			i_rdev;
+	off_t			i_size;
+	time_t			i_atime;
+	time_t			i_mtime;
+	time_t			i_ctime;
+	unsigned long		i_blksize;
+	unsigned long		i_blocks;
+	unsigned long		i_version;
+	unsigned long		i_nrpages;
+	struct semaphore	i_sem;
+	struct semaphore	i_atomic_write;
+	struct inode_operations	*i_op;
+	struct super_block	*i_sb;
+	struct wait_queue	*i_wait;
+	struct file_lock	*i_flock;
+	struct vm_area_struct	*i_mmap;
+	struct page		*i_pages;
+	struct dquot		*i_dquot[2 ];
+
+	unsigned long		i_state;
+
+	unsigned int		i_flags;
+	unsigned char		i_pipe;
+	unsigned char		i_sock;
+
+	int			i_writecount;
+	unsigned int		i_attr_flags;
+	__u32			i_generation;
+	union {
+		struct pipe_inode_info		pipe_i;
+		struct minix_inode_info		minix_i;
+		struct ext2_inode_info		ext2_i;
+		struct hpfs_inode_info		hpfs_i;
+		struct ntfs_inode_info          ntfs_i;
+		struct msdos_inode_info		msdos_i;
+		struct umsdos_inode_info	umsdos_i;
+		struct iso_inode_info		isofs_i;
+		struct nfs_inode_info		nfs_i;
+		struct sysv_inode_info		sysv_i;
+		struct affs_inode_info		affs_i;
+		struct ufs_inode_info		ufs_i;
+		struct efs_inode_info		efs_i;
+		struct romfs_inode_info		romfs_i;
+		struct coda_inode_info		coda_i;
+		struct smb_inode_info		smbfs_i;
+		struct hfs_inode_info		hfs_i;
+		struct adfs_inode_info		adfs_i;
+		struct qnx4_inode_info		qnx4_i;
+		struct socket			socket_i;
+		void				*generic_ip;
+	} u;
+};
+
+ 
+
+
+
+
+extern void __mark_inode_dirty(struct inode *);
+static inline void mark_inode_dirty(struct inode *inode)
+{
+	if (!(inode->i_state & 1 ))
+		__mark_inode_dirty(inode);
+}
+
+struct fown_struct {
+	int pid;		 
+	uid_t uid, euid;	 
+	int signum;		 
+};
+
+struct file {
+	struct file		*f_next, **f_pprev;
+	struct dentry		*f_dentry;
+	struct file_operations	*f_op;
+	mode_t			f_mode;
+	loff_t			f_pos;
+	unsigned int 		f_count, f_flags;
+	unsigned long 		f_reada, f_ramax, f_raend, f_ralen, f_rawin;
+	struct fown_struct	f_owner;
+	unsigned int		f_uid, f_gid;
+	int			f_error;
+
+	unsigned long		f_version;
+
+	 
+	void			*private_data;
+};
+
+extern int init_private_file(struct file *, struct dentry *, int);
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+typedef struct files_struct *fl_owner_t;
+
+struct file_lock {
+	struct file_lock *fl_next;	 
+	struct file_lock *fl_nextlink;	 
+	struct file_lock *fl_prevlink;	 
+	struct file_lock *fl_nextblock;  
+	struct file_lock *fl_prevblock;
+	fl_owner_t fl_owner;
+	unsigned int fl_pid;
+	struct wait_queue *fl_wait;
+	struct file *fl_file;
+	unsigned char fl_flags;
+	unsigned char fl_type;
+	off_t fl_start;
+	off_t fl_end;
+
+	void (*fl_notify)(struct file_lock *);	 
+
+	union {
+		struct nfs_lock_info	nfs_fl;
+	} fl_u;
+};
+
+extern struct file_lock			*file_lock_table;
+
+# 1 "/usr/src/linux/include/linux/fcntl.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/fcntl.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+struct flock {
+	short l_type;
+	short l_whence;
+	off_t l_start;
+	off_t l_len;
+	pid_t l_pid;
+};
+
+
+# 4 "/usr/src/linux/include/linux/fcntl.h" 2
+
+
+
+# 477 "/usr/src/linux/include/linux/fs.h" 2
+
+
+extern int fcntl_getlk(unsigned int fd, struct flock *l);
+extern int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l);
+
+ 
+extern void locks_remove_posix(struct file *, fl_owner_t id);
+extern void locks_remove_flock(struct file *);
+extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
+extern int posix_lock_file(struct file *, struct file_lock *, unsigned int);
+extern void posix_block_lock(struct file_lock *, struct file_lock *);
+extern void posix_unblock_lock(struct file_lock *);
+
+struct fasync_struct {
+	int    magic;
+	int    fa_fd;
+	struct fasync_struct	*fa_next;  
+	struct file 		*fa_file;
+};
+
+
+
+extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
+
+# 1 "/usr/src/linux/include/linux/minix_fs_sb.h" 1
+
+
+
+ 
+
+
+struct minix_sb_info {
+			unsigned long s_ninodes;
+			unsigned long s_nzones;
+			unsigned long s_imap_blocks;
+			unsigned long s_zmap_blocks;
+			unsigned long s_firstdatazone;
+			unsigned long s_log_zone_size;
+			unsigned long s_max_size;
+			int s_dirsize;
+			int s_namelen;
+			int s_link_max;
+			struct buffer_head ** s_imap;
+			struct buffer_head ** s_zmap;
+			struct buffer_head * s_sbh;
+			struct minix_super_block * s_ms;
+			unsigned short s_mount_state;
+			unsigned short s_version;
+};
+
+
+# 501 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/ext2_fs_sb.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/ext2_fs.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+struct ext2_acl_header	 
+{
+	__u32	aclh_size;
+	__u32	aclh_file_count;
+	__u32	aclh_acle_count;
+	__u32	aclh_first_acle;
+};
+
+struct ext2_acl_entry	 
+{
+	__u32	acle_size;
+	__u16	acle_perms;	 
+	__u16	acle_type;	 
+	__u16	acle_tag;	 
+	__u16	acle_pad1;
+	__u32	acle_next;	 
+					 
+};
+
+ 
+
+
+struct ext2_group_desc
+{
+	__u32	bg_block_bitmap;		 
+	__u32	bg_inode_bitmap;		 
+	__u32	bg_inode_table;		 
+	__u16	bg_free_blocks_count;	 
+	__u16	bg_free_inodes_count;	 
+	__u16	bg_used_dirs_count;	 
+	__u16	bg_pad;
+	__u32	bg_reserved[3];
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 	
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+struct ext2_inode {
+	__u16	i_mode;		 
+	__u16	i_uid;		 
+	__u32	i_size;		 
+	__u32	i_atime;	 
+	__u32	i_ctime;	 
+	__u32	i_mtime;	 
+	__u32	i_dtime;	 
+	__u16	i_gid;		 
+	__u16	i_links_count;	 
+	__u32	i_blocks;	 
+	__u32	i_flags;	 
+	union {
+		struct {
+			__u32  l_i_reserved1;
+		} linux1;
+		struct {
+			__u32  h_i_translator;
+		} hurd1;
+		struct {
+			__u32  m_i_reserved1;
+		} masix1;
+	} osd1;				 
+	__u32	i_block[(((12   + 1)  + 1)  + 1) ]; 
+	__u32	i_version;	 
+	__u32	i_file_acl;	 
+	__u32	i_dir_acl;	 
+	__u32	i_faddr;	 
+	union {
+		struct {
+			__u8	l_i_frag;	 
+			__u8	l_i_fsize;	 
+			__u16	i_pad1;
+			__u32	l_i_reserved2[2];
+		} linux2;
+		struct {
+			__u8	h_i_frag;	 
+			__u8	h_i_fsize;	 
+			__u16	h_i_mode_high;
+			__u16	h_i_uid_high;
+			__u16	h_i_gid_high;
+			__u32	h_i_author;
+		} hurd2;
+		struct {
+			__u8	m_i_frag;	 
+			__u8	m_i_fsize;	 
+			__u16	m_pad1;
+			__u32	m_i_reserved2[2];
+		} masix2;
+	} osd2;				 
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+struct ext2_super_block {
+	__u32	s_inodes_count;		 
+	__u32	s_blocks_count;		 
+	__u32	s_r_blocks_count;	 
+	__u32	s_free_blocks_count;	 
+	__u32	s_free_inodes_count;	 
+	__u32	s_first_data_block;	 
+	__u32	s_log_block_size;	 
+	__s32	s_log_frag_size;	 
+	__u32	s_blocks_per_group;	 
+	__u32	s_frags_per_group;	 
+	__u32	s_inodes_per_group;	 
+	__u32	s_mtime;		 
+	__u32	s_wtime;		 
+	__u16	s_mnt_count;		 
+	__s16	s_max_mnt_count;	 
+	__u16	s_magic;		 
+	__u16	s_state;		 
+	__u16	s_errors;		 
+	__u16	s_minor_rev_level; 	 
+	__u32	s_lastcheck;		 
+	__u32	s_checkinterval;	 
+	__u32	s_creator_os;		 
+	__u32	s_rev_level;		 
+	__u16	s_def_resuid;		 
+	__u16	s_def_resgid;		 
+	 
+
+
+
+
+
+
+
+
+
+
+
+
+	__u32	s_first_ino; 		 
+	__u16   s_inode_size; 		 
+	__u16	s_block_group_nr; 	 
+	__u32	s_feature_compat; 	 
+	__u32	s_feature_incompat; 	 
+	__u32	s_feature_ro_compat; 	 
+	__u8	s_uuid[16];		 
+	char	s_volume_name[16]; 	 
+	char	s_last_mounted[64]; 	 
+	__u32	s_algorithm_usage_bitmap;  
+	 
+
+
+
+	__u8	s_prealloc_blocks;	 
+	__u8	s_prealloc_dir_blocks;	 
+	__u16	s_padding1;
+	__u32	s_reserved[204];	 
+};
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+struct ext2_dir_entry {
+	__u32	inode;			 
+	__u16	rec_len;		 
+	__u16	name_len;		 
+	char	name[255 ];	 
+};
+
+ 
+
+
+
+
+
+struct ext2_dir_entry_2 {
+	__u32	inode;			 
+	__u16	rec_len;		 
+	__u8	name_len;		 
+	__u8	file_type;
+	char	name[255 ];	 
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+extern long long ext2_max_sizes[];
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+extern int ext2_permission (struct inode *, int);
+
+ 
+extern int ext2_group_sparse(int group);
+extern int ext2_new_block (const struct inode *, unsigned long,
+			   __u32 *, __u32 *, int *);
+extern void ext2_free_blocks (const struct inode *, unsigned long,
+			      unsigned long);
+extern unsigned long ext2_count_free_blocks (struct super_block *);
+extern void ext2_check_blocks_bitmap (struct super_block *);
+extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+						    unsigned int block_group,
+						    struct buffer_head ** bh);
+
+ 
+extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
+
+ 
+extern int ext2_check_dir_entry (const char *, struct inode *,
+				 struct ext2_dir_entry_2 *, struct buffer_head *,
+				 unsigned long);
+
+ 
+extern int ext2_read (struct inode *, struct file *, char *, int);
+extern int ext2_write (struct inode *, struct file *, char *, int);
+
+ 
+extern int ext2_sync_file (struct file *, struct dentry *);
+
+ 
+extern struct inode * ext2_new_inode (const struct inode *, int, int *);
+extern void ext2_free_inode (struct inode *);
+extern unsigned long ext2_count_free_inodes (struct super_block *);
+extern void ext2_check_inodes_bitmap (struct super_block *);
+
+ 
+extern int ext2_bmap (struct inode *, int);
+
+extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
+extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
+
+extern int ext2_getcluster (struct inode * inode, long block);
+extern void ext2_read_inode (struct inode *);
+extern void ext2_write_inode (struct inode *);
+extern void ext2_put_inode (struct inode *);
+extern void ext2_delete_inode (struct inode *);
+extern int ext2_sync_inode (struct inode *);
+extern int ext2_notify_change(struct dentry *, struct iattr *);
+extern void ext2_discard_prealloc (struct inode *);
+
+ 
+extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
+		       unsigned long);
+
+ 
+extern void ext2_release (struct inode *, struct file *);
+extern struct dentry *ext2_lookup (struct inode *, struct dentry *);
+extern int ext2_create (struct inode *,struct dentry *,int);
+extern int ext2_mkdir (struct inode *,struct dentry *,int);
+extern int ext2_rmdir (struct inode *,struct dentry *);
+extern int ext2_unlink (struct inode *,struct dentry *);
+extern int ext2_symlink (struct inode *,struct dentry *,const char *);
+extern int ext2_link (struct dentry *, struct inode *, struct dentry *);
+extern int ext2_mknod (struct inode *, struct dentry *, int, int);
+extern int ext2_rename (struct inode *, struct dentry *,
+			struct inode *, struct dentry *);
+
+ 
+extern void ext2_error (struct super_block *, const char *, const char *, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern   void ext2_panic (struct super_block *, const char *,
+				   const char *, ...)
+	__attribute__ ((noreturn,  format (printf, 3, 4)));
+extern void ext2_warning (struct super_block *, const char *, const char *, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern void ext2_put_super (struct super_block *);
+extern void ext2_write_super (struct super_block *);
+extern int ext2_remount (struct super_block *, int *, char *);
+extern struct super_block * ext2_read_super (struct super_block *,void *,int);
+extern int init_ext2_fs(void);
+extern int ext2_statfs (struct super_block *, struct statfs *, int);
+
+ 
+extern void ext2_truncate (struct inode *);
+
+ 
+
+
+
+ 
+extern struct inode_operations ext2_dir_inode_operations;
+
+ 
+extern struct inode_operations ext2_file_inode_operations;
+
+ 
+extern struct inode_operations ext2_symlink_inode_operations;
+
+
+
+
+# 19 "/usr/src/linux/include/linux/ext2_fs_sb.h" 2
+
+
+ 
+
+
+
+ 
+
+
+
+ 
+
+
+struct ext2_sb_info {
+	unsigned long s_frag_size;	 
+	unsigned long s_frags_per_block; 
+	unsigned long s_inodes_per_block; 
+	unsigned long s_frags_per_group; 
+	unsigned long s_blocks_per_group; 
+	unsigned long s_inodes_per_group; 
+	unsigned long s_itb_per_group;	 
+	unsigned long s_db_per_group;	 
+	unsigned long s_desc_per_block;	 
+	unsigned long s_groups_count;	 
+	struct buffer_head * s_sbh;	 
+	struct ext2_super_block * s_es;	 
+	struct buffer_head ** s_group_desc;
+	unsigned short s_loaded_inode_bitmaps;
+	unsigned short s_loaded_block_bitmaps;
+	unsigned long s_inode_bitmap_number[8 ];
+	struct buffer_head * s_inode_bitmap[8 ];
+	unsigned long s_block_bitmap_number[8 ];
+	struct buffer_head * s_block_bitmap[8 ];
+	unsigned long  s_mount_opt;
+	unsigned short s_resuid;
+	unsigned short s_resgid;
+	unsigned short s_mount_state;
+	unsigned short s_pad;
+	int s_addr_per_block_bits;
+	int s_desc_per_block_bits;
+	int s_inode_size;
+	int s_first_ino;
+	int s_feature_compat;
+	int s_feature_incompat;
+	int s_feature_ro_compat;
+};
+
+
+# 502 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/hpfs_fs_sb.h" 1
+
+
+
+struct hpfs_sb_info {
+	ino_t sb_root;			 
+	unsigned sb_fs_size;		 
+	unsigned sb_bitmaps;		 
+	unsigned sb_dirband_size;	 
+	unsigned sb_dmap;		 
+	unsigned sb_n_free;		 
+	unsigned sb_n_free_dnodes;	 
+	uid_t sb_uid;			 
+	gid_t sb_gid;			 
+	umode_t sb_mode;		 
+	unsigned sb_lowercase : 1;	 
+	unsigned sb_conv : 2;		 
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 503 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/ntfs_fs_sb.h" 1
+
+
+
+struct ntfs_sb_info{
+	 
+	ntfs_uid_t uid;
+	ntfs_gid_t gid;
+	ntmode_t umask;
+        unsigned int nct;
+	void *nls_map;
+	unsigned int ngt;
+	 
+	ntfs_size_t partition_bias;	 
+	 
+	ntfs_u32 at_standard_information;
+	ntfs_u32 at_attribute_list;
+	ntfs_u32 at_file_name;
+	ntfs_u32 at_volume_version;
+	ntfs_u32 at_security_descriptor;
+	ntfs_u32 at_volume_name;
+	ntfs_u32 at_volume_information;
+	ntfs_u32 at_data;
+	ntfs_u32 at_index_root;
+	ntfs_u32 at_index_allocation;
+	ntfs_u32 at_bitmap;
+	ntfs_u32 at_symlink;  
+	 
+	int blocksize;
+	int clusterfactor;
+	int clustersize;
+	int mft_recordsize;
+	int mft_clusters_per_record;
+	int index_recordsize;
+	int index_clusters_per_record;
+	int mft_cluster;
+	 
+	unsigned char *mft;
+	unsigned short *upcase;
+	unsigned int upcase_length;
+	 
+	struct ntfs_inode_info *mft_ino;
+	struct ntfs_inode_info *mftmirr;
+	struct ntfs_inode_info *bitmap;
+	struct super_block *sb;
+};
+
+
+# 504 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/msdos_fs_sb.h" 1
+
+
+# 1 "/usr/src/linux/include/linux/fat_cvf.h" 1
+
+
+
+
+
+struct cvf_format
+{ int cvf_version;
+  char* cvf_version_text;
+  unsigned long flags;
+  int (*detect_cvf) (struct super_block*sb);
+  int (*mount_cvf) (struct super_block*sb,char*options);
+  int (*unmount_cvf) (struct super_block*sb);
+  struct buffer_head* (*cvf_bread) (struct super_block*sb,int block);
+  struct buffer_head* (*cvf_getblk) (struct super_block*sb,int block);
+  void (*cvf_brelse) (struct super_block *sb,struct buffer_head *bh);
+  void (*cvf_mark_buffer_dirty) (struct super_block *sb,
+                              struct buffer_head *bh,
+                              int dirty_val);
+  void (*cvf_set_uptodate) (struct super_block *sb,
+                         struct buffer_head *bh,
+                         int val);
+  int (*cvf_is_uptodate) (struct super_block *sb,struct buffer_head *bh);
+  void (*cvf_ll_rw_block) (struct super_block *sb,
+                        int opr,
+                        int nbreq,
+                        struct buffer_head *bh[32]);
+  int (*fat_access) (struct super_block *sb,int nr,int new_value);
+  int (*cvf_statfs) (struct super_block *sb,struct statfs *buf, int bufsiz);
+  int (*cvf_bmap) (struct inode *inode,int block);
+  int (*cvf_smap) (struct inode *inode,int sector);
+  ssize_t (*cvf_file_read) ( struct file *, char *, size_t, loff_t *);
+  ssize_t (*cvf_file_write) ( struct file *, const char *, size_t, loff_t *);
+  int (*cvf_mmap) (struct file *, struct vm_area_struct *);
+  int (*cvf_readpage) (struct inode *, struct page *);
+  int (*cvf_writepage) (struct inode *, struct page *);
+  int (*cvf_dir_ioctl) (struct inode * inode, struct file * filp,
+                        unsigned int cmd, unsigned long arg);
+  void (*zero_out_cluster) (struct inode*, int clusternr);
+};
+
+int register_cvf_format(struct cvf_format*cvf_format);
+int unregister_cvf_format(struct cvf_format*cvf_format);
+void dec_cvf_format_use_count_by_version(int version);
+int detect_cvf(struct super_block*sb,char*force);
+
+extern struct cvf_format *cvf_formats[];
+extern int cvf_format_use_count[];
+
+
+# 3 "/usr/src/linux/include/linux/msdos_fs_sb.h" 2
+
+
+ 
+
+
+
+struct fat_mount_options {
+	uid_t fs_uid;
+	gid_t fs_gid;
+	unsigned short fs_umask;
+	unsigned short codepage;   
+	char *iocharset;           
+	unsigned char name_check;  
+	unsigned char conversion;  
+	unsigned quiet:1,          
+		 showexec:1,       
+		 sys_immutable:1,  
+		 dotsOK:1,         
+		 isvfat:1,         
+		 utf8:1,	   
+		 unicode_xlate:1,  
+		 posixfs:1,        
+		 numtail:1,        
+		 atari:1,          
+		 fat32:1;	   
+};
+
+struct vfat_unicode {
+	unsigned char uni1;
+	unsigned char uni2;
+};
+
+struct msdos_sb_info {
+	unsigned short cluster_size;  
+	unsigned char fats,fat_bits;  
+	unsigned short fat_start;
+	unsigned long fat_length;     
+	unsigned long dir_start;
+	unsigned short dir_entries;   
+	unsigned long data_start;     
+	unsigned long clusters;       
+	unsigned long root_cluster;   
+	unsigned long fsinfo_offset;  
+	struct wait_queue *fat_wait;
+	int fat_lock;
+	int prev_free;                
+	int free_clusters;            
+	struct fat_mount_options options;
+	struct nls_table *nls_disk;   
+	struct nls_table *nls_io;     
+	struct cvf_format* cvf_format;
+	void *dir_ops;		      
+	void (*put_super_callback)(struct super_block *);
+	void *private_data;	
+};
+
+
+# 505 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/iso_fs_sb.h" 1
+
+
+
+ 
+
+
+struct isofs_sb_info {
+	unsigned long s_ninodes;
+	unsigned long s_nzones;
+	unsigned long s_firstdatazone;
+	unsigned long s_log_zone_size;
+	unsigned long s_max_size;
+	
+	unsigned char s_high_sierra;  
+	unsigned char s_mapping;
+	unsigned char s_rock;
+	unsigned char s_joliet_level;
+	unsigned char s_utf8;
+	unsigned char s_cruft;  
+
+
+	unsigned char s_unhide;
+	unsigned char s_nosuid;
+	unsigned char s_nodev;
+	mode_t s_mode;
+	gid_t s_gid;
+	uid_t s_uid;
+	struct nls_table *s_nls_iocharset;  
+};
+
+
+# 506 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/nfs_fs_sb.h" 1
+
+
+
+
+# 1 "/usr/src/linux/include/linux/in.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+enum {
+  IPPROTO_IP = 0,		 
+  IPPROTO_ICMP = 1,		 
+  IPPROTO_IGMP = 2,		 
+  IPPROTO_IPIP = 4,		 
+  IPPROTO_TCP = 6,		 
+  IPPROTO_EGP = 8,		 
+  IPPROTO_PUP = 12,		 
+  IPPROTO_UDP = 17,		 
+  IPPROTO_IDP = 22,		 
+  IPPROTO_RSVP = 46,		 
+  IPPROTO_GRE = 47,		 
+
+  IPPROTO_IPV6	 = 41,		 
+
+  IPPROTO_PIM    = 103,		 
+
+  IPPROTO_ESP = 50,             
+  IPPROTO_AH = 51,              
+  IPPROTO_COMP   = 108,                 
+
+  IPPROTO_RAW	 = 255,		 
+  IPPROTO_MAX
+};
+
+
+ 
+struct in_addr {
+	__u32	s_addr;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+struct ip_mreq 
+{
+	struct in_addr imr_multiaddr;	 
+	struct in_addr imr_interface;	 
+};
+
+struct ip_mreqn
+{
+	struct in_addr	imr_multiaddr;		 
+	struct in_addr	imr_address;		 
+	int		imr_ifindex;		 
+};
+
+struct in_pktinfo
+{
+	int		ipi_ifindex;
+	struct in_addr	ipi_spec_dst;
+	struct in_addr	ipi_addr;
+};
+
+ 
+
+struct sockaddr_in {
+  sa_family_t		sin_family;	 
+  unsigned short int	sin_port;	 
+  struct in_addr	sin_addr;	 
+
+   
+  unsigned char		__pad[16  - sizeof(short int) -
+			sizeof(unsigned short int) - sizeof(struct in_addr)];
+};
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+ 
+
+
+ 
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+# 5 "/usr/src/linux/include/linux/nfs_fs_sb.h" 2
+
+
+ 
+
+
+struct nfs_server {
+	struct rpc_clnt *	client;		 
+	int			flags;		 
+	int			rsize;		 
+	int			wsize;		 
+	unsigned int		bsize;		 
+	unsigned int		acregmin;	 
+	unsigned int		acregmax;
+	unsigned int		acdirmin;
+	unsigned int		acdirmax;
+	char *			hostname;	 
+};
+
+ 
+
+
+struct nfs_sb_info {
+	struct nfs_server	s_server;
+	struct nfs_fh		s_root;
+};
+
+
+# 507 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/sysv_fs_sb.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+struct sysv_sb_info {
+	int	       s_type;		 
+	unsigned int   s_block_size;	 
+	unsigned int   s_block_size_1;	 
+	unsigned int   s_block_size_bits;	 
+	unsigned int   s_block_size_inc_bits;	 
+	unsigned int   s_block_size_dec_bits;	 
+	char	       s_convert;	 
+	char	       s_kludge_symlinks;  
+	char	       s_truncate;	 
+					 
+	nlink_t        s_link_max;	 
+	unsigned int   s_inodes_per_block;	 
+	unsigned int   s_inodes_per_block_1;	 
+	unsigned int   s_inodes_per_block_bits;	 
+	unsigned int   s_ind_per_block;		 
+	unsigned int   s_ind_per_block_1;	 
+	unsigned int   s_ind_per_block_bits;	 
+	unsigned int   s_ind_per_block_2;	 
+	unsigned int   s_ind_per_block_2_1;	 
+	unsigned int   s_ind_per_block_2_bits;	 
+	unsigned int   s_ind_per_block_3;	 
+	unsigned int   s_ind_per_block_block_size_1;	 
+	unsigned int   s_ind_per_block_block_size_bits;	 
+	unsigned int   s_ind_per_block_2_block_size_1;	 
+	unsigned int   s_ind_per_block_2_block_size_bits;  
+	unsigned int   s_ind0_size;		 
+	unsigned int   s_ind1_size;		 
+	unsigned int   s_ind2_size;		 
+	unsigned int   s_toobig_block;		 
+	unsigned int   s_block_base;	 
+	unsigned short s_fic_size;	 
+	unsigned short s_flc_size;	 
+	 
+	struct buffer_head *s_bh1;
+	struct buffer_head *s_bh2;
+	 
+
+	char *         s_sbd1;		 
+	char *         s_sbd2;		 
+	u16            *s_sb_fic_count;	 
+        u16            *s_sb_fic_inodes;  
+	u16            *s_sb_total_free_inodes;  
+	u16            *s_sb_flc_count;	 
+	u32	       *s_sb_flc_blocks;  
+	u32            *s_sb_total_free_blocks; 
+	u32            *s_sb_time;	 
+	u32            *s_sb_state;	 
+	 
+
+	u32            s_firstinodezone;  
+	u32            s_firstdatazone;	 
+	u32            s_ninodes;	 
+	u32            s_ndatazones;	 
+	u32            s_nzones;	 
+};
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 508 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/affs_fs_sb.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+struct affs_bm_info {
+	struct buffer_head *bm_bh;	 
+	s32 bm_firstblk;		 
+	s32 bm_key;			 
+	int bm_count;			 
+};
+
+struct affs_alloc_zone {
+	short az_size;			 
+	short az_count;			 
+	int az_free;			 
+};
+
+struct affs_zone {
+	unsigned long z_ino;		 
+	struct affs_bm_info *z_bm;	 
+	int z_start;			 
+	int z_end;			 
+	int z_az_no;			 
+	unsigned long z_lru_time;	 
+};
+
+struct affs_sb_info {
+	int s_partition_size;		 
+	int s_blksize;			 
+	s32 s_root_block;		 
+	int s_hashsize;			 
+	unsigned long s_flags;		 
+	s16 s_uid;			 
+	s16 s_gid;			 
+	umode_t s_mode;			 
+	int s_reserved;			 
+	struct buffer_head *s_root_bh;	 
+	struct affs_bm_info *s_bitmap;	 
+	int s_bm_count;			 
+	int s_nextzone;			 
+	int s_num_az;			 
+	struct affs_zone *s_zones;	 
+	struct affs_alloc_zone *s_alloc; 
+	char *s_zonemap;		 
+	char *s_prefix;			 
+	int s_prefix_len;		 
+	char s_volume[32];		 
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 509 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/ufs_fs_sb.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/ufs_fs.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+ 
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+            
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+struct ufs_timeval {
+	__s32	tv_sec;
+	__s32	tv_usec;
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+   
+struct ufs_dir_entry {
+	__u32  d_ino;			 
+	__u16  d_reclen;		 
+	union {
+		__u16	d_namlen;		 
+		struct {
+			__u8	d_type;		 
+			__u8	d_namlen;	 
+		} d_44;
+	} d_u;
+	__u8	d_name[255  + 1];	 
+};
+
+struct ufs_csum {
+	__u32	cs_ndir;	 
+	__u32	cs_nbfree;	 
+	__u32	cs_nifree;	 
+	__u32	cs_nffree;	 
+};
+
+ 
+
+
+struct ufs_super_block {
+	__u32	fs_link;	 
+	__u32	fs_rlink;	 
+	__u32	fs_sblkno;	 
+	__u32	fs_cblkno;	 
+	__u32	fs_iblkno;	 
+	__u32	fs_dblkno;	 
+	__u32	fs_cgoffset;	 
+	__u32	fs_cgmask;	 
+	__u32	fs_time;	 
+	__u32	fs_size;	 
+	__u32	fs_dsize;	 
+	__u32	fs_ncg;		 
+	__u32	fs_bsize;	 
+	__u32	fs_fsize;	 
+	__u32	fs_frag;	 
+ 
+	__u32	fs_minfree;	 
+	__u32	fs_rotdelay;	 
+	__u32	fs_rps;		 
+ 
+	__u32	fs_bmask;	 
+	__u32	fs_fmask;	 
+	__u32	fs_bshift;	 
+	__u32	fs_fshift;	 
+ 
+	__u32	fs_maxcontig;	 
+	__u32	fs_maxbpg;	 
+ 
+	__u32	fs_fragshift;	 
+	__u32	fs_fsbtodb;	 
+	__u32	fs_sbsize;	 
+	__u32	fs_csmask;	 
+	__u32	fs_csshift;	 
+	__u32	fs_nindir;	 
+	__u32	fs_inopb;	 
+	__u32	fs_nspf;	 
+ 
+	__u32	fs_optim;	 
+ 
+	union {
+		struct {
+			__u32	fs_npsect;	 
+		} fs_sun;
+		struct {
+			__s32	fs_state;	 
+		} fs_sunx86;
+	} fs_u1;
+	__u32	fs_interleave;	 
+	__u32	fs_trackskew;	 
+ 
+ 
+ 
+ 
+	__u32	fs_id[2];	 
+ 
+	__u32	fs_csaddr;	 
+	__u32	fs_cssize;	 
+	__u32	fs_cgsize;	 
+ 
+	__u32	fs_ntrak;	 
+	__u32	fs_nsect;	 
+	__u32	fs_spc;		 
+ 
+	__u32	fs_ncyl;	 
+ 
+	__u32	fs_cpg;		 
+	__u32	fs_ipg;		 
+	__u32	fs_fpg;		 
+ 
+	struct ufs_csum fs_cstotal;	 
+ 
+	__s8	fs_fmod;	 
+	__s8	fs_clean;	 
+	__s8	fs_ronly;	 
+	__s8	fs_flags;	 
+	__s8	fs_fsmnt[512 ];	 
+ 
+	__u32	fs_cgrotor;	 
+	__u32	fs_csp[31 ];	 
+	__u32	fs_maxcluster;
+	__u32	fs_cpc;		 
+	__u16	fs_opostbl[16][8];	 	
+	union {
+		struct {
+			__s32	fs_sparecon[53]; 
+			__s32	fs_reclaim;
+			__s32	fs_sparecon2[1];
+			__s32	fs_state;	 
+			__u32	fs_qbmask[2];	 
+			__u32	fs_qfmask[2];	 
+		} fs_sun;
+		struct {
+			__s32	fs_sparecon[53]; 
+			__s32	fs_reclaim;
+			__s32	fs_sparecon2[1];
+			__u32	fs_npsect;	 
+			__u32	fs_qbmask[2];	 
+			__u32	fs_qfmask[2];	 
+		} fs_sunx86;
+		struct {
+			__s32	fs_sparecon[50]; 
+			__s32	fs_contigsumsize; 
+			__s32	fs_maxsymlinklen; 
+			__s32	fs_inodefmt;	 
+			__u32	fs_maxfilesize[2];	 
+			__u32	fs_qbmask[2];	 
+			__u32	fs_qfmask[2];	 
+			__s32	fs_state;	 
+		} fs_44;
+	} fs_u2;
+	__s32	fs_postblformat;	 
+	__s32	fs_nrpos;		 
+	__s32	fs_postbloff;		 
+	__s32	fs_rotbloff;		 
+	__s32	fs_magic;		 
+	__u8	fs_space[1];		 
+};
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+struct	ufs_cylinder_group {
+	__u32	cg_link;		 
+	__u32	cg_magic;		 
+	__u32	cg_time;		 
+	__u32	cg_cgx;			 
+	__u16	cg_ncyl;		 
+	__u16	cg_niblk;		 
+	__u32	cg_ndblk;		 
+	struct	ufs_csum cg_cs;		 
+	__u32	cg_rotor;		 
+	__u32	cg_frotor;		 
+	__u32	cg_irotor;		 
+	__u32	cg_frsum[(8192  / 1024 ) ];	 
+	__u32	cg_btotoff;		 
+	__u32	cg_boff;		 
+	__u32	cg_iusedoff;		 
+	__u32	cg_freeoff;		 
+	__u32	cg_nextfreeoff;		 
+	union {
+		struct {
+			__u32	cg_clustersumoff;	 
+			__u32	cg_clusteroff;		 
+			__u32	cg_nclusterblks;	 
+			__u32	cg_sparecon[13];	 
+		} cg_44;
+		__u32	cg_sparecon[16];	 
+	} cg_u;
+	__u8	cg_space[1];		 
+ 
+};
+
+ 
+
+
+struct ufs_inode {
+	__u16	ui_mode;		 
+	__u16	ui_nlink;		 
+	union {
+		struct {
+			__u16	ui_suid;	 
+			__u16	ui_sgid;	 
+		} oldids;
+		__u32	ui_inumber;		 
+		__u32	ui_author;		 
+	} ui_u1;
+	__u64	ui_size;		 
+	struct ufs_timeval ui_atime;	 
+	struct ufs_timeval ui_mtime;	 
+	struct ufs_timeval ui_ctime;	 
+	union {
+		struct {
+			__u32	ui_db[12 ]; 
+			__u32	ui_ib[3 ]; 
+		} ui_addr;
+		__u8	ui_symlink[4*(12 + 3 )]; 
+	} ui_u2;
+	__u32	ui_flags;		 
+	__u32	ui_blocks;		 
+	__u32	ui_gen;			 
+	union {
+		struct {
+			__u32	ui_shadow;	 
+			__u32	ui_uid;		 
+			__u32	ui_gid;		 
+			__u32	ui_oeftflag;	 
+		} ui_sun;
+		struct {
+			__u32	ui_uid;		 
+			__u32	ui_gid;		 
+			__s32	ui_spare[2];	 
+		} ui_44;
+		struct {
+			__u32	ui_uid;		 
+			__u32	ui_gid;		 
+			__u16	ui_modeh;	 
+			__u16	ui_spare;	 
+			__u32	ui_trans;	 
+		} ui_hurd;
+	} ui_u3;
+};
+
+ 
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+extern int ufs_permission (struct inode *, int);
+
+ 
+extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
+extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
+extern unsigned ufs_new_fragments (struct inode *, u32 *, unsigned, unsigned, unsigned, int *);
+
+ 
+extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned);
+extern void ufs_put_cylinder (struct super_block *, unsigned);
+
+ 
+extern struct inode_operations ufs_dir_inode_operations;
+extern struct file_operations ufs_dir_operations;
+extern int ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, struct buffer_head *, unsigned long);
+
+ 
+extern struct inode_operations ufs_file_inode_operations;
+extern struct file_operations ufs_file_operations;
+
+ 
+extern void ufs_free_inode (struct inode *inode);
+extern struct inode * ufs_new_inode (const struct inode *, int, int *);
+
+ 
+extern int ufs_bmap (struct inode *, int);
+extern void ufs_read_inode (struct inode *);
+extern void ufs_put_inode (struct inode *);
+extern void ufs_write_inode (struct inode *);
+extern int ufs_sync_inode (struct inode *);
+extern void ufs_write_inode (struct inode *);
+extern void ufs_delete_inode (struct inode *);
+extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
+extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
+
+ 
+extern struct dentry *ufs_lookup (struct inode *, struct dentry *);
+extern int ufs_mkdir(struct inode *, struct dentry *, int);
+extern int ufs_rmdir (struct inode *, struct dentry *);
+extern int ufs_unlink (struct inode *, struct dentry *);
+extern int ufs_create (struct inode *, struct dentry *, int);
+extern int ufs_rename (struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int ufs_mknod (struct inode *, struct dentry *, int, int);
+extern int ufs_symlink (struct inode *, struct dentry *, const char *);
+extern int ufs_link (struct dentry *, struct inode *, struct dentry *);
+        
+ 
+extern struct super_operations ufs_super_ops;
+extern struct file_system_type ufs_fs_type;
+extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern int init_ufs_fs(void);
+extern void ufs_write_super (struct super_block *);
+
+ 
+extern struct inode_operations ufs_symlink_inode_operations;
+
+ 
+extern void ufs_truncate (struct inode *);
+
+
+
+
+# 17 "/usr/src/linux/include/linux/ufs_fs_sb.h" 2
+
+
+ 
+
+
+
+struct ufs_buffer_head {
+	unsigned fragment;			 
+	unsigned count;				 
+	struct buffer_head * bh[(8192  / 1024 ) ];	 
+};
+
+struct ufs_cg_private_info {
+	struct ufs_cylinder_group ucg;
+	__u32	c_cgx;		 
+	__u16	c_ncyl;		 
+	__u16	c_niblk;	 
+	__u32	c_ndblk;	 
+	__u32	c_rotor;	 
+	__u32	c_frotor;	 
+	__u32	c_irotor;	 
+	__u32	c_btotoff;	 
+	__u32	c_boff;		 
+	__u32	c_iusedoff;	 
+	__u32	c_freeoff;	 
+	__u32	c_nextfreeoff;	 
+	__u32	c_clustersumoff; 
+	__u32	c_clusteroff;	 
+	__u32	c_nclusterblks;	 
+};	
+
+struct ufs_sb_private_info {
+	struct ufs_buffer_head s_ubh;  
+	__u32	s_sblkno;	 
+	__u32	s_cblkno;	 
+	__u32	s_iblkno;	 
+	__u32	s_dblkno;	 
+	__u32	s_cgoffset;	 
+	__u32	s_cgmask;	 
+	__u32	s_size;		 
+	__u32	s_dsize;	 
+	__u32	s_ncg;		 
+	__u32	s_bsize;	 
+	__u32	s_fsize;	 
+	__u32	s_fpb;		 
+	__u32	s_minfree;	 
+	__u32	s_bmask;	 
+	__u32	s_fmask;	 
+	__u32	s_bshift;	 
+	__u32   s_fshift;	 
+	__u32	s_fpbshift;	 
+	__u32	s_fsbtodb;	 
+	__u32	s_sbsize;	 
+	__u32   s_csmask;	 
+	__u32	s_csshift;	 
+	__u32	s_nindir;	 
+	__u32	s_inopb;	 
+	__u32	s_nspf;		 
+	__u32	s_npsect;	 
+	__u32	s_interleave;	 
+	__u32	s_trackskew;	 
+	__u32	s_csaddr;	 
+	__u32	s_cssize;	 
+	__u32	s_cgsize;	 
+	__u32	s_ntrak;	 
+	__u32	s_nsect;	 
+	__u32	s_spc;		 
+	__u32	s_ipg;		 
+	__u32	s_fpg;		 
+	__u32	s_cpc;		 
+	__s32	s_contigsumsize; 
+	__s64	s_qbmask;	 
+	__s64	s_qfmask;	 
+	__s32	s_postblformat;	 
+	__s32	s_nrpos;	 
+        __s32	s_postbloff;	 
+	__s32	s_rotbloff;	 
+
+	__u32	s_fpbmask;	 
+	__u32	s_apb;		 
+	__u32	s_2apb;		 
+	__u32	s_3apb;		 
+	__u32	s_apbmask;	 
+	__u32	s_apbshift;	 
+	__u32	s_2apbshift;	 
+	__u32	s_3apbshift;	 
+	__u32	s_nspfshift;	 
+	__u32	s_nspb;		 
+	__u32	s_inopf;	 
+	__u32	s_sbbase;	 
+	__u32	s_bpf;		 
+	__u32	s_bpfshift;	 
+	__u32	s_bpfmask;	 
+};
+
+
+
+
+
+struct ufs_sb_info {
+	struct ufs_sb_private_info * s_uspi;	
+	struct ufs_csum	* s_csp[31 ];
+	unsigned s_swab;
+	unsigned s_flags;
+	struct buffer_head ** s_ucg;
+	struct ufs_cg_private_info * s_ucpi[8 ]; 
+	unsigned s_cgno[8 ];
+	unsigned short s_cg_loaded;
+	unsigned s_mount_opt;
+};
+
+ 
+
+
+
+
+
+struct ufs_super_block_first {
+	__u32	fs_link;
+	__u32	fs_rlink;
+	__u32	fs_sblkno;
+	__u32	fs_cblkno;
+	__u32	fs_iblkno;
+	__u32	fs_dblkno;
+	__u32	fs_cgoffset;
+	__u32	fs_cgmask;
+	__u32	fs_time;
+	__u32	fs_size;
+	__u32	fs_dsize;
+	__u32	fs_ncg;
+	__u32	fs_bsize;
+	__u32	fs_fsize;
+	__u32	fs_frag;
+	__u32	fs_minfree;
+	__u32	fs_rotdelay;
+	__u32	fs_rps;
+	__u32	fs_bmask;
+	__u32	fs_fmask;
+	__u32	fs_bshift;
+	__u32	fs_fshift;
+	__u32	fs_maxcontig;
+	__u32	fs_maxbpg;
+	__u32	fs_fragshift;
+	__u32	fs_fsbtodb;
+	__u32	fs_sbsize;
+	__u32	fs_csmask;
+	__u32	fs_csshift;
+	__u32	fs_nindir;
+	__u32	fs_inopb;
+	__u32	fs_nspf;
+	__u32	fs_optim;
+	union {
+		struct {
+			__u32	fs_npsect;
+		} fs_sun;
+		struct {
+			__s32	fs_state;
+		} fs_sunx86;
+	} fs_u1;
+	__u32	fs_interleave;
+	__u32	fs_trackskew;
+	__u32	fs_id[2];
+	__u32	fs_csaddr;
+	__u32	fs_cssize;
+	__u32	fs_cgsize;
+	__u32	fs_ntrak;
+	__u32	fs_nsect;
+	__u32	fs_spc;
+	__u32	fs_ncyl;
+	__u32	fs_cpg;
+	__u32	fs_ipg;
+	__u32	fs_fpg;
+	struct ufs_csum fs_cstotal;
+	__s8	fs_fmod;
+	__s8	fs_clean;
+	__s8	fs_ronly;
+	__s8	fs_flags;
+	__s8	fs_fsmnt[512  - 212];
+
+};
+
+struct ufs_super_block_second {
+	__s8	fs_fsmnt[212];
+	__u32	fs_cgrotor;
+	__u32	fs_csp[31 ];
+	__u32	fs_maxcluster;
+	__u32	fs_cpc;
+	__u16	fs_opostbl[82];
+};	
+
+struct ufs_super_block_third {
+	__u16	fs_opostbl[46];
+	union {
+		struct {
+			__s32	fs_sparecon[53]; 
+			__s32	fs_reclaim;
+			__s32	fs_sparecon2[1];
+			__s32	fs_state;	 
+			__u32	fs_qbmask[2];	 
+			__u32	fs_qfmask[2];	 
+		} fs_sun;
+		struct {
+			__s32	fs_sparecon[53]; 
+			__s32	fs_reclaim;
+			__s32	fs_sparecon2[1];
+			__u32	fs_npsect;	 
+			__u32	fs_qbmask[2];	 
+			__u32	fs_qfmask[2];	 
+		} fs_sunx86;
+		struct {
+			__s32	fs_sparecon[50]; 
+			__s32	fs_contigsumsize; 
+			__s32	fs_maxsymlinklen; 
+			__s32	fs_inodefmt;	 
+			__u32	fs_maxfilesize[2];	 
+			__u32	fs_qbmask[2];	 
+			__u32	fs_qfmask[2];	 
+			__s32	fs_state;	 
+		} fs_44;
+	} fs_u2;
+	__s32	fs_postblformat;
+	__s32	fs_nrpos;
+	__s32	fs_postbloff;
+	__s32	fs_rotbloff;
+	__s32	fs_magic;
+	__u8	fs_space[1];
+};
+
+
+# 510 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/efs_fs_sb.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+struct efs_super {
+	int32_t		fs_size;         
+	int32_t		fs_firstcg;      
+	int32_t		fs_cgfsize;      
+	short		fs_cgisize;      
+	short		fs_sectors;      
+	short		fs_heads;        
+	short		fs_ncg;          
+	short		fs_dirty;        
+	short		fs_filler;	 
+	int32_t		fs_time;         
+	int32_t		fs_magic;        
+	char		fs_fname[6];     
+	char		fs_fpack[6];     
+	int32_t		fs_bmsize;       
+	int32_t		fs_tfree;        
+	int32_t		fs_tinode;       
+	int32_t		fs_bmblock;      
+	int32_t		fs_replsb;       
+	int32_t		fs_lastialloc;   
+	char		fs_spare[20];    
+	int32_t		fs_checksum;     
+};
+
+ 
+struct efs_sb_info {
+	int32_t	fs_magic;	 
+	int32_t	fs_start;	 
+	int32_t	first_block;	 
+	int32_t	total_blocks;	 
+	int32_t	group_size;	  
+	int32_t	data_free;	 
+	int32_t	inode_free;	 
+	short	inode_blocks;	 
+	short	total_groups;	 
+};
+
+
+
+# 511 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/romfs_fs_sb.h" 1
+
+
+
+ 
+
+struct romfs_sb_info {
+	unsigned long s_maxsize;
+};
+
+
+# 512 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/smb_fs_sb.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/smb.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+enum smb_protocol { 
+	SMB_PROTOCOL_NONE, 
+	SMB_PROTOCOL_CORE, 
+	SMB_PROTOCOL_COREPLUS, 
+	SMB_PROTOCOL_LANMAN1, 
+	SMB_PROTOCOL_LANMAN2, 
+	SMB_PROTOCOL_NT1 
+};
+
+enum smb_case_hndl {
+	SMB_CASE_DEFAULT,
+	SMB_CASE_LOWER,
+	SMB_CASE_UPPER
+};
+
+struct smb_dskattr {
+        __u16 total;
+        __u16 allocblocks;
+        __u16 blocksize;
+        __u16 free;
+};
+
+struct smb_conn_opt {
+
+         
+	unsigned int fd;
+
+	enum smb_protocol protocol;
+	enum smb_case_hndl case_handling;
+
+	 
+
+	__u32              max_xmit;
+	__u16              server_uid;
+	__u16              tid;
+
+         
+        __u16              secmode;
+        __u16              maxmux;
+        __u16              maxvcs;
+        __u16              rawmode;
+        __u32              sesskey;
+
+	 
+	__u32              maxraw;
+	__u32              capabilities;
+	__s16              serverzone;
+};
+
+
+
+
+
+
+ 
+
+
+struct smb_fattr {
+
+	__u16 attr;
+
+	unsigned long	f_ino;
+	umode_t		f_mode;
+	nlink_t		f_nlink;
+	uid_t		f_uid;
+	gid_t		f_gid;
+	kdev_t		f_rdev;
+	off_t		f_size;
+	time_t		f_atime;
+	time_t		f_mtime;
+	time_t		f_ctime;
+	unsigned long	f_blksize;
+	unsigned long	f_blocks;
+};
+
+struct smb_dirent {
+	struct smb_fattr attr;
+
+	int f_pos;
+	int len;
+	__u8 name[255 ];
+};
+
+enum smb_conn_state {
+        CONN_VALID,              
+        CONN_INVALID,            
+
+        CONN_RETRIED             
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+# 15 "/usr/src/linux/include/linux/smb_fs_sb.h" 2
+
+
+ 
+
+
+
+
+struct smb_sb_info {
+        enum smb_conn_state state;
+	struct file * sock_file;
+
+        struct smb_mount_data *mnt;
+        unsigned char *temp_buf;
+
+	 
+
+
+	unsigned int generation;
+	pid_t conn_pid;
+	struct smb_conn_opt opt;
+
+	struct semaphore sem;
+	struct wait_queue * wait;
+
+	__u32              packet_size;
+	unsigned char *    packet;
+        unsigned short     rcls;  
+        unsigned short     err;
+
+         
+        void *data_ready;
+};
+
+
+
+
+# 513 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/hfs_fs_sb.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+struct hfs_name;
+
+typedef int (*hfs_namein_fn) (char *, const struct hfs_name *);
+typedef void (*hfs_nameout_fn) (struct hfs_name *, const char *, int);
+typedef void (*hfs_ifill_fn) (struct inode *, ino_t, const int);
+
+ 
+
+
+
+
+struct hfs_sb_info {
+	int			magic;		 
+	struct hfs_mdb		*s_mdb;		 
+	int			s_quiet;	 
+
+	int			s_lowercase;	 
+	int			s_afpd;		 
+	int                     s_version;       
+	hfs_namein_fn		s_namein;	 
+
+
+	hfs_nameout_fn		s_nameout;	 
+
+
+	hfs_ifill_fn		s_ifill;	 
+
+	const struct hfs_name	*s_reserved1;	 
+	const struct hfs_name	*s_reserved2;	 
+	__u32			s_type;		 
+	__u32			s_creator;	 
+	umode_t			s_umask;	 
+
+	uid_t			s_uid;		 
+	gid_t			s_gid;		 
+	char			s_conv;		 
+};
+
+
+# 514 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/adfs_fs_sb.h" 1
+ 
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/adfs_fs.h" 1
+
+
+
+
+ 
+
+
+
+ 
+
+
+struct adfs_discrecord {
+    unsigned char  log2secsize;
+    unsigned char  secspertrack;
+    unsigned char  heads;
+    unsigned char  density;
+    unsigned char  idlen;
+    unsigned char  log2bpmb;
+    unsigned char  skew;
+    unsigned char  bootoption;
+    unsigned char  lowsector;
+    unsigned char  nzones;
+    unsigned short zone_spare;
+    unsigned long  root;
+    unsigned long  disc_size;
+    unsigned short disc_id;
+    unsigned char  disc_name[10];
+    unsigned long  disc_type;
+    unsigned long  disc_size_high;
+    unsigned char  log2sharesize:4;
+    unsigned char  unused:4;
+    unsigned char  big_flag:1;
+};
+
+
+
+
+
+
+
+
+
+ 
+
+
+struct adfs_dirheader {
+	unsigned char startmasseq;
+	unsigned char startname[4];
+};
+
+
+
+
+
+ 
+
+
+struct adfs_direntry {
+	char dirobname[10];
+
+	__u8 dirload[4];
+	__u8 direxec[4];
+	__u8 dirlen[4];
+	__u8 dirinddiscadd[3];
+	__u8 newdiratts;
+
+
+
+
+
+
+
+};
+
+
+struct adfs_idir_entry {
+	__u32		inode_no;			 
+	__u32		file_id;			 
+	__u32		name_len;			 
+	__u32		size;				 
+	__u32		mtime;				 
+	__u32		filetype;			 
+	__u8		mode;				 
+	char		name[255 ];	 
+};
+
+ 
+
+
+union adfs_dirtail {
+	struct {
+		unsigned char dirlastmask;
+		char dirname[10];
+		unsigned char dirparent[3];
+		char dirtitle[19];
+		unsigned char reserved[14];
+		unsigned char endmasseq;
+		unsigned char endname[4];
+		unsigned char dircheckbyte;
+	} old;
+	struct {
+		unsigned char dirlastmask;
+		unsigned char reserved[2];
+		unsigned char dirparent[3];
+		char dirtitle[19];
+		char dirname[10];
+		unsigned char endmasseq;
+		unsigned char endname[4];
+		unsigned char dircheckbyte;
+	} new;
+};
+
+
+ 
+
+
+
+
+extern inline int adfs_checkbblk(unsigned char *ptr)
+{
+	unsigned int result = 0;
+	unsigned char *p = ptr + 511;
+
+	do {
+	        result = (result & 0xff) + (result >> 8);
+        	result = result + *--p;
+	} while (p != ptr);
+
+	return (result & 0xff) != ptr[511];
+}
+
+ 
+extern unsigned int adfs_val (unsigned char *p, int len);
+extern int adfs_dir_read_parent (struct inode *inode, struct buffer_head **bhp);
+extern int adfs_dir_read (struct inode *inode, struct buffer_head **bhp);
+extern int adfs_dir_check (struct inode *inode, struct buffer_head **bhp,
+			   int buffers, union adfs_dirtail *dtp);
+extern void adfs_dir_free (struct buffer_head **bhp, int buffers);
+extern int adfs_dir_get (struct super_block *sb, struct buffer_head **bhp,
+			 int buffers, int pos, unsigned long parent_object_id,
+			 struct adfs_idir_entry *ide);
+extern int adfs_dir_find_entry (struct super_block *sb, struct buffer_head **bhp,
+				int buffers, unsigned int index,
+				struct adfs_idir_entry *ide);
+
+ 
+extern int adfs_inode_validate (struct inode *inode);
+extern unsigned long adfs_inode_generate (unsigned long parent_id, int diridx);
+extern unsigned long adfs_inode_objid (struct inode *inode);
+extern unsigned int adfs_parent_bmap (struct inode *inode, int block);
+extern int adfs_bmap (struct inode *inode, int block);
+extern void adfs_read_inode (struct inode *inode);
+
+ 
+extern int adfs_map_lookup (struct super_block *sb, int frag_id, int offset);
+
+ 
+extern struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry);
+
+ 
+extern int init_adfs_fs (void);
+extern void adfs_error (struct super_block *, const char *, const char *, ...);
+
+ 
+
+
+
+ 
+extern struct inode_operations adfs_dir_inode_operations;
+
+ 
+extern struct inode_operations adfs_file_inode_operations;
+
+
+
+# 10 "/usr/src/linux/include/linux/adfs_fs_sb.h" 2
+
+
+ 
+
+
+struct adfs_sb_info {
+	struct buffer_head *s_sbh;	 
+	struct adfs_discrecord *s_dr;	 
+	uid_t	s_uid;			 
+	gid_t	s_gid;			 
+	int	s_owner_mask;		 
+	int	s_other_mask;		 
+	__u16	s_zone_size;		 
+	__u16	s_ids_per_zone;		 
+	__u32	s_idlen;		 
+	__u32	s_map_size;		 
+	__u32	s_zonesize;		 
+	__u32	s_map_block;		 
+	struct buffer_head **s_map;	 
+	__u32	s_root;			 
+	__s8	s_map2blk;		 
+};
+
+
+# 515 "/usr/src/linux/include/linux/fs.h" 2
+
+# 1 "/usr/src/linux/include/linux/qnx4_fs_sb.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/qnx4_fs.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+struct qnx4_inode_entry {
+	char		di_fname[16 ];
+	qnx4_off_t	di_size;
+	qnx4_xtnt_t	di_first_xtnt;
+	__u32		di_xblk;
+	__s32		di_ftime;
+	__s32		di_mtime;
+	__s32		di_atime;
+	__s32		di_ctime;
+	qnx4_nxtnt_t	di_num_xtnts;
+	qnx4_mode_t	di_mode;
+	qnx4_muid_t	di_uid;
+	qnx4_mgid_t	di_gid;
+	qnx4_nlink_t	di_nlink;
+	__u8		di_zero[4];
+	qnx4_ftype_t	di_type;
+	__u8		di_status;
+};
+
+struct qnx4_link_info {
+	char		dl_fname[48 ];
+	__u32		dl_inode_blk;
+	__u8		dl_inode_ndx;
+	__u8		dl_spare[10];
+	__u8		dl_status;
+};
+
+struct qnx4_xblk {
+	__u32		xblk_next_xblk;
+	__u32		xblk_prev_xblk;
+	__u8		xblk_num_xtnts;
+	__u8		xblk_spare[3];
+	__s32		xblk_num_blocks;
+	qnx4_xtnt_t	xblk_xtnts[60 ];
+	char		xblk_signature[8];
+	qnx4_xtnt_t	xblk_first_xtnt;
+};
+
+struct qnx4_super_block {
+	struct qnx4_inode_entry RootDir;
+	struct qnx4_inode_entry Inode;
+	struct qnx4_inode_entry Boot;
+	struct qnx4_inode_entry AltBoot;
+};
+
+
+
+
+
+
+
+
+
+
+
+extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry);
+extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
+extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
+
+extern struct buffer_head *qnx4_getblk(struct inode *, int, int);
+extern struct buffer_head *qnx4_bread(struct inode *, int, int);
+
+extern int init_qnx4_fs(void);
+extern int qnx4_create(struct inode *dir, struct dentry *dentry, int mode);
+extern struct inode_operations qnx4_file_inode_operations;
+extern struct inode_operations qnx4_dir_inode_operations;
+extern struct inode_operations qnx4_symlink_inode_operations;
+extern int qnx4_is_free(struct super_block *sb, long block);
+extern int qnx4_set_bitmap(struct super_block *sb, long block, int busy);
+extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode);
+extern void qnx4_truncate(struct inode *inode);
+extern void qnx4_free_inode(struct inode *inode);
+extern int qnx4_unlink(struct inode *dir, struct dentry *dentry);
+extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry);
+extern int qnx4_sync_file(struct file *file, struct dentry *dentry);
+extern int qnx4_sync_inode(struct inode *inode);
+extern int qnx4_bmap(struct inode *inode, int iblock);
+
+
+
+
+# 14 "/usr/src/linux/include/linux/qnx4_fs_sb.h" 2
+
+
+ 
+
+
+
+struct qnx4_sb_info {
+	struct buffer_head	*sb_buf;	 
+	struct qnx4_super_block	*sb;		 
+	unsigned int		Version;	 
+	struct qnx4_inode_entry	*BitMap;	 
+};
+
+
+# 516 "/usr/src/linux/include/linux/fs.h" 2
+
+
+extern struct list_head super_blocks;
+
+
+struct super_block {
+	struct list_head	s_list;		 
+	kdev_t			s_dev;
+	unsigned long		s_blocksize;
+	unsigned char		s_blocksize_bits;
+	unsigned char		s_lock;
+	unsigned char		s_rd_only;
+	unsigned char		s_dirt;
+	struct file_system_type	*s_type;
+	struct super_operations	*s_op;
+	struct dquot_operations	*dq_op;
+	unsigned long		s_flags;
+	unsigned long		s_magic;
+	unsigned long		s_time;
+	struct dentry		*s_root;
+	struct wait_queue	*s_wait;
+
+	struct inode		*s_ibasket;
+	short int		s_ibasket_count;
+	short int		s_ibasket_max;
+	struct list_head	s_dirty;	 
+
+	union {
+		struct minix_sb_info	minix_sb;
+		struct ext2_sb_info	ext2_sb;
+		struct hpfs_sb_info	hpfs_sb;
+		struct ntfs_sb_info     ntfs_sb;
+		struct msdos_sb_info	msdos_sb;
+		struct isofs_sb_info	isofs_sb;
+		struct nfs_sb_info	nfs_sb;
+		struct sysv_sb_info	sysv_sb;
+		struct affs_sb_info	affs_sb;
+		struct ufs_sb_info	ufs_sb;
+		struct efs_sb_info	efs_sb;
+		struct romfs_sb_info	romfs_sb;
+		struct smb_sb_info	smbfs_sb;
+		struct hfs_sb_info	hfs_sb;
+		struct adfs_sb_info	adfs_sb;
+		struct qnx4_sb_info	qnx4_sb;	   
+		void			*generic_sbp;
+	} u;
+	 
+
+
+
+	struct semaphore s_vfs_rename_sem;	 
+};
+
+ 
+
+
+extern int vfs_rmdir(struct inode *, struct dentry *);
+extern int vfs_unlink(struct inode *, struct dentry *);
+extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+
+ 
+
+
+
+
+
+typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t);
+	
+struct file_operations {
+	loff_t (*llseek) (struct file *, loff_t, int);
+	ssize_t (*read) (struct file *, char *, size_t, loff_t *);
+	ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
+	int (*readdir) (struct file *, void *, filldir_t);
+	unsigned int (*poll) (struct file *, struct poll_table_struct *);
+	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+	int (*mmap) (struct file *, struct vm_area_struct *);
+	int (*open) (struct inode *, struct file *);
+	int (*flush) (struct file *);
+	int (*release) (struct inode *, struct file *);
+	int (*fsync) (struct file *, struct dentry *);
+	int (*fasync) (int, struct file *, int);
+	int (*check_media_change) (kdev_t dev);
+	int (*revalidate) (kdev_t dev);
+	int (*lock) (struct file *, int, struct file_lock *);
+};
+
+struct inode_operations {
+	struct file_operations * default_file_ops;
+	int (*create) (struct inode *,struct dentry *,int);
+	struct dentry * (*lookup) (struct inode *,struct dentry *);
+	int (*link) (struct dentry *,struct inode *,struct dentry *);
+	int (*unlink) (struct inode *,struct dentry *);
+	int (*symlink) (struct inode *,struct dentry *,const char *);
+	int (*mkdir) (struct inode *,struct dentry *,int);
+	int (*rmdir) (struct inode *,struct dentry *);
+	int (*mknod) (struct inode *,struct dentry *,int,int);
+	int (*rename) (struct inode *, struct dentry *,
+			struct inode *, struct dentry *);
+	int (*readlink) (struct dentry *, char *,int);
+	struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int);
+	int (*readpage) (struct file *, struct page *);
+	int (*writepage) (struct file *, struct page *);
+	int (*bmap) (struct inode *,int);
+	void (*truncate) (struct inode *);
+	int (*permission) (struct inode *, int);
+	int (*smap) (struct inode *,int);
+	int (*updatepage) (struct file *, struct page *, unsigned long, unsigned int, int);
+	int (*revalidate) (struct dentry *);
+};
+
+struct super_operations {
+	void (*read_inode) (struct inode *);
+	void (*write_inode) (struct inode *);
+	void (*put_inode) (struct inode *);
+	void (*delete_inode) (struct inode *);
+	int (*notify_change) (struct dentry *, struct iattr *);
+	void (*put_super) (struct super_block *);
+	void (*write_super) (struct super_block *);
+	int (*statfs) (struct super_block *, struct statfs *, int);
+	int (*remount_fs) (struct super_block *, int *, char *);
+	void (*clear_inode) (struct inode *);
+	void (*umount_begin) (struct super_block *);
+};
+
+struct dquot_operations {
+	void (*initialize) (struct inode *, short);
+	void (*drop) (struct inode *);
+	int (*alloc_block) (const struct inode *, unsigned long, uid_t, char);
+	int (*alloc_inode) (const struct inode *, unsigned long, uid_t);
+	void (*free_block) (const struct inode *, unsigned long);
+	void (*free_inode) (const struct inode *, unsigned long);
+	int (*transfer) (struct dentry *, struct iattr *, uid_t);
+};
+
+struct file_system_type {
+	const char *name;
+	int fs_flags;
+	struct super_block *(*read_super) (struct super_block *, void *, int);
+	struct file_system_type * next;
+};
+
+extern int register_filesystem(struct file_system_type *);
+extern int unregister_filesystem(struct file_system_type *);
+
+ 
+
+ 
+
+
+
+
+
+extern int locks_mandatory_locked(struct inode *inode);
+extern int locks_mandatory_area(int read_write, struct inode *inode,
+				struct file *filp, loff_t offset,
+				size_t count);
+
+extern inline int locks_verify_locked(struct inode *inode)
+{
+	 
+
+
+	if ((((  inode  )->i_sb && (  inode  )->i_sb->s_flags & (  64  )) || (  inode  )->i_flags & (  64  ))   &&
+	    (inode->i_mode & (0002000  | 00010 )) == 0002000 )
+		return (locks_mandatory_locked(inode));
+	return (0);
+}
+
+extern inline int locks_verify_area(int read_write, struct inode *inode,
+				    struct file *filp, loff_t offset,
+				    size_t count)
+{
+	 
+
+
+	if ((((  inode  )->i_sb && (  inode  )->i_sb->s_flags & (  64  )) || (  inode  )->i_flags & (  64  ))   &&
+	    (inode->i_mode & (0002000  | 00010 )) == 0002000 )
+		return (locks_mandatory_area(read_write, inode, filp, offset,
+					     count));
+	return (0);
+}
+
+
+ 
+
+  __attribute__((regparm(0)))  int sys_open(const char *, int, int);
+  __attribute__((regparm(0)))  int sys_close(unsigned int);		 
+extern int do_truncate(struct dentry *, unsigned long);
+extern int get_unused_fd(void);
+extern void put_unused_fd(unsigned int);
+
+extern struct file *filp_open(const char *, int, int);
+extern int filp_close(struct file *, fl_owner_t id);
+
+extern char * getname(const char * filename);
+
+
+
+extern void kill_fasync(struct fasync_struct *fa, int sig);
+extern int register_blkdev(unsigned int, const char *, struct file_operations *);
+extern int unregister_blkdev(unsigned int major, const char * name);
+extern int blkdev_open(struct inode * inode, struct file * filp);
+extern int blkdev_release (struct inode * inode);
+extern struct file_operations def_blk_fops;
+extern struct inode_operations blkdev_inode_operations;
+
+ 
+extern int register_chrdev(unsigned int, const char *, struct file_operations *);
+extern int unregister_chrdev(unsigned int major, const char * name);
+extern int chrdev_open(struct inode * inode, struct file * filp);
+extern struct file_operations def_chr_fops;
+extern struct inode_operations chrdev_inode_operations;
+extern char * bdevname(kdev_t dev);
+extern char * cdevname(kdev_t dev);
+extern char * kdevname(kdev_t dev);
+
+
+extern void init_fifo(struct inode * inode);
+extern struct inode_operations fifo_inode_operations;
+
+ 
+extern void make_bad_inode(struct inode * inode);
+extern int is_bad_inode(struct inode * inode);
+
+extern struct file_operations connecting_fifo_fops;
+extern struct file_operations read_fifo_fops;
+extern struct file_operations write_fifo_fops;
+extern struct file_operations rdwr_fifo_fops;
+extern struct file_operations read_pipe_fops;
+extern struct file_operations write_pipe_fops;
+extern struct file_operations rdwr_pipe_fops;
+
+extern struct file_system_type *get_fs_type(const char *name);
+
+extern int fs_may_remount_ro(struct super_block *);
+extern int fs_may_mount(kdev_t dev);
+
+extern struct file *inuse_filps;
+
+extern void refile_buffer(struct buffer_head * buf);
+extern void set_writetime(struct buffer_head * buf, int flag);
+extern int try_to_free_buffers(struct page *, int wait);
+
+extern int nr_buffers;
+extern long buffermem;
+extern int nr_buffer_heads;
+
+
+
+
+
+
+void mark_buffer_uptodate(struct buffer_head * bh, int on);
+
+extern inline void mark_buffer_clean(struct buffer_head * bh)
+{
+	if (test_and_clear_bit(1 , &bh->b_state)) {
+		if (bh->b_list == 2 )
+			refile_buffer(bh);
+	}
+}
+
+extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag)
+{
+	if (!test_and_set_bit(1 , &bh->b_state)) {
+		set_writetime(bh, flag);
+		if (bh->b_list != 2 )
+			refile_buffer(bh);
+	}
+}
+
+extern int check_disk_change(kdev_t dev);
+extern int invalidate_inodes(struct super_block * sb);
+extern void invalidate_inode_pages(struct inode *);
+
+
+extern void __invalidate_buffers(kdev_t dev, int);
+extern int floppy_is_wp(int minor);
+extern void sync_inodes(kdev_t dev);
+extern void write_inode_now(struct inode *inode);
+extern void sync_dev(kdev_t dev);
+extern int fsync_dev(kdev_t dev);
+extern void sync_supers(kdev_t dev);
+extern int bmap(struct inode * inode,int block);
+extern int notify_change(struct dentry *, struct iattr *);
+extern int permission(struct inode * inode,int mask);
+extern int get_write_access(struct inode *inode);
+extern void put_write_access(struct inode *inode);
+extern struct dentry * open_namei(const char * pathname, int flag, int mode);
+extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev);
+extern int do_pipe(int *);
+
+ 
+extern int is_subdir(struct dentry *, struct dentry *);
+extern ino_t find_inode_number(struct dentry *, struct qstr *);
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int);
+extern struct dentry * __namei(const char *, unsigned int);
+
+
+
+
+extern void iput(struct inode *);
+extern struct inode * igrab(struct inode *inode);
+extern ino_t iunique(struct super_block *, ino_t);
+extern struct inode * iget(struct super_block *, unsigned long);
+extern struct inode * iget_in_use (struct super_block *, unsigned long);
+extern void clear_inode(struct inode *);
+extern struct inode * get_empty_inode(void);
+
+extern void insert_inode_hash(struct inode *);
+extern void remove_inode_hash(struct inode *);
+extern struct file * get_empty_filp(void);
+extern struct buffer_head * get_hash_table(kdev_t, int, int);
+extern struct buffer_head * getblk(kdev_t, int, int);
+extern struct buffer_head * find_buffer(kdev_t dev, int block, int size);
+extern void ll_rw_block(int, int, struct buffer_head * bh[]);
+extern int is_read_only(kdev_t);
+extern void __brelse(struct buffer_head *);
+extern inline void brelse(struct buffer_head *buf)
+{
+	if (buf)
+		__brelse(buf);
+}
+extern void __bforget(struct buffer_head *buf);
+extern inline void bforget(struct buffer_head *buf)
+{
+	if (buf)
+		__bforget(buf);
+}
+extern void set_blocksize(kdev_t dev, int size);
+extern unsigned int get_hardblocksize(kdev_t dev);
+extern struct buffer_head * bread(kdev_t dev, int block, int size);
+extern struct buffer_head * breada(kdev_t dev,int block, int size, 
+				   unsigned int pos, unsigned int filesize);
+
+extern int brw_page(int, struct page *, kdev_t, int [], int, int);
+
+extern int generic_readpage(struct file *, struct page *);
+extern int generic_file_mmap(struct file *, struct vm_area_struct *);
+extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t generic_file_write(struct file *, const char*, size_t, loff_t*);
+
+extern struct super_block *get_super(kdev_t dev);
+extern void put_super(kdev_t dev);
+unsigned long generate_cluster(kdev_t dev, int b[], int size);
+unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size);
+extern kdev_t ROOT_DEV;
+
+extern void show_buffers(void);
+extern void mount_root(void);
+
+
+
+
+
+
+extern ssize_t char_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t block_read(struct file *, char *, size_t, loff_t *);
+extern int read_ahead[];
+
+extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
+extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
+
+extern int block_fsync(struct file *, struct dentry *dir);
+extern int file_fsync(struct file *, struct dentry *dir);
+
+extern int inode_change_ok(struct inode *, struct iattr *);
+extern void inode_setattr(struct inode *, struct iattr *);
+
+extern __u32 inode_generation_count;
+
+
+
+
+# 20 "/usr/src/linux/include/linux/tty.h" 2
+
+# 1 "/usr/src/linux/include/linux/major.h" 1
+
+
+
+ 
+
+
+
+
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+  
+
+
+
+
+static __inline__ int scsi_blk_major(int m) {
+	return (((  m  ) == 8  || ((  m  ) >= 65  && (  m  ) <= 71 )) 	|| ( m ) == 11 ) ;
+}
+
+
+# 21 "/usr/src/linux/include/linux/tty.h" 2
+
+# 1 "/usr/src/linux/include/linux/termios.h" 1
+
+
+
+
+# 1 "/usr/src/linux/include/asm/termios.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/termbits.h" 1
+
+
+
+
+
+typedef unsigned char	cc_t;
+typedef unsigned int	speed_t;
+typedef unsigned int	tcflag_t;
+
+
+struct termios {
+	tcflag_t c_iflag;		 
+	tcflag_t c_oflag;		 
+	tcflag_t c_cflag;		 
+	tcflag_t c_lflag;		 
+	cc_t c_line;			 
+	cc_t c_cc[19 ];		 
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+# 4 "/usr/src/linux/include/asm/termios.h" 2
+
+# 1 "/usr/src/linux/include/asm/ioctls.h" 1
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+# 5 "/usr/src/linux/include/asm/termios.h" 2
+
+
+struct winsize {
+	unsigned short ws_row;
+	unsigned short ws_col;
+	unsigned short ws_xpixel;
+	unsigned short ws_ypixel;
+};
+
+
+struct termio {
+	unsigned short c_iflag;		 
+	unsigned short c_oflag;		 
+	unsigned short c_cflag;		 
+	unsigned short c_lflag;		 
+	unsigned char c_line;		 
+	unsigned char c_cc[8 ];	 
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+# 97 "/usr/src/linux/include/asm/termios.h"
+
+
+
+
+
+
+
+# 5 "/usr/src/linux/include/linux/termios.h" 2
+
+
+
+# 22 "/usr/src/linux/include/linux/tty.h" 2
+
+# 1 "/usr/src/linux/include/linux/tqueue.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct tq_struct {
+	struct tq_struct *next;		 
+	unsigned long sync;		 
+	void (*routine)(void *);	 
+	void *data;			 
+};
+
+typedef struct tq_struct * task_queue;
+
+
+
+extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk;
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern spinlock_t tqueue_lock;
+
+ 
+
+
+extern __inline__ void queue_task(struct tq_struct *bh_pointer,
+			   task_queue *bh_list)
+{
+	if (!test_and_set_bit(0,&bh_pointer->sync)) {
+		unsigned long flags;
+		do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+		bh_pointer->next = *bh_list;
+		*bh_list = bh_pointer;
+		__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+	}
+}
+
+ 
+
+
+extern __inline__ void run_task_queue(task_queue *list)
+{
+	if (*list) {
+		unsigned long flags;
+		struct tq_struct *p;
+
+		do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+		p = *list;
+		*list = ((void *)0) ;
+		__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+		
+		while (p) {
+			void *arg;
+			void (*f) (void *);
+			struct tq_struct *save_p;
+			arg    = p -> data;
+			f      = p -> routine;
+			save_p = p;
+			p      = p -> next;
+			__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") ;
+			save_p -> sync = 0;
+			(*f)(arg);
+		}
+	}
+}
+
+
+# 23 "/usr/src/linux/include/linux/tty.h" 2
+
+# 1 "/usr/src/linux/include/linux/tty_driver.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct tty_driver {
+	int	magic;		 
+	const char	*driver_name;
+	const char	*name;
+	int	name_base;	 
+	short	major;		 
+	short	minor_start;	 
+	short	num;		 
+	short	type;		 
+	short	subtype;	 
+	struct termios init_termios;  
+	int	flags;		 
+	int	*refcount;	 
+	struct proc_dir_entry *proc_entry;  
+	struct tty_driver *other;  
+
+	 
+
+
+	struct tty_struct **table;
+	struct termios **termios;
+	struct termios **termios_locked;
+	void *driver_state;	 
+	
+	 
+
+
+
+	int  (*open)(struct tty_struct * tty, struct file * filp);
+	void (*close)(struct tty_struct * tty, struct file * filp);
+	int  (*write)(struct tty_struct * tty, int from_user,
+		      const unsigned char *buf, int count);
+	void (*put_char)(struct tty_struct *tty, unsigned char ch);
+	void (*flush_chars)(struct tty_struct *tty);
+	int  (*write_room)(struct tty_struct *tty);
+	int  (*chars_in_buffer)(struct tty_struct *tty);
+	int  (*ioctl)(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg);
+	void (*set_termios)(struct tty_struct *tty, struct termios * old);
+	void (*throttle)(struct tty_struct * tty);
+	void (*unthrottle)(struct tty_struct * tty);
+	void (*stop)(struct tty_struct *tty);
+	void (*start)(struct tty_struct *tty);
+	void (*hangup)(struct tty_struct *tty);
+	void (*break_ctl)(struct tty_struct *tty, int state);
+	void (*flush_buffer)(struct tty_struct *tty);
+	void (*set_ldisc)(struct tty_struct *tty);
+	void (*wait_until_sent)(struct tty_struct *tty, int timeout);
+	void (*send_xchar)(struct tty_struct *tty, char ch);
+	int (*read_proc)(char *page, char **start, off_t off,
+			  int count, int *eof, void *data);
+	int (*write_proc)(struct file *file, const char *buffer,
+			  unsigned long count, void *data);
+
+	 
+
+
+	struct tty_driver *next;
+	struct tty_driver *prev;
+};
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+# 24 "/usr/src/linux/include/linux/tty.h" 2
+
+# 1 "/usr/src/linux/include/linux/tty_ldisc.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct tty_ldisc {
+	int	magic;
+	char	*name;
+	int	num;
+	int	flags;
+	 
+
+
+	int	(*open)(struct tty_struct *);
+	void	(*close)(struct tty_struct *);
+	void	(*flush_buffer)(struct tty_struct *tty);
+	ssize_t	(*chars_in_buffer)(struct tty_struct *tty);
+	ssize_t	(*read)(struct tty_struct * tty, struct file * file,
+			unsigned char * buf, size_t nr);
+	ssize_t	(*write)(struct tty_struct * tty, struct file * file,
+			 const unsigned char * buf, size_t nr);	
+	int	(*ioctl)(struct tty_struct * tty, struct file * file,
+			 unsigned int cmd, unsigned long arg);
+	void	(*set_termios)(struct tty_struct *tty, struct termios * old);
+	unsigned int (*poll)(struct tty_struct *, struct file *,
+			     struct poll_table_struct *);
+	
+	 
+
+
+	void	(*receive_buf)(struct tty_struct *, const unsigned char *cp,
+			       char *fp, int count);
+	int	(*receive_room)(struct tty_struct *);
+	void	(*write_wakeup)(struct tty_struct *);
+};
+
+
+
+
+
+
+# 25 "/usr/src/linux/include/linux/tty.h" 2
+
+# 1 "/usr/src/linux/include/linux/serialP.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+struct async_icount {
+	__u32	cts, dsr, rng, dcd, tx, rx;
+	__u32	frame, parity, overrun, brk;
+	__u32	buf_overrun;
+};
+
+struct serial_state {
+	int	magic;
+	int	baud_base;
+	int	port;
+	int	irq;
+	int	flags;
+	int	hub6;
+	int	type;
+	int	line;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	count;
+	unsigned short	close_delay;
+	unsigned short	closing_wait;  
+	struct async_icount	icount;	
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+	struct async_struct *info;
+};
+
+struct async_struct {
+	int			magic;
+	int			port;
+	int			hub6;
+	int			flags;
+	int			xmit_fifo_size;
+	struct serial_state	*state;
+	struct tty_struct 	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			quot;
+	int			x_char;	 
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	int			IER; 	 
+	int			MCR; 	 
+	unsigned long		event;
+	unsigned long		last_active;
+	int			line;
+	int			blocked_open;  
+	long			session;  
+	long			pgrp;  
+	unsigned char 		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct tq_struct	tqueue;
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+	struct wait_queue	*delta_msr_wait;
+	struct async_struct	*next_port;  
+	struct async_struct	*prev_port;
+};
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+struct rs_multiport_struct {
+	int		port1;
+	unsigned char	mask1, match1;
+	int		port2;
+	unsigned char	mask2, match2;
+	int		port3;
+	unsigned char	mask3, match3;
+	int		port4;
+	unsigned char	mask4, match4;
+	int		port_monitor;
+};
+
+
+# 26 "/usr/src/linux/include/linux/tty.h" 2
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+struct screen_info {
+	unsigned char  orig_x;			 
+	unsigned char  orig_y;			 
+	unsigned short dontuse1;		 
+	unsigned short orig_video_page;		 
+	unsigned char  orig_video_mode;		 
+	unsigned char  orig_video_cols;		 
+	unsigned short unused2;			 
+	unsigned short orig_video_ega_bx;	 
+	unsigned short unused3;			 
+	unsigned char  orig_video_lines;	 
+	unsigned char  orig_video_isVGA;	 
+	unsigned short orig_video_points;	 
+
+	 
+	unsigned short lfb_width;		 
+	unsigned short lfb_height;		 
+	unsigned short lfb_depth;		 
+	unsigned long  lfb_base;		 
+	unsigned long  lfb_size;		 
+	unsigned short dontuse2, dontuse3;	 
+	unsigned short lfb_linelength;		 
+	unsigned char  red_size;		 
+	unsigned char  red_pos;			 
+	unsigned char  green_size;		 
+	unsigned char  green_pos;		 
+	unsigned char  blue_size;		 
+	unsigned char  blue_pos;		 
+	unsigned char  rsvd_size;		 
+	unsigned char  rsvd_pos;		 
+	unsigned short vesapm_seg;		 
+	unsigned short vesapm_off;		 
+	unsigned short pages;			 
+						 
+};
+
+extern struct screen_info screen_info;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+struct tty_flip_buffer {
+	struct tq_struct tqueue;
+	struct semaphore pty_sem;
+	char		*char_buf_ptr;
+	unsigned char	*flag_buf_ptr;
+	int		count;
+	int		buf_num;
+	unsigned char	char_buf[2* 512 ];
+	char		flag_buf[2* 512 ];
+	unsigned char	slop[4];  
+};
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct tty_struct {
+	int	magic;
+	struct tty_driver driver;
+	struct tty_ldisc ldisc;
+	struct termios *termios, *termios_locked;
+	int pgrp;
+	int session;
+	kdev_t	device;
+	unsigned long flags;
+	int count;
+	struct winsize winsize;
+	unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
+	unsigned char low_latency:1, warned:1;
+	unsigned char ctrl_status;
+
+	struct tty_struct *link;
+	struct fasync_struct *fasync;
+	struct tty_flip_buffer flip;
+	int max_flip_cnt;
+	int alt_speed;		 
+	struct wait_queue *write_wait;
+	struct wait_queue *read_wait;
+	struct wait_queue *poll_wait;
+	struct tq_struct tq_hangup;
+	void *disc_data;
+	void *driver_data;
+
+
+	
+	 
+
+
+
+	unsigned int column;
+	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+	unsigned char closing:1;
+	unsigned short minimum_to_wake;
+	unsigned overrun_time;
+	int num_overrun;
+	unsigned long process_char_map[256/(8*sizeof(unsigned long))];
+	char *read_buf;
+	int read_head;
+	int read_tail;
+	int read_cnt;
+	unsigned long read_flags[4096 /(8*sizeof(unsigned long))];
+	int canon_data;
+	unsigned long canon_head;
+	unsigned int canon_column;
+	struct semaphore atomic_read;
+	struct semaphore atomic_write;
+	spinlock_t read_lock;
+};
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern void tty_write_flush(struct tty_struct *);
+
+extern struct termios tty_std_termios;
+extern struct tty_struct * redirect;
+extern struct tty_ldisc ldiscs[];
+extern int fg_console, last_console, want_console;
+
+extern int kmsg_redirect;
+
+extern unsigned long con_init(unsigned long);
+
+extern int rs_init(void);
+extern int lp_init(void);
+extern int pty_init(void);
+extern int tty_init(void);
+extern int mxser_init(void);
+extern int moxa_init(void);
+extern int ip2_init(void);
+extern int pcxe_init(void);
+extern int pc_init(void);
+extern int vcs_init(void);
+extern int rp_init(void);
+extern int cy_init(void);
+extern int stl_init(void);
+extern int stli_init(void);
+extern int riscom8_init(void);
+extern int specialix_init(void);
+extern int espserial_init(void);
+extern int macserial_init(void);
+
+extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
+			      const char *routine);
+extern char *tty_name(struct tty_struct *tty, char *buf);
+extern void tty_wait_until_sent(struct tty_struct * tty, long timeout);
+extern int tty_check_change(struct tty_struct * tty);
+extern void stop_tty(struct tty_struct * tty);
+extern void start_tty(struct tty_struct * tty);
+extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
+extern int tty_register_driver(struct tty_driver *driver);
+extern int tty_unregister_driver(struct tty_driver *driver);
+extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
+			     int buflen);
+extern void tty_write_message(struct tty_struct *tty, char *msg);
+
+extern int is_orphaned_pgrp(int pgrp);
+extern int is_ignored(int sig);
+extern int tty_signal(int sig, struct tty_struct *tty);
+extern void tty_hangup(struct tty_struct * tty);
+extern void tty_vhangup(struct tty_struct * tty);
+extern void tty_unhangup(struct file *filp);
+extern int tty_hung_up_p(struct file * filp);
+extern void do_SAK(struct tty_struct *tty);
+extern void disassociate_ctty(int priv);
+extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern int tty_get_baud_rate(struct tty_struct *tty);
+
+ 
+extern struct tty_ldisc tty_ldisc_N_TTY;
+
+ 
+extern int n_tty_ioctl(struct tty_struct * tty, struct file * file,
+		       unsigned int cmd, unsigned long arg);
+
+ 
+
+extern long serial_console_init(long kmem_start, long kmem_end);
+ 
+ 
+
+extern int pcxe_open(struct tty_struct *tty, struct file *filp);
+
+ 
+
+extern void console_print(const char *);
+
+ 
+
+extern int vt_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg);
+
+
+
+# 21 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/sem.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/ipc.h" 1
+
+
+
+
+
+
+
+struct ipc_perm
+{
+	__kernel_key_t	key;
+	__kernel_uid_t	uid;
+	__kernel_gid_t	gid;
+	__kernel_uid_t	cuid;
+	__kernel_gid_t	cgid;
+	__kernel_mode_t	mode; 
+	unsigned short	seq;
+};
+
+ 
+
+
+
+
+ 
+
+   
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+# 4 "/usr/src/linux/include/linux/sem.h" 2
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+ 
+struct semid_ds {
+	struct ipc_perm	sem_perm;		 
+	__kernel_time_t	sem_otime;		 
+	__kernel_time_t	sem_ctime;		 
+	struct sem	*sem_base;		 
+	struct sem_queue *sem_pending;		 
+	struct sem_queue **sem_pending_last;	 
+	struct sem_undo	*undo;			 
+	unsigned short	sem_nsems;		 
+};
+
+ 
+struct sembuf {
+	unsigned short  sem_num;	 
+	short		sem_op;		 
+	short		sem_flg;	 
+};
+
+ 
+union semun {
+	int val;			 
+	struct semid_ds *buf;		 
+	unsigned short *array;		 
+	struct seminfo *__buf;		 
+	void *__pad;
+};
+
+struct  seminfo {
+	int semmap;
+	int semmni;
+	int semmns;
+	int semmnu;
+	int semmsl;
+	int semopm;
+	int semume;
+	int semusz;
+	int semvmx;
+	int semaem;
+};
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+struct sem {
+	int	semval;		 
+	int	sempid;		 
+};
+
+ 
+struct sem_queue {
+	struct sem_queue *	next;	  
+	struct sem_queue **	prev;	  
+	struct wait_queue *	sleeper;  
+	struct sem_undo *	undo;	  
+	int    			pid;	  
+	int    			status;	  
+	struct semid_ds *	sma;	  
+	struct sembuf *		sops;	  
+	int			nsops;	  
+	int			alter;	  
+};
+
+ 
+
+
+struct sem_undo {
+	struct sem_undo *	proc_next;	 
+	struct sem_undo *	id_next;	 
+	int			semid;		 
+	short *			semadj;		 
+};
+
+  __attribute__((regparm(0)))  int sys_semget (key_t key, int nsems, int semflg);
+  __attribute__((regparm(0)))  int sys_semop (int semid, struct sembuf *sops, unsigned nsops);
+  __attribute__((regparm(0)))  int sys_semctl (int semid, int semnum, int cmd, union semun arg);
+
+
+
+
+# 22 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/signal.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/signal.h" 1
+
+
+
+
+
+ 
+struct siginfo;
+
+
+ 
+
+
+
+
+
+
+typedef unsigned long old_sigset_t;		 
+
+typedef struct {
+	unsigned long sig[(64  / 32 ) ];
+} sigset_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+typedef void (*__sighandler_t)(int);
+
+
+
+
+
+
+struct old_sigaction {
+	__sighandler_t sa_handler;
+	old_sigset_t sa_mask;
+	unsigned long sa_flags;
+	void (*sa_restorer)(void);
+};
+
+struct sigaction {
+	__sighandler_t sa_handler;
+	unsigned long sa_flags;
+	void (*sa_restorer)(void);
+	sigset_t sa_mask;		 
+};
+
+struct k_sigaction {
+	struct sigaction sa;
+};
+# 168 "/usr/src/linux/include/asm/signal.h"
+
+
+typedef struct sigaltstack {
+	void *ss_sp;
+	int ss_flags;
+	size_t ss_size;
+} stack_t;
+
+
+# 1 "/usr/src/linux/include/asm/sigcontext.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+struct _fpreg {
+	unsigned short significand[4];
+	unsigned short exponent;
+};
+
+struct _fpstate {
+	unsigned long 	cw,
+			sw,
+			tag,
+			ipoff,
+			cssel,
+			dataoff,
+			datasel;
+	struct _fpreg	_st[8];
+	unsigned long	status;
+};
+
+struct sigcontext {
+	unsigned short gs, __gsh;
+	unsigned short fs, __fsh;
+	unsigned short es, __esh;
+	unsigned short ds, __dsh;
+	unsigned long edi;
+	unsigned long esi;
+	unsigned long ebp;
+	unsigned long esp;
+	unsigned long ebx;
+	unsigned long edx;
+	unsigned long ecx;
+	unsigned long eax;
+	unsigned long trapno;
+	unsigned long err;
+	unsigned long eip;
+	unsigned short cs, __csh;
+	unsigned long eflags;
+	unsigned long esp_at_signal;
+	unsigned short ss, __ssh;
+	struct _fpstate * fpstate;
+	unsigned long oldmask;
+	unsigned long cr2;
+};
+
+
+
+# 177 "/usr/src/linux/include/asm/signal.h" 2
+
+
+
+
+extern __inline__ void sigaddset(sigset_t *set, int _sig)
+{
+	__asm__("btsl %1,%0" : "=m"(*set) : "ir"(_sig - 1) : "cc");
+}
+
+extern __inline__ void sigdelset(sigset_t *set, int _sig)
+{
+	__asm__("btrl %1,%0" : "=m"(*set) : "ir"(_sig - 1) : "cc");
+}
+
+extern __inline__ int __const_sigismember(sigset_t *set, int _sig)
+{
+	unsigned long sig = _sig - 1;
+	return 1 & (set->sig[sig / 32 ] >> (sig % 32 ));
+}
+
+extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
+{
+	int ret;
+	__asm__("btl %2,%1\n\tsbbl %0,%0"
+		: "=r"(ret) : "m"(*set), "ir"(_sig-1) : "cc");
+	return ret;
+}
+
+
+
+
+
+
+
+
+extern __inline__ int sigfindinword(unsigned long word)
+{
+	__asm__("bsfl %1,%0" : "=r"(word) : "rm"(word) : "cc");
+	return word;
+}
+
+
+
+
+# 4 "/usr/src/linux/include/linux/signal.h" 2
+
+# 1 "/usr/src/linux/include/asm/siginfo.h" 1
+
+
+
+
+
+ 
+
+typedef union sigval {
+	int sival_int;
+	void *sival_ptr;
+} sigval_t;
+
+
+
+
+typedef struct siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[((128 /sizeof(int)) - 3) ];
+
+		 
+		struct {
+			pid_t _pid;		 
+			uid_t _uid;		 
+		} _kill;
+
+		 
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		 
+		struct {
+			pid_t _pid;		 
+			uid_t _uid;		 
+			sigval_t _sigval;
+		} _rt;
+
+		 
+		struct {
+			pid_t _pid;		 
+			uid_t _uid;		 
+			int _status;		 
+			clock_t _utime;
+			clock_t _stime;
+		} _sigchld;
+
+		 
+		struct {
+			void *_addr;  
+		} _sigfault;
+
+		 
+		struct {
+			int _band;	 
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t;
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct sigevent {
+	sigval_t sigev_value;
+	int sigev_signo;
+	int sigev_notify;
+	union {
+		int _pad[((64 /sizeof(int)) - 3) ];
+
+		struct {
+			void (*_function)(sigval_t);
+			void *_attribute;	 
+		} _sigev_thread;
+	} _sigev_un;
+} sigevent_t;
+
+
+
+
+
+# 5 "/usr/src/linux/include/linux/signal.h" 2
+
+
+
+ 
+
+
+
+struct signal_queue
+{
+	struct signal_queue *next;
+	siginfo_t info;
+};
+
+ 
+
+
+
+# 61 "/usr/src/linux/include/linux/signal.h"
+
+
+
+# 1 "/usr/src/linux/include/linux/string.h" 1
+
+
+
+
+
+
+
+
+
+
+extern char * ___strtok;
+extern char * strcpy(char *,const char *);
+extern char * strncpy(char *,const char *, __kernel_size_t);
+extern char * strcat(char *, const char *);
+extern char * strncat(char *, const char *, __kernel_size_t);
+extern char * strchr(const char *,int);
+extern char * strrchr(const char *,int);
+extern char * strpbrk(const char *,const char *);
+extern char * strtok(char *,const char *);
+extern char * strstr(const char *,const char *);
+extern __kernel_size_t strlen(const char *);
+extern __kernel_size_t strnlen(const char *,__kernel_size_t);
+extern __kernel_size_t strspn(const char *,const char *);
+extern int strcmp(const char *,const char *);
+extern int strncmp(const char *,const char *,__kernel_size_t);
+extern int strnicmp(const char *, const char *, __kernel_size_t);
+
+extern void * memset(void *,int,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memmove(void *,const void *,__kernel_size_t);
+extern void * memscan(void *,int,__kernel_size_t);
+extern int memcmp(const void *,const void *,__kernel_size_t);
+
+ 
+
+
+# 1 "/usr/src/linux/include/asm/string.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern inline char * strcpy(char * dest,const char *src)
+{
+int d0, d1, d2;
+__asm__ __volatile__(
+	"cld\n"
+	"1:\tlodsb\n\t"
+	"stosb\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b"
+	: "=&S" (d0), "=&D" (d1), "=&a" (d2)
+	:"0" (src),"1" (dest) : "memory");
+return dest;
+}
+
+
+extern inline char * strncpy(char * dest,const char *src,size_t count)
+{
+int d0, d1, d2, d3;
+__asm__ __volatile__(
+	"cld\n"
+	"1:\tdecl %2\n\t"
+	"js 2f\n\t"
+	"lodsb\n\t"
+	"stosb\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n\t"
+	"rep\n\t"
+	"stosb\n"
+	"2:"
+	: "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
+	:"0" (src),"1" (dest),"2" (count) : "memory");
+return dest;
+}
+
+
+extern inline char * strcat(char * dest,const char * src)
+{
+int d0, d1, d2, d3;
+__asm__ __volatile__(
+	"cld\n\t"
+	"repne\n\t"
+	"scasb\n\t"
+	"decl %1\n"
+	"1:\tlodsb\n\t"
+	"stosb\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b"
+	: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+	: "0" (src), "1" (dest), "2" (0), "3" (0xffffffff):"memory");
+return dest;
+}
+
+
+extern inline char * strncat(char * dest,const char * src,size_t count)
+{
+int d0, d1, d2, d3;
+__asm__ __volatile__(
+	"cld\n\t"
+	"repne\n\t"
+	"scasb\n\t"
+	"decl %1\n\t"
+	"movl %8,%3\n"
+	"1:\tdecl %3\n\t"
+	"js 2f\n\t"
+	"lodsb\n\t"
+	"stosb\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n"
+	"2:\txorl %2,%2\n\t"
+	"stosb"
+	: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+	: "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count)
+	: "memory");
+return dest;
+}
+
+
+extern inline int strcmp(const char * cs,const char * ct)
+{
+int d0, d1;
+register int __res;
+__asm__ __volatile__(
+	"cld\n"
+	"1:\tlodsb\n\t"
+	"scasb\n\t"
+	"jne 2f\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n\t"
+	"xorl %%eax,%%eax\n\t"
+	"jmp 3f\n"
+	"2:\tsbbl %%eax,%%eax\n\t"
+	"orb $1,%%al\n"
+	"3:"
+	:"=a" (__res), "=&S" (d0), "=&D" (d1)
+		     :"1" (cs),"2" (ct));
+return __res;
+}
+
+
+extern inline int strncmp(const char * cs,const char * ct,size_t count)
+{
+register int __res;
+int d0, d1, d2;
+__asm__ __volatile__(
+	"cld\n"
+	"1:\tdecl %3\n\t"
+	"js 2f\n\t"
+	"lodsb\n\t"
+	"scasb\n\t"
+	"jne 3f\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n"
+	"2:\txorl %%eax,%%eax\n\t"
+	"jmp 4f\n"
+	"3:\tsbbl %%eax,%%eax\n\t"
+	"orb $1,%%al\n"
+	"4:"
+		     :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+		     :"1" (cs),"2" (ct),"3" (count));
+return __res;
+}
+
+
+extern inline char * strchr(const char * s, int c)
+{
+int d0;
+register char * __res;
+__asm__ __volatile__(
+	"cld\n\t"
+	"movb %%al,%%ah\n"
+	"1:\tlodsb\n\t"
+	"cmpb %%ah,%%al\n\t"
+	"je 2f\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n\t"
+	"movl $1,%1\n"
+	"2:\tmovl %1,%0\n\t"
+	"decl %0"
+	:"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
+return __res;
+}
+
+
+extern inline char * strrchr(const char * s, int c)
+{
+int d0, d1;
+register char * __res;
+__asm__ __volatile__(
+	"cld\n\t"
+	"movb %%al,%%ah\n"
+	"1:\tlodsb\n\t"
+	"cmpb %%ah,%%al\n\t"
+	"jne 2f\n\t"
+	"leal -1(%%esi),%0\n"
+	"2:\ttestb %%al,%%al\n\t"
+	"jne 1b"
+	:"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
+return __res;
+}
+
+
+extern inline size_t strlen(const char * s)
+{
+int d0;
+register int __res;
+__asm__ __volatile__(
+	"cld\n\t"
+	"repne\n\t"
+	"scasb\n\t"
+	"notl %0\n\t"
+	"decl %0"
+	:"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
+return __res;
+}
+
+extern inline void * __memcpy(void * to, const void * from, size_t n)
+{
+int d0, d1, d2;
+__asm__ __volatile__(
+	"cld\n\t"
+	"rep ; movsl\n\t"
+	"testb $2,%b4\n\t"
+	"je 1f\n\t"
+	"movsw\n"
+	"1:\ttestb $1,%b4\n\t"
+	"je 2f\n\t"
+	"movsb\n"
+	"2:"
+	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
+	:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
+	: "memory");
+return (to);
+}
+
+ 
+
+
+
+extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
+{
+	switch (n) {
+		case 0:
+			return to;
+		case 1:
+			*(unsigned char *)to = *(const unsigned char *)from;
+			return to;
+		case 2:
+			*(unsigned short *)to = *(const unsigned short *)from;
+			return to;
+		case 3:
+			*(unsigned short *)to = *(const unsigned short *)from;
+			*(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
+			return to;
+		case 4:
+			*(unsigned long *)to = *(const unsigned long *)from;
+			return to;
+		case 6:	 
+			*(unsigned long *)to = *(const unsigned long *)from;
+			*(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
+			return to;
+		case 8:
+			*(unsigned long *)to = *(const unsigned long *)from;
+			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
+			return to;
+		case 12:
+			*(unsigned long *)to = *(const unsigned long *)from;
+			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
+			*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
+			return to;
+		case 16:
+			*(unsigned long *)to = *(const unsigned long *)from;
+			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
+			*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
+			*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
+			return to;
+		case 20:
+			*(unsigned long *)to = *(const unsigned long *)from;
+			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
+			*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
+			*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
+			*(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
+			return to;
+	}
+
+
+
+
+
+
+
+
+{
+	int d0, d1, d2;
+	switch (n % 4) {
+		case 0: __asm__ __volatile__( "cld\n\t" "rep ; movsl"  ""  : "=&c" (d0), "=&D" (d1), "=&S" (d2) : "0" (n/4),"1" ((long) to),"2" ((long) from) : "memory"); ; return to;
+		case 1: __asm__ __volatile__( "cld\n\t" "rep ; movsl"  "\n\tmovsb"  : "=&c" (d0), "=&D" (d1), "=&S" (d2) : "0" (n/4),"1" ((long) to),"2" ((long) from) : "memory"); ; return to;
+		case 2: __asm__ __volatile__( "cld\n\t" "rep ; movsl"  "\n\tmovsw"  : "=&c" (d0), "=&D" (d1), "=&S" (d2) : "0" (n/4),"1" ((long) to),"2" ((long) from) : "memory"); ; return to;
+		default: __asm__ __volatile__( "cld\n\t" "rep ; movsl"  "\n\tmovsw\n\tmovsb"  : "=&c" (d0), "=&D" (d1), "=&S" (d2) : "0" (n/4),"1" ((long) to),"2" ((long) from) : "memory"); ; return to;
+	}
+}
+  
+
+}
+
+
+
+
+
+
+
+
+extern inline void * memmove(void * dest,const void * src, size_t n)
+{
+int d0, d1, d2;
+if (dest<src)
+__asm__ __volatile__(
+	"cld\n\t"
+	"rep\n\t"
+	"movsb"
+	: "=&c" (d0), "=&S" (d1), "=&D" (d2)
+	:"0" (n),"1" (src),"2" (dest)
+	: "memory");
+else
+__asm__ __volatile__(
+	"std\n\t"
+	"rep\n\t"
+	"movsb\n\t"
+	"cld"
+	: "=&c" (d0), "=&S" (d1), "=&D" (d2)
+	:"0" (n),
+	 "1" (n-1+(const char *)src),
+	 "2" (n-1+(char *)dest)
+	:"memory");
+return dest;
+}
+
+
+
+
+extern inline void * memchr(const void * cs,int c,size_t count)
+{
+int d0;
+register void * __res;
+if (!count)
+	return ((void *)0) ;
+__asm__ __volatile__(
+	"cld\n\t"
+	"repne\n\t"
+	"scasb\n\t"
+	"je 1f\n\t"
+	"movl $1,%0\n"
+	"1:\tdecl %0"
+	:"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
+return __res;
+}
+
+extern inline void * __memset_generic(void * s, char c,size_t count)
+{
+int d0, d1;
+__asm__ __volatile__(
+	"cld\n\t"
+	"rep\n\t"
+	"stosb"
+	: "=&c" (d0), "=&D" (d1)
+	:"a" (c),"1" (s),"0" (count)
+	:"memory");
+return s;
+}
+
+ 
+
+
+ 
+
+
+
+
+extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
+{
+int d0, d1;
+__asm__ __volatile__(
+	"cld\n\t"
+	"rep ; stosl\n\t"
+	"testb $2,%b3\n\t"
+	"je 1f\n\t"
+	"stosw\n"
+	"1:\ttestb $1,%b3\n\t"
+	"je 2f\n\t"
+	"stosb\n"
+	"2:"
+	: "=&c" (d0), "=&D" (d1)
+	:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
+	:"memory");
+return (s);	
+}
+
+ 
+
+extern inline size_t strnlen(const char * s, size_t count)
+{
+int d0;
+register int __res;
+__asm__ __volatile__(
+	"movl %2,%0\n\t"
+	"jmp 2f\n"
+	"1:\tcmpb $0,(%0)\n\t"
+	"je 3f\n\t"
+	"incl %0\n"
+	"2:\tdecl %1\n\t"
+	"cmpl $-1,%1\n\t"
+	"jne 1b\n"
+	"3:\tsubl %2,%0"
+	:"=a" (__res), "=&d" (d0)
+	:"c" (s),"1" (count));
+return __res;
+}
+ 
+
+ 
+
+
+
+extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
+{
+	switch (count) {
+		case 0:
+			return s;
+		case 1:
+			*(unsigned char *)s = pattern;
+			return s;
+		case 2:
+			*(unsigned short *)s = pattern;
+			return s;
+		case 3:
+			*(unsigned short *)s = pattern;
+			*(2+(unsigned char *)s) = pattern;
+			return s;
+		case 4:
+			*(unsigned long *)s = pattern;
+			return s;
+	}
+
+
+
+
+
+
+
+{
+	int d0, d1;
+	switch (count % 4) {
+		case 0: __asm__  __volatile__("cld\n\t" "rep ; stosl"  ""  : "=&c" (d0), "=&D" (d1) : "a" (pattern),"0" (count/4),"1" ((long) s) : "memory") ; return s;
+		case 1: __asm__  __volatile__("cld\n\t" "rep ; stosl"  "\n\tstosb"  : "=&c" (d0), "=&D" (d1) : "a" (pattern),"0" (count/4),"1" ((long) s) : "memory") ; return s;
+		case 2: __asm__  __volatile__("cld\n\t" "rep ; stosl"  "\n\tstosw"  : "=&c" (d0), "=&D" (d1) : "a" (pattern),"0" (count/4),"1" ((long) s) : "memory") ; return s;
+		default: __asm__  __volatile__("cld\n\t" "rep ; stosl"  "\n\tstosw\n\tstosb"  : "=&c" (d0), "=&D" (d1) : "a" (pattern),"0" (count/4),"1" ((long) s) : "memory") ; return s;
+	}
+}
+  
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+extern inline void * memscan(void * addr, int c, size_t size)
+{
+	if (!size)
+		return addr;
+	__asm__("cld
+		repnz; scasb
+		jnz 1f
+		dec %%edi
+1:		"
+		: "=D" (addr), "=c" (size)
+		: "0" (addr), "1" (size), "a" (c));
+	return addr;
+}
+
+
+
+# 37 "/usr/src/linux/include/linux/string.h" 2
+
+
+
+
+
+
+
+# 64 "/usr/src/linux/include/linux/signal.h" 2
+
+
+
+# 102 "/usr/src/linux/include/linux/signal.h"
+
+
+extern inline void  sigorsets (sigset_t *r, const sigset_t *a, const sigset_t *b) {	unsigned long a0, a1, a2, a3, b0, b1, b2, b3;	unsigned long i;	for (i = 0; i < (64  / 32 ) /4; ++i) {	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1];	a2 = a->sig[4*i+2]; a3 = a->sig[4*i+3];	b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1];	b2 = b->sig[4*i+2]; b3 = b->sig[4*i+3];	r->sig[4*i+0] =   (( a0 ) | (  b0 )) ;	r->sig[4*i+1] =   (( a1 ) | (  b1 )) ;	r->sig[4*i+2] =   (( a2 ) | (  b2 )) ;	r->sig[4*i+3] =   (( a3 ) | (  b3 )) ;	}	switch ((64  / 32 )  % 4) {	case 3:	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; a2 = a->sig[4*i+2]; b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; b2 = b->sig[4*i+2]; r->sig[4*i+0] =   (( a0 ) | (  b0 )) ;	r->sig[4*i+1] =   (( a1 ) | (  b1 )) ;	r->sig[4*i+2] =   (( a2 ) | (  b2 )) ;	break;	case 2:	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1];	b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1];	r->sig[4*i+0] =   (( a0 ) | (  b0 )) ;	r->sig[4*i+1] =   (( a1 ) | (  b1 )) ;	break;	case 1:	a0 = a->sig[4*i+0]; b0 = b->sig[4*i+0];	r->sig[4*i+0] =   (( a0 ) | (  b0 )) ;	break;	}	}
+
+
+extern inline void  sigandsets (sigset_t *r, const sigset_t *a, const sigset_t *b) {	unsigned long a0, a1, a2, a3, b0, b1, b2, b3;	unsigned long i;	for (i = 0; i < (64  / 32 ) /4; ++i) {	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1];	a2 = a->sig[4*i+2]; a3 = a->sig[4*i+3];	b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1];	b2 = b->sig[4*i+2]; b3 = b->sig[4*i+3];	r->sig[4*i+0] =   (( a0 ) & (  b0 )) ;	r->sig[4*i+1] =   (( a1 ) & (  b1 )) ;	r->sig[4*i+2] =   (( a2 ) & (  b2 )) ;	r->sig[4*i+3] =   (( a3 ) & (  b3 )) ;	}	switch ((64  / 32 )  % 4) {	case 3:	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; a2 = a->sig[4*i+2]; b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; b2 = b->sig[4*i+2]; r->sig[4*i+0] =   (( a0 ) & (  b0 )) ;  r->sig[4*i+1] =   (( a1 ) & (  b1 )) ;  r->sig[4*i+2] =   (( a2 ) & (  b2 )) ;  break;  case 2:	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1];	b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1];	r->sig[4*i+0] =   (( a0 ) & (  b0 )) ;  r->sig[4*i+1] =   (( a1 ) & (  b1 )) ;  break;  case 1:	a0 = a->sig[4*i+0]; b0 = b->sig[4*i+0];	r->sig[4*i+0] =   (( a0 ) & (  b0 )) ;  break;  }       }   // AMBIGUOUS
+
+
+extern inline void  signandsets (sigset_t *r, const sigset_t *a, const sigset_t *b) {	unsigned long a0, a1, a2, a3, b0, b1, b2, b3;	unsigned long i;	for (i = 0; i < (64  / 32 ) /4; ++i) {	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1];	a2 = a->sig[4*i+2]; a3 = a->sig[4*i+3];	b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1];	b2 = b->sig[4*i+2]; b3 = b->sig[4*i+3];	r->sig[4*i+0] =   (( a0 ) & ~(  b0 )) ;	r->sig[4*i+1] =   (( a1 ) & ~(  b1 )) ;	r->sig[4*i+2] =   (( a2 ) & ~(  b2 )) ;	r->sig[4*i+3] =   (( a3 ) & ~(  b3 )) ;	}	switch ((64  / 32 )  % 4) {	case 3:	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; a2 = a->sig[4*i+2]; b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; b2 = b->sig[4*i+2]; r->sig[4*i+0] =   (( a0 ) & ~(  b0 )) ;	r->sig[4*i+1] =   (( a1 ) & ~(  b1 )) ;	r->sig[4*i+2] =   (( a2 ) & ~(  b2 )) ;	break;	case 2:	a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1];	b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1];	r->sig[4*i+0] =   (( a0 ) & ~(  b0 )) ;	r->sig[4*i+1] =   (( a1 ) & ~(  b1 )) ;	break;	case 1:	a0 = a->sig[4*i+0]; b0 = b->sig[4*i+0];	r->sig[4*i+0] =   (( a0 ) & ~(  b0 )) ;	break;	}	}   // AMBIGUOUS
+
+
+
+
+
+
+
+# 134 "/usr/src/linux/include/linux/signal.h"
+
+
+extern inline void  signotset (sigset_t *set)	{	unsigned long i;	for (i = 0; i < (64  / 32 ) /4; ++i) {	set->sig[4*i+0] =   (~( set->sig[4*i+0] )) ;	set->sig[4*i+1] =   (~( set->sig[4*i+1] )) ;	set->sig[4*i+2] =   (~( set->sig[4*i+2] )) ;	set->sig[4*i+3] =   (~( set->sig[4*i+3] )) ;	}	switch ((64  / 32 )  % 4) {	case 3: set->sig[4*i+2] =   (~( set->sig[4*i+2] )) ;    case 2: set->sig[4*i+1] =   (~( set->sig[4*i+1] )) ;    case 1: set->sig[4*i+0] =   (~( set->sig[4*i+0] )) ;    }       }
+
+
+
+
+extern inline void sigemptyset(sigset_t *set)
+{
+	switch ((64  / 32 ) ) {
+	default:
+		(__builtin_constant_p(  0 ) ? (__builtin_constant_p( (  sizeof(sigset_t) ) ) ? __constant_c_and_count_memset(( ( set ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  sizeof(sigset_t) ) )) : __constant_c_memset(( ( set ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  sizeof(sigset_t) ) )))  : (__builtin_constant_p( (  sizeof(sigset_t) ) ) ? __memset_generic(( ( ( set ) ) ),( ( (  0 ) ) ),( ( (  sizeof(sigset_t) ) ) ))  : __memset_generic(( ( set ) ),( (  0 ) ),( (  sizeof(sigset_t) ) ))) ) ;
+		break;
+	case 2: set->sig[1] = 0;
+	case 1:	set->sig[0] = 0;
+		break;
+	}
+}
+
+extern inline void sigfillset(sigset_t *set)
+{
+	switch ((64  / 32 ) ) {
+	default:
+		(__builtin_constant_p(  -1 ) ? (__builtin_constant_p( (  sizeof(sigset_t) ) ) ? __constant_c_and_count_memset(( ( set ) ),( (0x01010101UL*(unsigned char)(  -1 )) ),( (  sizeof(sigset_t) ) )) : __constant_c_memset(( ( set ) ),( (0x01010101UL*(unsigned char)(  -1 )) ),( (  sizeof(sigset_t) ) )))  : (__builtin_constant_p( (  sizeof(sigset_t) ) ) ? __memset_generic(( ( ( set ) ) ),( ( (  -1 ) ) ),( ( (  sizeof(sigset_t) ) ) ))  : __memset_generic(( ( set ) ),( (  -1 ) ),( (  sizeof(sigset_t) ) ))) ) ;
+		break;
+	case 2: set->sig[1] = -1;
+	case 1:	set->sig[0] = -1;
+		break;
+	}
+}
+
+extern char * render_sigset_t(sigset_t *set, char *buffer);
+
+ 
+
+extern inline void sigaddsetmask(sigset_t *set, unsigned long mask)
+{
+	set->sig[0] |= mask;
+}
+
+extern inline void sigdelsetmask(sigset_t *set, unsigned long mask)
+{
+	set->sig[0] &= ~mask;
+}
+
+extern inline int sigtestsetmask(sigset_t *set, unsigned long mask)
+{
+	return (set->sig[0] & mask) != 0;
+}
+
+extern inline void siginitset(sigset_t *set, unsigned long mask)
+{
+	set->sig[0] = mask;
+	switch ((64  / 32 ) ) {
+	default:
+		(__builtin_constant_p(  0 ) ? (__builtin_constant_p( (  sizeof(long)*((64  / 32 ) -1) ) ) ? __constant_c_and_count_memset(( ( &set->sig[1] ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  sizeof(long)*((64  / 32 ) -1) ) )) : __constant_c_memset(( ( &set->sig[1] ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  sizeof(long)*((64  / 32 ) -1) ) )))  : (__builtin_constant_p( (  sizeof(long)*((64  / 32 ) -1) ) ) ? __memset_generic(( ( ( &set->sig[1] ) ) ),( ( (  0 ) ) ),( ( (  sizeof(long)*((64  / 32 ) -1) ) ) ))  : __memset_generic(( ( &set->sig[1] ) ),( (  0 ) ),( (  sizeof(long)*((64  / 32 ) -1) ) ))) ) ;
+		break;
+	case 2: set->sig[1] = 0;
+	case 1:
+	}
+}
+
+extern inline void siginitsetinv(sigset_t *set, unsigned long mask)
+{
+	set->sig[0] = ~mask;
+	switch ((64  / 32 ) ) {
+	default:
+		(__builtin_constant_p(  -1 ) ? (__builtin_constant_p( (  sizeof(long)*((64  / 32 ) -1) ) ) ? __constant_c_and_count_memset(( ( &set->sig[1] ) ),( (0x01010101UL*(unsigned char)(  -1 )) ),( (  sizeof(long)*((64  / 32 ) -1) ) )) : __constant_c_memset(( ( &set->sig[1] ) ),( (0x01010101UL*(unsigned char)(  -1 )) ),( (  sizeof(long)*((64  / 32 ) -1) ) )))  : (__builtin_constant_p( (  sizeof(long)*((64  / 32 ) -1) ) ) ? __memset_generic(( ( ( &set->sig[1] ) ) ),( ( (  -1 ) ) ),( ( (  sizeof(long)*((64  / 32 ) -1) ) ) ))  : __memset_generic(( ( &set->sig[1] ) ),( (  -1 ) ),( (  sizeof(long)*((64  / 32 ) -1) ) ))) ) ;
+		break;
+	case 2: set->sig[1] = -1;
+	case 1:
+	}
+}
+
+
+
+
+
+
+# 23 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/securebits.h" 1
+
+
+
+
+
+extern unsigned securebits;
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+# 24 "/usr/src/linux/include/linux/sched.h" 2
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+extern unsigned long avenrun[];		 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern int nr_running, nr_tasks;
+extern int last_pid;
+
+
+
+# 1 "/usr/src/linux/include/linux/param.h" 1
+
+
+
+
+
+
+# 70 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/resource.h" 1
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+struct	rusage {
+	struct timeval ru_utime;	 
+	struct timeval ru_stime;	 
+	long	ru_maxrss;		 
+	long	ru_ixrss;		 
+	long	ru_idrss;		 
+	long	ru_isrss;		 
+	long	ru_minflt;		 
+	long	ru_majflt;		 
+	long	ru_nswap;		 
+	long	ru_inblock;		 
+	long	ru_oublock;		 
+	long	ru_msgsnd;		 
+	long	ru_msgrcv;		 
+	long	ru_nsignals;		 
+	long	ru_nvcsw;		 
+	long	ru_nivcsw;		 
+};
+
+
+
+struct rlimit {
+	long	rlim_cur;
+	long	rlim_max;
+};
+
+
+
+
+
+
+
+
+ 
+
+
+
+# 1 "/usr/src/linux/include/asm/resource.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 36 "/usr/src/linux/include/asm/resource.h"
+
+
+
+
+# 58 "/usr/src/linux/include/linux/resource.h" 2
+
+
+
+# 71 "/usr/src/linux/include/linux/sched.h" 2
+
+# 1 "/usr/src/linux/include/linux/timer.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct timer_struct {
+	unsigned long expires;
+	void (*fn)(void);
+};
+
+extern unsigned long timer_active;
+extern struct timer_struct timer_table[32];
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+struct timer_list {
+	struct timer_list *next;  
+	struct timer_list *prev;
+	unsigned long expires;
+	unsigned long data;
+	void (*function)(unsigned long);
+};
+
+extern void add_timer(struct timer_list * timer);
+extern int  del_timer(struct timer_list * timer);
+
+ 
+
+
+
+
+void mod_timer(struct timer_list *timer, unsigned long expires);
+
+extern void it_real_fn(unsigned long);
+
+extern inline void init_timer(struct timer_list * timer)
+{
+	timer->next = ((void *)0) ;
+	timer->prev = ((void *)0) ;
+}
+
+extern inline int timer_pending(struct timer_list * timer)
+{
+	return timer->prev != ((void *)0) ;
+}
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 72 "/usr/src/linux/include/linux/sched.h" 2
+
+
+# 1 "/usr/src/linux/include/asm/processor.h" 1
+ 
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/vm86.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+struct vm86_regs {
+ 
+
+
+	long ebx;
+	long ecx;
+	long edx;
+	long esi;
+	long edi;
+	long ebp;
+	long eax;
+	long __null_ds;
+	long __null_es;
+	long __null_fs;
+	long __null_gs;
+	long orig_eax;
+	long eip;
+	unsigned short cs, __csh;
+	long eflags;
+	long esp;
+	unsigned short ss, __ssh;
+ 
+
+
+	unsigned short es, __esh;
+	unsigned short ds, __dsh;
+	unsigned short fs, __fsh;
+	unsigned short gs, __gsh;
+};
+
+struct revectored_struct {
+	unsigned long __map[8];			 
+};
+
+struct vm86_struct {
+	struct vm86_regs regs;
+	unsigned long flags;
+	unsigned long screen_bitmap;
+	unsigned long cpu_type;
+	struct revectored_struct int_revectored;
+	struct revectored_struct int21_revectored;
+};
+
+ 
+
+
+
+
+struct vm86plus_info_struct {
+	unsigned long force_return_for_pic:1;
+	unsigned long vm86dbg_active:1;        
+	unsigned long vm86dbg_TFpendig:1;      
+	unsigned long unused:28;
+	unsigned long is_vm86pus:1;	       
+	unsigned char vm86dbg_intxxtab[32];    
+};
+
+struct vm86plus_struct {
+	struct vm86_regs regs;
+	unsigned long flags;
+	unsigned long screen_bitmap;
+	unsigned long cpu_type;
+	struct revectored_struct int_revectored;
+	struct revectored_struct int21_revectored;
+	struct vm86plus_info_struct vm86plus;
+};
+
+
+ 
+
+
+
+
+
+
+
+
+struct kernel_vm86_regs {
+ 
+
+
+	long ebx;
+	long ecx;
+	long edx;
+	long esi;
+	long edi;
+	long ebp;
+	long eax;
+	long __null_ds;
+	long __null_es;
+	long orig_eax;
+	long eip;
+	unsigned short cs, __csh;
+	long eflags;
+	long esp;
+	unsigned short ss, __ssh;
+ 
+
+
+	unsigned short es, __esh;
+	unsigned short ds, __dsh;
+	unsigned short fs, __fsh;
+	unsigned short gs, __gsh;
+};
+
+struct kernel_vm86_struct {
+	struct kernel_vm86_regs regs;
+ 
+
+
+
+
+
+
+
+
+	unsigned long flags;
+	unsigned long screen_bitmap;
+	unsigned long cpu_type;
+	struct revectored_struct int_revectored;
+	struct revectored_struct int21_revectored;
+	struct vm86plus_info_struct vm86plus;
+	struct pt_regs *regs32;    
+ 
+
+
+
+
+
+
+
+
+
+};
+
+void handle_vm86_fault(struct kernel_vm86_regs *, long);
+int handle_vm86_trap(struct kernel_vm86_regs *, long, int);
+
+
+
+
+# 10 "/usr/src/linux/include/asm/processor.h" 2
+
+# 1 "/usr/src/linux/include/asm/math_emu.h" 1
+
+
+
+
+
+int restore_i387_soft(void *s387, struct _fpstate *buf);
+int save_i387_soft(void *s387, struct _fpstate * buf);
+
+ 
+
+
+
+struct info {
+	long ___orig_eip;
+	long ___ret_from_system_call;
+	long ___ebx;
+	long ___ecx;
+	long ___edx;
+	long ___esi;
+	long ___edi;
+	long ___ebp;
+	long ___eax;
+	long ___ds;
+	long ___es;
+	long ___orig_eax;
+	long ___eip;
+	long ___cs;
+	long ___eflags;
+	long ___esp;
+	long ___ss;
+	long ___vm86_es;  
+	long ___vm86_ds;
+	long ___vm86_fs;
+	long ___vm86_gs;
+};
+
+# 11 "/usr/src/linux/include/asm/processor.h" 2
+
+
+
+
+ 
+
+
+
+
+
+struct cpuinfo_x86 {
+	__u8	x86;		 
+	__u8	x86_vendor;	 
+	__u8	x86_model;
+	__u8	x86_mask;
+	char	wp_works_ok;	 
+	char	hlt_works_ok;	 
+	char	hard_math;
+	char	rfu;
+	int	cpuid_level;	 
+	__u32	x86_capability;
+	char	x86_vendor_id[16];
+	char	x86_model_id[64];
+	int 	x86_cache_size;   
+
+	int	fdiv_bug;
+	int	f00f_bug;
+	int	coma_bug;
+	unsigned long loops_per_sec;
+	unsigned long *pgd_quick;
+	unsigned long *pte_quick;
+	unsigned long pgtable_cache_sz;
+};
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern struct cpuinfo_x86 boot_cpu_data;
+
+
+
+
+
+
+
+
+
+extern char ignore_irq13;
+
+extern void identify_cpu(struct cpuinfo_x86 *);
+extern void print_cpu_info(struct cpuinfo_x86 *);
+extern void dodgy_tsc(void);
+
+ 
+
+
+extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+	__asm__("cpuid"
+		: "=a" (*eax),
+		  "=b" (*ebx),
+		  "=c" (*ecx),
+		  "=d" (*edx)
+		: "a" (op)
+		: "cc");
+}
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+extern int EISA_bus;
+extern int MCA_bus;
+
+ 
+
+extern unsigned int machine_id;
+extern unsigned int machine_submodel_id;
+extern unsigned int BIOS_revision;
+extern unsigned int mca_pentium_flag;
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+struct i387_hard_struct {
+	long	cwd;
+	long	swd;
+	long	twd;
+	long	fip;
+	long	fcs;
+	long	foo;
+	long	fos;
+	long	st_space[20];	 
+	long	status;		 
+};
+
+struct i387_soft_struct {
+	long	cwd;
+	long	swd;
+	long	twd;
+	long	fip;
+	long	fcs;
+	long	foo;
+	long	fos;
+	long	st_space[20];	 
+	unsigned char	ftop, changed, lookahead, no_update, rm, alimit;
+	struct info	*info;
+	unsigned long	entry_eip;
+};
+
+union i387_union {
+	struct i387_hard_struct hard;
+	struct i387_soft_struct soft;
+};
+
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
+struct thread_struct {
+	unsigned short	back_link,__blh;
+	unsigned long	esp0;
+	unsigned short	ss0,__ss0h;
+	unsigned long	esp1;
+	unsigned short	ss1,__ss1h;
+	unsigned long	esp2;
+	unsigned short	ss2,__ss2h;
+	unsigned long	cr3;
+	unsigned long	eip;
+	unsigned long	eflags;
+	unsigned long	eax,ecx,edx,ebx;
+	unsigned long	esp;
+	unsigned long	ebp;
+	unsigned long	esi;
+	unsigned long	edi;
+	unsigned short	es, __esh;
+	unsigned short	cs, __csh;
+	unsigned short	ss, __ssh;
+	unsigned short	ds, __dsh;
+	unsigned short	fs, __fsh;
+	unsigned short	gs, __gsh;
+	unsigned short	ldt, __ldth;
+	unsigned short	trace, bitmap;
+	unsigned long	io_bitmap[32 +1];
+	unsigned long	tr;
+	unsigned long	cr2, trap_no, error_code;
+	mm_segment_t	segment;
+ 
+	long debugreg[8];   
+ 
+	union i387_union i387;
+ 
+	struct vm86_struct * vm86_info;
+	unsigned long screen_bitmap;
+	unsigned long v86flags, v86mask, v86mode, saved_esp0;
+};
+
+
+
+
+
+# 271 "/usr/src/linux/include/asm/processor.h"
+
+
+# 282 "/usr/src/linux/include/asm/processor.h"
+
+ 
+struct mm_struct;
+
+ 
+extern void release_thread(struct task_struct *);
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+ 
+extern void copy_segments(int nr, struct task_struct *p, struct mm_struct * mm);
+extern void release_segments(struct mm_struct * mm);
+extern void forget_segments(void);
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+{
+	return ((unsigned long *)t->esp)[3];
+}
+
+extern struct task_struct * alloc_task_struct(void);
+extern void free_task_struct(struct task_struct *);
+
+
+
+
+
+# 74 "/usr/src/linux/include/linux/sched.h" 2
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+struct sched_param {
+	int sched_priority;
+};
+
+
+
+
+
+ 
+
+
+
+
+
+extern rwlock_t tasklist_lock;
+extern spinlock_t runqueue_lock;
+
+extern void sched_init(void);
+extern void init_idle(void);
+extern void show_state(void);
+extern void trap_init(void);
+
+
+extern signed long  schedule_timeout(signed long timeout)  __attribute__((regparm(3))) ;
+  __attribute__((regparm(0)))  void schedule(void);
+
+ 
+
+
+
+
+
+ 
+
+
+struct files_struct {
+	atomic_t count;
+	int max_fds;
+	int max_fdset;
+	int next_fd;
+	struct file ** fd;	 
+	fd_set *close_on_exec;
+	fd_set *open_fds;
+	fd_set close_on_exec_init;
+	fd_set open_fds_init;
+	struct file * fd_array[32  ];
+};
+
+
+# 156 "/usr/src/linux/include/linux/sched.h"
+
+struct fs_struct {
+	atomic_t count;
+	int umask;
+	struct dentry * root, * pwd;
+};
+
+
+
+
+
+
+
+ 
+
+
+ 
+
+
+struct mm_struct {
+	struct vm_area_struct *mmap;		 
+	struct vm_area_struct *mmap_avl;	 
+	struct vm_area_struct *mmap_cache;	 
+	pgd_t * pgd;
+	atomic_t count;
+	int map_count;				 
+	struct semaphore mmap_sem;
+	unsigned long context;
+	unsigned long start_code, end_code, start_data, end_data;
+	unsigned long start_brk, brk, start_stack;
+	unsigned long arg_start, arg_end, env_start, env_end;
+	unsigned long rss, total_vm, locked_vm;
+	unsigned long def_flags;
+	unsigned long cpu_vm_mask;
+	unsigned long swap_cnt;	 
+	unsigned long swap_address;
+	 
+
+
+
+	void * segments;
+};
+
+
+# 210 "/usr/src/linux/include/linux/sched.h"
+
+struct signal_struct {
+	atomic_t		count;
+	struct k_sigaction	action[64 ];
+	spinlock_t		siglock;
+};
+
+
+
+
+
+
+
+ 
+
+
+
+
+struct user_struct;
+
+struct task_struct {
+ 
+	volatile long state;	 
+	unsigned long flags;	 
+	int sigpending;
+	mm_segment_t addr_limit;	 
+
+
+
+	struct exec_domain *exec_domain;
+	long need_resched;
+
+ 
+	long counter;
+	long priority;
+	cycles_t avg_slice;
+ 
+	int has_cpu;
+	int processor;
+	int last_processor;
+	int lock_depth;		 	
+	struct task_struct *next_task, *prev_task;
+	struct task_struct *next_run,  *prev_run;
+
+ 
+	struct linux_binfmt *binfmt;
+	int exit_code, exit_signal;
+	int pdeath_signal;   
+	 
+	unsigned long personality;
+	int dumpable:1;
+	int did_exec:1;
+	pid_t pid;
+	pid_t pgrp;
+	pid_t tty_old_pgrp;
+	pid_t session;
+	 
+	int leader;
+	 
+
+
+
+
+	struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+
+	 
+	struct task_struct *pidhash_next;
+	struct task_struct **pidhash_pprev;
+
+	 
+	struct task_struct **tarray_ptr;
+
+	struct wait_queue *wait_chldexit;	 
+	struct semaphore *vfork_sem;		 
+	unsigned long policy, rt_priority;
+	unsigned long it_real_value, it_prof_value, it_virt_value;
+	unsigned long it_real_incr, it_prof_incr, it_virt_incr;
+	struct timer_list real_timer;
+	struct tms times;
+	unsigned long start_time;
+	long per_cpu_utime[1 ], per_cpu_stime[1 ];
+ 
+	unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
+	int swappable:1;
+ 
+	uid_t uid,euid,suid,fsuid;
+	gid_t gid,egid,sgid,fsgid;
+	int ngroups;
+	gid_t	groups[32 ];
+        kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
+	struct user_struct *user;
+ 
+	struct rlimit rlim[10 ];
+	unsigned short used_math;
+	char comm[16];
+ 
+	int link_count;
+	struct tty_struct *tty;  
+ 
+	struct sem_undo *semundo;
+	struct sem_queue *semsleeping;
+ 
+	struct thread_struct tss;
+ 
+	struct fs_struct *fs;
+ 
+	struct files_struct *files;
+ 
+	struct mm_struct *mm;
+
+ 
+	spinlock_t sigmask_lock;	 
+	struct signal_struct *sig;
+	sigset_t signal, blocked;
+	struct signal_queue *sigqueue, **sigqueue_tail;
+	unsigned long sas_ss_sp;
+	size_t sas_ss_size;
+	
+ 
+   	u32 parent_exec_id;
+   	u32 self_exec_id;
+
+ 
+	int oom_kill_try;
+};
+
+ 
+
+
+
+					 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+# 403 "/usr/src/linux/include/linux/sched.h"
+
+union task_union {
+	struct task_struct task;
+	unsigned long stack[2048];
+};
+
+extern union task_union init_task_union;
+
+extern struct   mm_struct init_mm;
+extern struct task_struct *task[512 ];
+
+extern struct task_struct **tarray_freelist;
+extern spinlock_t taskslot_lock;
+
+extern __inline__ void add_free_taskslot(struct task_struct **t)
+{
+	(void)( &taskslot_lock ) ;
+	*t = (struct task_struct *) tarray_freelist;
+	tarray_freelist = t;
+	do { } while(0) ;
+}
+
+extern __inline__ struct task_struct **get_free_taskslot(void)
+{
+	struct task_struct **tslot;
+
+	(void)( &taskslot_lock ) ;
+	if((tslot = tarray_freelist) != ((void *)0) )
+		tarray_freelist = (struct task_struct **) *tslot;
+	do { } while(0) ;
+
+	return tslot;
+}
+
+ 
+
+extern struct task_struct *pidhash[(512  >> 2) ];
+
+
+
+extern __inline__ void hash_pid(struct task_struct *p)
+{
+	struct task_struct **htable = &pidhash[(((( p->pid ) >> 8) ^ ( p->pid )) & ((512  >> 2)  - 1)) ];
+
+	if((p->pidhash_next = *htable) != ((void *)0) )
+		(*htable)->pidhash_pprev = &p->pidhash_next;
+	*htable = p;
+	p->pidhash_pprev = htable;
+}
+
+extern __inline__ void unhash_pid(struct task_struct *p)
+{
+	if(p->pidhash_next)
+		p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
+	*p->pidhash_pprev = p->pidhash_next;
+}
+
+extern __inline__ struct task_struct *find_task_by_pid(int pid)
+{
+	struct task_struct *p, **htable = &pidhash[(((( pid ) >> 8) ^ ( pid )) & ((512  >> 2)  - 1)) ];
+
+	for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
+		;
+
+	return p;
+}
+
+ 
+extern int alloc_uid(struct task_struct *p);
+void free_uid(struct task_struct *p);
+
+# 1 "/usr/src/linux/include/asm/current.h" 1
+
+
+
+struct task_struct;
+
+static inline struct task_struct * get_current(void)
+{
+	struct task_struct *current;
+	__asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));
+	return current;
+ }
+ 
+
+
+
+# 474 "/usr/src/linux/include/linux/sched.h" 2
+
+
+extern unsigned long volatile jiffies;
+extern unsigned long itimer_ticks;
+extern unsigned long itimer_next;
+extern struct timeval xtime;
+extern void do_timer(struct pt_regs *);
+
+extern unsigned int * prof_buffer;
+extern unsigned long prof_len;
+extern unsigned long prof_shift;
+
+
+
+extern void  __wake_up(struct wait_queue ** p, unsigned int mode)  __attribute__((regparm(3))) ;
+extern void  sleep_on(struct wait_queue ** p)  __attribute__((regparm(3))) ;
+extern long  sleep_on_timeout(struct wait_queue ** p,
+				      signed long timeout)  __attribute__((regparm(3))) ;
+extern void  interruptible_sleep_on(struct wait_queue ** p)  __attribute__((regparm(3))) ;
+extern long  interruptible_sleep_on_timeout(struct wait_queue ** p,
+						    signed long timeout)  __attribute__((regparm(3))) ;
+extern void  wake_up_process(struct task_struct * tsk)  __attribute__((regparm(3))) ;
+
+
+
+
+extern int in_group_p(gid_t grp);
+extern int in_egroup_p(gid_t grp);
+
+extern void flush_signals(struct task_struct *);
+extern void flush_signal_handlers(struct task_struct *);
+extern int dequeue_signal(sigset_t *block, siginfo_t *);
+extern int send_sig_info(int, struct siginfo *info, struct task_struct *);
+extern int force_sig_info(int, struct siginfo *info, struct task_struct *);
+extern int kill_pg_info(int, struct siginfo *info, pid_t);
+extern int kill_sl_info(int, struct siginfo *info, pid_t);
+extern int kill_proc_info(int, struct siginfo *info, pid_t);
+extern int kill_something_info(int, struct siginfo *info, int);
+extern void notify_parent(struct task_struct * tsk, int);
+extern void force_sig(int sig, struct task_struct * p);
+extern int send_sig(int sig, struct task_struct * p, int priv);
+extern int kill_pg(pid_t, int, int);
+extern int kill_sl(pid_t, int, int);
+extern int kill_proc(pid_t, int, int);
+extern int do_sigaction(int sig, const struct k_sigaction *act,
+			struct k_sigaction *oact);
+extern int do_sigaltstack(const stack_t *ss, stack_t *oss, unsigned long sp);
+
+extern inline int signal_pending(struct task_struct *p)
+{
+	return (p->sigpending != 0);
+}
+
+ 
+
+
+
+static inline void recalc_sigpending(struct task_struct *t)
+{
+	unsigned long ready;
+	long i;
+
+	switch ((64  / 32 ) ) {
+	default:
+		for (i = (64  / 32 ) , ready = 0; --i >= 0 ;)
+			ready |= t->signal.sig[i] &~ t->blocked.sig[i];
+		break;
+
+	case 4: ready  = t->signal.sig[3] &~ t->blocked.sig[3];
+		ready |= t->signal.sig[2] &~ t->blocked.sig[2];
+		ready |= t->signal.sig[1] &~ t->blocked.sig[1];
+		ready |= t->signal.sig[0] &~ t->blocked.sig[0];
+		break;
+
+	case 2: ready  = t->signal.sig[1] &~ t->blocked.sig[1];
+		ready |= t->signal.sig[0] &~ t->blocked.sig[0];
+		break;
+
+	case 1: ready  = t->signal.sig[0] &~ t->blocked.sig[0];
+	}
+
+	t->sigpending = (ready != 0);
+}
+
+ 
+
+static inline int on_sig_stack(unsigned long sp)
+{
+	return (sp >= get_current() ->sas_ss_sp
+		&& sp < get_current() ->sas_ss_sp + get_current() ->sas_ss_size);
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+	return (get_current() ->sas_ss_size == 0 ? 2 
+		: on_sig_stack(sp) ? 1  : 0);
+}
+
+extern int request_irq(unsigned int irq,
+		       void (*handler)(int, void *, struct pt_regs *),
+		       unsigned long flags, 
+		       const char *device,
+		       void *dev_id);
+extern void free_irq(unsigned int irq, void *dev_id);
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern inline int suser(void)
+{
+	if (! ( (1 << ( 0  +1)) & 0x00000000  ? (1 << ( 0  )) & 0x00000000  :	(1 << ( 0  )) & securebits )  && get_current() ->euid == 0) { 
+		get_current() ->flags |= 0x00000100 ;
+		return 1;
+	}
+	return 0;
+}
+
+extern inline int fsuser(void)
+{
+	if (! ( (1 << ( 0  +1)) & 0x00000000  ? (1 << ( 0  )) & 0x00000000  :	(1 << ( 0  )) & securebits )  && get_current() ->fsuid == 0) {
+		get_current() ->flags |= 0x00000100 ;
+		return 1;
+	}
+	return 0;
+}
+
+ 
+
+
+
+
+
+extern inline int capable(int cap)
+{
+
+	if (((  get_current() ->cap_effective  )  & (1 << (   cap  )) ) )
+
+
+
+        {
+		get_current() ->flags |= 0x00000100 ;
+		return 1;
+	}
+	return 0;
+}
+
+ 
+
+
+extern struct mm_struct * mm_alloc(void);
+static inline void mmget(struct mm_struct * mm)
+{
+	atomic_inc(&mm->count);
+}
+extern void mmput(struct mm_struct *);
+ 
+extern void mm_release(void);
+
+ 
+
+
+extern struct file ** alloc_fd_array(int);
+extern int expand_fd_array(struct files_struct *, int nr);
+extern void free_fd_array(struct file **, int);
+
+extern fd_set *alloc_fdset(int);
+extern int expand_fdset(struct files_struct *, int nr);
+extern void free_fdset(fd_set *, int);
+
+ 
+
+static inline int expand_files(struct files_struct *files, int nr)
+{
+	int err, expand = 0;
+
+
+
+	
+	if (nr >= files->max_fdset) {
+		expand = 1;
+		if ((err = expand_fdset(files, nr + 1)))
+			goto out;
+	}
+	if (nr >= files->max_fds) {
+		expand = 1;
+		if ((err = expand_fd_array(files, nr + 1)))
+			goto out;
+	}
+	err = expand;
+ out:
+
+
+
+
+	return err;
+}
+
+extern int  copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
+extern void flush_thread(void);
+extern void exit_thread(void);
+
+extern void exit_mm(struct task_struct *);
+extern void exit_fs(struct task_struct *);
+extern void exit_files(struct task_struct *);
+extern void exit_sighand(struct task_struct *);
+
+extern int do_execve(char *, char **, char **, struct pt_regs *);
+extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
+
+ 
+
+
+
+
+extern inline void __add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+//	wait->next = *p ? : ((struct wait_queue *)(( p )-1)) ;   // INVALID
+	*p = wait;
+}
+
+extern rwlock_t waitqueue_lock;
+
+extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	__add_wait_queue(p, wait);
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+extern inline void __remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+	struct wait_queue * next = wait->next;
+	struct wait_queue * head = next;
+	struct wait_queue * tmp;
+
+	while ((tmp = head->next) != wait) {
+		head = tmp;
+	}
+	head->next = next;
+}
+
+extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	__remove_wait_queue(p, wait);
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ; 
+}
+
+
+# 753 "/usr/src/linux/include/linux/sched.h"
+
+
+
+
+
+
+
+
+
+# 782 "/usr/src/linux/include/linux/sched.h"
+	
+
+
+
+
+
+
+
+
+
+# 801 "/usr/src/linux/include/linux/sched.h"
+
+
+# 812 "/usr/src/linux/include/linux/sched.h"
+
+
+
+
+
+
+
+# 21 "pc_keyb.c" 2
+
+# 1 "/usr/src/linux/include/linux/interrupt.h" 1
+ 
+
+
+
+
+
+
+
+struct irqaction {
+	void (*handler)(int, void *, struct pt_regs *);
+	unsigned long flags;
+	unsigned long mask;
+	const char *name;
+	void *dev_id;
+	struct irqaction *next;
+};
+
+extern volatile unsigned char bh_running;
+
+extern atomic_t bh_mask_count[32];
+extern unsigned long bh_active;
+extern unsigned long bh_mask;
+extern void (*bh_base[32])(void);
+
+  __attribute__((regparm(0)))  void do_bottom_half(void);
+
+ 
+
+   
+enum {
+	TIMER_BH = 0,
+	CONSOLE_BH,
+	TQUEUE_BH,
+	DIGI_BH,
+	SERIAL_BH,
+	RISCOM8_BH,
+	SPECIALIX_BH,
+	AURORA_BH,
+	ESP_BH,
+	NET_BH,
+	SCSI_BH,
+	IMMEDIATE_BH,
+	KEYBOARD_BH,
+	CYCLADES_BH,
+	CM206_BH,
+	JS_BH,
+	MACSERIAL_BH,
+	ISICOM_BH
+};
+
+# 1 "/usr/src/linux/include/asm/hardirq.h" 1
+
+
+
+
+
+extern unsigned int local_irq_count[1 ];
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 63 "/usr/src/linux/include/asm/hardirq.h"
+
+
+
+# 51 "/usr/src/linux/include/linux/interrupt.h" 2
+
+# 1 "/usr/src/linux/include/asm/softirq.h" 1
+
+
+
+
+
+
+extern unsigned int local_bh_count[1 ];
+
+
+
+
+
+
+
+
+# 58 "/usr/src/linux/include/asm/softirq.h"
+
+
+extern inline void start_bh_atomic(void)
+{
+	local_bh_count[0 ]++;
+	__asm__ __volatile__("": : :"memory") ;
+}
+
+extern inline void end_bh_atomic(void)
+{
+	__asm__ __volatile__("": : :"memory") ;
+	local_bh_count[0 ]--;
+}
+
+ 
+
+
+
+
+
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	unsigned long flags;
+
+	bh_base[nr] = routine;
+	((( &bh_mask_count[nr] )->counter) = (  0 )) ;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	bh_mask |= 1 << nr;
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+extern inline void remove_bh(int nr)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	bh_mask &= ~(1 << nr);
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+
+	__asm__ __volatile__("": : :"memory")  ;
+	bh_base[nr] = ((void *)0) ;
+}
+
+extern inline void mark_bh(int nr)
+{
+	set_bit(nr, &bh_active);
+}
+
+ 
+
+
+
+extern inline void disable_bh(int nr)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	bh_mask &= ~(1 << nr);
+	atomic_inc(&bh_mask_count[nr]);
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+	__asm__ __volatile__("": : :"memory")  ;
+}
+
+extern inline void enable_bh(int nr)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	if (atomic_dec_and_test(&bh_mask_count[nr]))
+		bh_mask |= 1 << nr;
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+
+# 52 "/usr/src/linux/include/linux/interrupt.h" 2
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern unsigned long probe_irq_on(void);	 
+extern int probe_irq_off(unsigned long);	 
+
+
+# 22 "pc_keyb.c" 2
+
+
+# 1 "/usr/src/linux/include/linux/mm.h" 1
+
+
+
+
+
+
+
+
+
+
+extern unsigned long max_mapnr;
+extern unsigned long num_physpages;
+extern void * high_memory;
+extern int page_cluster;
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+struct vm_area_struct {
+	struct mm_struct * vm_mm;	 
+	unsigned long vm_start;
+	unsigned long vm_end;
+
+	 
+	struct vm_area_struct *vm_next;
+
+	pgprot_t vm_page_prot;
+	unsigned short vm_flags;
+
+	 
+	short vm_avl_height;
+	struct vm_area_struct * vm_avl_left;
+	struct vm_area_struct * vm_avl_right;
+
+	 
+
+
+	struct vm_area_struct *vm_next_share;
+	struct vm_area_struct **vm_pprev_share;
+
+	struct vm_operations_struct * vm_ops;
+	unsigned long vm_offset;
+	struct file * vm_file;
+	unsigned long vm_pte;			 
+};
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+extern pgprot_t protection_map[16];
+
+
+ 
+
+
+
+
+struct vm_operations_struct {
+	void (*open)(struct vm_area_struct * area);
+	void (*close)(struct vm_area_struct * area);
+	void (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
+	void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot);
+	int (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags);
+	void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise);
+	unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access);
+	unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
+		unsigned long page);
+	int (*swapout)(struct vm_area_struct *, struct page *);
+	pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
+};
+
+ 
+
+
+
+
+
+
+
+typedef struct page {
+	 
+	struct page *next;
+	struct page *prev;
+	struct inode *inode;
+	unsigned long offset;
+	struct page *next_hash;
+	atomic_t count;
+	unsigned long flags;	 
+	struct wait_queue *wait;
+	struct page **pprev_hash;
+	struct buffer_head * buffers;
+} mem_map_t;
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern mem_map_t * mem_map;
+
+ 
+
+
+
+
+
+
+extern unsigned long  __get_free_pages(int gfp_mask, unsigned long gfp_order)  __attribute__((regparm(3))) ;
+
+extern inline unsigned long get_free_page(int gfp_mask)
+{
+	unsigned long page;
+
+	page = __get_free_pages(( gfp_mask ),0) ;
+	if (page)
+		(__builtin_constant_p(  0 ) ? (__builtin_constant_p( (  (1UL << 12 )  ) ) ? __constant_c_and_count_memset(( ( (void *)( page ) ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  (1UL << 12 )  ) )) : __constant_c_memset(( ( (void *)( page ) ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  (1UL << 12 )  ) )))  : (__builtin_constant_p( (  (1UL << 12 )  ) ) ? __memset_generic(( ( ( (void *)( page ) ) ) ),( ( (  0 ) ) ),( ( (  (1UL << 12 )  ) ) ))  : __memset_generic(( ( (void *)( page ) ) ),( (  0 ) ),( (  (1UL << 12 )  ) ))) )  ;
+	return page;
+}
+
+extern int low_on_memory;
+
+ 
+
+
+extern void  free_pages(unsigned long addr, unsigned long order)  __attribute__((regparm(3))) ;
+
+extern void  __free_pages(struct page *, unsigned long)  __attribute__((regparm(3))) ;
+
+extern void show_free_areas(void);
+extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
+	unsigned long address);
+
+extern void free_page_tables(struct mm_struct * mm);
+extern void clear_page_tables(struct mm_struct *, unsigned long, int);
+extern int new_page_tables(struct task_struct * tsk);
+
+extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
+extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma);
+extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
+extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
+
+extern void vmtruncate(struct inode * inode, unsigned long offset);
+extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
+extern int make_pages_present(unsigned long addr, unsigned long end);
+
+extern int pgt_cache_water[2];
+extern int check_pgt_cache(void);
+
+extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
+extern void mem_init(unsigned long start_mem, unsigned long end_mem);
+extern void show_mem(void);
+extern void si_meminfo(struct sysinfo * val);
+
+ 
+extern void vma_init(void);
+extern void merge_segments(struct mm_struct *, unsigned long, unsigned long);
+extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
+extern void build_mmap_avl(struct mm_struct *);
+extern void exit_mmap(struct mm_struct *);
+extern unsigned long get_unmapped_area(unsigned long, unsigned long);
+
+extern unsigned long do_mmap(struct file *, unsigned long, unsigned long,
+	unsigned long, unsigned long, unsigned long);
+extern int do_munmap(unsigned long, size_t);
+
+ 
+extern void remove_inode_page(struct page *);
+extern unsigned long page_unuse(struct page *);
+extern int shrink_mmap(int, int);
+extern void truncate_inode_pages(struct inode *, unsigned long);
+extern unsigned long get_cached_page(struct inode *, unsigned long, int);
+extern void put_cached_page(unsigned long);
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+static inline int expand_stack(struct vm_area_struct * vma, unsigned long address)
+{
+	unsigned long grow;
+
+	address &= (~((1UL << 12 ) -1)) ;
+	grow = vma->vm_start - address;
+	if ((vma->vm_end - address
+	    > get_current() ->rlim[3 ].rlim_cur) ||
+	    ((get_current() ->rlim[9 ].rlim_cur < ((long)(~0UL>>1)) ) &&
+	    ((vma->vm_mm->total_vm << 12 ) + grow
+	    > get_current() ->rlim[9 ].rlim_cur)))
+		return - 12 ;
+	vma->vm_start = address;
+	vma->vm_offset -= grow;
+	vma->vm_mm->total_vm += grow >> 12 ;
+	if (vma->vm_flags & 0x2000 )
+		vma->vm_mm->locked_vm += grow >> 12 ;
+	return 0;
+}
+
+ 
+extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
+
+ 
+
+static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
+{
+	struct vm_area_struct * vma = find_vma(mm,start_addr);
+
+	if (vma && end_addr <= vma->vm_start)
+		vma = ((void *)0) ;
+	return vma;
+}
+
+
+
+
+
+
+
+
+
+# 24 "pc_keyb.c" 2
+
+
+# 1 "/usr/src/linux/include/linux/init.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/init.h" 1
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+# 51 "/usr/src/linux/include/linux/init.h" 2
+
+# 60 "/usr/src/linux/include/linux/init.h"
+
+
+
+
+
+
+
+
+
+# 26 "pc_keyb.c" 2
+
+# 1 "/usr/src/linux/include/linux/kbd_ll.h" 1
+ 
+
+
+
+
+
+
+extern struct pt_regs *kbd_pt_regs;
+
+void handle_scancode(unsigned char scancode, int down);
+
+
+# 27 "pc_keyb.c" 2
+
+# 1 "/usr/src/linux/include/linux/delay.h" 1
+
+
+
+ 
+
+
+
+
+
+extern unsigned long loops_per_sec;
+
+# 1 "/usr/src/linux/include/asm/delay.h" 1
+
+
+
+ 
+
+
+
+
+ 
+extern void __const_udelay(unsigned long usecs);
+extern void __udelay(unsigned long usecs);
+extern void __delay(unsigned long loops);
+
+
+
+
+
+	
+
+# 12 "/usr/src/linux/include/linux/delay.h" 2
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 28 "pc_keyb.c" 2
+
+# 1 "/usr/src/linux/include/linux/random.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+ 
+
+
+ 
+
+
+ 
+
+
+ 
+
+
+
+
+
+ 
+
+
+ 
+
+
+struct rand_pool_info {
+	int	entropy_count;
+	int	buf_size;
+	__u32	buf[0];
+};
+
+ 
+
+
+
+extern void rand_initialize(void);
+extern void rand_initialize_irq(int irq);
+extern void rand_initialize_blkdev(int irq, int mode);
+
+extern void add_keyboard_randomness(unsigned char scancode);
+extern void add_mouse_randomness(__u32 mouse_data);
+extern void add_interrupt_randomness(int irq);
+extern void add_blkdev_randomness(int major);
+
+extern void get_random_bytes(void *buf, int nbytes);
+
+extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
+					__u16 sport, __u16 dport);
+extern __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr,
+				   __u16 sport, __u16 dport,
+				   __u32 sseq, __u32 count,
+				   __u32 data);
+extern __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr,
+				  __u32 daddr, __u16 sport,
+				  __u16 dport, __u32 sseq,
+				  __u32 count, __u32 maxdiff);
+
+
+extern struct file_operations random_fops, urandom_fops;
+
+
+
+
+
+# 29 "pc_keyb.c" 2
+
+# 1 "/usr/src/linux/include/linux/poll.h" 1
+
+
+
+# 1 "/usr/src/linux/include/asm/poll.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+
+# 4 "/usr/src/linux/include/linux/poll.h" 2
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/uaccess.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern int __verify_write(const void *, unsigned long);
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+	return (({ unsigned long flag,sum; asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" :"=&r" (flag), "=r" (sum) :"1" (  addr  ),"g" ((int)  size  ),"g" (get_current() ->addr_limit.seg)); flag; })  == 0)  ? 0 : - 14 ;
+}
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+struct exception_table_entry
+{
+	unsigned long insn, fixup;
+};
+
+ 
+extern unsigned long search_exception_table(unsigned long);
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern void __get_user_1(void);
+extern void __get_user_2(void);
+extern void __get_user_4(void);
+
+
+
+
+
+
+ 
+
+# 125 "/usr/src/linux/include/asm/uaccess.h"
+
+extern void __put_user_1(void);
+extern void __put_user_2(void);
+extern void __put_user_4(void);
+
+extern void __put_user_bad(void);
+
+
+
+
+
+
+
+
+# 148 "/usr/src/linux/include/asm/uaccess.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 171 "/usr/src/linux/include/asm/uaccess.h"
+
+struct __large_struct { unsigned long buf[100]; };
+
+
+ 
+
+
+
+
+
+# 194 "/usr/src/linux/include/asm/uaccess.h"
+
+
+
+
+
+
+
+
+
+
+extern long __get_user_bad(void);
+
+
+# 216 "/usr/src/linux/include/asm/uaccess.h"
+
+
+# 232 "/usr/src/linux/include/asm/uaccess.h"
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+# 274 "/usr/src/linux/include/asm/uaccess.h"
+
+
+# 302 "/usr/src/linux/include/asm/uaccess.h"
+
+ 
+
+
+static inline unsigned long
+__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
+{
+	do {	int __d0, __d1;	__asm__ __volatile__(	"0:	rep; movsl\n"	"	movl %3,%0\n"	"1:	rep; movsb\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	lea 0(%3,%0,4),%0\n"	"4:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosb\n"	"	popl %%eax\n"	"	popl %0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=&c"( n ), "=&D" (__d0), "=&S" (__d1)	: "r"( n  & 3), "0"( n  / 4), "1"( to ), "2"( from )	: "memory");	} while (0) ;
+	return n;
+}
+
+static inline unsigned long
+__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
+{
+	do {	int __d0, __d1;	__asm__ __volatile__(	"0:	rep; movsl\n"	"	movl %3,%0\n"	"1:	rep; movsb\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	lea 0(%3,%0,4),%0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,2b\n"	".previous"	: "=&c"( n ), "=&D" (__d0), "=&S" (__d1)	: "r"( n  & 3), "0"( n  / 4), "1"( to ), "2"( from )	: "memory");	} while (0) ;
+	return n;
+}
+
+
+ 
+
+# 404 "/usr/src/linux/include/asm/uaccess.h"
+
+ 
+
+# 540 "/usr/src/linux/include/asm/uaccess.h"
+
+unsigned long __generic_copy_to_user(void *, const void *, unsigned long);
+unsigned long __generic_copy_from_user(void *, const void *, unsigned long);
+
+static inline unsigned long
+__constant_copy_to_user(void *to, const void *from, unsigned long n)
+{
+	if ((({ unsigned long flag,sum; asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" :"=&r" (flag), "=r" (sum) :"1" (   to  ),"g" ((int)   n  ),"g" (get_current() ->addr_limit.seg)); flag; })  == 0) )
+		do {	int __d0, __d1;	switch ( n  & 3) {	default:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:\n"	".section .fixup,\"ax\"\n"	"2:	shl $2,%0\n"	"	jmp 1b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,2b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 1:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsb\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	shl $2,%0\n"	"4:	incl %0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 2:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsw\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	shl $2,%0\n"	"4:	addl $2,%0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 3:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsw\n"	"2:	movsb\n"	"3:\n"	".section .fixup,\"ax\"\n"	"4:	shl $2,%0\n"	"5:	addl $2,%0\n"	"6:	incl %0\n"	"	jmp 3b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,4b\n"	"	.long 1b,5b\n"	"	.long 2b,6b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	}	} while (0) ;
+	return n;
+}
+
+static inline unsigned long
+__constant_copy_from_user(void *to, const void *from, unsigned long n)
+{
+	if ((({ unsigned long flag,sum; asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" :"=&r" (flag), "=r" (sum) :"1" (   from  ),"g" ((int)   n  ),"g" (get_current() ->addr_limit.seg)); flag; })  == 0) )
+		do {	int __d0, __d1;	switch ( n  & 3) {	default:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:\n"	".section .fixup,\"ax\"\n"	"2:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosl\n"	"	popl %%eax\n"	"	popl %0\n"	"	shl $2,%0\n"	"	jmp 1b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,2b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 1:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsb\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosl\n"	"	stosb\n"	"	popl %%eax\n"	"	popl %0\n"	"	shl $2,%0\n"	"	incl %0\n"	"	jmp 2b\n"	"4:	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	stosb\n"	"	popl %%eax\n"	"	incl %0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 2:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsw\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosl\n"	"	stosw\n"	"	popl %%eax\n"	"	popl %0\n"	"	shl $2,%0\n"	"	addl $2,%0\n"	"	jmp 2b\n"	"4:	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	stosw\n"	"	popl %%eax\n"	"	addl $2,%0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 3:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsw\n"	"2:	movsb\n"	"3:\n"	".section .fixup,\"ax\"\n"	"4:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosl\n"	"	stosw\n"	"	stosb\n"	"	popl %%eax\n"	"	popl %0\n"	"	shl $2,%0\n"	"	addl $3,%0\n"	"	jmp 2b\n"	"5:	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	stosw\n"	"	stosb\n"	"	popl %%eax\n"	"	addl $3,%0\n"	"	jmp 2b\n"	"6:	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	stosb\n"	"	popl %%eax\n"	"	incl %0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,4b\n"	"	.long 1b,5b\n"	"	.long 2b,6b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	}	} while (0) ;
+	return n;
+}
+
+static inline unsigned long
+__constant_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
+{
+	do {	int __d0, __d1;	switch ( n  & 3) {	default:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:\n"	".section .fixup,\"ax\"\n"	"2:	shl $2,%0\n"	"	jmp 1b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,2b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 1:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsb\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	shl $2,%0\n"	"4:	incl %0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 2:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsw\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	shl $2,%0\n"	"4:	addl $2,%0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 3:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsw\n"	"2:	movsb\n"	"3:\n"	".section .fixup,\"ax\"\n"	"4:	shl $2,%0\n"	"5:	addl $2,%0\n"	"6:	incl %0\n"	"	jmp 3b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,4b\n"	"	.long 1b,5b\n"	"	.long 2b,6b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	}	} while (0) ;
+	return n;
+}
+
+static inline unsigned long
+__constant_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
+{
+	do {	int __d0, __d1;	switch ( n  & 3) {	default:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:\n"	".section .fixup,\"ax\"\n"	"2:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosl\n"	"	popl %%eax\n"	"	popl %0\n"	"	shl $2,%0\n"	"	jmp 1b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,2b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 1:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsb\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosl\n"	"	stosb\n"	"	popl %%eax\n"	"	popl %0\n"	"	shl $2,%0\n"	"	incl %0\n"	"	jmp 2b\n"	"4:	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	stosb\n"	"	popl %%eax\n"	"	incl %0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 2:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsw\n"	"2:\n"	".section .fixup,\"ax\"\n"	"3:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosl\n"	"	stosw\n"	"	popl %%eax\n"	"	popl %0\n"	"	shl $2,%0\n"	"	addl $2,%0\n"	"	jmp 2b\n"	"4:	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	stosw\n"	"	popl %%eax\n"	"	addl $2,%0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,3b\n"	"	.long 1b,4b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	case 3:	__asm__ __volatile__(	"0:	rep; movsl\n"	"1:	movsw\n"	"2:	movsb\n"	"3:\n"	".section .fixup,\"ax\"\n"	"4:	pushl %0\n"	"	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	rep; stosl\n"	"	stosw\n"	"	stosb\n"	"	popl %%eax\n"	"	popl %0\n"	"	shl $2,%0\n"	"	addl $3,%0\n"	"	jmp 2b\n"	"5:	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	stosw\n"	"	stosb\n"	"	popl %%eax\n"	"	addl $3,%0\n"	"	jmp 2b\n"	"6:	pushl %%eax\n"	"	xorl %%eax,%%eax\n"	"	stosb\n"	"	popl %%eax\n"	"	incl %0\n"	"	jmp 2b\n"	".previous\n"	".section __ex_table,\"a\"\n"	"	.align 4\n"	"	.long 0b,4b\n"	"	.long 1b,5b\n"	"	.long 2b,6b\n"	".previous"	: "=c"( n ), "=&S" (__d0), "=&D" (__d1)	: "1"( from ), "2"( to ), "0"( n /4)	: "memory");	break;	}	} while (0) ;
+	return n;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+long strncpy_from_user(char *dst, const char *src, long count);
+long __strncpy_from_user(char *dst, const char *src, long count);
+
+long strnlen_user(const char *str, long n);
+unsigned long clear_user(void *mem, unsigned long len);
+unsigned long __clear_user(void *mem, unsigned long len);
+
+
+# 11 "/usr/src/linux/include/linux/poll.h" 2
+
+
+
+struct poll_table_entry {
+	struct file * filp;
+	struct wait_queue wait;
+	struct wait_queue ** wait_address;
+};
+
+typedef struct poll_table_struct {
+	struct poll_table_struct * next;
+	unsigned int nr;
+	struct poll_table_entry * entry;
+} poll_table;
+
+
+
+extern void __pollwait(struct file * filp, struct wait_queue ** wait_address, poll_table *p);
+
+extern inline void poll_wait(struct file * filp, struct wait_queue ** wait_address, poll_table *p)
+{
+	if (p && wait_address)
+		__pollwait(filp, wait_address, p);
+}
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned long kernel_fd_set[((((1UL << 12 ) /(6*64))*64) *8 > (1024*1024)  ? (1024*1024)  : (((1UL << 12 ) /(6*64))*64) *8) / (8 * sizeof(unsigned long)) ];
+
+ 
+
+
+
+typedef struct {
+	unsigned long *in, *out, *ex;
+	unsigned long *res_in, *res_out, *res_ex;
+} fd_set_bits;
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+static inline
+int get_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset)
+{
+	nr = ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long)) ;   // AMBIGUOUS
+	if (ufdset) {
+		int error;
+		error = verify_area(1 , ufdset, nr);
+		if (!error && (__builtin_constant_p(  nr ) ?	__constant_copy_from_user_nocheck(( fdset ),(  ufdset ),(  nr )) :	__generic_copy_from_user_nocheck(( fdset ),(  ufdset ),(  nr ))) )
+			error = - 14 ;
+		return error;
+	}
+	(__builtin_constant_p(  0 ) ? (__builtin_constant_p( (  nr ) ) ? __constant_c_and_count_memset(( ( fdset ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  nr ) )) : __constant_c_memset(( ( fdset ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  nr ) )))  : (__builtin_constant_p( (  nr ) ) ? __memset_generic(( ( ( fdset ) ) ),( ( (  0 ) ) ),( ( (  nr ) ) ))  : __memset_generic(( ( fdset ) ),( (  0 ) ),( (  nr ) ))) ) ;
+	return 0;
+}
+
+static inline
+void set_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset)
+{
+	if (ufdset)
+		(__builtin_constant_p(  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  ) ?	__constant_copy_to_user_nocheck(( ufdset ),(  fdset ),(  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  )) :	__generic_copy_to_user_nocheck(( ufdset ),(  fdset ),(  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  ))) ;   // AMBIGUOUS
+}
+
+static inline
+void zero_fd_set(unsigned long nr, unsigned long *fdset)
+{
+        (__builtin_constant_p(  0 ) ? (__builtin_constant_p( (  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  ) ) ? __constant_c_and_count_memset(( ( fdset ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  ) )) : __constant_c_memset(( ( fdset ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  ) )))  : (__builtin_constant_p( (  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  ) ) ? __memset_generic(( ( ( fdset ) ) ),( ( (  0 ) ) ),( ( (  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  ) ) ))  : __memset_generic(( ( fdset ) ),( (  0 ) ),( (  ((((  nr  )+ (8*sizeof(long)) -1)/ (8*sizeof(long)) ) *sizeof(long))  ) ))) ) ;  // AMBIGUOUS
+}
+
+extern int do_select(int n, fd_set_bits *fds, long *timeout);
+
+
+
+
+# 30 "pc_keyb.c" 2
+
+# 1 "/usr/src/linux/include/linux/miscdevice.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+extern int misc_init(void);
+
+struct miscdevice 
+{
+	int minor;
+	const char *name;
+	struct file_operations *fops;
+	struct miscdevice * next, * prev;
+};
+
+extern int misc_register(struct miscdevice * misc);
+extern int misc_deregister(struct miscdevice * misc);
+
+
+# 31 "pc_keyb.c" 2
+
+# 1 "/usr/src/linux/include/linux/malloc.h" 1
+
+
+
+# 1 "/usr/src/linux/include/linux/slab.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+typedef struct kmem_cache_s kmem_cache_t;
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+extern long kmem_cache_init(long, long);
+extern void kmem_cache_sizes_init(void);
+extern kmem_cache_t *kmem_find_general_cachep(size_t);
+extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
+				       void (*)(void *, kmem_cache_t *, unsigned long),
+				       void (*)(void *, kmem_cache_t *, unsigned long));
+extern int kmem_cache_shrink(kmem_cache_t *);
+extern void *kmem_cache_alloc(kmem_cache_t *, int);
+extern void kmem_cache_free(kmem_cache_t *, void *);
+
+extern void *kmalloc(size_t, int);
+extern void kfree(const void *);
+extern void kfree_s(const void *, size_t);
+
+extern void kmem_cache_reap(int);
+extern int get_slabinfo(char *);
+
+ 
+extern kmem_cache_t	*vm_area_cachep;
+extern kmem_cache_t	*mm_cachep;
+
+
+
+
+# 4 "/usr/src/linux/include/linux/malloc.h" 2
+
+
+# 32 "pc_keyb.c" 2
+
+
+# 1 "/usr/src/linux/include/asm/keyboard.h" 1
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/linux/ioport.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+extern void reserve_setup(char *str, int *ints);
+extern int check_region(unsigned long from, unsigned long extent);
+extern void request_region(unsigned long from, unsigned long extent,const char *name);
+extern void release_region(unsigned long from, unsigned long extent);
+extern int get_ioport_list(char *);
+
+
+
+
+
+
+
+
+extern void autoirq_setup(int waittime);
+extern int autoirq_report(int waittime);
+
+
+# 17 "/usr/src/linux/include/asm/keyboard.h" 2
+
+# 1 "/usr/src/linux/include/asm/io.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern inline unsigned char  inb  (unsigned short port) { unsigned char  _v;  __asm__ __volatile__ ("in" "b" " %"  "w"  "1,%"   ""   "0"  : "=a" (_v) : "Nd" (port)   ); return _v; } extern inline unsigned char  inb_p (unsigned short port) { unsigned char  _v;  __asm__ __volatile__ ("in" "b" " %"  "w"  "1,%"   ""   "0"  "\noutb %%al,$0x80"   : "=a" (_v) : "Nd" (port)   ); return _v; } 
+
+
+extern inline unsigned short  inw  (unsigned short port) { unsigned short  _v;  __asm__ __volatile__ ("in" "w" " %"  "w"  "1,%"   ""   "0"  : "=a" (_v) : "Nd" (port)   ); return _v; } extern inline unsigned short  inw_p (unsigned short port) { unsigned short  _v;  __asm__ __volatile__ ("in" "w" " %"  "w"  "1,%"   ""   "0"  "\noutb %%al,$0x80"   : "=a" (_v) : "Nd" (port)   ); return _v; } 
+
+
+extern inline unsigned int  inl  (unsigned short port) { unsigned int  _v;  __asm__ __volatile__ ("in" "l" " %"  "w"  "1,%"   ""   "0"  : "=a" (_v) : "Nd" (port)   ); return _v; } extern inline unsigned int  inl_p (unsigned short port) { unsigned int  _v;  __asm__ __volatile__ ("in" "l" " %"  "w"  "1,%"   ""   "0"  "\noutb %%al,$0x80"   : "=a" (_v) : "Nd" (port)   ); return _v; } 
+
+
+extern inline void outb  (unsigned   char   value, unsigned short port) {  __asm__ __volatile__ ("out" "b" " %"   "b"   "0,%"  "w"  "1"  : : "a" (value), "Nd" (port)); } extern inline void outb_p (unsigned   char   value, unsigned short port) {  __asm__ __volatile__ ("out" "b" " %"   "b"   "0,%"  "w"  "1"  "\noutb %%al,$0x80"   : : "a" (value), "Nd" (port));} 
+extern inline void outw  (unsigned   short   value, unsigned short port) {  __asm__ __volatile__ ("out" "w" " %"   "w"   "0,%"  "w"  "1"  : : "a" (value), "Nd" (port)); } extern inline void outw_p (unsigned   short   value, unsigned short port) {  __asm__ __volatile__ ("out" "w" " %"   "w"   "0,%"  "w"  "1"  "\noutb %%al,$0x80"   : : "a" (value), "Nd" (port));} 
+extern inline void outl  (unsigned   int   value, unsigned short port) {  __asm__ __volatile__ ("out" "l" " %"      "0,%"  "w"  "1"  : : "a" (value), "Nd" (port)); } extern inline void outl_p (unsigned   int   value, unsigned short port) {  __asm__ __volatile__ ("out" "l" " %"      "0,%"  "w"  "1"  "\noutb %%al,$0x80"   : : "a" (value), "Nd" (port));} 
+
+extern inline void insb (unsigned short port, void * addr, unsigned long count) { __asm__ __volatile__ ("cld ; rep ; ins" "b" : "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } 
+extern inline void insw (unsigned short port, void * addr, unsigned long count) { __asm__ __volatile__ ("cld ; rep ; ins" "w" : "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } 
+extern inline void insl (unsigned short port, void * addr, unsigned long count) { __asm__ __volatile__ ("cld ; rep ; ins" "l" : "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } 
+
+extern inline void outsb (unsigned short port, const void * addr, unsigned long count) { __asm__ __volatile__ ("cld ; rep ; outs" "b" : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } 
+extern inline void outsw (unsigned short port, const void * addr, unsigned long count) { __asm__ __volatile__ ("cld ; rep ; outs" "w" : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } 
+extern inline void outsl (unsigned short port, const void * addr, unsigned long count) { __asm__ __volatile__ ("cld ; rep ; outs" "l" : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } 
+
+
+
+# 1 "/usr/src/linux/include/linux/vmalloc.h" 1
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/pgtable.h" 1
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/src/linux/include/asm/fixmap.h" 1
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+enum fixed_addresses {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	__end_of_fixed_addresses
+};
+
+extern void set_fixmap (enum fixed_addresses idx, unsigned long phys);
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+extern void __this_fixmap_does_not_exist(void);
+
+ 
+
+
+
+
+extern inline unsigned long fix_to_virt(const unsigned int idx)
+{
+	 
+
+
+
+
+
+
+
+
+	if (idx >= __end_of_fixed_addresses)
+		__this_fixmap_does_not_exist();
+
+        return ((0xffffe000UL)  - (( idx ) << 12 )) ;
+}
+
+
+# 17 "/usr/src/linux/include/asm/pgtable.h" 2
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	if (mm == get_current() ->mm)
+		do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0) ;
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+	unsigned long addr)
+{
+	if (vma->vm_mm == get_current() ->mm)
+		__asm__ __volatile__("invlpg %0": :"m" (*(char *)  addr )) ;
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+	unsigned long start, unsigned long end)
+{
+	if (mm == get_current() ->mm)
+		do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0) ;
+}
+
+# 163 "/usr/src/linux/include/asm/pgtable.h"
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+extern unsigned long pg0[1024];
+ 
+extern unsigned long empty_zero_page[1024];
+
+ 
+
+
+
+
+
+
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+
+
+
+
+ 
+
+
+ 
+
+
+ 
+ 
+
+
+ 
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+extern inline int pgd_none(pgd_t pgd)		{ return 0; }
+extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
+extern inline int pgd_present(pgd_t pgd)	{ return 1; }
+extern inline void pgd_clear(pgd_t * pgdp)	{ }
+
+ 
+
+
+
+extern inline int pte_read(pte_t pte)		{ return (( pte ).pte)  & 0x004 ; }
+extern inline int pte_exec(pte_t pte)		{ return (( pte ).pte)  & 0x004 ; }
+extern inline int pte_dirty(pte_t pte)		{ return (( pte ).pte)  & 0x040 ; }
+extern inline int pte_young(pte_t pte)		{ return (( pte ).pte)  & 0x020 ; }
+extern inline int pte_write(pte_t pte)		{ return (( pte ).pte)  & 0x002 ; }
+
+extern inline pte_t pte_rdprotect(pte_t pte)	{ (( pte ).pte)  &= ~0x004 ; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)	{ (( pte ).pte)  &= ~0x004 ; return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)	{ (( pte ).pte)  &= ~0x040 ; return pte; }
+extern inline pte_t pte_mkold(pte_t pte)	{ (( pte ).pte)  &= ~0x020 ; return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte)	{ (( pte ).pte)  &= ~0x002 ; return pte; }
+extern inline pte_t pte_mkread(pte_t pte)	{ (( pte ).pte)  |= 0x004 ; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)	{ (( pte ).pte)  |= 0x004 ; return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)	{ (( pte ).pte)  |= 0x040 ; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)	{ (( pte ).pte)  |= 0x020 ; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)	{ (( pte ).pte)  |= 0x002 ; return pte; }
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ (( pte ).pte)  = ((( pte ).pte)  & ((~((1UL << 12 ) -1))  | 0x020  | 0x040 ) ) | (( newprot ).pgprot) ; return pte; }
+
+
+
+
+
+
+
+ 
+
+
+
+ 
+
+
+ 
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+  
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+extern __inline__ pgd_t *get_pgd_slow(void)
+{
+	pgd_t *ret = (pgd_t *)__get_free_pages(( (0x04  | 0x01  | 0x10 )  ),0) , *init;
+
+	if (ret) {
+		init = (( &init_mm )->pgd + ((  0 ) >> 22 )) ;
+		(__builtin_constant_p(  0 ) ? (__builtin_constant_p( (  ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  * sizeof(pgd_t) ) ) ? __constant_c_and_count_memset(( ( ret ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  * sizeof(pgd_t) ) )) : __constant_c_memset(( ( ret ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  * sizeof(pgd_t) ) )))  : (__builtin_constant_p( (  ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  * sizeof(pgd_t) ) ) ? __memset_generic(( ( ( ret ) ) ),( ( (  0 ) ) ),( ( (  ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  * sizeof(pgd_t) ) ) ))  : __memset_generic(( ( ret ) ),( (  0 ) ),( (  ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  * sizeof(pgd_t) ) ))) ) ;
+		(__builtin_constant_p( 
+			(1024  - ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) ) ) * sizeof(pgd_t) ) ? __constant_memcpy(( ret + ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  ),(  init + ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  ),(  			(1024  - ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) ) ) * sizeof(pgd_t) )) : __memcpy(( ret + ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  ),(  init + ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) )  ),(  			(1024  - ((((unsigned long)(0xC0000000 ) ) ) / (1UL << 22 ) ) ) * sizeof(pgd_t) ))) ;
+	}
+	return ret;
+}
+
+extern __inline__ pgd_t *get_pgd_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = (boot_cpu_data .pgd_quick) ) != ((void *)0) ) {
+		(boot_cpu_data .pgd_quick)  = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		(boot_cpu_data .pgtable_cache_sz) --;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
+}
+
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+	*(unsigned long *)pgd = (unsigned long) (boot_cpu_data .pgd_quick) ;
+	(boot_cpu_data .pgd_quick)  = (unsigned long *) pgd;
+	(boot_cpu_data .pgtable_cache_sz) ++;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+	free_pages(( (unsigned long)pgd ),0) ;
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = (unsigned long *)(boot_cpu_data .pte_quick) ) != ((void *)0) ) {
+		(boot_cpu_data .pte_quick)  = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		(boot_cpu_data .pgtable_cache_sz) --;
+	}
+	return (pte_t *)ret;
+}
+
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+	*(unsigned long *)pte = (unsigned long) (boot_cpu_data .pte_quick) ;
+	(boot_cpu_data .pte_quick)  = (unsigned long *) pte;
+	(boot_cpu_data .pgtable_cache_sz) ++;
+}
+
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+	free_pages(( (unsigned long)pte ),0) ;
+}
+
+ 
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+	return (pmd_t *)0;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pte_kernel(pmd_t *pmd);
+
+
+
+
+
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> 12 ) & (1024  - 1);
+	if ((! ((  *pmd  ).pmd) ) ) {
+		pte_t * page = (pte_t *) get_pte_fast();
+		
+		if (!page)
+			return get_pte_kernel_slow(pmd, address);
+		(( *pmd ).pmd)  = (0x001  | 0x002  | 0x020  | 0x040 )  + ((unsigned long)( page )- ((unsigned long)(0xC0000000 ) ) ) ;   // AMBIGUOUS
+		return page + address;
+	}
+	if (((((  *pmd  ).pmd)  & (~(~((1UL << 12 ) -1))  & ~0x004 )) != (0x001  | 0x002  | 0x020  | 0x040 ) ) ) {
+		__bad_pte_kernel(pmd);
+		return ((void *)0) ;
+	}
+	return (pte_t *) ((unsigned long) ((void *)((unsigned long)( ((  *pmd  ).pmd)  & (~((1UL << 12 ) -1))  )+ ((unsigned long)(0xC0000000 ) ) )) )  + address;
+}
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> (12 -2)) & 4*(1024  - 1);
+
+	if ((! ((  *pmd  ).pmd) ) )
+		goto getnew;
+	if (((((  *pmd  ).pmd)  & (~(~((1UL << 12 ) -1))  & ~0x004 )) != (0x001  | 0x002  | 0x020  | 0x040 ) ) )
+		goto fix;
+	return (pte_t *) (((unsigned long) ((void *)((unsigned long)( ((  *pmd  ).pmd)  & (~((1UL << 12 ) -1))  )+ ((unsigned long)(0xC0000000 ) ) )) )  + address);
+getnew:
+{
+	unsigned long page = (unsigned long) get_pte_fast();
+
+	if (!page)
+		return get_pte_slow(pmd, address);
+	(( *pmd ).pmd)  = (0x001  | 0x002  | 0x004  | 0x020  | 0x040 )  + ((unsigned long)( page )- ((unsigned long)(0xC0000000 ) ) ) ;    // AMBIGUOUS
+	return (pte_t *) (page + address);
+}
+fix:
+	__bad_pte(pmd);
+	return ((void *)0) ;
+}
+
+
+
+
+
+extern inline void pmd_free(pmd_t * pmd)
+{
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+	return (pmd_t *) pgd;
+}
+
+
+
+
+extern int do_check_pgt_cache(int, int);
+
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+	struct task_struct * p;
+	pgd_t *pgd;
+
+
+
+
+	(void)( &tasklist_lock ) ;
+	for ( p  = & (init_task_union.task)  ; ( p  =  p ->next_task) != & (init_task_union.task)  ; )  {
+		if (!p->mm)
+			continue;
+		* (( p->mm )->pgd + (( address ) >> 22 ))  = entry;
+	}
+	do { } while(0) ;
+
+	for (pgd = (pgd_t *)(boot_cpu_data .pgd_quick) ; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> 22 ] = entry;
+
+
+
+
+
+
+
+}
+
+extern pgd_t swapper_pg_dir[1024];
+
+ 
+
+
+
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
+	unsigned long address, pte_t pte)
+{
+}
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+# 7 "/usr/src/linux/include/linux/vmalloc.h" 2
+
+
+struct vm_struct {
+	unsigned long flags;
+	void * addr;
+	unsigned long size;
+	struct vm_struct * next;
+};
+
+struct vm_struct * get_vm_area(unsigned long size);
+void vfree(void * addr);
+void * vmalloc(unsigned long size);
+long vread(char *buf, char *addr, unsigned long count);
+void vmfree_area_pages(unsigned long address, unsigned long size);
+int vmalloc_area_pages(unsigned long address, unsigned long size);
+
+
+
+# 101 "/usr/src/linux/include/asm/io.h" 2
+
+
+
+
+
+ 
+
+
+
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+	return ((unsigned long)( address ) & ~((unsigned long)(0xC0000000 ) ) ) ;   // AMBIGUOUS
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+	return ((void *)(((unsigned long)(0xC0000000 ) )  | (unsigned long)( address ))) ;
+}
+
+extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+extern inline void * ioremap (unsigned long offset, unsigned long size)
+{
+	return __ioremap(offset, size, 0);
+}
+
+ 
+
+
+
+
+extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+{
+        return __ioremap(offset, size, 0x010 );
+}
+
+extern void iounmap(void *addr);
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+static inline int check_signature(unsigned long io_addr,
+	const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if ((*(volatile unsigned char *) ((void *)(((unsigned long)(0xC0000000 ) )  | (unsigned long)(  io_addr  ))) )  != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
+
+
+
+
+# 18 "/usr/src/linux/include/asm/keyboard.h" 2
+
+
+
+
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+# 34 "pc_keyb.c" 2
+
+
+
+# 1 "/usr/src/linux/include/asm/irq.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+static __inline__ int irq_cannonicalize(int irq)
+{
+	return ((irq == 2) ? 9 : irq);
+}
+
+extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
+extern void enable_irq(unsigned int);
+
+
+# 37 "pc_keyb.c" 2
+
+
+
+ 
+
+# 1 "/usr/src/linux/include/linux/pc_keyb.h" 1
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+extern unsigned char pckbd_read_mask;
+extern unsigned char aux_device_present;
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct aux_queue {
+	unsigned long head;
+	unsigned long tail;
+	struct wait_queue *proc_list;
+	struct fasync_struct *fasync;
+	unsigned char buf[2048 ];
+};
+# 42 "pc_keyb.c" 2
+
+
+ 
+
+# 55 "pc_keyb.c"
+
+
+static void kbd_write_command_w(int data);
+static void kbd_write_output_w(int data);
+
+static void aux_write_ack(int val);
+
+
+//spinlock_t kbd_controller_lock = (spinlock_t) { } ;   // INVALID
+static unsigned char handle_kbd_event(void);
+
+ 
+static volatile unsigned char reply_expected = 0;
+static volatile unsigned char acknowledge = 0;
+static volatile unsigned char resend = 0;
+
+
+
+ 
+
+
+
+static int __attribute__ ((__section__ (".text.init")))  psaux_init(void);
+
+
+ 
+
+static struct aux_queue *queue;	 
+static int aux_count = 0;
+ 
+static unsigned char mouse_reply_expected = 0;
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+static void kb_wait(void)
+{
+	unsigned long timeout = 250 ;
+
+	do {
+		 
+
+
+
+		unsigned char status = handle_kbd_event();
+
+		if (! (status & 0x02 ))
+			return;
+		(	(__builtin_constant_p( 1 ) && ( 1 )<= 5 ) ? (__builtin_constant_p( ( 1 )*1000 ) ? __const_udelay(( ( 1 )*1000 ) * 0x10c6ul) : __udelay( ( 1 )*1000 ))  : ({unsigned long msec=( 1 ); while (msec--) (__builtin_constant_p( 1000 ) ? __const_udelay(( 1000 ) * 0x10c6ul) : __udelay( 1000 )) ;})) ;
+		timeout--;
+	} while (timeout);
+
+	printk("<4>"  "Keyboard timed out[1]\n");
+
+}
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+static unsigned char high_keys[128 - 89 ] = {
+  124 , 125 , 126 , 127 , 0, 0, 0,                    
+  0, 0, 0, 0, 0, 0, 0, 0,                             
+  0, 0, 0, 0, 0, 122 , 0, 123 ,           
+  0, 0, 0, 89 , 120 , 0, 0, 90 ,     
+  91 , 92 , 93 , 94 ,         
+  95 , 124 , 121 , 0                    
+};
+
+ 
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+static unsigned char e0_keys[128] = {
+  0, 0, 0, 0, 0, 0, 0, 0,			       
+  0, 0, 0, 0, 0, 0, 0, 0,			       
+  0, 0, 0, 0, 0, 0, 0, 0,			       
+  0, 0, 0, 0, 96 , 97 , 0, 0,	       
+  0, 0, 0, 0, 0, 0, 0, 0,			       
+  0, 0, 0, 0, 0, 0, 0, 0,			       
+  0, 0, 0, 0, 0, 98 , 0, 99 ,	       
+  100 , 0, 0, 0, 0, 113 , 114 , 115 ,	       
+  116 , 117 , 0, 0, 0, 0, 101 , 102 ,	       
+  103 , 104 , 0, 105 , 124 , 106 , 118 , 107 , 
+  108 , 109 , 110 , 111 , 0, 0, 0, 0,	       
+  0, 0, 0, 125 , 126 , 127 , 0, 0,	       
+  0, 0, 0, 0, 0, 0, 0, 0,			       
+  0, 0, 0, 0, 0, 0, 0, 112 ,		       
+  0, 0, 0, 0, 0, 0, 0, 0,			       
+  0, 0, 0, 0, 0, 0, 0, 0			       
+};
+
+int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	if (scancode < 89  || scancode > 255 || keycode > 127)
+	  return - 22 ;
+	if (scancode < 128)
+	  high_keys[scancode - 89 ] = keycode;
+	else
+	  e0_keys[scancode - 128] = keycode;
+	return 0;
+}
+
+int pckbd_getkeycode(unsigned int scancode)
+{
+	return
+	  (scancode < 89  || scancode > 255) ? - 22  :
+	  (scancode < 128) ? high_keys[scancode - 89 ] :
+	    e0_keys[scancode - 128];
+}
+
+static int do_acknowledge(unsigned char scancode)
+{
+	if (reply_expected) {
+	   
+
+
+
+
+		if (scancode == 0xFA ) {
+			acknowledge = 1;
+			reply_expected = 0;
+			return 0;
+		} else if (scancode == 0xFE ) {
+			resend = 1;
+			reply_expected = 0;
+			return 0;
+		}
+		 
+
+
+
+
+	}
+	return 1;
+}
+
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+		    char raw_mode)
+{
+	static int prev_scancode = 0;
+
+	 
+	if (scancode == 0xe0 || scancode == 0xe1) {
+		prev_scancode = scancode;
+		return 0;
+	}
+
+	 
+	if (scancode == 0x00 || scancode == 0xff) {
+		prev_scancode = 0;
+		return 0;
+	}
+
+	scancode &= 0x7f;
+
+	if (prev_scancode) {
+	   
+
+
+
+	  if (prev_scancode != 0xe0) {
+	      if (prev_scancode == 0xe1 && scancode == 0x1d) {
+		  prev_scancode = 0x100;
+		  return 0;
+	      } else if (prev_scancode == 0x100 && scancode == 0x45) {
+		  *keycode = 119 ;
+		  prev_scancode = 0;
+	      } else {
+
+		  if (!raw_mode)
+		    printk("<6>"  "keyboard: unknown e1 escape sequence\n");
+
+		  prev_scancode = 0;
+		  return 0;
+	      }
+	  } else {
+	      prev_scancode = 0;
+	       
+
+
+
+
+
+
+	       
+
+
+
+
+
+	      if (scancode == 0x2a || scancode == 0x36)
+		return 0;
+
+	      if (e0_keys[scancode])
+		*keycode = e0_keys[scancode];
+	      else {
+
+		  if (!raw_mode)
+		    printk("<6>"  "keyboard: unknown scancode e0 %02x\n",
+			   scancode);
+
+		  return 0;
+	      }
+	  }
+	} else if (scancode >= 89 ) {
+	     
+
+
+
+
+	     
+
+	     
+
+
+	  *keycode = high_keys[scancode - 89 ];
+
+	  if (!*keycode) {
+	      if (!raw_mode) {
+
+		  printk("<6>"  "keyboard: unrecognized scancode (%02x)"
+			 " - ignored\n", scancode);
+
+	      }
+	      return 0;
+	  }
+ 	} else
+	  *keycode = scancode;
+ 	return 1;
+}
+
+char pckbd_unexpected_up(unsigned char keycode)
+{
+	 
+
+	if (keycode >= 89  || keycode == 85)
+	    return 0;
+	else
+	    return 0200;
+}
+
+static inline void handle_mouse_event(unsigned char scancode)
+{
+
+	if (mouse_reply_expected) {
+		if (scancode == 0xFA ) {
+			mouse_reply_expected--;
+			return;
+		}
+		mouse_reply_expected = 0;
+	}
+    else if(scancode == 170 ){
+        queue->head = queue->tail = 0;   
+         
+	kb_wait();
+	outb( 0xD4  , 0x64 ) ;
+	kb_wait();
+	outb( 0xF4  , 0x60 ) ;
+	 
+	mouse_reply_expected++;
+	kb_wait();
+        return;
+    }
+
+	add_mouse_randomness(scancode);
+	if (aux_count) {
+		int head = queue->head;
+
+		queue->buf[head] = scancode;
+		head = (head + 1) & (2048 -1);
+		if (head != queue->tail) {
+			queue->head = head;
+			if (queue->fasync)
+				kill_fasync(queue->fasync, 29 );
+			__wake_up(( &queue->proc_list ),1 ) ;
+		}
+	}
+
+}
+
+ 
+
+
+
+
+
+
+static unsigned char handle_kbd_event(void)
+{
+	unsigned char status = inb(0x64 ) ;
+	unsigned int work = 10000;
+
+	while (status & 0x01 ) {
+		unsigned char scancode;
+
+		scancode = inb(0x60 ) ;
+
+
+
+		if (status & 0x20 ) {
+			handle_mouse_event(scancode);
+		} else {
+			if (do_acknowledge(scancode))
+				handle_scancode(scancode, !(scancode & 0x80));
+			mark_bh(KEYBOARD_BH);
+		}
+
+		status = inb(0x64 ) ;
+		
+		if(!work--)
+		{
+			printk("<3>"  "pc_keyb: controller jammed (0x%02X).\n",
+				status);
+			break;
+		}
+	}
+
+	return status;
+}
+
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	kbd_pt_regs = regs;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	handle_kbd_event();
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+ 
+
+
+
+
+
+
+static int send_data(unsigned char data)
+{
+	int retries = 3;
+
+	do {
+		unsigned long timeout = 1000 ;
+
+		acknowledge = 0;  
+		resend = 0;
+		reply_expected = 1;
+		kbd_write_output_w(data);
+		for (;;) {
+			if (acknowledge)
+				return 1;
+			if (resend)
+				break;
+			(	(__builtin_constant_p( 1 ) && ( 1 )<= 5 ) ? (__builtin_constant_p( ( 1 )*1000 ) ? __const_udelay(( ( 1 )*1000 ) * 0x10c6ul) : __udelay( ( 1 )*1000 ))  : ({unsigned long msec=( 1 ); while (msec--) (__builtin_constant_p( 1000 ) ? __const_udelay(( 1000 ) * 0x10c6ul) : __udelay( 1000 )) ;})) ;
+			if (!--timeout) {
+
+				printk("<4>"  "Keyboard timeout[2]\n");
+
+				return 0;
+			}
+		}
+	} while (retries-- > 0);
+
+	printk("<4>"  "keyboard: Too many NACKs -- noisy kbd cable?\n");
+
+	return 0;
+}
+
+void pckbd_leds(unsigned char leds)
+{
+	if (!send_data(0xED ) || !send_data(leds))
+	    send_data(0xF4 );	 
+}
+
+ 
+
+
+
+
+
+
+
+
+
+ int kbd_startup_reset __attribute__ ((__section__ (".data.init")))  = 0;
+
+
+
+
+ 
+void __attribute__ ((__section__ (".text.init")))  kbd_reset_setup(char *str, int *ints)
+{
+	kbd_startup_reset = 1;
+}
+
+
+
+
+static int __attribute__ ((__section__ (".text.init")))  kbd_read_data(void)
+{
+	int retval = (-1) ;
+	unsigned char status;
+
+	status = inb(0x64 ) ;
+	if (status & 0x01 ) {
+		unsigned char data = inb(0x60 ) ;
+
+		retval = data;
+		if (status & (0x40  | 0x80 ))
+			retval = (-2) ;
+	}
+	return retval;
+}
+
+static void __attribute__ ((__section__ (".text.init")))  kbd_clear_input(void)
+{
+	int maxread = 100;	 
+
+	do {
+		if (kbd_read_data() == (-1) )
+			break;
+	} while (--maxread);
+}
+
+static int __attribute__ ((__section__ (".text.init")))  kbd_wait_for_input(void)
+{
+	long timeout = 1000 ;
+
+	do {
+		int retval = kbd_read_data();
+		if (retval >= 0)
+			return retval;
+		(	(__builtin_constant_p( 1 ) && ( 1 )<= 5 ) ? (__builtin_constant_p( ( 1 )*1000 ) ? __const_udelay(( ( 1 )*1000 ) * 0x10c6ul) : __udelay( ( 1 )*1000 ))  : ({unsigned long msec=( 1 ); while (msec--) (__builtin_constant_p( 1000 ) ? __const_udelay(( 1000 ) * 0x10c6ul) : __udelay( 1000 )) ;})) ;
+	} while (--timeout);
+	return -1;
+}
+
+static void kbd_write_command_w(int data)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	kb_wait();
+	outb( data , 0x64 ) ;
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+static void kbd_write_output_w(int data)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	kb_wait();
+	outb( data , 0x60 ) ;
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+
+static void kbd_write_cmd(int cmd)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	kb_wait();
+	outb( 0x60  , 0x64 ) ;
+	kb_wait();
+	outb( cmd , 0x60 ) ;
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+
+static char * __attribute__ ((__section__ (".text.init")))  initialize_kbd(void)
+{
+	int status;
+
+	 
+
+
+
+
+	kbd_write_command_w(0xAA );
+	if (kbd_wait_for_input() != 0x55)
+		return "Keyboard failed self test";
+
+	 
+
+
+
+
+	kbd_write_command_w(0xAB );
+	if (kbd_wait_for_input() != 0x00)
+		return "Keyboard interface failed self test";
+
+	 
+
+
+	kbd_write_command_w(0xAE );
+
+	 
+
+
+
+
+
+
+
+	do {
+		kbd_write_output_w(0xFF );
+		status = kbd_wait_for_input();
+		if (status == 0xFA )
+			break;
+		if (status != 0xFE )
+			return "Keyboard reset failed, no ACK";
+	} while (1);
+
+	if (kbd_wait_for_input() != 0xAA )
+		return "Keyboard reset failed, no POR";
+
+	 
+
+
+
+
+
+	do {
+		kbd_write_output_w(0xF5 );
+		status = kbd_wait_for_input();
+		if (status == 0xFA )
+			break;
+		if (status != 0xFE )
+			return "Disable keyboard: no ACK";
+	} while (1);
+
+	kbd_write_command_w(0x60 );
+	kbd_write_output_w(0x01 
+			      | 0x04 
+			      | 0x20 
+			      | 0x40 );
+
+	 
+	kbd_write_command_w(0x20 );
+	if (!(kbd_wait_for_input() & 0x40 )) {
+		 
+
+
+
+		kbd_write_output_w(0xF0);
+		kbd_wait_for_input();
+		kbd_write_output_w(0x01);
+		kbd_wait_for_input();
+	}
+
+	
+	kbd_write_output_w(0xF4 );
+	if (kbd_wait_for_input() != 0xFA )
+		return "Enable keyboard: no ACK";
+
+	 
+
+
+	kbd_write_output_w(0xF3 );
+	if (kbd_wait_for_input() != 0xFA )
+		return "Set rate: no ACK";
+	kbd_write_output_w(0x00);
+	if (kbd_wait_for_input() != 0xFA )
+		return "Set rate: no ACK";
+
+	return ((void *)0) ;
+}
+
+void __attribute__ ((__section__ (".text.init")))  pckbd_init_hw(void)
+{
+	request_region(0x60, 16, "keyboard") ;
+
+	 
+	kbd_clear_input();
+
+	if (kbd_startup_reset) {
+		char *msg = initialize_kbd();
+		if (msg)
+			printk("<4>"  "initialize_kbd: %s\n", msg);
+	}
+
+
+	psaux_init();
+
+
+	 
+	request_irq(1 ,  keyboard_interrupt , 0, "keyboard", ((void *)0) ) ;
+}
+
+
+
+ 
+
+
+static int __attribute__ ((__section__ (".text.init")))  detect_auxiliary_port(void)
+{
+	unsigned long flags;
+	int loops = 10;
+	int retval = 0;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+
+	 
+
+
+
+
+
+
+	kb_wait();
+	outb( 0xD3  , 0x64 ) ;
+
+	kb_wait();
+	outb( 0x5a , 0x60 ) ;  
+
+	do {
+		unsigned char status = inb(0x64 ) ;
+
+		if (status & 0x01 ) {
+			(void) inb(0x60 ) ;
+			if (status & 0x20 ) {
+				printk("<6>"  "Detected PS/2 Mouse Port.\n");
+				retval = 1;
+			}
+			break;
+		}
+		(	(__builtin_constant_p( 1 ) && ( 1 )<= 5 ) ? (__builtin_constant_p( ( 1 )*1000 ) ? __const_udelay(( ( 1 )*1000 ) * 0x10c6ul) : __udelay( ( 1 )*1000 ))  : ({unsigned long msec=( 1 ); while (msec--) (__builtin_constant_p( 1000 ) ? __const_udelay(( 1000 ) * 0x10c6ul) : __udelay( 1000 )) ;})) ;
+	} while (--loops);
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+
+	return retval;
+}
+
+ 
+
+
+static void aux_write_dev(int val)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	kb_wait();
+	outb( 0xD4  , 0x64 ) ;
+	kb_wait();
+	outb( val , 0x60 ) ;
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+ 
+
+
+static void aux_write_ack(int val)
+{
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	kb_wait();
+	outb( 0xD4  , 0x64 ) ;
+	kb_wait();
+	outb( val , 0x60 ) ;
+	 
+	mouse_reply_expected++;
+	kb_wait();
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+}
+
+static unsigned char get_from_queue(void)
+{
+	unsigned char result;
+	unsigned long flags;
+
+	do { __asm__ __volatile__("pushfl ; popl %0":"=g" (    flags   ):   :"memory")  ; __asm__ __volatile__ ("cli": : :"memory")  ; } while (0) ;
+	result = queue->buf[queue->tail];
+	queue->tail = (queue->tail + 1) & (2048 -1);
+	__asm__ __volatile__("pushl %0 ; popfl":   :"g" (    flags   ):"memory")   ;
+	return result;
+}
+
+
+static inline int queue_empty(void)
+{
+	return queue->head == queue->tail;
+}
+
+static int fasync_aux(int fd, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(fd, filp, on, &queue->fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+
+ 
+
+
+
+
+static int release_aux(struct inode * inode, struct file * file)
+{
+	fasync_aux(-1, file, 0);
+	if (--aux_count)
+		return 0;
+	kbd_write_cmd((0x40  | 0x20  | 0x04  | 0x01 ) );			     
+	kbd_write_command_w(0xA7 );
+	free_irq(12 ,  ((void *)queue)  ) ;
+	return 0;
+}
+
+ 
+
+
+
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+	if (aux_count++) {
+		return 0;
+	}
+	queue->head = queue->tail = 0;		 
+	if (request_irq(12 ,  keyboard_interrupt , 0x04000000 , "PS/2 Mouse",   ((void *)queue)  ) ) {
+		aux_count--;
+		return - 16 ;
+	}
+	kbd_write_command_w(0xA8 );	 
+
+
+	aux_write_ack(0xF4 );  
+	kbd_write_cmd((0x40  | 0x04  | 0x02  | 0x01 ) );  
+
+	return 0;
+}
+
+ 
+
+
+
+static ssize_t read_aux(struct file * file, char * buffer,
+			size_t count, loff_t *ppos)
+{
+	struct wait_queue wait = { get_current() , ((void *)0)  };
+	ssize_t i = count;
+	unsigned char c;
+
+	if (queue_empty()) {
+		if (file->f_flags & 04000 )
+			return - 11 ;
+		add_wait_queue(&queue->proc_list, &wait);
+repeat:
+		get_current() ->state = 1 ;
+		if (queue_empty() && !signal_pending(get_current() )) {
+			schedule();
+			goto repeat;
+		}
+		get_current() ->state = 0 ;
+		remove_wait_queue(&queue->proc_list, &wait);
+	}
+	while (i > 0 && !queue_empty()) {
+		c = get_from_queue();
+		({	int __ret_pu;	switch(sizeof (*(  buffer++ ))) {	case 1:  __asm__ __volatile__("call __put_user_" "1"	:"=a" ( __ret_pu )	:"0" (   buffer++  ),"d" ( (__typeof__(*(  buffer++ )))( c ) )	:"cx") ; break;	case 2:  __asm__ __volatile__("call __put_user_" "2"	:"=a" ( __ret_pu )	:"0" (   buffer++  ),"d" ( (__typeof__(*(  buffer++ )))( c ) )	:"cx") ; break;	case 4:  __asm__ __volatile__("call __put_user_" "4"	:"=a" ( __ret_pu )	:"0" (   buffer++  ),"d" ( (__typeof__(*(  buffer++ )))( c ) )	:"cx") ; break;	default: __asm__ __volatile__("call __put_user_" "X"	:"=a" ( __ret_pu )	:"0" (   buffer++  ),"d" (  c  )	:"cx") ; break;	}	__ret_pu;	}) ;
+		i--;
+	}
+	if (count-i) {
+		file->f_dentry->d_inode->i_atime = (xtime.tv_sec) ;
+		return count-i;
+	}
+	if (signal_pending(get_current() ))
+		return - 512 ;
+	return 0;
+}
+
+ 
+
+
+
+static ssize_t write_aux(struct file * file, const char * buffer,
+			 size_t count, loff_t *ppos)
+{
+	ssize_t retval = 0;
+
+	if (count) {
+		ssize_t written = 0;
+
+		if (count > 32)
+			count = 32;  
+		do {
+			char c;
+//			({	int __ret_gu,__val_gu;	switch(sizeof (*(  buffer++ ))) {	case 1:  __asm__ __volatile__("call __get_user_" "1" :"=a" ( __ret_gu ),"=d" ( __val_gu ) :"0" (   buffer++  )) ; break;	case 2:  __asm__ __volatile__("call __get_user_" "2" :"=a" ( __ret_gu ),"=d" ( __val_gu ) :"0" (   buffer++  )) ; break;	case 4:  __asm__ __volatile__("call __get_user_" "4" :"=a" ( __ret_gu ),"=d" ( __val_gu ) :"0" (   buffer++  )) ; break;	default: __asm__ __volatile__("call __get_user_" "X" :"=a" ( __ret_gu ),"=d" ( __val_gu ) :"0" (   buffer++  )) ; break;	}	( c ) = (__typeof__(*(  buffer++ )))__val_gu;	__ret_gu;	}) ;    // TYPEOF
+			aux_write_dev(c);
+			written++;
+		} while (--count);
+		retval = - 5 ;
+		if (written) {
+			retval = written;
+			file->f_dentry->d_inode->i_mtime = (xtime.tv_sec) ;
+		}
+	}
+
+	return retval;
+}
+
+static unsigned int aux_poll(struct file *file, poll_table * wait)
+{
+	poll_wait(file, &queue->proc_list, wait);
+	if (!queue_empty())
+		return 0x0001  | 0x0040 ;
+	return 0;
+}
+
+struct file_operations psaux_fops = {
+	((void *)0) ,		 
+	read_aux,
+	write_aux,
+	((void *)0) , 		 
+	aux_poll,
+	((void *)0) , 		 
+	((void *)0) ,		 
+	open_aux,
+	((void *)0) ,		 
+	release_aux,
+	((void *)0) ,
+	fasync_aux,
+};
+
+ 
+
+
+static struct miscdevice psaux_mouse = {
+	1 , "psaux", &psaux_fops
+};
+
+static int __attribute__ ((__section__ (".text.init")))  psaux_init(void)
+{
+	if (!detect_auxiliary_port())
+		return - 5 ;
+
+	misc_register(&psaux_mouse);
+	queue = (struct aux_queue *) kmalloc(sizeof(*queue), (0x04  | 0x01  | 0x10 ) );
+	(__builtin_constant_p(  0 ) ? (__builtin_constant_p( (  sizeof(*queue) ) ) ? __constant_c_and_count_memset(( ( queue ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  sizeof(*queue) ) )) : __constant_c_memset(( ( queue ) ),( (0x01010101UL*(unsigned char)(  0 )) ),( (  sizeof(*queue) ) )))  : (__builtin_constant_p( (  sizeof(*queue) ) ) ? __memset_generic(( ( ( queue ) ) ),( ( (  0 ) ) ),( ( (  sizeof(*queue) ) ) ))  : __memset_generic(( ( queue ) ),( (  0 ) ),( (  sizeof(*queue) ) ))) ) ;
+	queue->head = queue->tail = 0;
+	queue->proc_list = ((void *)0) ;
+
+
+
+
+
+
+
+
+
+	outb( 0xA7  , 0x64 ) ;  
+	kbd_write_cmd((0x40  | 0x20  | 0x04  | 0x01 ) );  
+
+	return 0;
+}
+
+

Added: vendor/elsa/current/elkhound/in/qpsmall.i
===================================================================
--- vendor/elsa/current/elkhound/in/qpsmall.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/qpsmall.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,680 @@
+# 1 "qpmouse.c"
+ 
+
+
+static __inline__ void atomic_sub(int i, volatile atomic_t *v)
+{
+	__asm__ __volatile__(
+		""  "subl %1,%0"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) )
+		:"ir" (i), "m" ((*(volatile struct { int a[100]; } *) v ) ));
+}
+
+
+union task_union {
+	struct task_struct task;
+	unsigned long stack[2048];
+};
+
+extern union task_union init_task_union;
+
+extern struct   mm_struct init_mm;
+extern struct task_struct *task[512 ];
+
+extern struct task_struct **tarray_freelist;
+extern spinlock_t taskslot_lock;
+
+extern __inline__ void add_free_taskslot(struct task_struct **t)
+{
+	(void)( &taskslot_lock ) ;
+	*t = (struct task_struct *) tarray_freelist;
+	tarray_freelist = t;
+	do { } while(0) ;
+}
+
+extern __inline__ struct task_struct **get_free_taskslot(void)
+{
+	struct task_struct **tslot;
+
+	(void)( &taskslot_lock ) ;
+	if((tslot = tarray_freelist) != ((void *)0) )
+		tarray_freelist = (struct task_struct **) *tslot;
+	do { } while(0) ;
+
+	return tslot;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/home/scott/wrk/driver/linux/include/linux/module.h" 1
+ 
+
+
+
+
+
+
+
+
+# 1 "/home/scott/wrk/driver/linux/include/linux/config.h" 1
+
+
+
+# 1 "/home/scott/wrk/driver/linux/include/linux/autoconf.h" 1
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+# 4 "/home/scott/wrk/driver/linux/include/linux/config.h" 2
+
+
+
+# 10 "/home/scott/wrk/driver/linux/include/linux/module.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/home/scott/wrk/driver/linux/include/asm/atomic.h" 1
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+typedef struct { int counter; } atomic_t;
+
+
+
+
+
+
+
+static __inline__ void atomic_add(int i, volatile atomic_t *v)
+{
+	__asm__ __volatile__(
+		""  "addl %1,%0"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) )
+		:"ir" (i), "m" ((*(volatile struct { int a[100]; } *) v ) ));
+}
+
+static __inline__ void atomic_sub(int i, volatile atomic_t *v)
+{
+	__asm__ __volatile__(
+		""  "subl %1,%0"
+		:"=m" ((*(volatile struct { int a[100]; } *) v ) )
+		:"ir" (i), "m" ((*(volatile struct { int a[100]; } *) v ) ));
+}

Added: vendor/elsa/current/elkhound/in/qsort.c.in5
===================================================================
--- vendor/elsa/current/elkhound/in/qsort.c.in5	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/qsort.c.in5	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,94 @@
+#/* qsort.c (translated to C) */
+#/* quicksort for mutation testing  */
+
+##include <stdlib.h>     /* rand() */
+
+#/* ------------ FUNCTIONALITY ------------------- */
+#/* sort 'array' into ascending order */
+#/* bugs: this has especially bad behavior when the array is mostly */
+#/*       one element, but a single other element with lower value */
+#/*       than the rest.  e.g., 2 2 2 2 2 1 2 2 2 2 2 2 2 2 */
+void quickSort(int *array, int len)
+{
+  int pivotIndex, pivot, low, high;
+
+  #/* base case */
+  if (len <= 1) {
+    return;
+  }
+
+  #/* select pivot */
+  pivotIndex = rand() % len;
+  pivot = array[pivotIndex];
+
+  #/* partition */
+  low = 0;
+  high = len-1;
+  while (low < high) {
+    while (low < len &&
+           array[low] <= pivot) {
+      low++;
+    }
+    while (high >= 0 &&	       #/* ATAC: high >= 0 is never false */
+           array[high] > pivot) {     #/* pivots move to low parition */
+      high--;
+    }
+
+    if (low < high) {
+      #/* both low and high are in the wrong places -- swap them */
+      int temp = array[low];
+      array[low] = array[high];
+      array[high] = temp;
+
+      low++;
+      high--;
+    }
+  }
+
+  #/* ATAC: four uses of 'low' below here are never defined from low=0  */
+  #/*       at start of loop					       */
+
+  #/* 'low' is either pointing at the last elt. of the low partition, or */
+  #/* the first elt. of the high partition */
+  if (low < len &&
+      array[low] <= pivot) {
+    low++;     #/* make it point at first elt. of high partition */
+      #/* ATAC: never a use of low++ in first inner while loop */
+  }
+
+  if (low == len) {
+    #/* the entire array is in the low partition.. we check to see if it's already */
+    #/* sorted, because in particular if the array contains the same element in */
+    #/* every position, then we never accomplish anything by partitioning */
+
+    #/* is it already sorted? */
+    int i;
+    for (i=1; i<len; i++) {
+      if (array[i-1] > array[i]) {
+        break;   #/* not sorted */
+      }
+    }
+
+    if (i == len) {
+      #/* array is already sorted */
+      return;
+    }
+
+    #/* tail-recurse and try again */
+    quickSort(array, len);
+    return;
+  }
+
+  #/* recursively sort partitions */
+  quickSort(array, low);
+  quickSort(array+low, len-low);
+}
+
+
+#/* linkage */
+void sortAlgorithm(int *array, int len)
+{
+  quickSort(array, len);
+}
+
+

Added: vendor/elsa/current/elkhound/in/ssh-add2.c
===================================================================
--- vendor/elsa/current/elkhound/in/ssh-add2.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/in/ssh-add2.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,964 @@
+/*
+
+ssh-add.c
+
+  Authors:
+        Tatu Ylonen <ylo at ssh.com>
+        Markku-Juhani Saarinen <mjos at ssh.com>
+        Timo J. Rinne <tri at ssh.com>
+        Sami Lehtinen <sjl at ssh.com>
+
+  Copyright (C) 1997-2000 SSH Communications Security Corp, Helsinki, Finland
+  All rights reserved.
+
+  Adds an identity to the authentication server, or removes an identity.
+
+*/
+
+/*
+ * $Id: ssh-add2.c 467 2002-08-11 00:17:28Z scott $
+ * $Log$
+ * Revision 1.1  2002/08/11 00:17:28  scott
+ * removed some obsolete files, moved more input to in/
+ *
+ * Revision 1.1  2000/07/28 08:39:56  scott
+ * everything works and I can parse ssh-add2
+ * I am now working on improving the performance
+ *
+ * $EndLog$
+ */
+
+#include "sshincludes.h"
+#include "sshcrypt.h"
+#include "sshtimeouts.h"
+#include "sshuserfiles.h"
+#include "sshagent.h"
+#include "sshuser.h"
+#include "readpass.h"
+#include "sshuserfiles.h"
+#include "ssheloop.h"
+#include "sshgetopt.h"
+#include "sshmiscstring.h"
+#ifdef WITH_PGP
+#include "sshbuffer.h"
+#include "sshfilebuffer.h"
+#include "sshpgp.h"
+#include "ssh2pgp.h"
+#include "ssh2pubkeyencode.h"
+#include "ssh1keydecode.h"
+#endif /* WITH_PGP */
+#include "sshdsprintf.h"
+
+#define SSH_DEBUG_MODULE "SshAdd"
+
+#ifdef HAVE_LIBWRAP
+int allow_severity = SSH_LOG_INFORMATIONAL;
+int deny_severity = SSH_LOG_WARNING;
+#endif /* HAVE_LIBWRAP */
+
+#define EXIT_STATUS_OK          0
+#define EXIT_STATUS_NOAGENT     1
+#define EXIT_STATUS_BADPASS     2
+#define EXIT_STATUS_NOFILE      3
+#define EXIT_STATUS_NOIDENTITY  4
+#define EXIT_STATUS_ERROR       5
+
+typedef enum 
+{ 
+  LIST, 
+  ADD, 
+  ADD_URL,
+  DELETE,
+  DELETE_URL,
+  DELETE_ALL, 
+  LOCK, 
+  UNLOCK 
+} SshAgentAction;
+
+#ifdef WITH_PGP
+typedef enum
+{
+  PGP_KEY_NONE = 0,
+  PGP_KEY_NAME,
+  PGP_KEY_FINGERPRINT,
+  PGP_KEY_ID
+} SshAgentPgpKeyMode;
+#endif /* WITH_PGP */
+
+char *av0;
+
+/* Files to add/delete from agent. */
+char **files;
+int num_files;
+SshAgentAction action;
+#ifdef WITH_PGP
+SshAgentPgpKeyMode pgp_mode = PGP_KEY_NONE;
+char *pgp_keyring;
+#endif /* WITH_PGP */
+
+/* Possible attributes */
+SshUInt32 path_limit = 0xffffffff;
+char *path_constraint = NULL;
+Boolean forbid_compat = FALSE;
+SshTime key_timeout = 0;
+Boolean have_attrs = FALSE;
+SshUInt32 use_limit = 0xffffffff;
+
+/* Force to read passphrases from stdin. */
+int use_stdin = FALSE;
+
+/* Information about the current user. */
+SshUser user;
+
+void agent_completion(SshAgentError result, void *context);
+
+void add_file(SshAgent agent, const char *filename)
+{
+  SshPrivateKey key = NULL;
+  char *saved_comment, *comment = NULL, *pass;
+  int query_cnt;
+  unsigned char *certs = NULL;
+  size_t certs_len;
+  char privname[500], pubname[500];
+  unsigned long magic;
+  struct stat st;
+
+  if (action == ADD_URL)
+    {
+      printf("Adding URL identity: %s\n", filename);
+      snprintf(privname, sizeof(privname), "%s", filename);
+      if (have_attrs)
+        ssh_agent_add_with_attrs(agent, NULL, NULL, 0, privname,
+                                 path_limit, path_constraint, use_limit,
+                                 forbid_compat, key_timeout,
+                                 agent_completion, (void *)agent);
+      else
+        ssh_agent_add(agent, NULL, NULL, 0, privname,
+                      agent_completion, (void *)agent);
+      return;
+    }
+  else if (action == DELETE_URL)
+    {
+      printf("Deleting URL identity: %s\n", filename);
+      snprintf(privname, sizeof(privname), "%s", filename);
+      ssh_agent_delete(agent, NULL, 0, privname,
+                       agent_completion, (void *)agent);
+      return;
+    }
+#ifdef WITH_PGP
+  if (pgp_mode == PGP_KEY_NONE)
+#endif /* WITH_PGP */
+    {
+      /* Construct the names of the public and private key files. */
+      if (strlen(filename) > 4 &&
+          strcmp(filename + strlen(filename) - 4, ".pub") == 0)
+        {
+          snprintf(pubname, sizeof(pubname), "%s", filename);
+          snprintf(privname, sizeof(privname), "%s", filename);
+          privname[strlen(privname) - 4] = '\0';
+        }
+      else
+        {
+          snprintf(pubname, sizeof(pubname), "%s.pub", filename);
+          snprintf(privname, sizeof(privname), "%s", filename);
+        }
+    
+      if (action == ADD)
+        printf("Adding identity: %s\n", pubname);
+      else if (action == DELETE)
+        printf("Deleting identity: %s\n", pubname);
+    
+      if (stat(pubname, &st) < 0)
+        {
+          printf("Public key file %s does not exist.\n", pubname);
+          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+          return;
+        }
+    
+      if (stat(privname, &st) < 0)
+        {
+          printf("Private key file %s does not exist.\n", privname);
+          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+          return;
+        }
+    
+      /* Read the public key blob. */
+      magic = ssh2_key_blob_read(user, 
+                                 pubname,
+                                 TRUE,
+                                 &saved_comment,
+                                 &certs, 
+                                 &certs_len,
+                                 NULL);
+      if (magic != SSH_KEY_MAGIC_PUBLIC)
+        {
+          printf("Bad public key file %s\n", pubname);
+          ssh_xfree(certs);
+          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+          return;
+        }
+    
+      if (action == ADD)
+        {
+          /* Loop until we manage to load the file, or a maximum number of
+             attempts have been made.  First try with an empty passphrase. */
+          pass = ssh_xstrdup("");
+          query_cnt = 0;
+          while ((key = ssh_privkey_read(user, 
+                                         privname,
+                                         pass, 
+                                         &comment, 
+                                         NULL)) == NULL)
+            {
+              char buf[1024];
+              FILE *f;
+            
+              /* Free the old passphrase. */
+              memset(pass, 0, strlen(pass));
+              ssh_xfree(pass);
+            
+              query_cnt++;
+              if (query_cnt > 5)
+                {
+                  fprintf(stderr,
+                          "You don't seem to know the correct passphrase.\n");
+                  exit(EXIT_STATUS_BADPASS);
+                }
+            
+              /* Ask for a passphrase. */
+              if (!use_stdin && getenv("DISPLAY") && !isatty(fileno(stdin)))
+                {
+                  snprintf(buf, sizeof(buf),
+                           "ssh-askpass2 '%sEnter passphrase for %.100s'", 
+                           ((query_cnt <= 1) ? 
+                            "" : 
+                            "You entered wrong passphrase.  "), 
+                           saved_comment);
+                  f = popen(buf, "r");
+                  if (!fgets(buf, sizeof(buf), f))
+                    {
+                      pclose(f);
+                      ssh_xfree(saved_comment);
+                      exit(EXIT_STATUS_BADPASS);
+                    }
+                  pclose(f);
+                  if (strchr(buf, '\n'))
+                    *strchr(buf, '\n') = 0;
+                  pass = ssh_xstrdup(buf);
+                }
+              else
+                {
+                  if (query_cnt <= 1)
+                    {
+                      if ((strcmp(privname, saved_comment) == 0) ||
+                          (((strlen(privname) + 4) == strlen(saved_comment)) &&
+                           (strncmp(privname, 
+                                    saved_comment, 
+                                    strlen(privname)) == 0)))
+                        {
+                          printf("Need passphrase for %s.\n", 
+                                 privname);
+                        }
+                      else
+                        {
+                          printf("Need passphrase for %s (%s).\n", 
+                                 privname, saved_comment);
+                        }
+                    }
+                  else
+                    {
+                      printf("Bad passphrase.\n");
+                    }
+                  pass = ssh_read_passphrase("Enter passphrase: ", use_stdin);
+                  if (pass == NULL || strcmp(pass, "") == 0)
+                    {
+                      ssh_xfree(saved_comment);
+                      ssh_xfree(pass);
+                      exit(EXIT_STATUS_BADPASS);
+                    }
+                }
+            }
+          memset(pass, 0, strlen(pass));
+          ssh_xfree(pass);
+          ssh_xfree(saved_comment);
+          /* Construct a comment for the key by combining file name and
+             comment in the file. */
+          if ((saved_comment = strrchr(privname, '/')) != NULL)
+            saved_comment++;
+          else
+            saved_comment = privname;
+          saved_comment = ssh_string_concat_3(saved_comment, ": ", comment);
+        }
+      else
+        {
+          /* Construct a comment for the key by combining file name and
+             comment in the file. */
+          if ((saved_comment = strrchr(privname, '/')) != NULL)
+            saved_comment++;
+          else
+            saved_comment = privname;
+          if (comment)
+            saved_comment = ssh_string_concat_3(saved_comment, ": ", comment);
+          else
+            saved_comment = ssh_xstrdup(saved_comment);
+        }
+    
+      if (action == ADD)
+        {
+          /* Send the key to the authentication agent. */
+          if (have_attrs)
+            ssh_agent_add_with_attrs(agent, key, certs, certs_len, 
+                                     saved_comment, path_limit, 
+                                     path_constraint, use_limit,
+                                     forbid_compat, key_timeout,
+                                     agent_completion, (void *)agent);
+          else
+            ssh_agent_add(agent, key, certs, certs_len, saved_comment,
+                          agent_completion, (void *)agent);
+          ssh_private_key_free(key);
+        }
+      else if (action == DELETE)
+        {
+          ssh_agent_delete(agent, certs, certs_len, saved_comment,
+                           agent_completion, (void *)agent);
+        }
+      ssh_xfree(saved_comment);
+    }
+#ifdef WITH_PGP
+  else
+    {
+      unsigned char *blob, *public_blob;
+      size_t blob_len, public_blob_len;
+      Boolean found = FALSE;
+      unsigned long id;
+      char *endptr;
+      SshPgpSecretKey pgp_key;
+      SshPrivateKey key;
+      char buf[1024];
+      FILE *f;
+
+      comment = NULL;
+      switch (pgp_mode)
+        {
+        case PGP_KEY_NAME:
+          found = ssh2_find_pgp_secret_key_with_name(user,
+                                                     pgp_keyring,
+                                                     filename,
+                                                     &blob,
+                                                     &blob_len,
+                                                     &comment);
+          break;
+          
+        case PGP_KEY_FINGERPRINT:
+          found = ssh2_find_pgp_secret_key_with_fingerprint(user,
+                                                            pgp_keyring,
+                                                            filename,
+                                                            &blob,
+                                                            &blob_len,
+                                                            &comment);
+          break;
+          
+        case PGP_KEY_ID:
+          id = strtoul(filename, &endptr, 0);
+          if ((*filename != '\0') && (*endptr == '\0'))
+            {
+              found = ssh2_find_pgp_secret_key_with_id(user,
+                                                       pgp_keyring,
+                                                       id,
+                                                       &blob,
+                                                       &blob_len,
+                                                       &comment);
+            }
+          else
+            {
+              fprintf(stderr, "%s: invalid pgp key id \"%s\".\n", 
+                      av0, filename);
+              found = FALSE;
+            }
+          break;
+          
+        default:
+          ssh_fatal("internal error");
+        }
+      if (! found)
+        {
+          fprintf(stderr, "%s: pgp key \"%s\" not found.\n", 
+                  av0, filename);
+          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+          return;
+        }
+      if (ssh_pgp_secret_key_decode(blob, blob_len, &pgp_key) == 0)
+        {
+          fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
+                  av0, filename);
+          memset(blob, 'F', blob_len);
+          ssh_xfree(blob);
+          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+          return;
+        }
+
+      if ((public_blob_len = ssh_encode_pubkeyblob(pgp_key->public_key->key,
+                                                   &public_blob)) == 0)
+        {
+          fprintf(stderr, "%s: unable to encode pgp key \"%s\".\n", 
+                  av0, filename);
+          ssh_pgp_secret_key_free(pgp_key);
+          memset(blob, 'F', blob_len);
+          ssh_xfree(blob);
+          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+          return;
+        }
+      if (action == ADD)
+        {
+          query_cnt = 0;
+          while ((pgp_key->key == NULL) &&
+                 (pgp_key->decryption_failed == TRUE))
+            {
+              query_cnt++;
+              if (query_cnt > 5)
+                {
+                  fprintf(stderr,
+                          "You don't seem to know the correct passphrase.\n");
+                  exit(EXIT_STATUS_BADPASS);
+                }
+              /* Ask for a passphrase. */
+              if (!use_stdin && getenv("DISPLAY") && !isatty(fileno(stdin)))
+                {
+                  snprintf(buf, sizeof(buf),
+                           "ssh-askpass2 '%sEnter passphrase for \"%.100s\"'", 
+                           ((query_cnt <= 1) ? 
+                            "" : 
+                            "You entered wrong passphrase.  "), 
+                           comment);
+                  f = popen(buf, "r");
+                  if (!fgets(buf, sizeof(buf), f))
+                    {
+                      pclose(f);
+                      fprintf(stderr, "No passphrase.\n");
+                      exit(EXIT_STATUS_BADPASS);
+                    }
+                  pclose(f);
+                  if (strchr(buf, '\n'))
+                    *strchr(buf, '\n') = 0;
+                  pass = ssh_xstrdup(buf);
+                }
+              else
+                {
+                  if (query_cnt <= 1)
+                    printf("Need passphrase for \"%s\".\n", comment);
+                  else
+                    printf("Bad passphrase.\n");
+                  pass = ssh_read_passphrase("Enter passphrase: ", use_stdin);
+                  if (pass == NULL || strcmp(pass, "") == 0)
+                    {
+                      ssh_xfree(pass);
+                      fprintf(stderr, "No passphrase.\n");
+                      exit(EXIT_STATUS_BADPASS);
+                    }
+                }
+              ssh_pgp_secret_key_free(pgp_key);
+              if (ssh_pgp_secret_key_decode_with_passphrase(blob, 
+                                                            blob_len, 
+                                                            pass,
+                                                            &pgp_key) == 0)
+                {
+                  memset(pass, 0, strlen(pass));
+                  ssh_xfree(pass);
+                  fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
+                          av0, filename);
+                  memset(blob, 'F', blob_len);
+                  ssh_xfree(blob);
+                  ssh_xfree(public_blob);
+                  (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+                  return;
+                }
+              memset(pass, 0, strlen(pass));
+              ssh_xfree(pass);
+            }
+          if (pgp_key->key == NULL)
+            {
+              fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
+                      av0, filename);
+              ssh_xfree(public_blob);
+              ssh_pgp_secret_key_free(pgp_key);
+              (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+              return;
+            }
+          memset(blob, 'F', blob_len);
+          ssh_xfree(blob);
+          if (ssh_private_key_copy(pgp_key->key, &key) != SSH_CRYPTO_OK)
+            {
+              fprintf(stderr, "%s: unable to export pgp key \"%s\".\n", 
+                      av0, filename);
+              ssh_pgp_secret_key_free(pgp_key);
+              (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
+              return;
+            }
+          ssh_pgp_secret_key_free(pgp_key);
+          if (have_attrs)
+            ssh_agent_add_with_attrs(agent, key, 
+                                     public_blob, public_blob_len, 
+                                     comment, path_limit, 
+                                     path_constraint, use_limit,
+                                     forbid_compat, key_timeout,
+                                     agent_completion, (void *)agent);
+          else
+            ssh_agent_add(agent, key, 
+                          public_blob, public_blob_len, comment, 
+                          agent_completion, (void *)agent);
+          ssh_xfree(comment);
+          ssh_xfree(public_blob);
+          ssh_private_key_free(key);
+          return;
+        }
+      else if (action == DELETE)
+        {
+          ssh_agent_delete(agent, 
+                           public_blob, 
+                           public_blob_len, 
+                           filename,
+                           agent_completion,
+                           (void *)agent);
+          ssh_pgp_secret_key_free(pgp_key);
+          memset(blob, 'F', blob_len);
+          ssh_xfree(blob);
+          ssh_xfree(public_blob);
+          return;
+        }
+    }
+#endif /* WITH_PGP */
+}
+
+void agent_completion(SshAgentError result, void *context)
+{
+  SshAgent agent = (SshAgent)context;
+
+  switch (result)
+    {
+    case SSH_AGENT_ERROR_OK:
+      break;
+
+    case SSH_AGENT_ERROR_TIMEOUT:
+      fprintf(stderr, "Authentication agent timed out.\n");
+      exit(EXIT_STATUS_NOAGENT);
+      
+    case SSH_AGENT_ERROR_KEY_NOT_FOUND:
+      fprintf(stderr,
+              "Requested key not in possession of authentication agent.\n");
+      exit(EXIT_STATUS_NOIDENTITY);
+      
+    case SSH_AGENT_ERROR_DECRYPT_FAILED:
+      fprintf(stderr, "Decryption failed.\n");
+      exit(EXIT_STATUS_ERROR);
+      
+    case SSH_AGENT_ERROR_SIZE_ERROR:
+      fprintf(stderr, "Argument size error.\n");
+      exit(EXIT_STATUS_ERROR);
+      
+    case SSH_AGENT_ERROR_KEY_NOT_SUITABLE:
+      fprintf(stderr, 
+              "The specified key is not suitable for the operation.\n");
+      exit(EXIT_STATUS_ERROR);
+      
+    case SSH_AGENT_ERROR_DENIED:
+      fprintf(stderr, "The requested operation was denied.\n");
+      exit(EXIT_STATUS_ERROR);
+      
+    case SSH_AGENT_ERROR_FAILURE:
+      fprintf(stderr, "The requested operation failed.\n");
+      exit(EXIT_STATUS_ERROR);
+      
+    case SSH_AGENT_ERROR_UNSUPPORTED_OP:
+      fprintf(stderr, "The requested operation is not supported.\n");
+      exit(EXIT_STATUS_ERROR);
+      
+    case SSH_AGENT_ERROR_BUSY:
+      fprintf(stderr, "The authentication agent is busy.\n");
+      exit(EXIT_STATUS_ERROR);
+      
+    default:
+      fprintf(stderr, "Authentication agent failed with error %d\n",
+              (int)result);
+      exit(EXIT_STATUS_ERROR);
+    }
+
+  /* The last operation was successful.  Check if there is more work to do. */
+  if (num_files <= 0)
+    {
+      /* All operations performed. */
+      exit(EXIT_STATUS_OK);
+    }
+
+  /* Add any files listed. */
+  num_files--;
+  add_file(agent, *files++);
+  /* A callback should already have been scheduled to occur at some point. */
+}
+
+void agent_list_callback(SshAgentError error, unsigned int num_keys,
+                             SshAgentKeyInfo keys, void *context)
+{
+  SshAgent agent = (SshAgent)context;
+  int i;
+
+  if (error != SSH_AGENT_ERROR_OK)
+    {
+      agent_completion(error, (void *)agent);
+      ssh_fatal("agent_list_callback: agent_completion returned after error");
+    }
+
+  if (num_keys == 0)
+    printf("The authorization agent has no keys.\n");
+  else
+    {
+      if (num_keys == 1)
+        printf("The authorization agent has one key:\n");
+      else
+        printf("The authorization agent has %d keys:\n", num_keys);
+      for (i = 0; i < num_keys; i++)
+        printf("%s\n", keys[i].description);
+    }
+  agent_completion(SSH_AGENT_ERROR_OK, (void *)agent);
+}
+
+void agent_open_callback(SshAgent agent, void *context)
+{
+  char buf[1024];
+  FILE *f;
+  char *password, *password_vrfy;
+
+  if (!agent)
+    {
+      fprintf(stderr,
+        "Failed to connect to authentication agent - agent not running?\n");
+      exit(EXIT_STATUS_NOAGENT);
+    }
+
+  switch (action)
+    {
+    case DELETE_ALL:
+      fprintf(stderr, "Deleting all identities.\n");
+      ssh_agent_delete_all(agent, agent_completion, (void *)agent);
+      break;
+      
+    case LIST:
+      fprintf(stderr, "Listing identities.\n");
+      ssh_agent_list(agent, agent_list_callback, (void *)agent);
+      break;
+      
+    case LOCK:
+      if (!use_stdin && getenv("DISPLAY") && !isatty(fileno(stdin)))
+        {
+          snprintf(buf, sizeof (buf),
+                   "ssh-askpass2 'Enter lock passphrase'");
+          f = popen(buf, "r");
+          if (! fgets(buf, sizeof (buf), f))
+            {
+              pclose(f);
+              exit(EXIT_STATUS_BADPASS);
+            }
+          pclose(f);
+          if (strchr(buf, '\n'))
+            *strchr(buf, '\n') = 0;
+          password = ssh_xstrdup(buf);
+        }
+      else
+        {
+          password = ssh_read_passphrase("Enter lock password: ", use_stdin);
+          if (password == NULL)
+            {
+              fprintf(stderr, "Unable to read password.\n");
+                exit(EXIT_STATUS_BADPASS);
+            }
+          password_vrfy = ssh_read_passphrase("Again: ", use_stdin);
+          if (password_vrfy == NULL)
+            {
+              fprintf(stderr, "Unable to read password.\n");
+              exit(EXIT_STATUS_BADPASS);
+            }
+          if (strcmp(password, password_vrfy) != 0)
+            {
+              fprintf(stderr, "Passwords don't match.\n");
+              exit(EXIT_STATUS_BADPASS);
+            }
+        }
+      ssh_agent_lock(agent, password, agent_completion, (void *)agent);
+      break;
+
+    case UNLOCK:
+      if (!use_stdin && getenv("DISPLAY") && !isatty(fileno(stdin)))
+        {
+          snprintf(buf, sizeof (buf),
+                   "ssh-askpass2 'Enter unlock passphrase'");
+          f = popen(buf, "r");
+          if (! fgets(buf, sizeof (buf), f))
+            {
+              pclose(f);
+              exit(EXIT_STATUS_BADPASS);
+            }
+          pclose(f);
+          if (strchr(buf, '\n'))
+            *strchr(buf, '\n') = 0;
+          password = ssh_xstrdup(buf);
+        }
+      else
+        {
+          password = ssh_read_passphrase("Enter lock password: ", use_stdin);
+          if (password == NULL)
+            {
+              exit(EXIT_STATUS_BADPASS);
+            }
+        }
+      ssh_agent_unlock(agent, password, agent_completion, (void *)agent);
+      break;
+
+    case DELETE:
+    case DELETE_URL:
+    case ADD:
+    case ADD_URL:
+      /* Let the completion do all the work. */
+      agent_completion(SSH_AGENT_ERROR_OK, (void *)agent);
+      break;
+
+    default:
+      ssh_fatal("agent_open_callback: bad action %d\n", (int)action);
+    }
+}
+
+void usage(void);
+void usage()
+{
+  fprintf(stderr, "Usage: %s [-l] [-d] [-D] [-p] [-t key_exp] [-f hop_limit] [-1] [files...]\n", av0);
+}
+
+/* This is the main program for the agent. */
+
+int main(int ac, char **av)
+{
+  int opt, i;
+  DIR *ssh2dir = NULL;
+  char *ssh2dirname;
+  Boolean dynamic_array = FALSE;
+  struct dirent * cand;
+
+  /* Save program name. */
+  if (strchr(av[0], '/'))
+    av0 = strrchr(av[0], '/') + 1;
+  else
+    av0 = av[0];
+
+  user = ssh_user_initialize(NULL, FALSE);
+
+#ifdef WITH_PGP
+  pgp_keyring = ssh_xstrdup(SSH_PGP_SECRET_KEY_FILE);
+#endif /* WITH_PGP */
+
+  action = ADD;
+  while ((opt = ssh_getopt(ac, av, "ldDput:f:F:1LUNPI", NULL)) != EOF)
+    {
+      if (!ssh_optval)
+        {
+          usage();
+          exit(EXIT_STATUS_ERROR);
+        }
+      switch (opt)
+        {
+        case 'N':
+#ifdef WITH_PGP
+          pgp_mode = PGP_KEY_NAME;
+#else /* WITH_PGP */
+          fprintf(stderr, "%s: PGP keys not supported.\n", av0);
+          exit(EXIT_STATUS_ERROR);
+#endif /* WITH_PGP */
+          break;
+
+        case 'P':
+#ifdef WITH_PGP
+          pgp_mode = PGP_KEY_FINGERPRINT;
+#else /* WITH_PGP */
+          fprintf(stderr, "%s: PGP keys not supported.\n", av0);
+          exit(EXIT_STATUS_ERROR);
+#endif /* WITH_PGP */
+          break;
+
+        case 'I':
+#ifdef WITH_PGP
+          pgp_mode = PGP_KEY_ID;
+#else /* WITH_PGP */
+          fprintf(stderr, "%s: PGP keys not supported.\n", av0);
+          exit(EXIT_STATUS_ERROR);
+#endif /* WITH_PGP */
+          break;
+
+        case 'R':
+#ifdef WITH_PGP
+          ssh_xfree(pgp_keyring);
+          pgp_keyring = ssh_xstrdup(ssh_optarg);
+#else /* WITH_PGP */
+          fprintf(stderr, "%s: PGP keys not supported.\n", av0);
+          exit(EXIT_STATUS_ERROR);
+#endif /* WITH_PGP */
+          break;
+
+        case 'l':
+          action = LIST;
+          break;
+
+        case 'p':
+          use_stdin = TRUE;
+          break;
+
+        case 'd':
+          if (action == ADD_URL)
+            action = DELETE_URL;
+          else
+            action = DELETE;
+          break;
+
+        case 'D':
+          action = DELETE_ALL;
+          break;
+
+        case 't':
+          if (ssh_optargnum)
+            {
+              key_timeout = (SshTime)(ssh_optargval * 60);
+            }
+          else
+            {
+              usage();
+              exit(EXIT_STATUS_ERROR);
+            }
+          have_attrs = TRUE;
+          break;
+
+        case 'f':
+          if (ssh_optargnum)
+            {
+              path_limit = (SshUInt32)ssh_optargval;
+            }
+          else
+            {
+              usage();
+              exit(EXIT_STATUS_ERROR);
+            }
+          have_attrs = TRUE;
+          break;
+
+        case 'F':
+          path_constraint = ssh_xstrdup(ssh_optarg);
+          have_attrs = TRUE;
+          break;
+
+        case '1':
+          forbid_compat = TRUE;
+          have_attrs = TRUE;
+          break;
+
+        case 'u':
+          if (action == DELETE)
+            action = DELETE_URL;
+          else
+            action = ADD_URL;
+          break;
+
+        case 'L':
+          action = LOCK;
+          break;
+
+        case 'U':
+          action = UNLOCK;
+          break;
+
+        default:
+          usage();
+          exit(EXIT_STATUS_ERROR);
+        }
+    }
+
+#ifdef WITH_PGP
+  if (pgp_keyring[0] != '/')
+    {
+      char buf[1024];
+      snprintf(buf, sizeof (buf), "%s/%s/%s", 
+               ssh_user_dir(user), 
+               SSH_USER_DIR,
+               pgp_keyring);
+      ssh_xfree(pgp_keyring);
+      pgp_keyring = ssh_xstrdup(buf);
+    }
+#endif /* WITH_PGP */
+
+  files = &av[ssh_optind];
+  num_files = ac - ssh_optind;
+
+  /* Fetch default from ~/.ssh2/id_* (the first that we happen to get) */
+
+#define ID_PREFIX "id"
+  
+  if (num_files == 0 && action != LIST && action != DELETE_ALL &&
+      action != LOCK && action != UNLOCK)
+    {
+#ifdef WITH_PGP
+      if (pgp_mode != PGP_KEY_NONE)
+        {
+          fprintf(stderr, "%s: Nothing to do!\n",  av0);
+          exit(EXIT_STATUS_ERROR);
+        }
+#endif /* WITH_PGP */
+      ssh_dsprintf(&ssh2dirname, "%s/%s", ssh_user_dir(user), SSH_USER_DIR);
+      ssh2dir = opendir(ssh2dirname);
+
+      if (!ssh2dir)
+        {
+          fprintf(stderr, "%s: Can't open directory \"%s\"", av0, ssh2dirname);
+          exit(EXIT_STATUS_ERROR);
+        }
+          
+      while ((cand = readdir(ssh2dir)) != NULL)
+        {
+          if ((strlen(cand->d_name) > strlen(ID_PREFIX)) &&
+              (strncmp(cand->d_name, ID_PREFIX, strlen(ID_PREFIX)) == 0) &&
+              ((strlen(cand->d_name) < 4) ||
+               (strcmp(cand->d_name + strlen(cand->d_name) - 4,
+                       ".pub") != 0)) &&
+              ((((cand->d_name)[strlen(ID_PREFIX)]) == '_') ||
+               (((cand->d_name)[strlen(ID_PREFIX)]) == '-') ||
+               (((cand->d_name)[strlen(ID_PREFIX)]) == '.') ||
+               (((cand->d_name)[strlen(ID_PREFIX)]) == '(') ||
+               (((cand->d_name)[strlen(ID_PREFIX)]) == '[') ||
+               (((cand->d_name)[strlen(ID_PREFIX)]) == '<') ||
+               (((cand->d_name)[strlen(ID_PREFIX)]) == '>')))
+            {
+              files = ssh_xcalloc(2, sizeof(char *));
+              ssh_dsprintf(&files[0], "%s/%s", ssh2dirname, cand->d_name);
+              ssh_xfree(ssh2dirname);
+              num_files++;
+              dynamic_array = TRUE;
+              break;
+            }
+        }
+      (void)closedir(ssh2dir);
+    }
+  
+  signal(SIGPIPE, SIG_IGN);
+  
+  ssh_event_loop_initialize();
+  
+  ssh_agent_open(agent_open_callback, NULL);
+
+  ssh_event_loop_run();
+  ssh_event_loop_uninitialize();
+
+  if (dynamic_array)
+    {
+      for(i = 0; i < num_files ; i++)
+        {
+          ssh_xfree(files[i]);
+        }
+      ssh_xfree(files);
+    }
+  
+  ssh_user_free(user, FALSE);
+  exit(EXIT_STATUS_OK);
+}

Added: vendor/elsa/current/elkhound/index.html
===================================================================
--- vendor/elsa/current/elkhound/index.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/index.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,292 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elkhound Overview</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+</HEAD>
+
+<body>
+
+<center><h2>
+Elkhound Overview
+</h2></center>
+
+<p>
+Elkhound is a parser generator, similar to <a
+href="http://www.gnu.org/software/bison/bison.html">Bison</a>.  The
+parsers it generates use the Generalized LR (GLR) parsing algorithm.
+GLR works with <em>any</em> context-free grammar, whereas LR parsers
+(such as Bison) require grammars to be LALR(1).
+
+<p>
+This page is an overview of the implementation.  Additional documentation
+is available:
+<ul>
+<li><a href="manual.html">Elkhound manual</a>
+<li><a href="tutorial.html">Elkhound tutorial</a>
+<li><a href="faq.html">Frequently Asked Questions</a>
+<li><a href="algorithm.html">Overview of the algorithm and its history</a>
+</ul>
+
+<p>
+To download Elkhound and Elsa, see the
+<a href="http://www.cs.berkeley.edu/~smcpeak/elkhound/">Elkhound distribution page</a>.
+
+<p>
+Elkhound requires the following external software:
+<ul>
+<li><a href="../ast/index.html">ast</a>, a system for making abstract syntax trees.
+<li><a href="../smbase/index.html">smbase</a>, my utility library.
+<li><a href="http://www.gnu.org/software/flex/flex.html">Flex</a>,
+    a lexical analyzer generator.
+<li><a href="http://www.gnu.org/software/bison/bison.html">Bison</a>,
+    a parser generator.  (Elkhound does not need Bison once it has been compiled.)
+</ul>
+
+<p>
+Build instructions:
+<pre>
+  $ ./configure
+  $ make
+  $ make check
+</pre>
+<a href="configure"><tt>./configure</tt></a> understands
+<a href="gendoc/configure.txt">these options</a>.  You can also
+look at the <a href="Makefile.in">Makefile</a>.
+
+<p>
+Module List:
+<ul>
+
+<li><a href="asockind.h">asockind.h</a>,
+    <a href="asockind.cc">asockind.cc</a>:
+AssocKind, an enumeration of the kinds of associativity.
+
+<li><a href="cyctimer.h">cyctimer.h</a>,
+    <a href="cyctimer.cc">cyctimer.cc</a>:
+CycleTimer, which times a section of code in cycles and milliseconds.
+
+<li><a href="emitcode.h">emitcode.h</a>,
+    <a href="emitcode.cc">emitcode.cc</a>:
+EmitCode, a class to manage the printing of generated code.  Its
+main contribution is knowledge of how to insert #line directives.
+
+<li><a href="flatutil.h">flatutil.h</a>:
+A few utilities on top of the Flatten interface
+(<a href="../smbase/flatten.h">smbase/flatten.h</a>).
+
+<li><a href="genml.h">genml.h</a>, 
+    <a href="genml.cc">genml.cc</a>:
+This module generates parse tables as ML syntax, for when Elkhound is
+running in ML mode.
+
+<li><a href="glr.h">glr.h</a>,
+    <a href="glr.cc">glr.cc</a>:
+Core module for the Elkhound parser (the on-line component, not the
+offline parser generator).  Implements a variant of the GLR
+parsing algorithm.  See <a href="glr.h">glr.h</a> for
+more info.
+
+<li><a href="gramanl.h">gramanl.h</a>,
+    <a href="gramanl.cc">gramanl.cc</a>:
+Grammar analysis module.  Includes algorithms for computing parse
+tables.  Also includes the main() for the parser generator program,
+called 'elkhound'.
+
+<li><a href="gramast.ast">gramast.ast</a>:
+Grammar AST.  The input grammar is initially parsed into an AST,
+before a corresponding Grammar (<a href="grammar.h">grammar.h</a>)
+object is created.
+
+<li><a href="gramexpl.cc">gramexpl.cc</a>:
+Aborted attempt to make an interactive grammar analyzer/explorer/modifier.
+
+<li><a href="gramlex.lex">gramlex.lex</a>:
+Lexical analyzer for grammar input files.  Uses
+<a href="../ast/gramlex.h">ast/gramlex.h</a> and
+<a href="../ast/gramlex.cc">ast/gramlex.cc</a>.
+
+<li><a href="grammar.h">grammar.h</a>,
+    <a href="grammar.cc">grammar.cc</a>:
+Analysis-time representation of a grammar.  Stores symbols,
+productions, etc.  Note that the grammar is distilled down to parse
+tables for the parser itself; this representation is not normally
+available during parsing.
+
+<li><a href="grampar.y">grampar.y</a>,
+    <a href="grampar.h">grampar.h</a>,
+    <a href="grampar.cc">grampar.cc</a>:
+Grammar parser module.
+
+<li><a href="lexerint.h">lexerint.h</a>:
+LexerInterface, the interface the parser uses to access the
+lexical analyzer.
+
+<li><a href="mlsstr.h">mlsstr.h</a>,
+    <a href="mlsstr.cc">mlsstr.cc</a>:
+Module for parsing embedded fragments of ML in reduction actions.
+
+<li><a href="parsetables.h">parsetables.h</a>,
+    <a href="parsetables.cc">parsetables.cc</a>,
+    <a href="emittables.cc">emittables.cc</a>:
+ParseTables, a container class for the parse tables of a grammar.
+The parser generator creates the tables, then
+<a href="emittables.cc">emittables.cc</a> renders the tables out
+as code for use by the parser during parsing.
+
+<li><a href="ptreeact.h">ptreeact.h</a>,
+    <a href="ptreeact.cc">ptreeact.cc</a>:
+A generic set of user actions that build parse trees for any grammar.
+By making a ParseTreeLexer and ParseTreeActions, you can have a
+version of your parser which just makes (and optionally prints) a
+parse tree.  This is very useful for debugging grammars.
+
+<li><a href="ptreenode.h">ptreenode.h</a>,
+    <a href="ptreenode.cc">ptreenode.cc</a>:
+PTreeNode, a generic parse tree node.  Forms the basis for the
+parse trees constructed by <a href="ptreeact.cc">ptreeact.cc</a>.
+
+<li><a href="rcptr.h">rcptr.h</a>:
+RCPtr, a reference-counting pointer.  Used by the parser core
+to maintain the stack node reference counts.
+
+<li><a href="trivlex.h">trivlex.h</a>,
+    <a href="trivlex.cc">trivlex.cc</a>,
+    <a href="trivmain.cc">trivmain.cc</a>:
+Lexer and driver program for experimental grammars.
+
+<li><a href="useract.h">useract.h</a>,
+    <a href="useract.cc">useract.cc</a>:
+UserActions interface, used by the parser core to invoke the
+actions associated with reductions (and other events).
+
+<li><a href="util.h">util.h</a>:
+Some random macros.
+
+</ul>
+
+
+<p>
+I used <a href="../smbase/scan-depends.pl">smbase/scan-depends.pl</a>
+to make dependency diagrams of the parser generator, and the run-time
+parser.
+
+<p>
+The parser generator:<br>
+<img src="gendoc/elkhound_dep.png" alt="Elkhound dependencies"><br>
+Or as <a href="gendoc/elkhound_dep.ps">Postscript</a>.
+
+<p>
+The run-time parser:<br>
+<img src="gendoc/glr.png" alt="GLR Parser dependencies"><br>
+Or as <a href="gendoc/glr.ps">Postscript</a>.
+   
+
+<p>
+Miscellanous files:
+<p>
+<ul>
+
+<li><a href="find-extra-deps">find-extra-deps</a>:
+This script finds dependencies among automatically-generated
+source files.  Output is <a href="extradep.mk">extradep.mk</a>.
+
+<a href="make-lrtable-graph">make-lrtable-graph</a>:
+Given the <tt>.out</tt> file from a run of Elkhound with the
+<tt>-tr lrtable</tt> option, produce a Dot-format graph of the
+parsing automaton.
+
+<li><a href="make-tok">make-tok</a>:
+Read a C++ header file containing a token code enumeration
+declaration, and produce a corresponding <tt>.tok</tt> file for 
+Elkhound.
+
+<li><a href="make-trivparser.pl">make-trivparser.pl</a>:
+This script makes an Elkhound .gr file from a more-compact
+description of an experimental grammar.
+
+<li><a href="perf">perf</a>:
+Run some performance tests.
+
+<li><a href="regrtest">regrtest</a>:
+Run the regression tests.
+
+</ul>
+
+
+<p>
+Interesting subdirectories:
+<p>
+<ul>
+
+<li><a href="asfsdf">asfsdf</a>:
+Contains a few examples written for the ASF+SDF meta-framework, for
+performance comparison with Elkhound.
+
+<li><a href="c">c</a>:                          
+
+Contains a C parser written in Elkhound.  The grammar is almost free
+of shift/reduce conflicts.  It uses the lexer hack (feedback from the
+symbol table into the lexer) to distinguish variables from types.  The
+lexer itself is very slow (just bad engineering).  This parser could
+be evolved into something useful in its own right, but at this time
+it's mostly just a test of Elkhound's deterministic parser.
+
+<li><a href="cc2">cc2</a>:
+This is a C++ parser that uses the C++ Standard's grammar without
+modification.  Consequently, it has many shift/reduce and
+reduce/reduce conflicts, and also many true ambiguities.  This grammar
+is not a very good grammar to use for parsing C++ input; rather, it's
+essentially the skeleton on which the standard's English description
+hangs.  Nevertheless, it's useful because it will output exactly the
+parse tree (ambiguities and all) that the standard grammar induces,
+and this can then be compared to similar output from Elsa
+
+<li><a href="examples">examples</a>:
+Contains some example parsers written with Elkhound:
+
+  <ul>
+
+  <li><a href="examples/arith">examples/arith</a>:
+  Simple parser for arithmetic expressions.  This example was intended
+  to introduce a new user to some of Elkhound's syntax and semantics.
+
+  <li><a href="examples/cdecl">examples/cdecl</a>:
+  This contains an abstracted fragment of the C grammar, demonstrating the
+  ambiguity between variable and type names.  The accompanying code
+  resolves the ambiguity using reduction cancellation.
+
+  <li><a href="examples/cexp">examples/cexp</a>:
+  This has two examples of parsing C expressions.  The examples are
+  old and don't show much; I used them to test Elkhound during early
+  development.
+  
+  <li><a href="examples/gcom">examples/gcom</a>:
+  One of several directories of files used in the
+  <a href="tutorial.html">tutorial</a>.
+  
+  </ul>
+  
+<li><a href="in">in</a>:
+This has a bunch of inputs for various testing grammars.
+
+<li><a href="triv">triv</a>:
+This is a collection of micro-grammars for performance and correctness
+testing.  The name "triv" comes from the fact that they all use the
+trival lexer, i.e. a lexer that yields every character as a separate
+token.
+
+</ul>
+
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+
+</HTML>

Added: vendor/elsa/current/elkhound/lexerint.h
===================================================================
--- vendor/elsa/current/elkhound/lexerint.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/lexerint.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,91 @@
+// lexerint.h            see license.txt for copyright and terms of use
+// LexerInterface, the interface the GLR parser uses
+// to access the lexer's token stream
+
+#ifndef LEXERINT_H
+#define LEXERINT_H
+
+#include "useract.h"      // SemanticValue
+#include "srcloc.h"       // SourceLoc
+#include "str.h"          // string
+
+// This 'interface' is a collection of variables describing
+// the current token.  I don't use a bunch of pure-virtual
+// functions because of the cost of calling them; everything
+// here will be in the inner loop of the parser.
+class LexerInterface {
+public:     // types
+  // This special constant is the initial value of 'sval'.  It is used
+  // to heuristically detect when the user has failed to prime the
+  // lexer by loading it with the first token.  The number itself
+  // is arbitrary, but should not be 0 or any other value that is
+  // likely to be used as a legitimate sval for EOF.
+  enum { DEFAULT_UNPRIMED_SVAL = 0x34D9423E };
+
+public:     // data
+  // NOTE: All of these fields are *written* by the lexer, and
+  // *read* by the parser.
+
+  // token classification; this is what the parser will use to
+  // make parsing decisions; this code must correspond to something
+  // declared in the 'terminals' section of the grammar; when this
+  // is 0, it is the final (end-of-file) token; the parser is allowed
+  // to change this for its own purposes, and currently does so for
+  // token reclassification
+  int type;
+
+  // semantic value; this is what will be passed to the reduction
+  // actions when this token is on the right hand side of a rule
+  SemanticValue sval;
+
+  // source location of the token; this will only be used if the
+  // parser has been compiled to automatically propagate it
+  SourceLoc loc;
+
+public:     // funcs
+  LexerInterface()
+    : type(0),
+      sval((SemanticValue)DEFAULT_UNPRIMED_SVAL),
+      loc(SL_UNKNOWN)
+  {}
+  virtual ~LexerInterface() {}
+
+
+  // retrieve the next token; the lexer should respond by filling in
+  // the above fields with new values, to describe the next token; the
+  // lexer indicates end of file by putting 0 into 'type'; when the
+  // LexerInterface object is first passed to the parser, the above
+  // fields should already be set correctly (i.e. the parser will make
+  // its first call to 'nextToken' *after* processing the first token)
+  typedef void (*NextTokenFunc)(LexerInterface *);
+
+  // get the function which we'll call to get the next token
+  //
+  // Why the two-step approach?  Virtual method calls are more
+  // expensive than simple indirect function calls, and this happens
+  // in the inner parsing loop.  If C++ had a way to explicitly cache
+  // the result of a method lookup this wouldn't be necessary.
+  virtual NextTokenFunc getTokenFunc() const=0;
+
+  
+  // The following functions are called to help create diagnostic
+  // reports.  They should describe the current token (the one
+  // which the above fields refer to) in more-or-less human-readable
+  // terms.
+
+  // describe the token; for tokens with multiple spellings (e.g.
+  // identifiers), this should include the actual token spelling
+  // if possible; note that if the token has been reclassified,
+  // then the 'type' field above might have been changed by the
+  // parser, in which case this function should ideally print
+  // a description which takes the new type into account
+  virtual string tokenDesc() const=0;
+
+  // describe a token kind; this is different from tokenDesc(), since
+  // it need not correspond to the token kind that was just yielded,
+  // and hence any related lexeme data cannot be assumed to be
+  // available; this is used during error diagnosis
+  virtual string tokenKindDesc(int kind) const=0;
+};
+
+#endif // LEXERINT_H

Added: vendor/elsa/current/elkhound/license.txt
===================================================================
--- vendor/elsa/current/elkhound/license.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/license.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+The software in this directory is
+Copyright (c) 2002, Regents of the University of California
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above 
+      copyright notice, this list of conditions and the following 
+      disclaimer in the documentation and/or other materials provided 
+      with the distribution.
+
+    * Neither the name of the University of California, Berkeley nor 
+      the names of its contributors may be used to endorse or promote 
+      products derived from this software without specific prior 
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: vendor/elsa/current/elkhound/make-lrtable-graph
===================================================================
--- vendor/elsa/current/elkhound/make-lrtable-graph	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/make-lrtable-graph	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,102 @@
+#!/usr/bin/perl -w
+# given as input the .out from running Elkhound, containing
+# a description of the LR tables, create a Dot graph with
+# the LR table nicely displayed (www.research.att.com/sw/tools/graphviz/)
+
+if (-t <STDIN>) {
+  print("usage: $0 <grammar.out >grammar.dot\n");
+  exit(0);
+}
+
+# accumulated lines for the current state
+$stateLines = "";
+
+# current state number
+$stateNum = 0;
+
+# set of edges printed, indexed by strings e.g. "s1,s2"
+%EDGES = ();
+
+# dump accumulated lines
+sub dumpState {
+  if ($stateLines) {
+    print($stateLines, "\" ];\n");
+  }
+  $stateLines = "";
+}
+
+print("digraph g {\n");
+
+while (defined($line = <STDIN>)) {
+  chomp($line);
+
+  # de-uglify my synthesized name
+  $line =~ s/__EarlyStartSymbol/S\'/g;
+
+  # beginning of a state?
+  ($n) = ($line =~ m/^State (\d+), sample/);
+  if (defined($n)) {
+    dumpState();
+
+    $stateNum = $n;
+    $stateLines = "  \"s$stateNum\" [ shape = \"box\"\n" .
+                  "    label = \"State $stateNum";
+
+    next;
+  }
+
+  # edge?  $item2 gets the symbol to right of dot
+  ($item1, $item2, $item3, $dest) =
+    ($line =~ m/^  (.+)\. ([^ ,]+)(.+\S)\s+--> (\d+)$/);
+  if (defined($dest)) {
+    $item = "$item1. $item2$item3";    # rebuild full item text
+
+    # edge index
+    $edgeIdx = "$stateNum,$dest";
+    if (defined($EDGES{$edgeIdx})) {
+      # already printed, skip it (but check that it is the same)
+      if ($EDGES{$edgeIdx} ne $item2) {
+        print STDERR ("what the?  edge $edgeIdx has conflicting label?\n");
+        exit(2);
+      }
+    }
+    else {
+      # emit an edge in the dot graph
+      print("  \"s$stateNum\" -> \"s$dest\" [ label = \"$item2\" ];\n");
+      $EDGES{$edgeIdx} = $item2;
+    }
+
+    # add the item to the state lines
+    $stateLines .= "\\n$item";
+
+    next;
+  }
+
+  # missed edge line?
+  if ($line =~ m/-->/) {
+    print STDERR ("warning: unrecognized: $line\n");
+    next;
+  }
+
+  # after-state summary?
+  if ($line =~ m/can reduce by/) {
+    next;
+  }
+
+  # reducible item?
+  ($item) = ($line =~ m/^  (.+->.+\.)\s*$/);         # last reduction, no lookahead
+  if (defined($item)) {
+    $stateLines .= "\\n$item  (R)";
+    next;
+  }
+  ($item) = ($line =~ m/^  (.+->.+\.,.*\S)\s*$/);    # reduction w/ lookahead
+  if (defined($item)) {
+    $stateLines .= "\\n$item  (R)";
+    next;
+  }
+}
+
+dumpState();
+print("}\n");
+
+# EOF


Property changes on: vendor/elsa/current/elkhound/make-lrtable-graph
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/make-tok
===================================================================
--- vendor/elsa/current/elkhound/make-tok	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/make-tok	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,81 @@
+#!/usr/bin/perl -w
+# given a header file with an enumeration that specifies all
+# of the token codes, create a file suitable for inclusion
+# into an Elkhound grammar that contains the same tokens
+# and codes
+
+use strict 'subs';
+
+if (@ARGV != 1) {
+  print(<<"EOF");
+usage: $0 enum-name <tokens.h >tokens.tok
+
+This script reads a C/C++ header file as input, finds the named
+enumeration, and extracts token names and codes.  The output is
+a list of tokens suitable for inclusion in an Elkhound grammar.
+EOF
+  exit(2);
+}
+
+$enumName = $ARGV[0];
+
+# scan for the beginning of the enum
+while (defined($line = <STDIN>)) {
+  if ($line =~ m"enum\s+$enumName\b") {
+    last;   # found it
+  }
+}
+
+if (!defined($line)) {
+  print STDERR ("error: did not find the beginning of $enumName\n");
+  exit(2);
+}
+
+# interpret lines of the enum; assume they are at most one per line
+$nextCode = 0;
+while (defined($line = <STDIN>)) {
+  # skip comments, blank lines
+  chomp($line);
+  if ($line =~ m,^\s*(//.*)?$,) { next; }
+
+  # is this the end of the enum?
+  if ($line =~ m"^\s*};") {
+    exit(0);    # all done
+  }
+
+  ($name, $code, $trailing) =
+    $line =~ m/^\s*([A-Za-z0-9_]+)([^,]*),(.*)$/;
+  if (!defined($name)) {
+    print STDERR ("warning: unrecognized line: $line\n");
+    next;
+  }
+
+  # does the code say anything?
+  if ($code !~ m/^\s*$/) {
+    ($num) =
+      $code =~ m/^\s*=\s*(\d+)$/;
+    if (!defined($num)) {
+      print STDERR ("warning: unrecognized token number: $code\n");
+    }
+    else {
+      $nextCode = $num;
+    }
+  }
+
+  # does the trailing part of the line contain a quoted string?
+  # if so, that will be taken as the alias
+  ($alias) =
+    $trailing =~ m/(".*")/;
+  if (!defined($alias)) {
+    $alias = "";    # no alias
+  }
+
+  # emit the token for Elkhound
+  printf("  %3d : %-30s %s;\n", $nextCode, $name, $alias);
+  
+  # automatic increment, as in C
+  $nextCode++;
+}
+
+print STDERR ("error: did not find end of $enumName");
+exit(2);


Property changes on: vendor/elsa/current/elkhound/make-tok
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/make-trivparser.pl
===================================================================
--- vendor/elsa/current/elkhound/make-trivparser.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/make-trivparser.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,163 @@
+#!/usr/bin/perl -w
+# given a partial grammar spec on input, write a grammar spec
+# on output which is well-formed, and whose actions just print
+# the productions that drive them
+
+use strict 'subs';
+
+if (@ARGV < 1) {
+  print("usage: $0 [-ptree] NAME < NAME.gr.in > NAME.gr\n",
+        "  -ptree: emit code to build a parse tree\n");
+  exit(0);
+}
+                          
+my $ptree = 0;
+if ($ARGV[0] eq "-ptree") {
+  $ptree = 1;
+  shift @ARGV;
+}
+
+$name = $ARGV[0];
+
+
+$nodeType = "[int]";
+if ($ptree) {
+  $nodeType = "[PTreeNode*]";
+}
+
+
+print("// automatically produced by $0\n",
+      "// do not edit directly\n",
+      "\n");
+
+
+sub preamble {
+  # insert standard preamble
+  my $addlIncl = "";
+  my $addlExt = "";
+  if ($ptree) {
+    $addlIncl = "#include \"ptreenode.h\"    // PTreeNode";
+    $addlExt = ".tree";
+  }
+
+  print(<<"EOF");
+
+    verbatim [
+      #include <iostream.h>     // cout
+      $addlIncl
+
+      extern int count;
+    ]
+
+    context_class $name : public UserActions {
+    };
+
+    impl_verbatim [
+      UserActions *makeUserActions()
+      {
+        return new $name;
+      }
+
+      int count = 0;
+    ]
+
+EOF
+}
+
+
+# add actions
+while (defined($line = <STDIN>)) {
+  # insert preamble right before terminals
+  if ($line =~ /^\s*terminals/) {
+    preamble();
+    print($line);
+
+    # add EOF terminal
+    print("  0 : EOF ;\n");
+    next;
+  }
+
+  # remember last-seen nonterm
+  ($prefix, $tail, $nonterm) = ($line =~ m/^(.*)nonterm\s+((\S+)\s+.*)$/);
+  if (defined($nonterm)) {
+    if (!defined($curNT)) {
+      # this is the first nonterminal; insert dummy start rule
+      #print("// dummy first rule\n",
+      #      "nonterm$nodeType DummyStart -> tree:$nonterm EOF [ return tree; ]\n",
+      #      "\n");
+    }
+
+    $curNT = $nonterm;
+    print("${prefix}nonterm$nodeType $tail\n");
+
+    # add a rule for merging
+    if ($ptree) {
+      print(#"  fun merge(t1, t2)   [ return new PTreeNode(PTREENODE_MERGE, t1, t2); ]\n",
+            "  fun merge(t1, t2)   [ t1->addAlternative(t2); return t1; ]\n",
+            "  fun del(t)          []\n",
+            "  fun dup(t)          [ return t; ]\n",
+            "\n");
+    }
+    else {
+      #print("  fun merge(t1, t2)          [ cout << \"merged $nonterm\\n\"; return t1; ]\n\n");
+    }
+
+    next;
+  }
+
+  # add actions to rules without them
+  ($space, $rule) = ($line =~ /^(\s*)(->.*);\s*$/);
+  if (defined($rule)) {
+    $len = length($space) + length($rule);
+    print($space, $rule, " " x (25-$len));
+    
+    # text of the rule with quotes escaped
+    ($ruleText = $rule) =~ s/\"/\\\"/g;
+
+    if ($ptree) {
+      print("[ return new PTreeNode(\"$curNT $ruleText\"");
+
+      # work through the rule RHS, finding subtrees to attach
+      $tail = substr($rule, 2);      # remove the leading "->"
+      for(;;) {
+        my ($unused, $tag, $symbol, $rest) =
+          ($tail =~ m/\s*(([a-z][a-zA-Z_0-9]*):)?([a-zA-Z]+)\s*(.*)/);
+        if (!defined($symbol)) {
+          last;
+        }
+        if (defined($tag)) {
+          # subtree to put into the node
+          print(", $tag");
+        }
+        $tail = $rest;
+
+        pretendUsed($unused);
+      }
+      print("); ]\n");
+    }
+    else {
+      print("[ cout << \"reduced by $curNT $ruleText\\n\"; return ++count; ]\n");
+    }
+    next;
+  }
+
+  # expand terminals (single letter with *no* semicolon, and possibly
+  # a comment); this avoids having to remember the ascii code for some
+  # letter..
+  ($letter, $comment) = ($line =~ m|^\s*([a-z])\s*(//.*)?$|);
+  if (defined($letter)) {
+    if (!defined($comment)) {
+      $comment = "";
+    }
+    printf("  %d : $letter ;   $comment\n", ord(uc($letter)));
+    next;
+  }
+
+  print($line);
+}
+
+exit(0);
+
+
+sub pretendUsed {
+}


Property changes on: vendor/elsa/current/elkhound/make-trivparser.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/manual.html
===================================================================
--- vendor/elsa/current/elkhound/manual.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/manual.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1053 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elkhound Manual</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175% }
+    a.toc:link { text-decoration: none }
+    a.toc:visited { text-decoration: none }
+  </style>
+</HEAD>
+
+<body>
+
+<center>
+<p class="title"><b>Elkhound Manual</b></p>
+</center>
+
+<p>
+This page describes the input format for grammars for the Elkhound
+parser generator, and the features of that generator.
+
+<p>
+Related pages:
+<ul>
+<li><a href="index.html">Elkhound overview</a>
+<li><a href="tutorial.html">Elkhound tutorial</a>
+</ul>
+
+<p>
+If you'd like to look at a simple grammar while reading this
+description, see <a
+href="examples/arith/arith.gr">examples/arith/arith.gr</a>, a parser
+for simple arithmetic expressions.
+
+<p>
+To find out how to run the tool, run <tt>./elkhound</tt> without
+arguments (or search for "usage:" in 
+<a href="gramanl.cc">gramanl.cc</a>).
+
+
+<h1>Contents</h1>
+                          
+<p>
+<!-- BEGIN CONTENTS -->
+<!-- automatically generated by insert-html-toc; do not edit the TOC directly -->
+<ul>
+  <li><a class="toc" href="#lexical">1. Lexical structure</a>
+  <li><a class="toc" href="#context_class">2. Context Class</a>
+  <li><a class="toc" href="#terminals">3. Terminals</a>
+  <ul>
+    <li><a class="toc" href="#token_types">3.1 Token Types</a>
+    <li><a class="toc" href="#token_dup_del">3.2 dup/del</a>
+    <li><a class="toc" href="#token_classify">3.3 classify</a>
+    <li><a class="toc" href="#token_prec_assoc">3.4 Precedence/associativity specifications</a>
+    <li><a class="toc" href="#lexerint">3.5 Lexer Interface</a>
+  </ul>
+  <li><a class="toc" href="#nonterminals">4. Nonterminals</a>
+  <ul>
+    <li><a class="toc" href="#dup">4.1 dup</a>
+    <li><a class="toc" href="#del">4.2 del</a>
+    <li><a class="toc" href="#merge">4.3 merge</a>
+    <li><a class="toc" href="#keep">4.4 keep</a>
+    <li><a class="toc" href="#precedence">4.5 precedence</a>
+    <li><a class="toc" href="#forbid">4.6 forbid_next</a>
+  </ul>
+  <li><a class="toc" href="#options">5. Options</a>
+  <ul>
+    <li><a class="toc" href="#useGCDefaults">5.1 useGCDefaults</a>
+    <li><a class="toc" href="#defaultMergeAborts">5.2 defaultMergeAborts</a>
+    <li><a class="toc" href="#expected_stats">5.3 Expected conflicts, unreachable symbols</a>
+    <li><a class="toc" href="#allow_continued_nonterminals">5.4 allow_continued_nonterminals</a>
+  </ul>
+  <li><a class="toc" href="#ocaml">6. OCaml</a>
+  <li><a class="toc" href="#prec_assoc">7. Precedence and Associativity</a>
+  <ul>
+    <li><a class="toc" href="#prec_assoc_meaning">7.1 Meaning of prec/assoc specifications</a>
+    <li><a class="toc" href="#prec_assoc_attach">7.2 Attaching prec/assoc to tokens and productions</a>
+    <li><a class="toc" href="#prec_assoc_resolution">7.3 Conflict resolution with prec/assoc specifications</a>
+    <li><a class="toc" href="#prec_assoc_example_arith">7.4 Example: Arithmetic grammar</a>
+    <li><a class="toc" href="#prec_assoc_example_else">7.5 Example: Dangling else</a>
+    <li><a class="toc" href="#prec_assoc_further">7.6 Further directions</a>
+  </ul>
+</ul>
+<!-- END CONTENTS -->
+
+<a name="lexical"></a>
+<h1>1. Lexical structure</h1>
+
+<p>
+The grammar file format is free-form, meaning that all whitespace is
+considered equivalent.  In the C tradition, grouping is generally
+denoted by enclosing things in braces ("{" and "}").  Strings are
+enclosed in double-quotes ("").
+
+<p>
+Grammar files may include other grammar files, by writing
+include("other_file_name").
+
+<p>
+Comments can use the C++ "//" syntax or the C "/**/" syntax.
+
+<a name="context_class"></a>
+<h1>2. Context Class</h1>
+
+<p>
+The parser's action functions are all members of a C++ context
+class.  As the grammar author, you must define the context class.
+The class is introduced with the "<tt>context_class</tt>" keyword,
+followed by ordinary C++ syntax for classes (ending with "<tt>};</tt>");
+
+
+<a name="terminals"></a>
+<h1>3. Terminals</h1>
+
+<p>
+The user must declare of all the tokens, also called terminals.  A
+block of terminal declarations looks like:
+<pre>
+  terminals {
+    0 : TOK_EOF;
+    1 : TOK_NUMBER;              // no alias
+    2 : TOK_PLUS     "+";        // alias is "+" (including quotes)
+    3 : TOK_MINUS    "-";
+    4 : TOK_TIMES    "*";
+    5 : TOK_DIVIDE   "/";
+    6 : TOK_LPAREN   "(";
+    7 : TOK_RPAREN   ")";
+  }
+</pre>
+
+<p>
+Each statement gives a unique numeric code (e.g. 3), a canonical
+name (e.g. TOK_MINUS), and an optional alias (e.g. "-").  Either the
+name or the alias may appear in the grammar productions, though the
+usual style is to use aliases for tokens that always have the same
+spelling (like "+"), and the name for others (like TOK_NUMBER).
+
+<p>
+Normally it's expected the tokens will be described in their own
+file, and the <a href="make-tok">make-tok</a> script will create
+the token list seen above.
+
+<a name="token_types"></a>
+<h2>3.1 Token Types</h2>
+
+<p>
+In addition to declaring the numeric codes and aliases of the tokens,
+the user must declare types for semantic values of tokens, if those
+values are used by reduction actions (specifically, if their occurence
+on a right-hand-side includes a label, denoted with a colon ":").
+
+<p>
+The syntax for declaring a token type is
+<blockquote>
+  <tt>token(</tt><i>type</i><tt>) </tt><i>token_name</i><tt>;</tt>
+</blockquote>
+or, if specifying terminal functions,
+<blockquote>
+  <tt>token(</tt><i>type</i><tt>) </tt><i>token_name</i><tt> {</tt><br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>terminal_functions</i><br>
+  <tt>}</tt>
+</blockquote>
+
+<p>
+The terminal functions are explained in the next sections.
+
+<a name="token_dup_del"></a>
+<h2>3.2 dup/del</h2>
+
+<p>
+Terminals can have <tt>dup</tt> and <tt>del</tt> functions, just like
+nonterminals.  See <a href="#dup">below</a> for more information.
+
+<a name="token_classify"></a>
+<h2>3.3 classify</h2>
+
+<p>
+In some situations, it is convenient to be able to alter the classification
+of a token after it is yielded by the lexer but before the parser sees it,
+in particular before it is compared to lookahead sets.  For this purpose,
+each time a token is yielded from the lexer, it is passed to that token's
+<tt>classify()</tt> function.  <tt>classify</tt> accepts a single argument,
+the semantic value associated with that token.  It returns the token's
+new classification, as a token id.  (It cannot change the semantic value.)
+
+<p>
+The main way it differs from simply modifying the lexer is that the
+<tt>classify</tt> function has access to the parser context class, whereas
+the lexer presumably does not.  In any case, it's something of a hack, and
+best used sparingly.
+
+<p>
+As a representative example, here is the <tt>classify</tt> function from
+<a href="c/c.gr">c/c.gr</a>, used to implement the lexer hack for a C parser:
+<pre>
+  token(StringRef) L2_NAME {
+    fun classify(s) {
+      if (isType(s)) {
+        return L2_TYPE_NAME;
+      }
+      else {
+        return L2_VARIABLE_NAME;
+      }
+    }
+  }
+</pre>
+
+<a name="token_prec_assoc"></a>
+<h2>3.4 Precedence/associativity specifications</h2>
+
+<p>
+Inside a block that begins with "<tt>precedence {</tt>" and ends with
+"<tt>}</tt>", one may list directives of the form
+<blockquote>
+  <i>dir</i> &nbsp;&nbsp;&nbsp; <i>num</i> &nbsp;&nbsp;&nbsp; <i>tok...</i> &nbsp;&nbsp;&nbsp; <tt>;</tt>
+</blockquote>
+where <i>dir</i> is a precedence direction, <i>num</i> a precedence
+number, and <i>tok...</i> a sequence of tokens (either token names or
+aliases).  The effect is to associate <i>dir</i>/<i>num</i> with
+each listed token.  The meaning of such specifications is explained
+in Section&nbsp;7, below.
+
+
+<a name="lexerint"></a>
+<h2>3.5 Lexer Interface</h2>
+
+<p>
+The terminals specification given in the grammar file is a description
+of the output of the lexer.  This section describes the mechanism by which
+the lexer provides that output.
+
+<p>
+The parser interacts with the lexer through the API defined in the
+<a href="lexerint.h"><tt>lexerint.h</tt></a> file.  The lexer must
+implement (inherit from) LexerInterface.  When the parser asks the
+lexer for a token by invoking its <tt>NextTokenFunc</tt>, the
+lexer describes the current token by filling in the three data fields 
+of LexerInterface:
+<ul>
+<li><tt>type</tt>: The token code as defined in the <tt>terminals</tt> list
+    (Section&nbsp;3).
+<li><tt>sval</tt>: The semantic value, a value of the type given in the
+    Token Types specification (Section&nbsp;3.1) for the token whose
+    code is in <tt>type</tt>.
+<li><tt>loc</tt>: The source location of the start of the current token.
+    You only need to fill this in if you plan on using the value of
+    <tt>loc</tt> from within reduction action functions.
+</ul>
+The parser will then do its work by reading these fields, and when it
+is ready for the next token, will invoke the <tt>NextTokenFunc</tt>
+again.
+
+<p>
+<blockquote>
+<b>Rationale:</b> The rationale for this very imperative style of
+interface is performance.  It's faster to share storage between the
+parser and lexer than to have the parser make a separate copy of this
+information.  Since token retrieval is in the inner loop of the
+parser, saving just a few instructions can be significant.
+</blockquote>
+
+<p>
+The actual mechanism for invoking <tt>NextTokenFunc</tt> is a little
+convoluted.  The parser first calls <tt>getTokenFunc()</tt>, a virtual
+method, which returns a function pointer.  This pointer is stored in
+the parser when it first starts up.  The parser then invokes this
+function pointer each time it wants a new token, passing a pointer
+to the LexerInterface as an argument.
+
+<p>
+This means that the lexer must define <em>two</em> functions, a
+static method (or a nonmember function) that does token retrieval,
+and a virtual method that just returns a pointer to the first
+function.
+
+<p>
+<blockquote>
+<b>Rationale</b>: Again, performance is the main consideration.  The
+cost of a virtual method dispatch is two memory reads plus an
+indirect function call (with data dependencies separating each step),
+whereas calling a function pointer requires
+only the indirect call.  Originally, Elsa used a virtual function
+dispatch, and switching to this approach produced a significant
+speedup (I no longer remember the exact numbers, I'd guess it was
+5-10%).
+</blockquote>
+
+<p>
+Finally, there are two functions, <tt>tokenDesc</tt> and
+<tt>tokenKindDesc</tt>, that are used for diagnostic purposes.
+When there is a parse error, the parser will call these functions
+to obtain descriptions of tokens for use in the error message.
+
+
+<a name="nonterminals"></a>
+<h1>4. Nonterminals</h1>
+
+<p>
+Following the terminals, the bulk of the grammar is one or more
+nonterminals.  Each nonterminal declaration specifies all of the
+productions for which it is the left-hand-side.
+
+<p>
+A simple nonterminal might be:
+<pre>
+  nonterm(int) Exp {
+    -&gt; e1:Exp "+" e2:Exp        { return e1 + e2; }
+    -&gt; n:TOK_NUMBER             { return n; }
+  }
+</pre>
+
+<p>
+The type of the semantic value yielded by the productions is given
+in parentheses, after the keyword "<tt>nonterm</tt>".  In this case,
+<tt>int</tt> is the type.  The type can be omitted if productions
+do not yield interesting semantic values.
+
+<p>
+In the example, Exp has two productions, <tt>Exp -&gt; Exp "+"
+Exp</tt> and <tt>Exp -&gt; TOK_NUMBER</tt>.  The "<tt>-&gt;</tt>"
+keyword introduces a production.
+
+<p>
+Right-hand-side symbols can be given names, by putting the name
+before a colon (":") and the symbol.  These names can be used in
+the action functions to refer to the semantic values of the
+subtrees (like Bison's <tt>$1</tt>, <tt>$2</tt>, etc.).  Note that
+action functions <tt>return</tt> their value, as opposed to (say)
+assigning to <tt>$$</tt>.
+
+<p>
+There are four kinds of nontermial functions, described below.
+
+<a name="dup"></a>
+<h2>4.1 dup</h2>
+
+<p>
+Because of the way the GLR algorithm operates, a semantic value
+yielded (returned) by one action may be passed as an argument
+to <em>more than one</em> action.  This is in contrast to Bison,
+where each semantic value is yielded exactly once.
+
+<p>
+Depending on what the actions actually do, i.e. what the semantic
+values actually mean, the user may need to intervene to help
+manage the sharing of semantic values.  For example, if the
+values form a tree where memory is managed by reference counting,
+then the reference count of a value would need to be increased
+each time it is yielded.
+
+<p>
+The <tt>dup()</tt> nonterminal function is intended to support the
+kind of sharing management alluded to above.  Each time a semantic
+value is to be passed to an action, it first is passed to the
+associated <tt>dup()</tt> function.  The value returned by
+<tt>dup()</tt> is stored back in the parser's data structures,
+for use the next time the value must be passed to an action.
+Effectively, by calling <tt>dup()</tt>, the parser is announcing,
+"I am about to surrender this value to an action; please give me
+a value to use in its place next time."
+
+<p>
+Common <tt>dup()</tt> strategies:
+<ul>
+<li>Return <tt>NULL</tt>.  This is the default.  This expresses the
+    intent that the value <em>not</em> be passed more than once (since
+    any subsequent actions will receive <tt>NULL</tt> arguments).
+<li>Return the argument.  This is the default if the
+    <tt>useGCDefaults</tt> option is specified.  This is useful when
+    the semantic values can be shared arbitrarily without special handling.
+<li>Increment a reference count, make a deep copy, etc.  Various
+    possibilities exist depending on the particular sharing
+    management in use.
+</ul>
+
+<a name="del"></a>
+<h2>4.2 del</h2>
+
+<p>
+A natural counterpart to <tt>dup()</tt>, <tt>del()</tt> accepts values
+that are not going to be passed to any more actions (this happens
+when, for example, one of the potential parsers fails to make further
+progress).  It does not return anything.
+
+<p>
+Common <tt>del()</tt> strategies:
+<ul>
+<li>Print a warning.  This is the default, since an unhandled
+    <tt>del()</tt> may be the cause of a memory leak, depending
+    on the memory management strategy in use.
+<li>Do nothing.  This is the default if the <tt>useGCDefaults</tt>
+    option is specified.
+<li>Decrement a reference count, deallocate, etc.  Depending on
+    the programmer's intended memory management scheme, the
+    value passed to <tt>del()</tt> can be treated appropriately.
+</ul>
+
+<a name="merge"></a>
+<h2>4.3 merge</h2>
+
+<p>
+An <em>ambiguity</em> is the condition when a single sequence of
+tokens can be parsed as some nonterminal in more than one way.
+During parsing, when an ambiguity is encountered, the semantic
+values from the different parses are passed to the nonterminal's
+<tt>merge()</tt> function, two at a time.
+
+<p>
+Merge accepts two competing semantic value arguments, and returns a
+semantic value that will stand for the ambiguous region in all future
+reductions.  Both the arguments and the return value have the type of
+the nonterminal's usual semantic values.
+
+<p>
+If there are more than two parses, the first two will be merged, the
+result of which will be merged with the third, and so on until they
+are all merged.  At each step, the first argument is the one that
+may have resulted from a previous <tt>merge()</tt>, and the second
+argument is not (unless it is the result of merging from further
+down in the parse forest).
+
+<p>
+Common <tt>merge()</tt> strategies:
+<ul>
+<li>Print a message to the effect that the ambiguity is unexpected,
+    and return one of the arguments arbitrarily.  This is the
+    default behavior.
+<li>Abort the program.  This is a more severe response than the
+    first one, and is the default if the <tt>defaultMergeAborts</tt>
+    option is specified.
+<li>Examine the two semantic values, and apply some disambiguation
+    criteria to choose which to retain.  Then return only the
+    retained value.  Note that <tt>merge()</tt> is being given exclusive
+    right to access both values; if it chooses to only return one of
+    them for future reductions, then the other should probably be
+    treated similarly to calling <tt>del()</tt> (though in fact, literally
+    calling <tt>del()</tt> is not possible in the current implementation).
+<li>Create some explicit representation of the ambiguity.  This is how
+    the Elsa C++ parser handles most of the ambiguities in its C++ grammar,
+    due to the type/variable ambiguity.
+</ul>
+
+<p>
+<b>Note that ambiguity is different from a reduce/reduce conflict.</b>
+A reduce/reduce conflict happens when
+the top few symbols of the parse stack can be reduced by two different
+rules.  It is not (necessarily) an ambiguity, as the reduced input
+portions are different.  In <tt>merge()</tt>, the merging fragments arise from
+reductions applied to the *same* sequence of ground terminals.
+
+<p>
+For example, the following unambiguous(!) grammar
+<pre>
+  S -&gt; B a c | b A a d
+  B -&gt; b a a
+  A -&gt; a a
+</pre>
+has a reduce/reduce conflict because after seeing "baa" with "a" in the
+lookahead, the parser cannot tell whether to reduce the topmost "aa" to A,
+or the entire "baa" to B, since it only has one token of lookahead and
+can't see whether the token after the lookahead is "c" or "d".
+
+<p>
+On the other hand, the ambiguous grammar
+<pre>
+  S -&gt; A b | a b
+  A -&gt; a
+</pre>
+contains no reduce/reduce conflicts.  The only conflict is a shift/reduce,
+as after seeing "a" with "b" as lookahead the parser cannot tell whether
+to reduce "a" to A, or shift the "b" and later reduce the combination
+directly as S.
+
+<p>
+Conceptually, if you imagine a nondeterministic LALR parsing algorithm,
+conflicts are split (choice) points and ambiguities are join points.  You
+cannot have a join without a split, but there is no easy way (in fact it's
+undecidable) to compute a precise relationship between splits and possible
+future joins.  Both shift/reduce and reduce/reduce are split points,
+whereas <tt>merge()</tt> is a join.
+
+
+<a name="keep"></a>
+<h2>4.4 keep</h2>
+
+<p>
+Sometimes, a potential ambiguity can be prevented if a semantic value
+can be determined to be invalid in isolation (as opposed to waiting to
+see a competing alternative in <tt>merge()</tt>).  To support such
+determination, each nonterminal can have a <tt>keep()</tt> function,
+which returns <tt>true</tt> if its semantic value argument should be
+retained (as usual) or <tt>false</tt> if its argument should be
+suppressed, as if the reduction never happened.
+
+<p>
+If <tt>keep</tt> returns <tt>false</tt>, the parser does <em>not</em>
+call <tt>del()</tt> on that value; it is regarded as disposed by
+<tt>keep</tt>.
+
+<p>
+Common <tt>keep</tt> strategies:
+<ul>
+<li>Always return <tt>true</tt>.  This is the default.
+<li>Look at the argument, and return <tt>false</tt> if for some reason
+    it should be discarded, particularly if it will otherwise lead to
+    an ambiguity.  This is the intended usage.
+<li>As a variation of the above, the reduction action itself can make
+    the determination of suitability, and return a special value like
+    <tt>NULL</tt> if it wants to cancel the reduction.  Then,
+    <tt>keep()</tt> simply checks for the special value.  In fact,
+    since <tt>keep()</tt> is a somewhat expensive option in terms of
+    performance, I am considering eliminating <tt>keep()</tt> in favor
+    of a built-in <tt>NULL</tt> check.
+</ul>
+
+
+<a name="precedence"></a>
+<h2>4.5 precedence</h2>
+
+<p>
+A rule can be annotated with an explicit precedence specification,
+for example:
+<pre>
+  nonterm N {
+    -&gt; A B C     precedence("+")   { /*...*/ }
+  }
+</pre>
+
+<p>
+This specification has the effect of assigning the rule
+"<tt>N -&gt; A B C</tt>" the same precedence level as the terminal "+".
+See <a href="#prec_assoc">Section 7</a> for more information on what
+this does.
+
+
+<a name="forbid"></a>
+<h2>4.6 forbid_next</h2>
+
+<p>
+A rule can also be annotated with one or more <em>forbidden
+lookahead</em> declarations, for example:
+<pre>
+  nonterm N {
+    -&gt; A B C     forbid_next("+") forbid_next("*")  { /*...*/ }
+  }
+</pre>
+
+<p>
+This specification means that the rule "<tt>N -&gt; A B C</tt>" can
+not be used to reduce if the next symbol is either "+" or "*".
+
+
+<a name="options"></a>
+<h1>5. Options</h1>
+
+<p>
+A number of variations in parser generator behavior can be requested
+through the use of the <tt>option</tt> syntax:
+<blockquote>
+  <tt>option </tt><i>option_name</i><tt>;</tt>
+</blockquote>
+or, for options that accept an argument:
+<blockquote>
+  <tt>option </tt><i>option_name</i> <i>option_argument</i><tt>;</tt>
+</blockquote>
+The <i>option_name</i> is an identifier from among those listed below,
+and <i>option_argument</i> is an integer.
+
+<p>
+Option processing is implemented in 
+<a href="grampar.cc"><tt>grampar.cc</tt></a>,
+function <tt>astParseOptions</tt>.
+The various options are described in the following sections.
+
+<a name="useGCDefaults"></a>
+<h2>5.1 useGCDefaults</h2>
+
+<p>
+The command
+<pre>
+  option useGCDefaults;
+</pre>
+instructs the parser generator to make the tacit assumption that sharing
+management is automatic (e.g. via a garbage collector), and hence set the
+default terminal and nonterminal functions appropriately.
+
+<p>
+In fact, most users of Elkhound will probably want to specify this
+option during initial grammar development, to reduce the amount
+of specification needed to get started.  The rationale for not making
+<tt>useGCDefaults</tt> the global default is that users should be aware
+that the issue of sharing management is being swept under the carpet.
+
+<a name="defaultMergeAborts"></a>
+<h2>5.2 defaultMergeAborts</h2>
+
+<p>
+The command
+<pre>
+  option defaultMergeAborts;
+</pre>
+instructs the parser generator that if the grammar does not specify a
+<tt>merge()</tt> function, the supplied default should print a message
+and then abort the program.  This is a good idea once it is believed
+that all the ambiguities have been handled by <tt>merge()</tt> functions.
+
+<a name="expected_stats"></a>
+<h2>5.3 Expected conflicts, unreachable symbols</h2>
+
+<p>
+Nominally, the parser generator expects there to be no shift/reduce
+and no reduce/reduce conflicts, and no unreachable (from the start
+symbol) symbols.  Of course, the whole point of using GLR is to allow
+conflicts, but it is still generally profitable to keep track of how
+many conflicts are present at a given stage of grammar development,
+since a sudden explosion of conflicts often indicates a grammar bug.
+
+<p>
+So, the user can declare how many conflicts of each type are expected.
+For example,
+<pre>
+  option shift_reduce_conflicts 40;
+  option reduce_reduce_conflicts 30;
+</pre>
+specifies that 40 S/R conflicts and 30 R/R conflicts are expected.  If
+the parser generator finds matching statistics, it will suppress
+reporting of such statistics; if there is a difference, it will be
+reported.
+
+<p>
+Similarly, one can indicate the expected number of unreachable
+syhmbols (this usually corresponds to a grammar in development, where
+part of the grammar has been deliberately disabled by making it
+inaccessible):
+<pre>
+  option unreachable_nonterminals 3;
+  option unreachable_terminals 2;
+</pre>
+
+<a name="allow_continued_nonterminals"></a>
+<h2>5.4 allow_continued_nonterminals</h2>
+
+<p>
+By default, Elkhound will complain if there is more than one
+definition of a given nonterminal.  However, if you say
+<pre>
+  option allow_continued_nonterminals;
+</pre>
+then Elkhound will treat input like
+<pre>
+  nonterm(type) N {
+    -&gt; A ;
+  }
+  nonterm(type) N {
+    -&gt; B ;
+  }
+</pre>
+as equivalent to
+<pre>
+  nonterm(type) N {
+    -&gt; A ;
+    -&gt; B ;
+  }
+</pre>
+
+
+<p>
+The nonterminal types, if specified, must be identical.  
+
+<p>
+Since Elkhound just concatenates the bodies, specification functions 
+(like <tt>merge()</tt>) must be given at most once across all
+continuations, and they apply to the whole (concatenated) nonterminal.
+
+<p>
+This feature is mostly useful for automatically-generated grammars,
+particularly those created by textually combining elements from
+two or more human-written grammars.
+
+
+<a name="ocaml"></a>
+<h1>6. OCaml</h1>
+
+<p>
+By default, Elkhound generates a parser in C++.  By specifying
+"<tt>-ocaml</tt>" on the command line,
+the user can request that instead the parser generate OCaml code.
+Please see <a href="ocaml/">ocaml/</a>, probably starting with
+the example driver <a href="ocaml/main.ml">ocaml/main.ml</a>.
+
+<p>
+The lexer interface for OCaml is given in 
+<a href="ocaml/lexerint.ml">ocaml/lexerint.ml</a>.  It is similar
+to the C++ interface except I have not yet (2005-06-13) implemented
+support for source location propagation, so there is no <tt>loc</tt>
+field.  Also, since OCaml does not have function pointers, it uses
+an ordinary virtual dispatch to get the next token.
+
+<a name="prec_assoc"></a>
+<h1>7. Precedence and Associativity</h1>
+
+<p>
+Precedence and associativity ("prec/assoc") declarations are a
+technique for statically resolving conflicts.  They are often
+convenient, but can also be confusing.
+
+<p>
+Precisely understanding prec/assoc requires some familiarity of the
+details of LR parsing, in particular the difference between "shift"
+and "reduce".  The following description assumes the reader is
+familiar with these concepts.  If you are not, Section&nbsp;2 of the
+<a href="http://www.cs.berkeley.edu/~smcpeak/elkhound/elkhound.ps">Elkhound
+technical report</a> contains a brief description.
+
+<a name="prec_assoc_meaning"></a>
+<h2>7.1 Meaning of prec/assoc specifications</h2>
+
+<p>
+A prec/assoc specification is a precedence number, and an associativity
+direction.  Precedence numbers are integers, where larger integers
+have "higher precedence".  An associativity direction is one of
+the following:
+<table border="2">
+  <tr>
+    <th>Name</th>
+    <th>Mnemonic</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>left</td>
+    <td>left associative</td>
+    <td>Resolve shift/reduce by reducing.</td>
+  </tr>
+  <tr>
+    <td>right</td>
+    <td>right associative</td>
+    <td>Resolve shift/reduce by shifting.</td>
+  </tr>
+  <tr>
+    <td>nonassoc</td>
+    <td>non associative</td>
+    <td>"Resolve" shift/reduce by deleting <em>both</em> possibilities,
+        consequently making associative uses into parse-time syntax errors.</td>
+  </tr>
+  <tr>
+    <td>prec</td>
+    <td>specify only precedence</td>
+    <td>This directive asserts that a grammar does not have a conflict that
+        would require using the associativity direction; if it does,
+        it is a parser-generation-time error.</td>
+   </tr>
+   <tr>
+     <td>assoc_split</td>
+     <td></td>
+     <td>Do not resolve the conflict; the GLR algorithm will split the
+         parse stack as necessary.</td>
+   </tr>
+</table>
+
+<a name="prec_assoc_attach"></a>
+<h2>7.2 Attaching prec/assoc to tokens and productions</h2>
+
+<p>
+Each token can be associated with a prec/assoc specification.
+By default, a token has no prec/assoc specification.  However, a
+specification can be attached via the <tt>precedence</tt> block of the
+<tt>terminals</tt> section of the grammar file (see Section 3.4, above).
+
+<p>
+Each production can be associated with a precedence number.
+If a production includes any terminals among its RHS elements, then
+the production inherits the precedence number of the <em>rightmost</em>
+terminal in the RHS; if the rightmost terminal has no prec/assoc
+specification, then the rule has no precedence.  The precedence
+number can also be explicitly supplied by writing
+<blockquote>
+  <tt>precedence (</tt> <i>tok</i> <tt>)</tt>
+</blockquote>
+at the end of the RHS (just before the action).  This will use the
+precedence of <i>tok</i> instead of the rightmost terminal.
+
+
+<a name="prec_assoc_resolution"></a>
+<h2>7.3 Conflict resolution with prec/assoc specifications</h2>
+
+<p>
+The resulting token and rule prec/assoc info is used during parser
+generation (only), to resolve shift/reduce and reduce/reduce conflicts.
+"Resolving" a conflict means removing one of the possible actions from the
+parse tables.  It is implemented in <tt>GrammarAnalysis::resolveConflicts()</tt>.
+
+<p>
+When a shift/reduce conflict is encountered between token and a rule, if
+the token has higher precedence, then a shift is used, otherwise a reduce
+is used.  If they have the same precedence, then the associativity direction
+of the token is consulted, using the resolution procedures described in
+the table above.
+
+<p>
+When a reduce/reduce conflict is encountered, the highest precedence rule
+is chosen.
+
+<p>
+In both cases, if either conflicting entity does not have any prec/assoc
+specification, then no resolution is done, and the GLR algorithm will
+split the parse stack at parse time as necessary.
+
+
+<a name="prec_assoc_example_arith"></a>
+<h2>7.4 Example: Arithmetic grammar</h2>
+
+<p>
+The canonical example of using prec/assoc is to give a grammar for
+arithmetic expressions, using an ambiguous grammar (for convenience)
+and prec/assoc to resolve the ambiguities.  The grammar is typically
+(e.g., <a href="examples/arith/arith.gr">arith.gr</a>) something like
+<pre>
+  nonterm Expr {
+    -&gt; Expr "+" Expr ;
+    -&gt; Expr "-" Expr ;
+    -&gt; Expr "*" Expr ;
+    -&gt; Expr "/" Expr ;
+    -&gt; TOK_NUMBER ;
+  }
+</pre>
+with a precedence specification like
+<pre>
+  precedence {
+    left 20 "*" "/";
+    left 10 "+" "-";
+  }
+</pre>
+
+<p>
+Consider parsing the input "1 + 2 * 3".  This should parse like
+"1 + (2 * 3)".  The crucial moment during the parsing algorithm
+comes when the parser sees the "*" in its lookahead.  At that moment, 
+the parse stack looks like
+<pre>
+  Expr(2)                       <-- top of stack (most recently shifted)
+  +
+  Expr(1)                       <-- bottom of stack
+</pre>
+
+<p>
+If the parser were to <em>reduce</em>, via the rule "<tt>Expr -&gt; Expr + Expr</tt>",
+then the stack would become
+<pre>
+  Expr(Expr(1)+Expr(2))         <-- top/bottom of stack
+</pre>
+which means the final parse would be "(1 + 2) * 3", which is wrong.
+
+<p>
+Alternatively, if the parser were to <em>shift</em>, the stack becomes
+<pre>
+  *                             &lt;-- top of stack
+  Expr(2)
+  +
+  Expr(1)                       &lt;-- bottom of stack
+</pre>
+Then after one more shift, we have
+<pre>
+  Expr(3)                       &lt;-- top of stack
+  *
+  Expr(2)
+  +
+  Expr(1)                       &lt;-- bottom of stack
+</pre>
+and the only choice is to reduce via "<tt>Expr -&gt; Expr * Expr</tt>", leading to
+the configuration
+<pre>
+  Expr(Expr(2)*Expr(3))         &lt;-- top of stack
+  +
+  Expr(1)                       &lt;-- bottom of stack
+</pre>
+and one more reduce yields
+<pre>
+  Expr( Expr(1) + Expr(Expr(2)*Expr(3)) )    &lt;-- top/bottom
+</pre>
+which is the desired "1 + (2 * 3)" interpretation.
+
+<p>
+The parsing choice above is a <em>shift/reduce conflict</em>; the parser
+must choose between shifting "*" and reducing via "<tt>Expr -&gt; Expr + Expr</tt>".
+Now, the prec/assoc spec says that "*" has higher precedence than "+",
+and the rule is (by default) given the precedence of the latter.
+Consequently, the shift is chosen, so that the "*" will ultimately
+be reduced before the "+".
+
+<p>
+One can do similar reasoning for the case of "1 + 2 + 3", which should
+parse as "(1 + 2) + 3", and does so because "+" is declared to be left-associative:
+reduces are preferred to shifts (reduce early instead of reducing late).
+
+<a name="prec_assoc_example_else"></a>
+<h2>7.5 Example: Dangling else</h2>
+
+<p>
+As another example of using prec/assoc to resolve grammar ambiguity,
+we can consider the classic "dangling else" problem.  Many languages,
+such as C, have two rules for the "if" statement:
+<pre>
+  nonterm Stmt {
+    -&gt; "if" "(" Expr ")" Stmt ;
+    -&gt; "if" "(" Expr ")" Stmt "else" Stmt ;
+    ...
+  }
+</pre>
+This grammar is ambiguous; for example, the input
+<pre>
+  if (P)   if (Q)   a=b;   else   c=d;
+</pre>
+could be parsed as
+<pre>
+  if (P) {
+    if (Q)
+      a=b;
+    else        // associated with inner "if"
+      c=d;
+  }
+</pre>
+or as
+<pre>
+  if (P) {
+    if (Q)
+      a=b;
+  }
+  else          // associated with outer "if"
+    c=d;
+</pre>
+
+<p>
+As with all uses of prec/assoc, it is possible to resolve the
+ambiguity by modifying the grammar.  (Actually, I'm not 100% sure
+about this fact, especially because of LALR vs LR.  But it seems
+to be true in practice.)  However, in this case, doing so
+means duplicating the entire Stmt nonterm, creating one case for when
+it is the first thing in the then-block of an "if" statement with an
+"else" clause (in which case the version missing an "else" is not
+allowed), and another case for when it is not.  Such savagery to
+the grammar is usually unacceptable.
+
+<p>
+There is an easy fix with prec/assoc, however: simply declare
+"else" to be right-associative, and (explicitly) give both "if" rules
+the precedence of the "else" token:
+<pre>
+  terminals {
+    precedence {
+      right 100 "else";     // precedence number irrelevant
+    }
+  }
+  ...
+  nonterm Stmt {
+    -&gt; "if" "(" Expr ")" Stmt                   precedence("else");
+    -&gt; "if" "(" Expr ")" Stmt "else" Stmt       precedence("else");
+    ...
+  }
+</pre>
+At the crucial moment, the lookahead is "else" and the stack is
+<pre>
+  Stmt(a=b;)                          &lt;-- top
+  ")"
+  Expr(Q)
+  "("
+  "if"
+  ")"
+  Expr(P)
+  "("
+  "if"                                &lt;-- bottom
+</pre>
+The conflict is between shifting "else" and reducing via
+"<tt>Stmt -&gt; if ( Expr ) Stmt</tt>".  Since the precedence of both
+the token and the rule is the same, the associativity direction
+of the token is consulted.  That direction is "right", which means
+to reduce late, i.e. shift.  After shifting "else", then the rest of the input,
+and reducing "c=d;", we have
+<pre>
+  Stmt(c=d;)                          &lt;-- top
+  "else"
+  Stmt(a=b;)
+  ")"
+  Expr(Q)
+  "("
+  "if"
+  ")"
+  Expr(P)
+  "("
+  "if"                                &lt;-- bottom
+</pre>
+Finally, the algorithm reduces via
+"<tt>Stmt -&gt; if ( Expr ) Stmt else Stmt</tt>", yielding
+<pre>
+  If(Q, Stmt(a=b;), Stmt(c=d;))       &lt;-- top
+  ")"
+  Expr(P)
+  "("
+  "if"                                &lt;-- bottom
+</pre>
+and one more reduce yields
+<pre>
+  If(P,   If(Q, Stmt(a=b;), Stmt(c=d;))  )
+</pre>
+which corresponds to binding the "else" to the innermost "if".
+
+<a name="prec_assoc_further"></a>
+<h2>7.6 Further directions</h2>
+
+<p>
+As illustrated in the "dangling else" example, prec/assoc specifications
+need not involve "operators" with a classic "precedence order".  Arguably,
+such cases constitute a hack, wherein the grammar designer takes advantage
+of knowledge of the parsing algorithm in use.  It would perhaps be better
+if there were some kind of parsing-algorithm-neutral specification technique
+that could subsume LR prec/assoc, but be translated into LR prec/assoc
+if that is the algorithm in use.  But I do not know of such a technique.
+(At one point I played with using attribute grammars and planned some
+static analysis to figure out when an attribute grammar's inherited
+attributes could be replaced with an equivalent prec/assoc spec, but it turned
+out to be hard so I abandoned the attempt.)
+
+<p>
+Not every use of prec/assoc is to resolve an actual grammatical
+ambiguity.  It is possible for the grammar to be unambiguous, but
+still have a conflict, in which case a prec/assoc specification
+may be a good way to resolve it, if performance is a concern.
+
+<p>
+I think the best advice is: if you are not very familiar with LR
+parsing, ignore prec/assoc.  Either write an unambiguous grammar, or
+use Elkhound's <tt>merge</tt> feature to do disambiguation; in either
+case, the conflicts only affect performance and so can be ignored.
+If you <em>are</em> familiar with LR parsing, then use your judgment
+as to whether a given situation is right for prec/assoc.  They can
+seem appealing since they yield fast parsers, but it can be difficult 
+to determine the actual language accepted by an LR parser with prec/assoc.
+
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+
+</HTML>

Added: vendor/elsa/current/elkhound/mkdist
===================================================================
--- vendor/elsa/current/elkhound/mkdist	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/mkdist	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,47 @@
+#!/bin/sh
+# make a tarball for distribution
+      
+# bail on error
+set -e
+
+# tarball dist name; e.g. elkhound-2002.08.12
+distname=elkhound-`date "+%Y.%m.%d"`
+echo $distname
+
+mkdir $distname || exit
+cd $distname || exit
+
+# main stuff
+cvs export -D now smbase || exit
+cvs export -D now ast || exit
+cvs export -D now parsgen || exit
+
+# toplevel files
+cp parsgen/toplevel/* .
+
+
+# package it up
+cd ..
+targz $distname || exit
+rm -rf $distname
+
+# test it
+untargz ${distname}.tar.gz
+cd ${distname}
+./configure
+make
+cd parsgen
+./regrtest
+
+# blow away the test directory
+if [ "$1" != "-keep" ]; then
+  cd ../..
+  rm -rf $distname
+fi
+
+
+
+
+
+
+


Property changes on: vendor/elsa/current/elkhound/mkdist
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/mlsstr.cc
===================================================================
--- vendor/elsa/current/elkhound/mlsstr.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/mlsstr.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,500 @@
+// mlsstr.cc            see license.txt for copyright and terms of use
+// code for mlsstr.h
+// based on ccsstr.cc
+
+#include "mlsstr.h"      // this module
+#include "xassert.h"     // xassert
+#include "exc.h"         // xformat
+#include "strutil.h"     // string, replace
+
+#include <iostream.h>    // cout
+#include <ctype.h>       // isspace
+
+
+MLSubstrate::MLSubstrate(ReportError *err)
+  : EmbeddedLang(err)
+{
+  reset();
+}
+
+void MLSubstrate::reset(int initNest)
+{
+  state = ST_NORMAL;
+  delims.empty();
+  nestingBias = initNest;
+  comNesting = 0;
+  prev = 0;
+  text.setlength(0);
+}
+
+
+MLSubstrate::~MLSubstrate()
+{}
+
+
+void MLSubstrate::handle(char const *str, int len, char finalDelim)
+{
+  text.append(str, len);
+
+  for (; len>0; len--,str++) {
+  process_char_again:
+    switch (state) {
+      case ST_NORMAL:
+        switch (*str) {
+          case '{':
+          case '(':
+          case '[':
+            if (!inComment()) {
+              delims.push(*str);
+            }
+            break;
+
+          case '}':
+          case ')':
+          case ']':
+            if (inComment()) {
+              if (prev == '*' && *str == ')') {
+                comNesting--;
+              }
+            }
+            else if (nesting() == 0) {
+              err->reportError(stringc
+                << "unexpected closing delimiter `" << *str
+                << "' -- probably due to missing `" << finalDelim << "'");
+            }
+            else {
+              char o = delims.top();
+              char c = *str;
+              if (!(( o=='{' && c=='}' ) ||
+                    ( o=='(' && c==')' ) ||
+                    ( o=='[' && c==']' ))) {
+                err->reportError(stringc
+                  << "opening delimiter `" << o
+                  << "' does not match closing delimiter `" << c << "'");
+              }
+              delims.pop();
+            }
+            break;
+
+          case '\"':
+            state = ST_STRING;
+            break;
+
+          case '\'':
+            if (isalnum(prev) || prev=='_' || prev=='\'') {
+              // this is a prime on a variable name; stay in normal mode
+            }
+            else {
+              state = ST_APOSTROPHE1;
+            }
+            break;
+
+          case '*':
+            if (prev == '(') {
+              if (comNesting == 0) {
+                // undo 'delims.push()' from the '('
+                xassert(nesting() > 0);
+                delims.pop();
+              }
+              comNesting++;
+
+              // if the next char is ')', i.e. input was "(*)", do
+              // not allow it to use this '*' to finish the comment
+              prev = 0;
+              continue;
+            }
+            break;
+        }
+        break;
+
+      case ST_APOSTROPHE1:
+        // While the OCaml manual does not specify how to disambiguate
+        // between character literals and type variables, the ocaml
+        // lexer (parsing/lexer.mll) uses (approximately) the
+        // following rules:
+        //
+        //   - If the input is (apostrophe, char, apostrophe), it is
+        //     a character literal.
+        //   - If the input is (apostrophe, backslash), it is the start
+        //     of a a character literal.
+        //   - Any other occurrence of apostrophe starts a type variable.
+        if (*str == '\\') {
+          state = ST_CHAR;
+        }
+        else {
+          state = ST_APOSTROPHE2;
+        }
+        break;
+        
+      case ST_APOSTROPHE2:
+        if (*str == '\'') {
+          state = ST_NORMAL;    // finishes the character literal
+        }
+        else {                  
+          // whole thing is a type variable; but if *str is something
+          // like ')' then we need to consider its effects on nesting
+          state = ST_NORMAL;
+          goto process_char_again;
+        }
+        break;
+
+      case ST_STRING:
+      case ST_CHAR:
+        if (prev != '\\') {
+          if ((state == ST_STRING && *str == '\"') ||
+              (state == ST_CHAR && *str == '\'')) {
+            state = ST_NORMAL;
+          }
+          else if (*str == '\n') {
+            // actually, ocaml allows unescaped newlines in string literals
+            //err->reportError("unterminated string or char literal");
+          }
+        }
+        else {
+          prev = 0;      // the backslash cancels any specialness of *str
+          continue;
+        }
+        break;
+
+      #if 0   // old
+      case ST_COMMENT:
+        if (prev == '(' && *str == '*') {
+          comNesting++;
+          prev = 0;      // like above
+          continue;
+        }
+        else if (prev == '*' && *str == ')') {
+          xassert(comNesting >= 0);
+          if (comNesting == 0) {
+            // done with comment
+            state = ST_NORMAL;
+          }
+          else {
+            // decrease nesting
+            comNesting--;
+          }
+        }
+        break;
+      #endif // 0
+
+      default:
+        xfailure("unknown state");
+    }
+
+    prev = *str;
+  }
+}
+
+
+bool MLSubstrate::zeroNesting() const
+{
+  return state == ST_NORMAL && nesting() == 0 && !inComment();
+}
+
+
+string MLSubstrate::getFuncBody() const
+{
+  return text;
+}
+
+
+// 4/29/04: I have no idea if this is right or not.. this is the
+// definition from ccsstr.cc.
+string MLSubstrate::getDeclName() const
+{
+  // go with the rather inelegant heuristic that the word
+  // just before the first '(' is the function's name
+  char const *start = text.c_str();
+  char const *p = start;
+  
+  // find first '('
+  while (*p && *p!='(') { p++; }
+  if (!*p) {
+    xformat("missing '('");
+  }             
+  if (p == start) {
+    xformat("missing name");
+  }
+
+  // skip backward past any whitespace before the '('
+  p--;
+  while (p>=start && isspace(*p)) { p--; }
+  if (p<start) {
+    xformat("missing name");
+  }
+  char const *nameEnd = p+1;    // char just past last
+  
+  // move backward through the name
+  while (p>=start && 
+         (isalnum(*p) || *p=='_'))
+    { p--; }
+  p++;    // move back to most recent legal char
+  
+  // done
+  return substring(p, nameEnd-p);
+}
+
+
+// ------------------ test code -------------------
+#ifdef TEST_MLSSTR
+
+#define ML MLSubstrate
+#define Test MLSubstrateTest
+
+// test code is put into a class just so that MLSubstrate
+// can grant it access to private fields
+class Test {
+public:
+  void feed(ML &ml, char const *src, bool allowErrors = false);
+  void silentFeed(ML &ml, char const *src);
+  void test(char const *src, ML::State state, int nesting,
+            int comNesting, char prev);
+  void normal(char const *src, int nesting);
+  void str(char const *src, int nesting, bool bs);
+  void yes(char const *src);
+  void no(char const *src);
+  void name(char const *body, char const *n);
+  void badname(char const *body);
+  void bad(char const *body);
+  int main(int argc, char *argv[]);
+};
+
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+void Test::feed(ML &ml, char const *src, bool allowErrors)
+{
+  int origErrors = simpleReportError.errors;
+
+  cout << "trying: " << src << endl;
+  silentFeed(ml, src);
+
+  if (!allowErrors &&
+      origErrors != simpleReportError.errors) {
+    xfailure(stringc << "caused error: " << src);
+  }
+}
+
+void Test::silentFeed(ML &ml, char const *src)
+{
+  while (*src) {
+    // feed it in 10 char increments, to test split processing too
+    int len = min(strlen(src), 10);
+    ml.handle(src, len, '}');
+    src += len;
+  }
+}
+
+
+void Test::test(char const *src, ML::State state, int nesting,
+                int comNesting, char prev)
+{
+  ML ml;
+  feed(ml, src);
+
+  if (!( ml.state == state &&
+         ml.nesting() == nesting &&
+         ml.comNesting == comNesting &&
+         ml.prev == prev )) {
+    xfailure(stringc << "failed on src: " << src);
+  }
+}
+
+
+void Test::normal(char const *src, int nesting)
+{
+  test(src, ML::ST_NORMAL, nesting, 0, src[strlen(src)-1]);
+}
+
+void Test::str(char const *src, int nesting, bool bs)
+{
+  char prev = (bs? '\\' : src[strlen(src)-1]);
+  test(src, ML::ST_STRING, nesting, 0, prev);
+
+  // repeat the test with single-tick
+  //
+  // 2005-01-25: No, OCaml's character-literal rules do not treat
+  // quote and apostrophe similarly.
+  //string another = replace(src, "\"", "\'");
+  //test(another, ML::ST_CHAR, nesting, 0, prev);
+}
+
+
+void Test::yes(char const *src)
+{
+  ML ml;
+  feed(ml, src);
+
+  xassert(ml.zeroNesting());
+}
+
+void Test::no(char const *src)
+{
+  ML ml;
+  feed(ml, src);
+
+  xassert(!ml.zeroNesting());
+}
+
+void Test::name(char const *body, char const *n)
+{
+  ML ml;
+  feed(ml, body);
+  xassert(ml.getDeclName().equals(n));
+}
+
+void Test::badname(char const *body)
+{
+  ML ml;
+  feed(ml, body);
+  try {
+    ml.getDeclName();
+    xbase("got a name when it shoudn't have!");
+  }
+  catch (...)
+    {}
+}
+
+void Test::bad(char const *body)
+{
+  int origErrors = simpleReportError.errors;
+
+  ML ml;
+  feed(ml, body, true /*allowErrors*/);
+
+  if (origErrors == simpleReportError.errors) {
+    xbase(stringc << "should have caused an error: " << body);
+  }
+}
+
+
+int Test::main(int argc, char *argv[])
+{
+  if (argc >= 2) {
+    // analyze the files passed as an argument, expecting them to be
+    // complete caml source files, ending in normal mode with all
+    // delimiters closed         
+    for (int i=1; i<argc; i++) {
+      string text = readStringFromFile(argv[i]);
+      
+      ML ml;
+      silentFeed(ml, text.c_str());
+
+      if (ml.state != ML::ST_NORMAL) {
+        xbase(stringc << argv[i] << ": ended in state " << (int)ml.state);
+      }
+      if (ml.nesting() != 0) {
+        xbase(stringc << argv[i] << ": ended with nesting " << ml.nesting());
+      }
+      if (ml.inComment()) {
+        xbase(stringc << argv[i] << ": ended in a comment");
+      }
+      if (simpleReportError.errors != 0) {
+        xbase(stringc << argv[i] << ": caused errors");
+      }
+
+      cout << argv[i] << ": ok\n";
+    }
+    return 0;
+  }
+
+  normal("int main()", 0);
+  normal("int main() { hi", 1);
+  normal("int main() { hi {", 2);
+  normal("int main() { hi { foo[5", 3);
+  normal("int main() { hi { foo[5] and ", 2);
+  normal("int main() { hi { foo[5] and } bar ", 1);
+  normal("int main() { hi { foo[5] and } bar } baz ", 0);
+
+  normal("main() { printf(\"hello \\ world\"); ret", 1);
+
+  normal("()[]{}([{}])", 0);
+  normal("{ ()[]{}([{}]) } ", 0);
+  normal("( ()[]{}([{}]) )", 0);
+  normal("[ ()[]{}([{}]) ]", 0);
+  normal("\"foo\" ()[]{}([{}])", 0);
+
+  str("main() { printf(\"hello", 2, false);
+  str("main() { printf(\"hello \\", 2, true);
+  str("main() { printf(\"hello \\ world", 2, false);
+  str("main() { printf(\"hello \\ world\", \"hi", 2, false);
+  
+  // escaped newline
+  normal("main() { printf(\"hello \\\n world\"); }", 0);
+
+  // newlines do not have to be escaped!
+  normal("main() { printf(\"hello \n world\"); }", 0);
+
+  test("\"a\" 'b' (", ML::ST_NORMAL, 1, 0, '(');
+  test("\"a\" '\\n' (", ML::ST_NORMAL, 1, 0, '(');
+  test("\"a\" '\\\\' (", ML::ST_NORMAL, 1, 0, '(');
+
+  // here, the "'b" is to be treated as a type variable
+  test("\"a\" 'b (", ML::ST_NORMAL, 1, 0, '(');
+  test("\"a\" ('b) (", ML::ST_NORMAL, 1, 0, '(');
+
+  // and here it is a prime ending the name of a variable
+  test("\"a\" b' (", ML::ST_NORMAL, 1, 0, '(');
+  test("\"a\" (b') (", ML::ST_NORMAL, 1, 0, '(');
+  test("\"a\" let b=b' (", ML::ST_NORMAL, 1, 0, '(');
+  test("\"a\" let b=b'' (", ML::ST_NORMAL, 1, 0, '(');
+  test("\"a\" let b=b''' (", ML::ST_NORMAL, 1, 0, '(');
+
+  // test comments, particularly testing
+  test("(", ML::ST_NORMAL, 1, 0, '(');
+  test("(*", ML::ST_NORMAL, 0, 1, 0);
+  test("(*)", ML::ST_NORMAL, 0, 1, ')');
+  test("(*)(", ML::ST_NORMAL, 0, 1, '(');
+  test("(*)(*", ML::ST_NORMAL, 0, 2, 0);
+  test("(*)(*)", ML::ST_NORMAL, 0, 2, ')');
+  test("(*)(*)*", ML::ST_NORMAL, 0, 2, '*');
+  test("(*)(*)*)", ML::ST_NORMAL, 0, 1, ')');
+  test("(*)(*)*)*", ML::ST_NORMAL, 0, 1, '*');
+  test("(*)(*)*)*)", ML::ST_NORMAL, 0, 0, ')');
+
+  test("(*(*(*(*", ML::ST_NORMAL, 0, 4, 0);
+
+  yes("main() {}");
+  yes("main() { printf(\"foo\", 3, 4 (*yep{*)); }");
+  yes("some (* junk {\n more*)");
+  yes("'\\''");
+  yes("\"\\\"\"");
+  yes("[][][][][]");
+  yes("\"[[[\"");
+  yes("*");
+  yes("(* [ / * [ *)");
+  yes("(* \"(*\" *)");     // quoted open-comment ignored
+
+  no("\"");
+  no("(");
+  no(" ( (* ) *) ");
+
+  name("int main()", "main");
+  name("int eval(Environment &env)", "eval");
+  name("man()", "man");
+  badname("(");
+  badname("  (");
+  badname("  ");
+  badname("");
+  bad(")");
+  badname("main");
+
+  cout << "\nmlsstr: all tests PASSED\n";
+
+  return 0;
+}
+
+int main(int argc, char *argv[])
+{
+  //xBase::logExceptions = false;
+  try {
+    Test t;
+    return t.main(argc, argv);
+  }
+  catch (xBase &x) {
+    cout << endl << x << endl;
+    return 10;
+  }
+}
+
+#endif // TEST_MLSSTR

Added: vendor/elsa/current/elkhound/mlsstr.h
===================================================================
--- vendor/elsa/current/elkhound/mlsstr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/mlsstr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,56 @@
+// mlsstr.h            see license.txt for copyright and terms of use
+// handles lexically embedded ML
+// based on ccsstr.h
+
+#ifndef MLSSTR_H
+#define MLSSTR_H
+
+#include "embedded.h"      // EmbeddedLang
+#include "array.h"         // ArrayStack
+
+class MLSubstrateTest;
+
+class MLSubstrate : public EmbeddedLang {
+private:
+  enum State {
+    ST_NORMAL,       // normal text
+    ST_STRING,       // inside a string literal
+    ST_CHAR,         // inside a char literal
+    ST_APOSTROPHE1,  // last char was an apostrophe
+    ST_APOSTROPHE2,  // char before last was an apostrophe
+    NUM_STATES
+  } state;
+  ArrayStack<char> delims; // stack of paren/bracket/brace delimiters
+  int nestingBias;         // modifies the nesting level
+  int comNesting;          // depth of comment nesting; 0 means not in comment
+  char prev;               // previous character
+
+  // NOTE: Because ocaml wants (**) to be usable to comment out
+  // arbitrary code sequences, the comment-ness is mostly orthogonal
+  // to other lexing state.  e.g., the syntax (* "(*" *) will be
+  // parsed as a (complete) comment.
+
+  // so test code can interrogate internal state
+  friend class MLSubstrateTest;
+
+private:
+  // depth of delimiter nesting
+  int nesting() const { return delims.length() + nestingBias; }
+  
+  // whether we are in a comment
+  bool inComment() const { return comNesting>0; }
+
+public:
+  MLSubstrate(ReportError *err = NULL);
+  virtual ~MLSubstrate();
+
+  // EmbeddedLang entry points (see gramlex.h for description
+  // of each function)
+  virtual void reset(int initNest = 0);
+  virtual void handle(char const *str, int len, char finalDelim);
+  virtual bool zeroNesting() const;
+  virtual string getFuncBody() const;
+  virtual string getDeclName() const;
+};
+
+#endif // MLSSTR_H

Added: vendor/elsa/current/elkhound/ocaml/arith.gr
===================================================================
--- vendor/elsa/current/elkhound/ocaml/arith.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/arith.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,54 @@
+// arith.gr
+// parser for a very simple language of arithmetic expressions
+// testing example for OCaml backend
+
+
+context_class arith {
+public:
+};
+
+
+terminals {
+  0 : TOK_EOF;
+  1 : TOK_NUMBER;              // no alias
+  2 : TOK_PLUS     "+";        // alias is "+" (including quotes)
+  3 : TOK_MINUS    "-";
+  4 : TOK_TIMES    "*";
+  5 : TOK_DIVIDE   "/";
+  6 : TOK_LPAREN   "(";
+  7 : TOK_RPAREN   ")";
+
+  token(int) TOK_NUMBER;       // numbers have associated int-typed values
+
+  precedence {
+    // high precedence
+    left 20 "*" "/";
+    left 10 "+" "-";
+    // low precedence
+  }
+}
+
+
+impl_verbatim {
+  (* this is verbatim code that gets inserted into arith.ml *)
+}
+
+nonterm(int) Exp {
+  -> e1:Exp "+" e2:Exp        { e1 + e2 }
+
+  -> e1:Exp "-" e2:Exp        { e1 - e2 }
+  -> e1:Exp "*" e2:Exp        { e1 * e2 }
+  -> e1:Exp "/" e2:Exp        { e1 / e2 }
+  -> n:TOK_NUMBER             { n }
+  -> p:ParenthesizedExp       { p }
+}
+
+// I've separated this rule out into its own nonterminal just to
+// show an example of having more than one nonterminal in a grammar.
+nonterm(int) ParenthesizedExp {
+  // messing around with embedded fragments..
+  -> "(" e:Exp ")"            { e   (* [ *) }
+}
+
+
+// EOF

Added: vendor/elsa/current/elkhound/ocaml/arraystack.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/arraystack.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/arraystack.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,160 @@
+(* arraystack.ml *)
+(* stack of pointers implemented as an array *)
+
+
+(* grow an array *)
+let growArray (arr: 'a array) (newLen: int) (null: 'a) : 'a array =
+begin
+  let newArr : 'a array = (Array.make newLen null) in
+
+  (* copy *)
+  (Array.blit
+    arr                   (* source array *)
+    0                     (* source start position *)
+    newArr                (* dest array *)
+    0                     (* dest start position *)
+    (Array.length arr)    (* number of elements to copy *)
+  );
+
+  (* return new array *)
+  newArr
+end
+
+
+(* ensure the array has at least the given index, growing its size
+ * if necessary (by doubling) *)
+let ensureIndexDoubler (arr: 'a array ref) (idx: int) (null: 'a) : unit =
+begin
+  while ((Array.length !arr) < (idx+1)) do
+    arr := (growArray !arr ((Array.length !arr) * 2) null);
+  done;
+end
+
+
+(* the stack must be given a dummy value for unused array slots *)
+class ['a] tArrayStack (null: 'a) =
+object (self)
+  (* ---- data ---- *)
+  (* number of (non-null) elements in the array *)
+  val mutable len: int = 0;
+
+  (* the array; its length may be greater than 'poolLength', to
+   * accomodate adding more elements without resizing the array *)
+  val mutable arr: 'a array = (Array.make 16 null);
+
+  (* ---- funcs ---- *)
+  method length() : int = len
+
+  method isEmpty() : bool = len=0
+  method isNotEmpty() : bool = len>0
+
+  (* get topmost element but don't change what is stored *)
+  method top() : 'a =
+  begin
+    arr.(len-1)
+  end
+
+  (* get topmost and remove it *)
+  method pop() : 'a =
+  begin
+    len <- len - 1;
+    arr.(len)
+  end
+
+  (* add a new topmost element *)
+  method push (obj: 'a) : unit =
+  begin
+    if (len = (Array.length arr)) then (
+      (* need to expand the array *)
+      arr <- (growArray arr (len*2) null);
+    );
+
+    (* put new element into the array at the end *)
+    arr.(len) <- obj;
+    len <- len + 1;
+  end
+
+  (* get arbitrary element *)
+  method elt (i: int) : 'a =
+  begin
+    arr.(i)
+  end
+
+  (* set arbitrary element *)
+  method setElt (i: int) (v: 'a) : unit =
+  begin
+    arr.(i) <- v
+  end
+
+  (* iterate *)
+  method iter (f: 'a -> unit) : unit =
+  begin
+    for i=0 to len-1 do
+      (f (arr.(i)))
+    done;
+  end
+
+  (* search and return the element index, or -1 for not found *)
+  method findIndex (f: 'a -> bool) : int =
+  begin
+    (* ug.. must use tail recursion just so I can break early... *)
+    let rec loop (i: int) : int =
+    begin
+      if (i > len-1) then (
+        -1                 (* not found *)
+      )
+      else if (f (arr.(i))) then (
+        i                  (* found *)
+      )
+      else (
+        (loop (i+1))       (* keep looking *)
+      )
+    end in
+
+    (loop 0)
+  end
+
+  (* search and return the element, or None *)
+  method findOption (f: 'a -> bool) : 'a option =
+  begin
+    let idx:int = (self#findIndex f) in
+    if (idx < 0) then (
+      None                 (* not found *)
+    )
+    else (
+      (Some arr.(idx))     (* found *)
+    )
+  end
+
+  (* search *)
+  method contains (f: 'a -> bool) : bool =
+  begin
+    ((self#findIndex f) >= 0)
+  end
+
+
+  (* just for 'swapWith' *)
+  (* I tried making them 'private' but that only allows method calls
+   * within the *same* object, not merely the same *type* object
+   * as in C++ *)
+  method (*private*) private_getArray() : 'a array = arr
+  method (*private*) private_setLength(l: int) : unit = len <- l
+  method (*private*) private_setArray(a: 'a array) : unit = arr <- a
+
+  (* swap contents with another array stack *)
+  method swapWith (obj: 'a tArrayStack) : unit =
+  begin
+    let tmpLen:int = len in
+    let tmpArr:'a array = arr in
+
+    len <- (obj#length());
+    arr <- (obj#private_getArray());
+
+    (obj#private_setLength tmpLen);
+    (obj#private_setArray tmpArr);
+  end
+
+end
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/een.gr
===================================================================
--- vendor/elsa/current/elkhound/ocaml/een.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/een.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// een.gr
+// test of ambiguous grammars in OCaml backend
+
+context_class een {
+  ()       // this is just to test the delimeter balancing
+};
+
+
+terminals {
+  0 : TOK_EOF;
+  1 : TOK_NUMBER;
+  2 : TOK_PLUS     "+";
+}
+
+
+nonterm(int) Exp {
+  // I just want to count the total number of parses
+  fun merge(a,b)              { a + b }
+  -> e1:Exp "+" e2:Exp        { e1 * e2 }
+  -> TOK_NUMBER               { 1 }
+}
+
+
+// EOF

Added: vendor/elsa/current/elkhound/ocaml/glr.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/glr.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/glr.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1591 @@
+(* glr.ml *)
+(* GLR parser *)
+(* based on elkhound/glr.h and elkhound/glr.cc *)
+
+open Arraystack      (* tArrayStack *)
+open Objpool         (* tObjPool *)
+open Useract         (* tSemanticValue *)
+open Lexerint        (* tLexerInterface *)
+open Parsetables     (* action/goto/etc. *)
+open Smutil          (* getSome, etc. *)
+
+
+(* Relative to C++ implementation, what is not done:
+ *   - Token reclassification
+ *   - Table compression
+ *   - Heavy testing of the mini-LR core
+ *)
+
+
+(* when true, print parse actions *)
+let traceParse:bool = false
+
+(* when true, keep some statistics useful for performance evaluation *)
+let accounting:bool = true
+
+(* when true, we call the user's keep() functions *)
+let use_keep:bool = true
+
+(* when true, use the mini LR core *)
+let use_mini_lr:bool = true
+
+
+(* NOTE: in some cases, more detailed comments can be found in
+ * elkhound/glr.h, as these data structures mirror the ones
+ * defined there *)
+
+
+(* identifier for a symbol *)
+type tSymbolId = int
+
+
+(* link from one stack node to another *)
+type tSiblingLink = {
+  (* stack node we're pointing at; == cNULL_STACK_NODE if none *)
+  mutable sib: tStackNode;
+
+  (* semantic value on this link *)
+  mutable sval: tSemanticValue;
+
+  (* TODO: source location *)
+
+  (* possible TODO: yield count *)
+}
+
+(* node in the GLR graph-structured stack; all fields are
+ * mutable because these are stored in a pool for explicit re-use *)
+and tStackNode = {
+  (* LR parser state when this node is at the top *)
+  mutable state: tStateId;
+
+  (* pointers to adjacent (to the left) stack nodes *)
+  (* possible TODO: put links into a pool so I can deallocate them *)
+  mutable leftSiblings: tSiblingLink list;
+
+  (* logically first sibling in the sibling list; separated out
+   * from 'leftSiblings' for performance reasons *)
+  mutable firstSib: tSiblingLink;
+
+  (* number of sibling links pointing at this node, plus the
+   * number of worklists this node appears in *)
+  mutable referenceCount: int;
+
+  (* number of links we can follow to the left before hitting a node
+   * that has more than one sibling *)
+  mutable determinDepth: int;
+
+  (* for access to parser context in a few unusual situations *)
+  mutable glr: tGLR;
+
+  (* position of token that was active when this node was created
+   * (or pulled from pool); used in yield-then-merge calculations *)
+  mutable column: int;
+}
+
+(* this is a path that has been queued for reduction;
+ * all fields mutable to support pooling *)
+and tPath = {
+  (* rightmost state's id *)
+  mutable startStateId: tStateId;
+
+  (* production we're going to reduce with *)
+  mutable prodIndex: int;
+
+  (* column from leftmost stack node *)
+  mutable startColumn: int;
+
+  (* the leftmost stack node itself *)
+  mutable leftEdgeNode: tStackNode;
+
+  (* array of sibling links, i.e. the path; 0th element is
+   * leftmost link *)
+  sibLinks: tSiblingLink array ref;
+
+  (* corresponding array of symbol ids to interpret svals *)
+  symbols: tSymbolId array ref;
+
+  (* next path in dequeueing order *)
+  mutable next: tPath option;
+}
+
+(* priority queue of reduction paths *)
+and tReductionPathQueue = {
+  (* head of the list, first to dequeue *)
+  mutable top: tPath option;
+
+  (* pool of path objects *)
+  pathPool: tPath tObjectPool;
+
+  (* need our own copy of the tables pointer *)
+  rpqTables: tParseTables;      (* name can't collide with tGLR.tables.. ! *)
+}
+
+
+(* GLR parser object *)
+(* some mutable fields are for hack in 'makeGLR' *)
+and tGLR = {
+  (* user-specified actions *)
+  userAct: tUserActions;
+
+  (* parse tables from the grammar *)
+  tables: tParseTables;
+
+  (* for debugging, so I can ask for token descriptions in places *)
+  mutable lexerPtr: tLexerInterface option;
+
+  (* set of topmost parser nodes *)
+  mutable topmostParsers: tStackNode tArrayStack;
+
+  (* treat this as a local variable of rwlProcessWorklist, included
+   * here just to avoid unnecessary repeated allocation *)
+  toPass: tSemanticValue array;
+
+  (* swapped with 'topmostParsers' periodically, for performance reasons *)
+  mutable prevTopmost: tStackNode tArrayStack;
+
+  (* node allocation pool; shared with innerGlrParse *)
+  mutable stackNodePool: tStackNode tObjectPool;
+
+  (* reduction queue and pool *)
+  mutable pathQueue: tReductionPathQueue;
+
+  (* when true, print some diagnosis of failed parses *)
+  mutable noisyFailedParse: bool;
+
+  (* current token number *)
+  mutable globalNodeColumn: int;
+  
+  (* parser action statistics *)
+  mutable detShift: int;
+  mutable detReduce: int;
+  mutable nondetShift: int;
+  mutable nondetReduce: int;
+}
+
+
+
+(* what follows is based on elkhound/glr.cc *)
+
+
+(* -------------------- misc constants --------------------- *)
+(* maximum RHS length for mini-lr core *)
+let cMAX_RHSLEN = 30
+
+let cTYPICAL_MAX_REDUCTION_PATHS = 5
+
+let cINITIAL_RHSLEN_SIZE = 10
+
+
+(* ------------------ accounting statistics ----------------- *)
+let numStackNodesAllocd: int ref = ref 0
+
+let maxStackNodesAllocd: int ref = ref 0
+
+
+(* ----------------- front ends to user code --------------- *)
+let symbolDescription (sym: tSymbolId) (user: tUserActions) 
+                      (sval: tSemanticValue) : string =
+begin
+  if (symIsTerm sym) then (
+    (user.terminalDescription (symAsTerm sym) sval)
+  )
+  else (
+    (user.nonterminalDescription (symAsNonterm sym) sval)
+  )
+end
+
+let duplicateSemanticValue (glr: tGLR) (sym: tSymbolId) (sval: tSemanticValue)
+  : tSemanticValue =
+begin
+  (assert (sym <> 0));
+                                
+  (* the C++ implementation checks for NULL sval, but I don't think
+   * that can be here in the ML version, and I'm not convinced the
+   * check would even be safe *)
+
+  if (symIsTerm sym) then (
+    (glr.userAct.duplicateTerminalValue (symAsTerm sym) sval)
+  )
+  else (
+    (glr.userAct.duplicateNontermValue (symAsNonterm sym) sval)
+  )
+end
+
+let deallocateSemanticValue (sym: tSymbolId) (user: tUserActions) 
+                            (sval: tSemanticValue) : unit =
+begin
+  (assert (sym <> 0));
+
+  if (symIsTerm sym) then (
+    (user.deallocateTerminalValue (symAsTerm sym) sval)
+  )
+  else (
+    (user.deallocateNontermValue (symAsNonterm sym) sval)
+  )
+end
+
+
+(* --------------------- SiblingLink ----------------------- *)
+(* NULL sibling link *)
+let cNULL_SIBLING_LINK:tSiblingLink = {
+  sib = (Obj.magic []);
+  sval = cNULL_SVAL;
+}
+
+let makeSiblingLink (s: tStackNode) (sv: tSemanticValue) : tSiblingLink =
+begin
+  { sib=s; sval=sv; }
+end
+
+
+(* --------------------- StackNode -------------------------- *)
+(* NULL stack node *)
+let cNULL_STACK_NODE:tStackNode = {
+  state          = cSTATE_INVALID;
+  leftSiblings   = [];
+  firstSib       = (Obj.magic []);
+  referenceCount = 0;
+  determinDepth  = 0;
+  glr            = (Obj.magic []);
+  column         = 0
+}
+
+let emptyStackNode(g : tGLR) : tStackNode =
+begin
+  {
+    state = cSTATE_INVALID;
+    leftSiblings = [];
+    firstSib = (makeSiblingLink cNULL_STACK_NODE cNULL_SVAL);
+    referenceCount = 0;
+    determinDepth = 0;
+    glr = g;
+    column = 0
+  }
+end
+
+
+let getNodeSymbol (ths: tStackNode) : tSymbolId =
+begin
+  ths.glr.tables.stateSymbol.(ths.state)
+end
+
+let rec deallocSemanticValues (ths: tStackNode) : unit =
+begin
+  if (ths.firstSib.sib != cNULL_STACK_NODE) then (
+    (deallocateSemanticValue (getNodeSymbol ths) ths.glr.userAct ths.firstSib.sval)
+  );
+
+  (List.iter
+    (fun s -> (
+      (deallocateSemanticValue (getNodeSymbol ths) ths.glr.userAct s.sval);
+
+      (* this is implicit in the C++ version, due to Owner<> *)
+      (decRefCt s.sib)
+    ))
+    ths.leftSiblings);
+  ths.leftSiblings <- [];
+end
+
+and initStackNode (ths: tStackNode) (st: tStateId) : unit =
+begin
+  ths.state <- st;
+  (assert (isEmpty ths.leftSiblings));
+  (assert (ths.firstSib.sib == cNULL_STACK_NODE));
+  ths.referenceCount <- 0;
+  ths.determinDepth <- 1;
+
+  if (accounting) then (
+    (incr numStackNodesAllocd);
+    if (!numStackNodesAllocd > !maxStackNodesAllocd) then (
+      maxStackNodesAllocd := !numStackNodesAllocd;
+    );
+    (*
+      (Printf.printf "(!!!) init stack node: num=%d max=%d\n"
+                     !numStackNodesAllocd
+                     !maxStackNodesAllocd);
+      (flush stdout);
+    *)
+  );
+end
+
+and deinitStackNode (ths: tStackNode) : unit =
+begin
+  (deallocSemanticValues ths);
+
+  (* this is implicit in the C++ implementation because firstSib.sib
+   * is an RCPtr in C++ *)
+  (if (ths.firstSib.sib != cNULL_STACK_NODE) then (
+    (decRefCt ths.firstSib.sib)
+  ));
+
+  ths.firstSib.sib <- cNULL_STACK_NODE;
+
+  if (accounting) then (
+    (decr numStackNodesAllocd);
+    (*
+      (Printf.printf "(...) deinit stack node: num=%d max=%d\n"
+                     !numStackNodesAllocd
+                     !maxStackNodesAllocd);
+      (flush stdout);
+    *)
+  );
+end
+
+and incRefCt (ths: tStackNode) : unit =
+begin
+  ths.referenceCount <- ths.referenceCount + 1;
+end
+
+and decRefCt (ths: tStackNode) : unit =
+begin
+  (assert (ths.referenceCount > 0));
+
+  ths.referenceCount <- ths.referenceCount - 1;
+
+  (*(Printf.printf "decrementing node %d to %d\n" ths.state ths.referenceCount);*)
+  (*(flush stdout);*)
+
+  if (ths.referenceCount = 0) then (
+    (deinitStackNode ths);
+    (ths.glr.stackNodePool#dealloc ths)
+  )
+end
+
+let hasZeroSiblings (ths: tStackNode) : bool =
+begin
+  (ths.firstSib.sib == cNULL_STACK_NODE)
+end
+
+let hasOneSibling (ths: tStackNode) : bool =
+begin
+  (ths.firstSib.sib != cNULL_STACK_NODE) && (isEmpty ths.leftSiblings)
+end
+
+let hasMultipleSiblings (ths: tStackNode) : bool =
+begin
+  (isNotEmpty ths.leftSiblings)
+end
+
+let addFirstSiblingLink_noRefCt (ths: tStackNode) (leftSib: tStackNode)
+                                (sval: tSemanticValue) : unit =
+begin
+  (assert (hasZeroSiblings ths));
+
+  ths.determinDepth <- leftSib.determinDepth + 1;
+
+  (assert (ths.firstSib.sib == cNULL_STACK_NODE));
+  ths.firstSib.sib <- leftSib;     (* update w/o refct *)
+
+  ths.firstSib.sval <- sval;
+end
+
+let addAdditionalSiblingLink (ths: tStackNode) (leftSib: tStackNode)
+                             (sval: tSemanticValue) : tSiblingLink =
+begin
+  (* now there is a second outgoing pointer *)
+  ths.determinDepth <- 0;
+
+  (* this was implicit in the C++ verison *)
+  (incRefCt leftSib);
+
+  let link:tSiblingLink = (makeSiblingLink leftSib sval) in
+  ths.leftSiblings <- link :: ths.leftSiblings;
+  link
+end
+
+let addSiblingLink (ths: tStackNode) (leftSib: tStackNode)
+                   (sval: tSemanticValue) : tSiblingLink =
+begin
+  if (ths.firstSib.sib == cNULL_STACK_NODE) then (
+    (addFirstSiblingLink_noRefCt ths leftSib sval);
+
+    (* manually inc refct *)
+    (incRefCt leftSib);
+
+    (* pointer to firstSib.. *)
+    ths.firstSib
+  )
+  else (
+    (addAdditionalSiblingLink ths leftSib sval)
+  )
+end
+
+let getUniqueLink (ths: tStackNode) : tSiblingLink =
+begin
+  (assert (hasOneSibling ths));
+  ths.firstSib
+end
+
+let getLinkTo (ths: tStackNode) (another: tStackNode)
+  : tSiblingLink (*not tStackNode!*) option =
+begin
+  (* first? *)
+  if (ths.firstSib.sib == another) then (
+    (Some ths.firstSib)
+  )
+
+  else (
+    (* rest? *)
+    try
+      let link:tSiblingLink = (List.find
+        (fun candidate -> (candidate.sib == another))
+        ths.leftSiblings) in
+      (Some link)
+    with Not_found ->
+      None
+  )
+end
+
+(* printAllocStats goes here *)
+
+let computeDeterminDepth (ths: tStackNode) : int =
+begin
+  if (hasZeroSiblings ths) then (
+    1
+  )
+  else if (hasOneSibling ths) then (
+    (* sibling's plus one *)
+    ths.firstSib.sib.determinDepth + 1
+  )
+  else (
+    (assert (hasMultipleSiblings ths));
+    0
+  )
+end
+
+let checkLocalInvariants (ths: tStackNode) : bool =
+begin
+  (computeDeterminDepth ths) = ths.determinDepth;
+end
+
+
+(* ----------------------- stack node list ops ---------------------- *)
+let decParserList (lst: tStackNode tArrayStack) : unit =
+begin
+  (lst#iter (fun n -> (decRefCt n)))
+end
+
+let incParserList (lst: tStackNode tArrayStack) : unit =
+begin
+  (lst#iter (fun n -> (incRefCt n)))
+end
+
+let parserListContains (lst: tStackNode tArrayStack) (n: tStackNode) : bool =
+begin
+  (lst#contains (fun n2 -> n2 == n))
+end
+
+
+(* ----------------------------- GLR --------------------------------- *)
+let rec makeGLR (tablesIn: tParseTables) (actions:tUserActions) : tGLR =
+begin
+  let glr:tGLR = {
+    userAct = actions;
+    tables = tablesIn;
+    lexerPtr = None;
+    topmostParsers = ((Obj.magic []) : tStackNode tArrayStack);  (* HACK!! *)
+    toPass = (Array.make cMAX_RHSLEN cNULL_SVAL);
+    prevTopmost = ((Obj.magic []) : tStackNode tArrayStack);     (* HACK!! *)
+    stackNodePool = ((Obj.magic []) : tStackNode tObjectPool);   (* HACK!! *)
+    pathQueue = ((Obj.magic []) : tReductionPathQueue);          (* HACK!! *)
+    noisyFailedParse = true;
+    globalNodeColumn = 0;
+    detShift = 0;
+    detReduce = 0;
+    nondetShift = 0;
+    nondetReduce = 0
+  } in
+
+  (* finish nasty hack: I've got a bootstrapping problem where I can't
+   * make the pool before the GLR, nor the other way around; so I fell back
+   * on the trusted_cast to get it off the ground, and now I have to
+   * fix it
+   *
+   * The main problem here is that because I'm doing explicit deallocation,
+   * ML gets to see the objects while they're in limbo.  I *could* mark
+   * some fields 'option' but that would not properly reflect the design.
+   * So I prefer this local (if gross) hack to something that pollutes the
+   * design itself.
+   *
+   * In fact, I *did* use the 'option' approach for tSiblingLink.sib,
+   * and it is indeed a pain.
+   * UPDATE: Switched to using Obj.magic there too, for performance.
+   *)
+
+  glr.topmostParsers <- (new tArrayStack cNULL_STACK_NODE);
+  glr.prevTopmost <- (new tArrayStack cNULL_STACK_NODE);
+  glr.stackNodePool <- (new tObjectPool (fun () -> (emptyStackNode glr)));
+  glr.pathQueue <- (makeReductionPathQueue tablesIn);
+                   
+  if (use_mini_lr) then (
+    (* check that none of the productions exceed cMAX_RHSLEN *)
+    for i=0 to (glr.tables.numProds-1) do
+      let len:int = (getProdInfo_rhsLen glr.tables i) in
+      if (len > cMAX_RHSLEN) then (
+        (* I miss token concatenation...*)
+        (Printf.printf "Production %d contains %d right-hand side symbols,\nbut the GLR core has been compiled with a limit of %d.\nPlease adjust cMAX_RHSLEN and recompile the GLR core.\n"
+                       i len cMAX_RHSLEN);
+        (flush stdout);
+        (failwith "cannot continue");
+      );
+    done;
+  );
+
+  glr
+end
+
+(* printConfig goes here *)
+
+and grabTopSval (glr: tGLR) (node: tStackNode) : tSemanticValue =
+begin
+  let sib:tSiblingLink = (getUniqueLink node) in
+  let ret:tSemanticValue = sib.sval in
+  sib.sval <- (duplicateSemanticValue glr (getNodeSymbol node) sib.sval);
+
+  (* TRSACTION("dup'd " << ret << " for top sval, yielded " << sib->sval); *)
+
+  ret
+end
+
+
+(* macro in C++ version *)
+and mMAKE_STACK_NODE (*dest is retval*) (state: tStateId) (glr: tGLR)
+                     (pool: tStackNode tObjectPool) : tStackNode =
+begin
+  let dest:tStackNode = (pool#alloc()) in
+  (initStackNode dest state);
+  dest.column <- glr.globalNodeColumn;
+  dest
+end
+
+and makeStackNode (glr: tGLR) (state: tStateId) : tStackNode =
+begin
+  (mMAKE_STACK_NODE state glr glr.stackNodePool)
+end
+
+
+and addTopmostParser (glr: tGLR) (parsr: tStackNode) : unit =
+begin
+  (assert (checkLocalInvariants parsr));
+
+  (glr.topmostParsers#push parsr);
+  (incRefCt parsr);
+
+  (* no USE_PARSER_INDEX *)
+end
+
+
+(* buildParserIndex goes here *)
+
+and glrParse (glr: tGLR) (lexer: tLexerInterface)
+             (treeTop: tSemanticValue ref) : bool =
+begin
+  (* should reset this to None on all exit paths *)
+  glr.lexerPtr <- (Some lexer);
+
+  let ret:bool = (innerGlrParse glr lexer treeTop) in
+
+  (* this takes care of above obligation unless exception, oh well *)
+  glr.lexerPtr <- None;
+
+  ret
+end
+
+and innerGlrParse (glr: tGLR) (lexer: tLexerInterface)
+                  (treeTop: tSemanticValue ref) : bool =
+begin
+  (* make some things into local variables *)
+  let userAct:tUserActions = glr.userAct in
+  let tables:tParseTables = glr.tables in
+  let topmostParsers: tStackNode tArrayStack = glr.topmostParsers in
+
+  (*nextToken*)
+
+  (*reclassifier*)
+
+  (* the C++ implementation is careful to allocate the main pointer on
+   * the stack to save an indirection; but I can't do that in the ML
+   * version, so may as well just let the GLR object own the pool *)
+  let stackNodePool: tStackNode tObjectPool = glr.stackNodePool in
+
+  glr.globalNodeColumn <- 0;
+  begin
+    let first:tStackNode = (makeStackNode glr 0(*startState*)) in
+    (addTopmostParser glr first);
+  end;
+
+  (* array for passing semantic values in the mini lr core *)
+  let toPass: tSemanticValue array = (Array.make cMAX_RHSLEN cNULL_SVAL) in
+
+  let localDetShift: int ref = ref 0 in
+  let localDetReduce: int ref = ref 0 in
+
+  (* main parsing loop *)
+  try
+    let rec main_loop (jump_to_mini_lr:bool) : bool =
+    begin(
+      if (not jump_to_mini_lr) then (
+        if (traceParse) then (
+          (Printf.printf "---- processing token %s, %d active parsers ----\n"
+                         (lexer#tokenDesc())
+                         (glr.topmostParsers#length())
+          );
+          (Printf.printf "Stack:%s\n" (stackSummary glr));
+          (flush stdout);
+        );
+
+        (* reclassifyToken *)
+      );
+      
+      (* ------------ glr parser ------------ *)
+      (* pulled out so I can use this block of statements in several places *)
+      let glrParseToken () : unit =
+      begin
+        if (not (nondeterministicParseToken glr)) then (
+          (raise Exit)              (* "return false" *)
+        );
+
+        (* goto label: getNextToken *)
+        (* last token? *)
+        if (lexer#atEOF()) then (
+          (raise End_of_file)       (* "break" *)
+        );
+
+        (* get the next token *)
+        (lexer#getToken());
+      end in
+
+      (* --------- mini-lr parser ------- *)
+      (* see elkhound/glr.cc for more details *)
+      (* goto label: tryDeterministic *)
+      if (use_mini_lr &&
+          (topmostParsers#length()) = 1) then (
+        let parsr: tStackNode ref = ref (topmostParsers#top()) in
+        (assert (!parsr.referenceCount = 1));
+
+        let tok:int = (lexer#getTokType()) in
+        let action:tActionEntry = (getActionEntry_noError tables !parsr.state tok) in
+
+        if (isReduceAction action) then (
+          if (accounting) then (
+            (incr localDetReduce);
+          );
+          let prodIndex:int = (decodeReduce action !parsr.state) in
+          let rhsLen:int = (getProdInfo_rhsLen tables prodIndex) in
+          if (rhsLen <= !parsr.determinDepth) then (
+            (* can reduce unambiguously *)
+            let lhsIndex:int = (getProdInfo_lhsIndex tables prodIndex) in
+
+            let startStateId:int = !parsr.state in
+
+            (assert (rhsLen <= cMAX_RHSLEN));
+
+            (* loop for arbitrary rhsLen *)
+            for i = rhsLen-1 downto 0 do
+              (* grab the (only) sibling of 'parsr' *)
+              let sib:tSiblingLink = !parsr.firstSib in
+
+              (* store its semantic value in the 'toPass' array *)
+              toPass.(i) <- sib.sval;
+
+              (* pop 'parsr' and move to next one *)
+              (stackNodePool#dealloc !parsr);
+              let prev:tStackNode = !parsr in
+              parsr := sib.sib;
+
+              (assert (!parsr.referenceCount = 1));
+              (assert (prev.referenceCount = 1));
+
+              (* adjust a couple things about 'prev' reflecting
+               * that it has been deallocated *)
+              (decr numStackNodesAllocd);
+              prev.firstSib.sib <- cNULL_STACK_NODE;
+
+              (assert (!parsr.referenceCount = 1));
+            done;
+
+            (* call the user's action function (TREEBUILD) *)
+            let sval:tSemanticValue =
+              (userAct.reductionAction prodIndex toPass) in
+
+            (* now, do an abbreviated 'glrShiftNonterminal' *)
+            let newState:int = (decodeGoto
+              (getGotoEntry tables !parsr.state lhsIndex)
+            lhsIndex) in
+
+            if (traceParse) then (
+              (Printf.printf "state %d, (unambig) reduce by %d (len=%d), back to %d then out to %d\n"
+                             startStateId
+                             prodIndex
+                             rhsLen
+                             !parsr.state
+                             newState);
+              (flush stdout);
+            );
+
+            (* the sole reference is the 'parsr' variable *)
+            (assert (!parsr.referenceCount = 1));
+
+            (* push new state *)
+            let newNode:tStackNode =
+              (mMAKE_STACK_NODE newState glr stackNodePool) in
+
+            (addFirstSiblingLink_noRefCt newNode !parsr sval);
+
+            (assert (!parsr.referenceCount = 1));
+
+            (* replace old topmost parser with 'newNode' *)
+            (topmostParsers#setElt 0 newNode);
+            (incRefCt newNode);
+            (assert (newNode.referenceCount = 1));
+
+            (* does the user want to keep it? *)
+            if (use_keep &&
+                (not (userAct.keepNontermValue lhsIndex sval))) then (
+              (printParseErrorMessage glr newNode.state);
+              if (accounting) then (
+                glr.detShift <- glr.detShift + !localDetShift;
+                glr.detReduce <- glr.detReduce + !localDetReduce;
+              );
+
+              (raise Exit)               (* "return false" *)
+            );
+
+            (* we have not shifted a token, so again try to use
+             * the deterministic core *)
+            (main_loop true(*jump*))     (* "goto tryDeterministic;" *)
+          )
+          else (
+            (* deterministic depth insufficient: use GLR *)
+            (glrParseToken());
+            (main_loop false)            (* tail call *)
+          )
+        )
+
+        else if (isShiftAction tables action) then (
+          if (accounting) then (
+            (incr localDetShift);
+          );
+
+          (* can shift unambiguously *)
+          let newState:int = (decodeShift action tok) in
+
+          if (traceParse) then (
+            (Printf.printf "state %d, (unambig) shift token %d, to state %d\n"
+                           !parsr.state
+                           tok
+                           newState);
+            (flush stdout);
+          );
+
+          glr.globalNodeColumn <- glr.globalNodeColumn + 1;
+
+          let rightSibling:tStackNode =
+            (mMAKE_STACK_NODE newState glr stackNodePool) in
+
+          (addFirstSiblingLink_noRefCt rightSibling !parsr (lexer#getSval()));
+
+          (* replace 'parsr' with 'rightSibling' *)
+          (topmostParsers#setElt 0 rightSibling);
+
+          (assert (!parsr.referenceCount = 1));
+          (assert (rightSibling.referenceCount = 0));
+
+          rightSibling.referenceCount <- 1;
+
+          (* get next token *)
+          (* "goto getNextToken;" *)
+          begin
+            (* last token? *)
+            if (lexer#atEOF()) then (
+              (raise End_of_file)       (* "break" *)
+            );
+
+            (* get the next token *)
+            (lexer#getToken());
+          end;
+          (main_loop false)      (* tail call *)
+        )
+
+        else (
+          (* error or ambig; not deterministic *)
+          (glrParseToken());
+          (main_loop false)      (* tail call *)
+        )
+      )
+
+      else (
+        (* mini lr core disabled, use full GLR *)
+        (glrParseToken());
+        (main_loop false)        (* tail call *)
+      )
+    )end in
+    (main_loop false)
+  with
+  | Exit -> false
+  | End_of_file -> (
+      if (accounting) then (
+        glr.detShift <- glr.detShift + !localDetShift;
+        glr.detReduce <- glr.detReduce + !localDetReduce;
+      );
+
+      (* end of parse *)
+      (cleanupAfterParse glr (*timer*) treeTop)
+    )
+end
+
+(* stackTraceString *)
+
+
+and curToken (glr: tGLR) : int =
+begin
+  ((getSome glr.lexerPtr)#getTokType())
+end
+
+and nondeterministicParseToken (glr: tGLR) : bool =
+begin
+  let lastToDie: tStateId ref = ref cSTATE_INVALID in
+
+  (* seed the reduction worklist by analyzing the top nodes *)
+  (glr.topmostParsers#iter
+    (fun parsr ->
+     begin
+       let tt:int = (curToken glr) in
+       let action:tActionEntry = (getActionEntry glr.tables parsr.state tt) in
+       let actions:int = (rwlEnqueueReductions glr parsr action None(*sibLink*)) in
+       
+       if (actions = 0) then (
+         if (traceParse) then (
+           (Printf.printf "parser in state %d died\n" parsr.state);
+           (flush stdout)
+         );
+         lastToDie := parsr.state;
+       );
+     end));
+
+  (* drop into worklist processing loop *)
+  (rwlProcessWorklist glr);
+
+  (* do all shifts last *)
+  (rwlShiftTerminals glr);
+
+  (* error? *)
+  if (glr.topmostParsers#isEmpty()) then (
+    (printParseErrorMessage glr !lastToDie);
+    false
+  )
+  else (
+    true
+  )
+end
+
+
+and printParseErrorMessage (glr: tGLR) (lastToDie: tStateId) : unit =
+begin
+  if (not glr.noisyFailedParse) then () 
+  else begin
+    let lexer:tLexerInterface = (getSome glr.lexerPtr) in
+
+    if (not (lastToDie = cSTATE_INVALID)) then (
+      (Printf.printf "In state %d, I expected one of these tokens:\n" lastToDie);
+      for i = 0 to (glr.tables.numTerms - 1) do
+        let act:int = (getActionEntry glr.tables lastToDie i) in
+        if (not (isErrorAction (*tables*) act)) then (
+          (Printf.printf "  [%d] %s\n" i (lexer#tokenKindDesc i));
+        );
+      done;
+    )
+    else (
+      (Printf.printf "(expected-token info not available due to nondeterministic mode\n");
+    );
+
+    (Printf.printf (*loc*) "Parse error (state %d) at %s\n"
+                   lastToDie
+                   (lexer#tokenDesc()));
+
+    (flush stdout);
+  end 
+end
+
+
+and doReductionAction (glr: tGLR) (productionId: int)
+                      (svals: tSemanticValue array) : tSemanticValue =
+begin
+  (glr.userAct.reductionAction productionId svals)
+end
+
+
+and cleanupAfterParse (*timer*) (glr: tGLR) (treeTop: tSemanticValue ref) : bool =
+begin
+  if (traceParse) then (
+    (Printf.printf "Parse succeeded!\n");
+    (flush stdout);
+  );
+
+  if (not ((glr.topmostParsers#length()) = 1)) then (
+    (Printf.printf "parsing finished with %d active parsers!\n"
+                   (glr.topmostParsers#length()));
+    (flush stdout);
+    false     (* return *)
+  )
+  else begin
+    let last:tStackNode = (glr.topmostParsers#top()) in
+
+    (* prepare to run final action *)
+    let arr: tSemanticValue array = (Array.make 2 cNULL_SVAL) in
+    let nextToLast: tStackNode = (getUniqueLink last).sib in
+    arr.(0) <- (grabTopSval glr nextToLast);      (* sval we want *)
+    arr.(1) <- (grabTopSval glr last);            (* EOF's sval *)
+
+    (* reduce *)
+    treeTop := (doReductionAction glr glr.tables.finalProductionIndex arr);
+
+    (* before pool goes away.. *)
+    (decParserList glr.topmostParsers);
+
+    true
+  end 
+end
+
+
+and pullFromTopmostParsers (glr: tGLR) (parsr: tStackNode) : unit =
+begin
+  let last:int = (glr.topmostParsers#length()) - 1 in
+
+  try
+    for i=0 to last do
+      if ((glr.topmostParsers#elt i) = parsr) then (
+        (* remove by swapping *)
+        if (i < last) then (
+          (glr.topmostParsers#setElt i (glr.topmostParsers#elt last));
+        );
+        ignore (glr.topmostParsers#pop());   (* removes a reference *)
+        (decRefCt parsr);                    (* so decrement *)
+        raise Exit;      (* "break" *)
+      )
+    done
+  with
+  | Exit -> ()
+end
+
+
+and canMakeProgress (glr: tGLR) (parsr: tStackNode) : bool =
+begin
+  let entry:int =
+    (getActionEntry glr.tables parsr.state (curToken glr)) in
+    
+  (isShiftAction glr.tables entry) ||
+  (isReduceAction (*tables*) entry) ||
+  (not (isErrorAction (*tables*) entry))
+end
+
+
+and findTopmostParser (glr: tGLR) (state: tStateId) : tStackNode option =
+begin
+  (* always using the *not* USE_PARSER_INDEX case *)
+  (glr.topmostParsers#findOption
+    (fun n -> n.state = state))
+end
+
+
+(* dumpGSS goes here *)
+(* dumpGSSEdge goes here *)
+
+
+and stackSummary (glr: tGLR) : string =
+begin
+  (* nodes already printed *)
+  let printed: tStackNode list ref = ref [] in
+
+  (* loop/fold *)
+  let len:int = (glr.topmostParsers#length ()) in
+  let rec loop (acc: string) (i: int) : string =
+  begin
+    if (i > len-1) then (
+      acc                      (* done *)
+    )
+    else (
+      let n:tStackNode = (glr.topmostParsers#elt i) in
+
+      (loop
+        (acc ^ " (" ^ (string_of_int i) ^ ": " ^
+         (innerStackSummary printed n) ^
+         ")")
+        (i+1)
+      )
+    )
+  end in
+
+  (loop "" 0)
+end
+  
+and nodeSummary (node: tStackNode) : string =
+begin
+  (string_of_int node.state) ^ 
+  "[" ^ (string_of_int node.referenceCount) ^ "]"
+end
+
+and innerStackSummary (printed: tStackNode list ref) (node: tStackNode) : string =
+begin
+  if (List.exists
+       (fun (n:tStackNode) -> n = node)
+       !printed) then (
+    (* already printed *)
+    "(rep:" ^ (nodeSummary node) ^ ")"
+  ) 
+  
+  else (  
+    (* remember that we've now printed 'node' *)
+    printed := node :: !printed;
+
+    if (node.firstSib.sib == cNULL_STACK_NODE) then (
+      (* no siblings *)
+      (nodeSummary node)
+    )
+
+    else if (isEmpty node.leftSiblings) then (
+      (* one sibling *)
+      (nodeSummary node) ^ "-" ^ 
+      (innerStackSummary printed node.firstSib.sib)
+    )
+
+    else (
+      (* multiple siblings *)
+      let tmp1:string =       (* force order of eval *)
+        (nodeSummary node) ^ "-(" ^
+        (innerStackSummary printed node.firstSib.sib) in
+      tmp1 ^ (List.fold_left 
+        (fun (acc:string) (link:tSiblingLink) -> (
+          acc ^ "|" ^ (innerStackSummary printed link.sib)
+        ))
+        ""
+        node.leftSiblings
+      ) ^
+      ")"
+    )
+  )
+end
+
+
+(* ------------------------ RWL algorithm ------------------------- *)
+and makePath() : tPath =
+begin
+  {
+    startStateId = cSTATE_INVALID;
+    prodIndex = -1;
+    startColumn = -1;
+    leftEdgeNode = cNULL_STACK_NODE;
+    sibLinks = ref (Array.make cINITIAL_RHSLEN_SIZE cNULL_SIBLING_LINK);
+    symbols = ref (Array.make cINITIAL_RHSLEN_SIZE 0);
+    next = None;
+  }
+end
+
+
+and initPath (ths: tPath) (ssi: tStateId) (pi: int) (rhsLen: int) : unit =
+begin
+  ths.startStateId <- ssi;
+  ths.prodIndex <- pi;
+
+  (* just use the 0th elements as the dummy 'null' value *)
+  (ensureIndexDoubler ths.sibLinks rhsLen ((!(ths.sibLinks)).(0)));
+  (ensureIndexDoubler ths.symbols rhsLen ((!(ths.symbols)).(0)));
+end
+
+
+and makeReductionPathQueue (tablesIn: tParseTables) : tReductionPathQueue =
+begin
+  let allocator() : tPath = (makePath ()) in
+  {
+    top = None;
+    pathPool = (new tObjectPool allocator);
+    rpqTables = tablesIn;
+  }
+end
+
+
+and newPath (ths: tReductionPathQueue) (ssi: tStateId) (pi: int) 
+            (rhsLen: int) : tPath =
+begin
+  let p:tPath = (ths.pathPool#alloc()) in
+  (initPath p ssi pi rhsLen);
+  p
+end
+
+
+and insertPathCopy (ths:tReductionPathQueue) (src: tPath) 
+                   (leftEdge: tStackNode) : unit =
+begin
+  let rhsLen:int = (getProdInfo_rhsLen ths.rpqTables src.prodIndex) in
+
+  (* make a new node *)
+  let p:tPath = (ths.pathPool#alloc()) in
+  (initPath p src.startStateId src.prodIndex rhsLen);
+  
+  (* fill in left edge info *)
+  p.leftEdgeNode <- leftEdge;
+  p.startColumn <- leftEdge.column;
+  
+  (* copy path info *)
+  (Array.blit
+    !(src.sibLinks)       (* source array *)
+    0                     (* source start position *)
+    !(p.sibLinks)         (* dest array *)
+    0                     (* dest start position *)
+    rhsLen                (* number of elements to copy *)
+  );
+  (Array.blit
+    !(src.symbols)        (* source array *)
+    0                     (* source start position *)
+    !(p.symbols)          (* dest array *)
+    0                     (* dest start position *)
+    rhsLen                (* number of elements to copy *)
+  );
+  
+  (* find proper place to insert new path *)
+  if ((isNone ths.top) || (goesBefore ths p (getSome ths.top))) then (
+    (* prepend *)
+    p.next <- ths.top;
+    ths.top <- (Some p);
+  )
+  else (
+    (* search *)
+    let prev: tPath ref = ref (getSome ths.top) in
+    while ((isSome !prev.next) && (not (goesBefore ths p (getSome !prev.next)))) do
+      prev := (getSome !prev.next);
+    done;
+
+    (* insert *)
+    p.next <- !prev.next;
+    !prev.next <- (Some p);
+  );
+end
+
+and goesBefore (ths: tReductionPathQueue) (p1: tPath) (p2: tPath) : bool =
+begin
+  if (p1.startColumn > p2.startColumn) then (
+    (* 'p1' spans fewer tokens, so it goes first *)
+    true
+  )
+  else if (p2.startColumn > p1.startColumn) then (
+    (* same logic *)
+    false
+  )
+  else (
+    (* equal start columns, compare nonterm ids *)
+    let p1NtIndex:int = (getProdInfo_lhsIndex ths.rpqTables p1.prodIndex) in
+    let p2NtIndex:int = (getProdInfo_lhsIndex ths.rpqTables p2.prodIndex) in
+    
+    (* check nonterm order *)
+    let ord1:int = (getNontermOrdinal ths.rpqTables p1NtIndex) in
+    let ord2:int = (getNontermOrdinal ths.rpqTables p2NtIndex) in
+    
+    ord1 < ord2
+  )
+end
+
+
+and dequeue (ths: tReductionPathQueue) : tPath =
+begin
+  let ret:tPath = (getSome ths.top) in
+  ths.top <- ret.next;
+  ret
+end
+
+
+and deletePath (ths: tReductionPathQueue) (p: tPath) : unit =
+begin
+  (ths.pathPool#dealloc p);
+end
+
+
+and queueIsNotEmpty (ths: tReductionPathQueue) : bool =
+begin
+  (isSome ths.top)
+end
+
+and rwlProcessWorklist (glr: tGLR) : unit =
+begin
+  while (queueIsNotEmpty glr.pathQueue) do
+    (* process enabled reductions in priority order *)
+    let path:tPath = (dequeue glr.pathQueue) in
+    
+    (* production info *)
+    let rhsLen:int = (getProdInfo_rhsLen glr.tables path.prodIndex) in
+    let lhsIndex:int = (getProdInfo_lhsIndex glr.tables path.prodIndex) in
+    
+    if (traceParse) then (
+      (Printf.printf "state %d, reducing by production %d (rhsLen=%d), back to state %d\n"
+                     path.startStateId
+                     path.prodIndex
+                     rhsLen
+                     path.leftEdgeNode.state);
+      (flush stdout);
+    );
+    
+    if (accounting) then (
+      glr.nondetReduce <- glr.nondetReduce + 1;
+    );
+    
+    (* leftEdge *)
+    
+    (* before calling user's code, duplicate svals *)
+    for i = (rhsLen-1) downto 0 do
+      let sib:tSiblingLink = (!(path.sibLinks)).(i) in
+
+      (* put the sval in the array that will be passed to the user *)
+      glr.toPass.(i) <- sib.sval;
+
+      (* source loc stuff *)
+
+      (* ask user to duplicate, store that back in 'sib' *)
+      sib.sval <- (duplicateSemanticValue glr (!(path.symbols)).(i) sib.sval);
+    done;
+    
+    (* invoke user's reduction action (TREEBUILD) *)
+    let sval:tSemanticValue =
+      (doReductionAction glr path.prodIndex glr.toPass) in
+
+    (* did user want to keep? *)
+    if (use_keep &&
+        (not (glr.userAct.keepNontermValue lhsIndex sval))) then (
+      (* cancelled; drop on floor *)
+    )
+    else (
+      (* shift the nonterminal, sval *)
+      let newLink: tSiblingLink option =
+        (rwlShiftNonterminal glr path.leftEdgeNode lhsIndex sval) in
+
+      if (isSome newLink) then (
+        (* for each 'finished' parser, enqueue actions enabled by the new link *)
+        (glr.topmostParsers#iter
+          (fun parsr ->
+            let action:tActionEntry =
+              (getActionEntry glr.tables parsr.state (curToken glr)) in
+            ignore (rwlEnqueueReductions glr parsr action newLink)
+          ));
+      );
+    );
+                                   
+    (* we dequeued it above, and are now done with it, so recycle
+     * it for future use *)
+    (deletePath glr.pathQueue path)
+  done;
+end
+
+
+and rwlShiftNonterminal (glr: tGLR) (leftSibling: tStackNode) (lhsIndex: int)
+                        (sval: tSemanticValue) : tSiblingLink option =
+begin
+  (* consult goto table to find where to go upon "shifting" the nonterminal *)
+  let rightSiblingState:tStateId =
+    (decodeGoto (getGotoEntry glr.tables leftSibling.state lhsIndex) lhsIndex) in
+    
+  if (traceParse) then (
+    (Printf.printf "state %d, shift nonterm %d, to state %d\n"
+                   leftSibling.state
+                   lhsIndex
+                   rightSiblingState);
+    (flush stdout);
+  );
+  
+  (* is there already an active parser with this state? *)
+  match (findTopmostParser glr rightSiblingState) with
+  | Some(rightSibling) -> (     (* rightSibling:tStackNode *)
+      match (getLinkTo rightSibling leftSibling) with
+      | Some(sibLink) -> (      (* sibLink:tSiblingLink *)
+          (* we already have a sibling link, don't need a new one *)
+
+          (* +--------------------------------------------------+
+           * | it is here that we are bringing the tops of two  |
+           * | alternative parses together (TREEBUILD)          |
+           * +--------------------------------------------------+
+           *)
+
+          (* dead tree optimization *)
+          if (not (canMakeProgress glr rightSibling)) then (
+            if (traceParse) then (
+              (Printf.printf "avoided a merge by noticing the state was dead\n");
+              (flush stdout);
+            );
+            (deallocateSemanticValue (getNodeSymbol rightSibling) glr.userAct sval);
+          )
+          else (
+            (* call user's merge code *)
+            sibLink.sval <-
+              (glr.userAct.mergeAlternativeParses lhsIndex sibLink.sval sval);
+          );
+
+          (* ok, done *)
+          None
+
+          (* didn't add a link, no potential for new paths *)
+        )
+
+      | None -> (
+          (* no suitable sibling link already, so add it *)
+          let sibLink:tSiblingLink = (addSiblingLink rightSibling leftSibling sval) in
+
+          (* recompute depths; TODO: do the topological sort thing *)
+          if (rightSibling.referenceCount > 1) then (
+            let changes: int ref = ref 1 in
+            let iters: int ref = ref 0 in
+            while (!changes > 0) do
+              changes := 0;
+              (glr.topmostParsers#iter
+                (fun parsr -> (
+                  let newDepth:int = (computeDeterminDepth parsr) in
+                  if (newDepth <> parsr.determinDepth) then (
+                    (incr changes);
+                    parsr.determinDepth <- newDepth;
+                  );
+                )));
+              (incr iters);
+              (assert (!iters < 1000));     (* protect against infinite loop *)
+              (* computeDepthIters++; *)
+            done;
+          );
+
+          (* inform caller of new link *)
+          (Some sibLink)
+        )
+    )
+
+  | None -> (
+      (* not already active parser in this state, so make one *)
+      let rightSibling:tStackNode = (makeStackNode glr rightSiblingState) in
+      
+      (* add link *)
+      ignore (addSiblingLink rightSibling leftSibling sval);
+      
+      (* extend frontier *)
+      (addTopmostParser glr rightSibling);
+      
+      (* enqueue this new parser's reductions *)
+      let action:tActionEntry =
+        (getActionEntry glr.tables rightSibling.state (curToken glr)) in
+      ignore (rwlEnqueueReductions glr rightSibling action None(*siblink*));
+          
+      (* caller doesn't need to do anything more *)
+      None
+    )
+end
+
+  
+(* returns # of actions *)
+and rwlEnqueueReductions (glr: tGLR) (parsr: tStackNode) (action: tActionEntry)
+                         (mustUseLink: tSiblingLink option) : int =
+begin
+  (assert (checkLocalInvariants parsr));
+
+  if (isShiftAction glr.tables action) then (
+    (* do nothing, only looking for reductions *)
+    1
+  )
+  else if (isReduceAction (*tables*) action) then (
+    let prodIndex = (decodeReduce (*tables*) action parsr.state) in
+
+    (* production info *)
+    let rhsLen:int = (getProdInfo_rhsLen glr.tables prodIndex) in
+    (assert (rhsLen >= 0));       (* paranoia *)
+
+    (* make a prototype path; used to control recursion *)
+    let proto:tPath =
+      (newPath glr.pathQueue parsr.state prodIndex rhsLen) in
+
+    (* kick off the recursion *)
+    (rwlRecursiveEnqueue glr proto rhsLen parsr mustUseLink);
+
+    (* deallocate prototype *)
+    (deletePath glr.pathQueue proto);
+
+    1
+  )
+  else if (isErrorAction (*tables*) action) then (
+    (* parser just dies *)
+    0
+  )
+  else (
+    (* ambiguous; check for reductions in list of actions *)
+    let firstEntry:int = (decodeAmbigAction glr.tables action parsr.state) in
+    let numEntries:int = glr.tables.ambigTable.(firstEntry) in
+    for i = 1 to numEntries do
+      (* ignore return value because I know it will be 1 *)
+      ignore (rwlEnqueueReductions glr parsr glr.tables.ambigTable.(firstEntry+i) mustUseLink);
+    done;
+
+    numEntries
+  )
+end
+
+
+(* same argument meanings as for 'rwlRecursiveEnqueue' *)
+and rwlCollectPathLink
+  (glr: tGLR)
+  (proto: tPath)
+  (popsRemaining: int)
+  (currentNode: tStackNode)
+  (mustUseLink: tSiblingLink option)
+  (linkToAdd: tSiblingLink)         (* extra *)
+  : unit =
+begin
+  (!(proto.sibLinks)).(popsRemaining) <- linkToAdd;
+  (!(proto.symbols)).(popsRemaining) <- (getNodeSymbol currentNode);
+
+  if (someEquals mustUseLink linkToAdd) then (
+    (* consume must-use link *)
+    (rwlRecursiveEnqueue glr proto popsRemaining linkToAdd.sib
+                         None(*mustUse*));
+  )
+  else (
+    (rwlRecursiveEnqueue glr proto popsRemaining linkToAdd.sib
+                         mustUseLink);
+  );
+end
+
+(* recursive depth-first enumeration of paths *)
+and rwlRecursiveEnqueue
+  (glr: tGLR)
+  (proto: tPath)                      (* prototype path, with path so far *)
+  (popsRemaining: int)                (* # of links yet to traverse to find a full path *)
+  (currentNode: tStackNode)           (* node we're at in the path *)
+  (mustUseLink: tSiblingLink option)  (* link the path must use (if not None) *)
+  : unit =
+begin
+  if (popsRemaining = 0) then (
+    (* found path *)
+    
+    (* must have used the link *)
+    if (isSome mustUseLink) then (
+      (* do nothing *)
+    )
+    else (
+      (* copy the prototype path, it's the one we want *)
+      (insertPathCopy glr.pathQueue proto currentNode)
+    );
+  )
+
+  else (
+    (* explore currentNode's siblings *)
+    (rwlCollectPathLink glr proto (popsRemaining-1) currentNode mustUseLink
+                        currentNode.firstSib);
+
+    (List.iter
+      (fun sibling -> (
+        (rwlCollectPathLink glr proto (popsRemaining-1) currentNode mustUseLink
+                            sibling)
+      ))
+      currentNode.leftSiblings
+    );
+  );
+end
+
+
+and rwlShiftTerminals (glr: tGLR) : unit =
+begin
+  glr.globalNodeColumn <- glr.globalNodeColumn + 1;
+  
+  (* move all parsers from 'topmostParsers' to 'prevTopmost' *)
+  (assert (glr.prevTopmost#isEmpty()));
+  (glr.prevTopmost#swapWith glr.topmostParsers);
+  (assert (glr.topmostParsers#isEmpty()));
+
+  (* grab current token since we'll need it and the access 
+   * isn't all that fast here in ML *)
+  let token:int = (curToken glr) in
+
+  (* for token multi-yield.. *)
+  let prev: tSiblingLink option ref = ref None in
+
+  while (glr.prevTopmost#isNotEmpty()) do
+    (* take the node from 'prevTopmost'; the refcount transfers
+     * from 'prevTopmost' to (local variable) 'leftSibling' *)
+    let leftSibling:tStackNode = (glr.prevTopmost#pop()) in
+    (assert (leftSibling.referenceCount >= 1));   (* for the local *)
+
+    (* can this parser shift? *)
+    let action:tActionEntry =
+      (getActionEntry glr.tables leftSibling.state token) in
+
+    (* if we find a shift, this will be set to something valid *)
+    let newState: tStateId ref = ref cSTATE_INVALID in
+
+    (* consult action table, looking for shifts *)
+    if (isShiftAction glr.tables action) then (
+      (* unambiguous shift *)
+      newState := (decodeShift (*tables*) action token);
+    )
+    else if ((isReduceAction (*tables*) action) ||
+             (isErrorAction (*tables*) action)) then (
+      (* unambiguous reduction or error *)
+    )
+    else (
+      (* nondeterministic *)
+      let firstEntry:int = (decodeAmbigAction glr.tables action leftSibling.state) in
+      let numEntries:int = glr.tables.ambigTable.(firstEntry) in
+
+      for i=1 to numEntries do
+        let action:tActionEntry = glr.tables.ambigTable.(firstEntry+i) in
+        if (isShiftAction glr.tables action) then (
+          (* a shift was among the conflicted actions *)
+          newState := (decodeShift (*tables*) action token);
+
+          (* would like to break out, but I can't, so just eat the wasted time.. *)
+        );
+      done;
+    );
+
+    if (!newState <> cSTATE_INVALID) then (
+      (* found a shift *)
+
+      glr.nondetShift <- glr.nondetShift + 1;
+
+      if (traceParse) then (
+        (Printf.printf "state %d, shift token %s, to state %d\n"
+                       leftSibling.state
+                       ((getSome glr.lexerPtr)#tokenDesc())
+                       !newState);
+        (flush stdout);
+      );
+
+      (* already a parser in this state? *)
+      let rightSibling:tStackNode =
+        match (findTopmostParser glr !newState) with
+        | Some(rs) -> rs     (* use existing *)
+        | None -> (
+            (* must make a new stack node *)
+            let rs:tStackNode = (makeStackNode glr !newState) in
+
+            (* add it to active parsers *)
+            (addTopmostParser glr rs);
+
+            rs               (* use new *)
+          )
+      in
+
+      (* semantic value for this token *)
+      let sval:tSemanticValue =
+        match !prev with
+        | None -> ((getSome glr.lexerPtr)#getSval())    (* usual case *)
+
+        | Some(prev) -> (
+            (* the 'sval' we just grabbed has already been claimed by
+             * 'prev.sval'; get a fresh one by duplicating the latter *)
+            (glr.userAct.duplicateTerminalValue token prev.sval)
+          )
+      in
+
+      (* add sibling link now *)
+      prev := (Some (addSiblingLink rightSibling leftSibling sval));
+
+      (* see comments in glr.cc for explanation *)
+      (assert (rightSibling.referenceCount = 1));
+    );
+    
+    (* pending decrement of leftSibling, which is about to go out of scope *)
+    (decRefCt leftSibling);
+  done;
+end
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/lexer.mll
===================================================================
--- vendor/elsa/current/elkhound/ocaml/lexer.mll	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/lexer.mll	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+(* lexer.mll *)
+(* based on an example from camllex documentation *)
+
+{
+  (* this encodes both the token kind (the constructor name) and
+   * its lexeme (the constructor arguments);
+   * unlike lex, ocamllex does not separate the concepts
+   *)
+  type tToken =
+    | EOF
+    | INT of int        (* integer literal *)
+    | PLUS
+    | MINUS
+    | TIMES
+    | DIV
+    | LPAREN
+    | RPAREN
+
+  (* The following functions should probably be implemented by
+   * some automatic translator, given the definition of tToken.
+   * ocamlyacc does this (to some degree), but Elkhound does not.
+   *)
+
+  (* break out the token kind as an integer *)
+  let tokenKind (t:tToken) : int =
+  begin
+    match t with
+    | EOF ->     0
+    | INT(_) ->  1
+    | PLUS ->    2
+    | MINUS ->   3
+    | TIMES ->   4
+    | DIV ->     5
+    | LPAREN ->  6
+    | RPAREN ->  7
+  end
+
+  (* render a token kind code as a string *)
+  let tokenKindDesc (t:int) : string =
+  begin
+    match t with
+    | 0 ->       "EOF"
+    | 1 ->       "INT"
+    | 2 ->       "+"
+    | 3 ->       "-"
+    | 4 ->       "*"
+    | 5 ->       "/"
+    | 6 ->       "("
+    | 7 ->       ")"
+    | _ ->       (failwith "bad token kind")
+  end
+
+  (* render a full tToken as a string *)
+  let tokenDesc (t:tToken) : string =
+  begin
+    match t with
+    | INT(i) ->  "INT(" ^ (string_of_int i) ^ ")"
+    | _ ->       (tokenKindDesc (tokenKind t))
+  end
+}
+
+rule readToken = parse
+    [' ' '\t' '\n']     { readToken lexbuf }     (* skip whitespace *)
+  | ['0'-'9']+          { INT(int_of_string(Lexing.lexeme lexbuf)) }
+  | '+'                 { PLUS }
+  | '-'                 { MINUS }
+  | '*'                 { TIMES }
+  | '/'                 { DIV }
+  | '('                 { LPAREN }
+  | ')'                 { RPAREN }
+  | eof                 { EOF }

Added: vendor/elsa/current/elkhound/ocaml/lexerint.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/lexerint.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/lexerint.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,48 @@
+(* lexerint.ml *)
+(* lexer interface *)
+(* based on elkhound/lexerint.h *)
+
+
+open Useract      (* tSemanticValue *)
+
+
+(* the GLR parser will interact with the lexer via this interface *)
+class virtual tLexerInterface =
+object (self)
+  (* ---- data ---- *)
+  (* the following fields are used to describe the *current* token;
+   * they are changed by getToken() each time it is called *)
+
+  (* token classification, used by parser to make parsing decisions;
+   * the value 0 means end of file *)
+  val mutable tokType:int = 0;
+
+  (* semantic value of the token *)
+  val mutable sval:tSemanticValue = (Obj.repr 0);
+
+  (* lexerint.h has a 'loc' field here... *)
+
+  (* ---- funcs ---- *)
+  (* data members aren't public... *)
+  method getTokType() : int =           tokType
+  method atEOF() : bool =               tokType=0
+  method getSval() : tSemanticValue =   sval
+
+  (* convenience during testing *)
+  method setIntSval (i:int) : unit =    sval <- (Obj.repr i)
+  method getIntSval() : int =          (Obj.obj sval : int)
+
+  (* interface that must be implemented *)
+  
+  (* retrieve the next token, storing its information in tokType & sval *)
+  method virtual getToken : unit -> unit
+
+  (* yield a description of the current token *)
+  method virtual tokenDesc : unit -> string
+
+  (* yield a description of an arbitrary token kind *)
+  method virtual tokenKindDesc : int -> string
+end
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/lrparse.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/lrparse.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/lrparse.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,162 @@
+(* lrparse.ml *)
+(* deterministic LALR(1) parser *)
+
+open Lexerint       (* tLexerInterface *)
+open Parsetables    (* actionTable, etc. *)
+open Useract        (* reductionAction *)
+
+
+type tStateId = int
+
+let debug : bool = false
+
+let stateStack : tStateId array ref = ref (Array.make 10 0)
+let svalStack : Obj.t array ref = ref (Array.make 10 (Obj.repr 0))
+let stackLen : int ref = ref 0
+
+let pushStateSval (state : tStateId) (sval : Obj.t) : unit =
+begin
+  if ((Array.length !stateStack) = !stackLen) then (
+    (* must make it bigger *)
+    let newStateStack : tStateId array = (Array.make (!stackLen * 2) 0) in
+    let newSvalStack : Obj.t array = (Array.make (!stackLen * 2) (Obj.repr 0)) in
+
+    (* copy *)
+    (Array.blit
+      !stateStack           (* source array *)
+      0                     (* source start position *)
+      newStateStack         (* dest array *)
+      0                     (* dest start position *)
+      !stackLen             (* number of elements to copy *)
+    );
+    (Array.blit
+      !svalStack            (* source array *)
+      0                     (* source start position *)
+      newSvalStack          (* dest array *)
+      0                     (* dest start position *)
+      !stackLen             (* number of elements to copy *)
+    );
+
+    (* switch from old to new *)
+    stateStack := newStateStack;
+    svalStack := newSvalStack;
+  );
+
+  (* put new element into the stack at the end *)
+  (!stateStack).(!stackLen) <- state;
+  (!svalStack).(!stackLen) <- sval;
+  (incr stackLen);
+end
+
+let topState() : tStateId =
+begin
+  (!stateStack).(!stackLen - 1)
+end
+
+let parse (lex:tLexerInterface) (tables:tParseTables) (actions:tUserActions) 
+  : tSemanticValue =
+begin
+  (* initial state *)
+  (pushStateSval 0 (Obj.repr 0));
+
+  (* loop over all tokens until EOF and stack has just start symbol *)
+  while (not ((lex#getTokType()) = 0)) ||
+        (!stackLen > 2) do
+    let tt:int = (lex#getTokType()) in        (* token type *)
+    let state:tStateId = (topState()) in      (* current state *)
+
+    if (debug) then (
+      (Printf.printf "state=%d tokType=%d sval=%d desc=\"%s\"\n"
+                     state
+                     tt
+                     (lex#getIntSval())
+                     (lex#tokenDesc())
+                   );
+      (flush stdout);
+    );
+
+    (* read from action table *)
+    let act:tActionEntry = (getActionEntry tables state tt) in
+
+    (* shift? *)
+    if (isShiftAction tables act) then (
+      let dest:tStateId = (decodeShift act tt) in   (* destination state *)
+      (pushStateSval dest (lex#getSval()));
+
+      (* next token *)
+      (lex#getToken());
+             
+      if (debug) then (
+        (Printf.printf "shift to state %d\n" dest);
+        (flush stdout);
+      );
+    )
+
+    (* reduce? *)
+    else if (isReduceAction act) then (
+      let rule:int = (decodeReduce act state) in    (* reduction rule *)
+      let ruleLen:int = (getProdInfo_rhsLen tables rule) in
+      let lhs:int = (getProdInfo_lhsIndex tables rule) in
+
+      (* make an array of semantic values for the action rule; this does
+       * an extra copy if we're already using a linear stack, but will
+       * be needed for GLR so I'll do it this way *)
+      let svalArray : Obj.t array = (Array.make ruleLen (Obj.repr 0)) in
+      (Array.blit
+        !svalStack            (* source array *)
+        (!stackLen - ruleLen) (* source start position *)
+        svalArray             (* dest array *)
+        0                     (* dest start position *)
+        ruleLen               (* number of elements to copy *)
+      );
+
+      (* invoke user's reduction action *)
+      let sval:Obj.t = (actions.reductionAction rule svalArray) in
+
+      (* pop 'ruleLen' elements *)
+      stackLen := (!stackLen - ruleLen);
+      let newTopState:int = (topState()) in
+
+      (* get new state *)
+      let dest:tStateId = (decodeGoto (getGotoEntry tables newTopState lhs) lhs) in
+      (pushStateSval dest sval);
+
+      if (debug) then (
+        (Printf.printf "reduce by rule %d (len=%d, lhs=%d), goto state %d\n"
+                       rule ruleLen lhs dest);
+        (flush stdout);
+      );
+    )
+
+    (* error? *)
+    else if (isErrorAction act) then (
+      (Printf.printf "parse error in state %d\n" state);
+      (flush stdout);
+      (failwith "parse error");
+    )
+
+    (* bad code? *)
+    else (
+      (failwith "bad action code");
+    );
+  done;
+
+  (* print final parse stack *)
+  if (debug) then (
+    (Printf.printf "final parse stack (up is top):\n");
+    let i:int ref = ref (pred !stackLen) in
+    while (!i >= 0) do
+      (Printf.printf "  %d\n" (!stateStack).(!i));
+      (decr i);
+    done;
+    (flush stdout);
+  );
+
+  (* return value: sval of top element *)
+  let topSval:Obj.t = (!svalStack).(!stackLen - 1) in
+
+  topSval
+end
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/main.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/main.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/main.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,242 @@
+(* main.ml *)
+(* driver for an Elkhound parser written in OCaml *)
+
+open Lexerint      (* tLexerInterface *)
+open Lrparse       (* parse *)
+open Glr           (* tGLR, makeGLR, glrParse *)
+open Useract       (* tSemanticValue *)
+open Parsetables   (* tParseTables *)
+open Useract       (* tUserActions *)
+open Arith         (* arithParseTables, arithUserActions *)
+open Een           (* eenParseTables, eenUserActions *)
+open Ptreeact      (* tParseTreeLexer, makeParseTreeActions *)
+open Ptreenode     (* tPTreeNode, printTree *)
+open Lexer         (* tToken, readToken *)
+(* also uses Oc_arith, but with explicit qualification *)
+
+
+(* ------------------ lexer ------------------- *)
+let useHardcoded:bool = false        (* set to true for testing with ocamldebug *)
+
+class tLexer =
+object (self)
+  inherit tLexerInterface
+
+  (* stdin *)
+  val lexbuf:Lexing.lexbuf =
+    if (useHardcoded) then (
+      (Lexing.from_string "2+3")     (* hardcoded input *)
+    )
+    else (
+      (Lexing.from_channel stdin)
+    );
+
+  (* this method exists so that I can give the lexbuf directly to an
+   * ocamlyacc parser, for performance/testing purposes *)
+  method getLexbuf() : Lexing.lexbuf =
+  begin
+    lexbuf
+  end
+
+  method getToken() : unit =
+  begin
+    (* read from stdin *)
+    let t:tToken = (readToken lexbuf) in
+    
+    (* break the tToken apart into a kind and an sval; perhaps
+     * this belongs in lexer.mll too? *)
+    match t with
+    | INT(i) -> (
+        tokType <- 1;
+        (self#setIntSval i);
+      )
+    | _ -> (
+        tokType <- (tokenKind t);
+        (self#setIntSval 0);           (* clear previous *)
+      )
+  end
+
+  method tokenDesc() : string =
+  begin
+    let kindDesc:string = (self#tokenKindDesc tokType) in
+    if (tokType = 1) then (
+      kindDesc ^ "(" ^ (string_of_int (self#getIntSval())) ^ ")"
+    )
+    else
+      kindDesc
+  end
+
+  method tokenKindDesc (kind:int) : string =
+  begin
+    (Lexer.tokenKindDesc kind)
+  end
+end
+
+
+let printTokens (lex:tLexerInterface) : unit =
+begin
+  (lex#getToken ());
+  while (not ((lex#getTokType()) = 0)) do
+    (Printf.printf "tokType=%d sval=%d desc=\"%s\"\n"
+                   (lex#getTokType())
+                   (lex#getIntSval())
+                   (lex#tokenDesc())
+                 );
+    (flush stdout);
+    (lex#getToken ());
+  done
+end
+
+
+(* Substitute readToken; I need to translate between the tokens
+ * that my lexer yields and the tokens that the ocamlyacc parser
+ * expects.  I *could* have just used the ocamlyacc tokens
+ * throughout, but then this example would be more dependent on
+ * ocamlyacc than I want. *)
+let ocReadToken (lexbuf: Lexing.lexbuf) : Oc_arith.token =
+begin
+  let t: tToken = (Lexer.readToken lexbuf) in
+  match t with
+  | EOF ->       Oc_arith.EOF
+  | INT(n) ->    Oc_arith.TOK_NUMBER(n)
+  | PLUS ->      Oc_arith.TOK_PLUS
+  | MINUS ->     Oc_arith.TOK_MINUS
+  | TIMES ->     Oc_arith.TOK_TIMES
+  | DIV ->       Oc_arith.TOK_DIVIDE
+  | LPAREN ->    Oc_arith.TOK_LPAREN
+  | RPAREN ->    Oc_arith.TOK_RPAREN
+end
+
+
+(* --------------------- main -------------------- *)
+let main() : unit =
+begin
+  (* random tests *)
+  (if false then (
+    (Printf.printf "Sys.max_array_length: %d\n" Sys.max_array_length);
+    (Printf.printf "Sys.max_string_length: %d\n" Sys.max_string_length);
+  ));
+
+  (* defaults *)
+  let useGLR: bool ref = ref true in
+  let useArith: bool ref = ref true in
+  let justTokens: bool ref = ref false in
+  let usePTree: bool ref = ref false in
+  let useOcamlyacc: bool ref = ref false in
+
+  (* process arguments *)
+  for i=1 to ((Array.length Sys.argv) - 1) do
+    match Sys.argv.(i) with
+    | "lr" ->         useGLR := false
+    | "glr" ->        useGLR := true
+    | "arith" ->      useArith := true
+    | "een" ->        useArith := false
+    | "tokens" ->     justTokens := true
+    | "ptree" ->      usePTree := true
+    | "ocamlyacc" ->  useOcamlyacc := true
+    | op -> (
+        (Printf.printf "unknown option: %s\n" op);
+        (flush stdout);
+        (failwith "bad command line syntax");
+      )
+  done;
+
+  (* create the lexer *)
+  let lex_orig:tLexer = (new tLexer) in
+  let lex:tLexerInterface = (lex_orig :> tLexerInterface) in
+  if (!justTokens) then (
+    (* just print all the tokens and bail *)
+    (printTokens lex);
+    (raise Exit);       (* close enough *)
+  );
+
+  if (!useOcamlyacc) then (
+    let lexbuf: Lexing.lexbuf = (lex_orig#getLexbuf ()) in
+    let result: int = (Oc_arith.main ocReadToken lexbuf) in
+    (Printf.printf "ocamlyacc result: %d\n" result);
+    (raise Exit);
+  );
+
+  (* prime the lexer: get first token *)
+  (lex#getToken());
+
+  (* get parse tables and user actions, depending on which
+   * grammar the user wants to use *)
+  let (tables:tParseTables), (actions:tUserActions) =
+    if (!useArith) then (
+      (arithParseTables, arithUserActions)
+    )
+    else (
+      (eenParseTables, eenUserActions)
+    )
+  in
+
+  (* substitute tree-building actions? *)
+  let (lex':tLexerInterface), (actions':tUserActions) =
+    if (!usePTree) then (
+      ((new tParseTreeLexer lex actions),      (* tree lexer *)
+       (makeParseTreeActions actions tables))  (* tree actions *)
+    )
+    else (
+      (lex, actions)                           (* unchanged *)
+    )
+  in
+  
+  (* parse the input *)
+  let sval:tSemanticValue =
+    if (not !useGLR) then (
+      (* use LR *)
+      (parse lex' tables actions')
+    )
+    else (
+      (* use GLR *)
+      let glr:tGLR = (makeGLR tables actions') in
+      let treeTop: tSemanticValue ref = ref cNULL_SVAL in
+
+      if (not (glrParse glr lex' treeTop)) then (
+        (failwith "GLR parse error")
+      );
+
+      (* print accounting statistics from glr.ml *)
+      (Printf.printf "stack nodes: num=%d max=%d\n"
+                     !numStackNodesAllocd
+                     !maxStackNodesAllocd);
+      (Printf.printf "detShift:     %d\n" glr.detShift);
+      (Printf.printf "detReduce:    %d\n" glr.detReduce);
+      (Printf.printf "nondetShift:  %d\n" glr.nondetShift);
+      (Printf.printf "nondetReduce: %d\n" glr.nondetReduce);
+      (flush stdout);
+      
+      !treeTop
+    )
+  in
+
+  (* interpret the result *)
+  if (not !usePTree) then (
+    (* assume it's an int *)
+    let s:int = ((Obj.obj sval) : int) in
+    (Printf.printf "%s parse result: %d\n"
+                   (if (!useGLR) then "GLR" else "LR")
+                   s);
+  )
+  else (
+    (* it's a tree *)
+    let t:tPTreeNode = ((Obj.obj sval) : tPTreeNode) in
+    (printTree t stdout true(*expand*));
+  );
+  (flush stdout);
+
+end
+;;
+
+let outerMain() : unit =
+begin
+  try
+    (main())
+  with
+  | Exit -> ()
+end
+;;
+
+Printexc.catch outerMain()
+;;

Added: vendor/elsa/current/elkhound/ocaml/objpool.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/objpool.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/objpool.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+(* objpool.ml *)
+(* pool of allocated objects for explicit re-use *)
+                                  
+(* This object pool maintains a set of objects that are available
+ * for use.  It must be given a way to create new objects. *)
+class ['a] tObjectPool (allocFunc: unit -> 'a) =
+object (self)
+  (* implementation is just an array of elements that have been made
+   * available for re-use; this should be regarded as private
+   * inheritance, though I don't see how to do that in OCaml *)
+  inherit (*PRIVATE*) ['a] Arraystack.tArrayStack (allocFunc ())
+
+  (* ---- funcs ---- *)
+  (* retrieve an object ready to be used; might return a pool element,
+   * or if the pool is empty, will make a new element *)
+  method alloc() : 'a =
+  begin
+    if (self#isNotEmpty()) then (
+      (* just grab the topmost element in the pool stack *)
+      (self#pop())
+    )
+
+    else (
+      (* make a new object; I thought about making several at a time
+       * but there seems little advantage.. *)
+      (allocFunc ())
+    )
+  end
+
+  (* return an object to the pool so it can be re-used *)
+  method dealloc (obj: 'a) : unit =
+  begin
+    (* put the element into the stack *)
+    (self#push obj);
+  end
+end
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/oc_arith.mly
===================================================================
--- vendor/elsa/current/elkhound/ocaml/oc_arith.mly	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/oc_arith.mly	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+/* oc_arith.mly */
+/* arith grammar, ocamlyacc syntax */
+
+%token EOF
+%token <int> TOK_NUMBER
+%token TOK_PLUS
+%token TOK_MINUS
+%token TOK_TIMES
+%token TOK_DIVIDE
+%token TOK_LPAREN
+%token TOK_RPAREN
+
+/* low precedence */
+%left TOK_PLUS TOK_MINUS
+%left TOK_TIMES TOK_DIVIDE
+/* high precedence */
+
+%start main
+%type <int> main
+%type <int> exp
+%type <int> parenthesizedExp
+
+%%
+
+main:
+    exp EOF                    { $1 }
+;
+
+exp:
+    exp TOK_PLUS exp           { $1 + $3 }
+  | exp TOK_MINUS exp          { $1 - $3 }
+  | exp TOK_TIMES exp          { $1 * $3 }
+  | exp TOK_DIVIDE exp         { $1 / $3 }
+  | TOK_NUMBER                 { $1 }
+  | parenthesizedExp           { $1 }
+;
+
+parenthesizedExp:
+    TOK_LPAREN exp TOK_RPAREN  { $2 }
+;
+
+/* EOF */

Added: vendor/elsa/current/elkhound/ocaml/occ2/lexer.mll
===================================================================
--- vendor/elsa/current/elkhound/ocaml/occ2/lexer.mll	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/occ2/lexer.mll	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,151 @@
+(* lexer.mll *)
+(* simple lexer for C++ *)
+
+{
+  open Parser
+  exception Eof
+}
+
+rule token = parse
+(* whitespace *)
+  [' ' '\t' '\n']+                { token lexbuf }     (* skip ws *)
+
+(* keywords, operators *)
+| "asm"                           { TOK_ASM }
+| "auto"                          { TOK_AUTO }
+| "break"                         { TOK_BREAK }
+| "bool"                          { TOK_BOOL }
+| "case"                          { TOK_CASE }
+| "catch"                         { TOK_CATCH }
+| "cdecl"                         { TOK_CDECL }
+| "char"                          { TOK_CHAR }
+| "class"                         { TOK_CLASS }
+| "const"                         { TOK_CONST }
+| "const_cast"                    { TOK_CONST_CAST }
+| "continue"                      { TOK_CONTINUE }
+| "default"                       { TOK_DEFAULT }
+| "delete"                        { TOK_DELETE }
+| "do"                            { TOK_DO }
+| "double"                        { TOK_DOUBLE }
+| "dynamic_cast"                  { TOK_DYNAMIC_CAST }
+| "else"                          { TOK_ELSE }
+| "enum"                          { TOK_ENUM }
+| "explicit"                      { TOK_EXPLICIT }
+| "export"                        { TOK_EXPORT }
+| "extern"                        { TOK_EXTERN }
+| "false"                         { TOK_FALSE }
+| "float"                         { TOK_FLOAT }
+| "for"                           { TOK_FOR }
+| "friend"                        { TOK_FRIEND }
+| "goto"                          { TOK_GOTO }
+| "if"                            { TOK_IF }
+| "inline"                        { TOK_INLINE }
+| "int"                           { TOK_INT }
+| "long"                          { TOK_LONG }
+| "mutable"                       { TOK_MUTABLE }
+| "namespace"                     { TOK_NAMESPACE }
+| "new"                           { TOK_NEW }
+| "operator"                      { TOK_OPERATOR }
+| "pascal"                        { TOK_PASCAL }
+| "private"                       { TOK_PRIVATE }
+| "protected"                     { TOK_PROTECTED }
+| "public"                        { TOK_PUBLIC }
+| "register"                      { TOK_REGISTER }
+| "reinterpret_cast"              { TOK_REINTERPRET_CAST }
+| "return"                        { TOK_RETURN }
+| "short"                         { TOK_SHORT }
+| "signed"                        { TOK_SIGNED }
+| "sizeof"                        { TOK_SIZEOF }
+| "static"                        { TOK_STATIC }
+| "static_cast"                   { TOK_STATIC_CAST }
+| "struct"                        { TOK_STRUCT }
+| "switch"                        { TOK_SWITCH }
+| "template"                      { TOK_TEMPLATE }
+| "this"                          { TOK_THIS }
+| "throw"                         { TOK_THROW }
+| "true"                          { TOK_TRUE }
+| "try"                           { TOK_TRY }
+| "typedef"                       { TOK_TYPEDEF }
+| "typeid"                        { TOK_TYPEID }
+| "typename"                      { TOK_TYPENAME }
+| "union"                         { TOK_UNION }
+| "unsigned"                      { TOK_UNSIGNED }
+| "using"                         { TOK_USING }
+| "virtual"                       { TOK_VIRTUAL }
+| "void"                          { TOK_VOID }
+| "volatile"                      { TOK_VOLATILE }
+| "wchar_t"                       { TOK_WCHAR_T }
+| "while"                         { TOK_WHILE }
+| "("                             { TOK_LPAREN }
+| ")"                             { TOK_RPAREN }
+| "["                             { TOK_LBRACKET }
+| "]"                             { TOK_RBRACKET }
+| "->"                            { TOK_ARROW }
+| "::"                            { TOK_COLONCOLON }
+| "."                             { TOK_DOT }
+| "!"                             { TOK_BANG }
+| "~"                             { TOK_TILDE }
+| "+"                             { TOK_PLUS }
+| "-"                             { TOK_MINUS }
+| "++"                            { TOK_PLUSPLUS }
+| "--"                            { TOK_MINUSMINUS }
+| "&"                             { TOK_AND }
+| "*"                             { TOK_STAR }
+| ".*"                            { TOK_DOTSTAR }
+| "->*"                           { TOK_ARROWSTAR }
+| "/"                             { TOK_SLASH }
+| "%"                             { TOK_PERCENT }
+| "<<"                            { TOK_LEFTSHIFT }
+| ">>"                            { TOK_RIGHTSHIFT }
+| "<"                             { TOK_LESSTHAN }
+| "<="                            { TOK_LESSEQ }
+| ">"                             { TOK_GREATERTHAN }
+| ">="                            { TOK_GREATEREQ }
+| "=="                            { TOK_EQUALEQUAL }
+| "!="                            { TOK_NOTEQUAL }
+| "^"                             { TOK_XOR }
+| "|"                             { TOK_OR }
+| "&&"                            { TOK_ANDAND }
+| "||"                            { TOK_OROR }
+| "?"                             { TOK_QUESTION }
+| ":"                             { TOK_COLON }
+| "="                             { TOK_EQUAL }
+| "*="                            { TOK_STAREQUAL }
+| "/="                            { TOK_SLASHEQUAL }
+| "%="                            { TOK_PERCENTEQUAL }
+| "+="                            { TOK_PLUSEQUAL }
+| "-="                            { TOK_MINUSEQUAL }
+| "&="                            { TOK_ANDEQUAL }
+| "^="                            { TOK_XOREQUAL }
+| "|="                            { TOK_OREQUAL }
+| "<<="                           { TOK_LEFTSHIFTEQUAL }
+| ">>="                           { TOK_RIGHTSHIFTEQUAL }
+| ","                             { TOK_COMMA }
+| "..."                           { TOK_ELLIPSIS }
+| ";"                             { TOK_SEMICOLON }
+| "{"                             { TOK_LBRACE }
+| "}"                             { TOK_RBRACE }
+| "__attribute__"                 { TOK___ATTRIBUTE__ }
+| "__FUNCTION__"                  { TOK___FUNCTION__ }
+| "__label__"                     { TOK___LABEL__ }
+| "__PRETTY_FUNCTION__"           { TOK___PRETTY_FUNCTION__ }
+| "__typeof__"                    { TOK___TYPEOF__ }
+
+(* C++ comments *)
+| "//" [^ '\n']*                  { token lexbuf }
+
+(* C comments *)
+| "/*" ([^ '*']| "*"* [^ '*' '/'])* "*"+ "/"     { token lexbuf }
+| "/*" ([^ '*']| "*"* [^ '*' '/'])* "*"*         { failwith "unterminated comment" }
+
+(* identifier *)
+['A'-'Z' 'a'-'z' '_'] ['A'-'Z' 'a'-'z' '_' '0'-'9']*     { TOK_NAME }
+
+(* integer literal *)
+['1'-'9']['0'-'9']*{INT_SUFFIX}?           |
+[0][0-7]*{INT_SUFFIX}?             |
+[0][xX][0-9A-Fa-f]+{INT_SUFFIX}?   {
+
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/occ2/occ2.gr
===================================================================
--- vendor/elsa/current/elkhound/ocaml/occ2/occ2.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/occ2/occ2.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1226 @@
+// occ2.gr            see license.txt for copyright and terms of use
+// starting over with a C++ grammar
+// working from ISO/IEC 14882:1998(E)
+// Ocaml version
+
+option lang_OCaml;
+
+context_class cc2 {
+public:
+};
+
+
+terminals {
+  include("tokens.tok")
+}
+
+
+// start symbol
+nonterm StartSymbol -> TranslationUnit;
+
+
+// map from my lexer's names into the Standard's names
+nonterm Identifier -> TOK_NAME;
+
+nonterm IntegerLiteral -> TOK_INT_LITERAL;
+
+nonterm CharacterLiteral -> TOK_CHAR_LITERAL;
+
+nonterm FloatingLiteral -> TOK_FLOAT_LITERAL;
+
+nonterm StringLiteral -> TOK_STRING_LITERAL;
+
+nonterm BooleanLiteral {
+  -> "true";
+  -> "false";
+}
+
+
+// -------------------- A.1 Keywords --------------------
+
+nonterm TypedefName {
+  -> Identifier;
+}
+
+nonterm NamespaceName {
+  -> OriginalNamespaceName;
+  -> NamespaceAlias;
+}
+
+nonterm OriginalNamespaceName {
+  -> Identifier;
+}
+
+nonterm NamespaceAlias {
+  -> Identifier;
+}
+
+nonterm ClassName {
+  -> Identifier;
+  -> TemplateId;
+}
+
+nonterm EnumName {
+  -> Identifier;
+}
+
+nonterm TemplateName {
+  -> Identifier;
+}
+
+
+// -------------------- A.2 Lexical conventions --------------------
+
+// since I assume the use of a conventional lexical analyzer, I don't
+// reproduce all of the rules from the standard here; instead I list
+// the tokens I assume will be exported by the lexer:
+
+//   Identifier
+//   IntegerLiteral
+//   CharacterLiteral
+//   FloatingLiteral
+//   StringLiteral
+//   BooleanLiteral
+//   keywords: "this", "if", ...
+//   operators: "+", "-", ...
+//   punctuators: "(", ")", ";", ...
+
+nonterm Literal {
+  -> IntegerLiteral;
+  -> CharacterLiteral;
+  -> FloatingLiteral;
+  -> StringLiteral;
+  -> BooleanLiteral;
+}
+
+
+// -------------------- A.3 Basic concepts --------------------
+
+nonterm TranslationUnit {
+  -> DeclarationSeqOpt;
+}
+
+
+// -------------------- A.4 Expressions --------------------
+
+nonterm PrimaryExpression {
+  -> Literal;
+  -> "this";
+  -> "(" Expression ")";
+  -> IdExpression;
+}
+
+nonterm IdExpression {
+  -> UnqualifiedId;
+  -> QualifiedId;
+}
+
+nonterm UnqualifiedId {
+  -> Identifier;
+  -> OperatorFunctionId;
+  -> ConversionFunctionId;
+  -> "~" ClassName;
+  -> TemplateId;
+}
+
+nonterm ColonColonOpt {
+  -> empty;
+  -> "::";
+}
+
+nonterm TemplateOpt {
+  -> empty;
+  -> "template";
+}
+
+nonterm QualifiedId {
+  -> ColonColonOpt NestedNameSpecifier TemplateOpt UnqualifiedId;
+  -> "::" Identifier;
+  -> "::" OperatorFunctionId;
+  -> "::" TemplateId;
+}
+
+nonterm NestedNameSpecifierOpt {
+  -> empty;
+  -> NestedNameSpecifier;
+}
+
+nonterm NestedNameSpecifier {
+  -> ClassOrNamespaceName "::" NestedNameSpecifierOpt;
+  -> ClassOrNamespaceName "::" "template" NestedNameSpecifier;
+}
+
+nonterm ClassOrNamespaceName {
+  -> ClassName;
+  -> NamespaceName;
+}                                                
+
+nonterm ExpressionListOpt {
+  -> empty;
+  -> ExpressionList;
+}
+
+nonterm PostfixExpression {
+  fun merge(l,r) [ l ]
+
+  -> PrimaryExpression;
+  -> PostfixExpression "[" Expression "]";
+  -> PostfixExpression "(" ExpressionListOpt ")";
+  -> SimpleTypeSpecifier "(" ExpressionListOpt ")";
+  -> "typename" ColonColonOpt NestedNameSpecifier Identifier "(" ExpressionListOpt ")";
+  -> "typename" ColonColonOpt NestedNameSpecifier TemplateOpt TemplateId "(" ExpressionListOpt ")";
+  -> PostfixExpression "." TemplateOpt IdExpression;
+  -> PostfixExpression "->" TemplateOpt IdExpression;
+  -> PostfixExpression "." PseudoDestructorName;
+  -> PostfixExpression "->" PseudoDestructorName;
+  -> PostfixExpression "++";
+  -> PostfixExpression "--";
+  -> "dynamic_cast"     "<" TypeId ">" "(" Expression ")";
+  -> "static_cast"      "<" TypeId ">" "(" Expression ")";
+  -> "reinterpret_cast" "<" TypeId ">" "(" Expression ")";
+  -> "const_cast"       "<" TypeId ">" "(" Expression ")";
+  -> "typeid" "(" Expression ")";
+  -> "typeid" "(" TypeId ")";
+}
+
+nonterm ExpressionList {
+  -> AssignmentExpression;
+  -> ExpressionList "," AssignmentExpression;
+}
+
+nonterm PseudoDestructorName {
+  -> ColonColonOpt NestedNameSpecifierOpt TypeName "::" "~" TypeName;
+  -> ColonColonOpt NestedNameSpecifier "template" TemplateId "::" "~" TypeName;
+  -> ColonColonOpt NestedNameSpecifierOpt "~" TypeName;
+}
+
+nonterm UnaryExpression {
+  fun merge(l,r) [ l ]
+
+  -> PostfixExpression;
+  -> "++" CastExpression;
+  -> "--" CastExpression;
+  -> UnaryOperator CastExpression;
+  -> "sizeof" UnaryExpression;
+  -> "sizeof" "(" TypeId ")";
+  -> NewExpression;
+  -> DeleteExpression;
+}
+
+nonterm UnaryOperator {
+  -> "*";
+  -> "&";
+  -> "+";
+  -> "-";
+  -> "!";
+  -> "~";
+}
+  
+nonterm NewPlacementOpt {
+  -> empty;
+  -> NewPlacement;
+}
+
+nonterm NewInitializerOpt {
+  -> empty;
+  -> NewInitializer;
+}
+
+nonterm NewExpression {
+  -> ColonColonOpt "new" NewPlacementOpt NewTypeId NewInitializerOpt;
+  -> ColonColonOpt "new" NewPlacementOpt "(" TypeId ")" NewInitializerOpt;
+}
+
+nonterm NewPlacement {
+  -> "(" ExpressionList ")";
+}                           
+
+nonterm NewDeclaratorOpt {
+  -> empty;
+  -> NewDeclarator;
+}
+
+nonterm NewTypeId {
+  -> TypeSpecifierSeq NewDeclaratorOpt;
+}
+
+nonterm NewDeclarator {
+  -> PtrOperator NewDeclaratorOpt;
+  -> DirectNewDeclarator;
+}
+
+nonterm DirectNewDeclarator {
+  -> "[" Expression "]";
+  -> DirectNewDeclarator "[" ConstantExpression "]";
+}
+
+nonterm NewInitializer {
+  -> "(" ExpressionListOpt ")";
+}
+
+nonterm DeleteExpression {
+  -> ColonColonOpt "delete" CastExpression;
+  -> ColonColonOpt "delete" "[" "]" CastExpression;
+}
+
+nonterm CastExpression {
+  fun merge(l,r) [ l ]
+
+  -> UnaryExpression;
+  -> "(" TypeId ")" CastExpression;
+}
+
+nonterm PmExpression {
+  -> CastExpression;
+  -> PmExpression ".*" CastExpression;
+  -> PmExpression "->*" CastExpression;
+}
+
+nonterm MultiplicativeExpression {
+  -> PmExpression;
+  -> MultiplicativeExpression "*" PmExpression;
+  -> MultiplicativeExpression "/" PmExpression;
+  -> MultiplicativeExpression "%" PmExpression;
+}
+
+nonterm AdditiveExpression {
+  fun merge(l,r) [ l ]
+
+  -> MultiplicativeExpression;
+  -> AdditiveExpression "+" MultiplicativeExpression;
+  -> AdditiveExpression "-" MultiplicativeExpression;
+}
+
+nonterm ShiftExpression {
+  -> AdditiveExpression;
+  -> ShiftExpression "<<" AdditiveExpression;
+  -> ShiftExpression ">>" AdditiveExpression;
+}
+
+nonterm RelationalExpression {
+  fun merge(l,r) { l }
+
+  -> ShiftExpression;
+  -> RelationalExpression "<" ShiftExpression;
+  -> RelationalExpression ">" ShiftExpression;
+  -> RelationalExpression "<=" ShiftExpression;
+  -> RelationalExpression ">=" ShiftExpression;
+}
+
+nonterm EqualityExpression {
+  -> RelationalExpression;
+  -> EqualityExpression "==" RelationalExpression;
+  -> EqualityExpression "!=" RelationalExpression;
+}
+
+nonterm AndExpression {
+  fun merge(l,r) [ l ]
+
+  -> EqualityExpression;
+  -> AndExpression "&" EqualityExpression;
+}
+
+nonterm ExclusiveOrExpression {
+  -> AndExpression;
+  -> ExclusiveOrExpression "^" AndExpression;
+}
+
+nonterm InclusiveOrExpression {
+  -> ExclusiveOrExpression;
+  -> InclusiveOrExpression "|" ExclusiveOrExpression;
+}
+
+nonterm LogicalAndExpression {
+  -> InclusiveOrExpression;
+  -> LogicalAndExpression "&&" InclusiveOrExpression;
+}
+
+nonterm LogicalOrExpression {
+  -> LogicalAndExpression;
+  -> LogicalOrExpression "||" LogicalAndExpression;
+}
+
+nonterm ConditionalExpression {
+  -> LogicalOrExpression;
+  -> LogicalOrExpression "?" Expression ":" AssignmentExpression;
+}
+
+nonterm AssignmentExpression {
+  -> ConditionalExpression;
+  -> LogicalOrExpression AssignmentOperator AssignmentExpression;
+  -> ThrowExpression;
+}
+
+nonterm AssignmentOperator {
+  -> "=";
+  -> "*=";
+  -> "/=";
+  -> "%=";
+  -> "+=";
+  -> "-=";
+  -> ">>=";
+  -> "<<=";
+  -> "&=";
+  -> "^=";
+  -> "|=";
+}
+
+nonterm Expression {
+  -> AssignmentExpression;
+  -> Expression "," AssignmentExpression;
+}
+
+nonterm ConstantExpression {
+  -> ConditionalExpression;
+}
+
+
+// -------------------- A.5 Statements --------------------
+
+nonterm Statement {
+  fun merge(l,r) [ l ]
+
+  -> LabeledStatement;
+  -> ExpressionStatement;
+  -> CompoundStatement;
+  -> SelectionStatement;
+  -> IterationStatement;
+  -> JumpStatement;
+  -> DeclarationStatement;
+  -> TryBlock;
+}
+
+nonterm LabeledStatement {
+  -> Identifier ":" Statement;
+  -> "case" ConstantExpression ":" Statement;
+  -> "default" ":" Statement;      // note: linux kernel contains "switch (..) { ... default: }" ..
+}
+
+nonterm ExpressionOpt {
+  -> empty;
+  -> Expression;
+}
+
+nonterm ExpressionStatement {
+  -> ExpressionOpt ";";
+}
+
+nonterm StatementSeqOpt {
+  -> empty;
+  -> StatementSeq;
+}
+
+nonterm CompoundStatement {
+  -> "{" StatementSeqOpt "}";
+}
+
+nonterm StatementSeq {
+  -> Statement;
+  -> StatementSeq Statement;
+}
+
+nonterm SelectionStatement {
+  -> "if" "(" Condition ")" Statement;
+  -> "if" "(" Condition ")" Statement "else" Statement;
+  -> "switch" "(" Condition ")" Statement;
+}
+
+nonterm Condition {
+  -> Expression;
+  -> TypeSpecifierSeq Declarator "=" AssignmentExpression;     // ?
+}
+  
+nonterm ConditionOpt {
+  -> empty;
+  -> Condition;
+}
+
+nonterm IterationStatement {
+  -> "while" "(" Condition ")" Statement;
+  -> "do" Statement "while" "(" Expression ")" ";";
+  -> "for" "(" ForInitStatement ConditionOpt ";" ExpressionOpt ")" Statement;
+}
+
+nonterm ForInitStatement {
+  fun merge(l,r) [ l ]
+
+  -> ExpressionStatement;
+  -> SimpleDeclaration;
+}
+
+nonterm JumpStatement {
+  -> "break" ";";
+  -> "continue" ";";
+  -> "return" ExpressionOpt ";";
+  -> "goto" Identifier ";";
+}
+
+nonterm DeclarationStatement {
+  -> BlockDeclaration;
+}
+
+
+// -------------------- A.6 Declarations --------------------
+
+nonterm DeclarationSeq {
+  -> Declaration;
+  -> DeclarationSeq Declaration;
+}
+
+nonterm Declaration {
+  -> BlockDeclaration;
+  -> FunctionDefinition;
+  -> TemplateDeclaration;
+  -> ExplicitInstantiation;
+  -> ExplicitSpecialization;
+  -> LinkageSpecification;
+  -> NamespaceDefinition;
+}
+
+nonterm BlockDeclaration {
+  -> SimpleDeclaration;
+  -> AsmDefinition;
+  -> NamespaceAliasDefinition;
+  -> UsingDeclaration;
+  -> UsingDirective;
+}
+
+nonterm DeclSpecifierSeqOpt {
+  -> empty;
+  -> DeclSpecifierSeq;
+}
+
+nonterm InitDeclaratorListOpt {
+  -> empty;
+  -> InitDeclaratorList;
+}
+
+// Q: why is the InitDeclaratorList optional?  "int ;" is not valid
+// Q: for that matter, why is the DeclSpecifierSeq optional?  ";" is
+// not a valid declaration (it's a statement)
+nonterm SimpleDeclaration {
+  fun merge(l,r) [ l ]
+
+  -> DeclSpecifierSeqOpt InitDeclaratorListOpt ";";
+}
+
+nonterm DeclSpecifier {
+  -> StorageClassSpecifier;
+  -> TypeSpecifier;
+  -> FunctionSpecifier;
+  -> "friend";
+  -> "typedef";
+}
+
+nonterm DeclSpecifierSeq {
+  -> DeclSpecifierSeqOpt DeclSpecifier;
+}
+
+nonterm StorageClassSpecifier {
+  -> "auto";
+  -> "register";
+  -> "static";
+  -> "extern";
+  -> "mutable";
+}
+
+nonterm FunctionSpecifier {
+  -> "inline";
+  -> "virtual";
+  -> "explicit";
+}
+
+// repeated in spec
+//nonterm TypedefName {
+//  -> Identifier;
+//} 
+
+nonterm TypeSpecifier {
+  -> SimpleTypeSpecifier;
+  -> ClassSpecifier;
+  -> EnumSpecifier;
+  -> ElaboratedTypeSpecifier;
+  -> CvQualifier;
+}
+
+nonterm SimpleTypeSpecifier {
+  -> ColonColonOpt NestedNameSpecifierOpt TypeName;
+  -> ColonColonOpt NestedNameSpecifier "template" TemplateId;
+  -> "char";
+  -> "wchar_t";
+  -> "bool";
+  -> "short";
+  -> "int";
+  -> "long";
+  -> "signed";
+  -> "unsigned";
+  -> "float";
+  -> "double";
+  -> "void";
+}
+
+nonterm TypeName {
+  fun merge(l,r) [ l ]
+
+  -> ClassName;
+  -> EnumName;
+  -> TypedefName;
+}
+
+nonterm ElaboratedTypeSpecifier {
+  -> ClassKey ColonColonOpt NestedNameSpecifierOpt Identifier;
+  -> "enum" ColonColonOpt NestedNameSpecifierOpt Identifier;
+  -> "typename" ColonColonOpt NestedNameSpecifier Identifier;
+  -> "typename" ColonColonOpt NestedNameSpecifier TemplateOpt TemplateId;
+}
+
+// this is repeated in the spec
+//nonterm EnumName {
+//  -> Identifier;
+//}
+
+nonterm IdentifierOpt {
+  -> empty;
+  -> Identifier;
+}
+        
+nonterm EnumeratorListOpt {
+  -> empty;
+  -> EnumeratorList;
+}
+
+nonterm EnumSpecifier {
+  -> "enum" IdentifierOpt "{" EnumeratorListOpt "}";
+}
+
+nonterm EnumeratorList {
+  -> EnumeratorDefinition;
+  -> EnumeratorList "," EnumeratorDefinition;
+}
+
+nonterm EnumeratorDefinition {
+  -> Enumerator;
+  -> Enumerator "=" ConstantExpression;
+}
+
+nonterm Enumerator {
+  -> Identifier;
+}
+
+// repeated in spec
+//nonterm NamespaceName {
+//  -> OriginalNamespaceName;
+//  -> NamespaceAlias;
+//} 
+
+// repeated in spec
+//nonterm OriginalNamespaceName {
+//  -> Identifier;
+//} 
+
+nonterm NamespaceDefinition {
+  -> NamedNamespaceDefinition;
+  -> UnnamedNamespaceDefinition;
+}
+
+nonterm NamedNamespaceDefinition {
+  -> OriginalNamespaceDefinition;
+  -> ExtensionNamespaceDefinition;
+}
+
+nonterm OriginalNamespaceDefinition {
+  -> "namespace" Identifier "{" NamespaceBody "}";
+}
+
+nonterm ExtensionNamespaceDefinition {
+  -> "namespace" OriginalNamespaceName "{" NamespaceBody "}";
+}
+
+nonterm UnnamedNamespaceDefinition {
+  -> "namespace" "{" NamespaceBody "}";
+}
+
+nonterm DeclarationSeqOpt {
+  -> empty;
+  -> DeclarationSeq;
+}
+
+nonterm NamespaceBody {
+  -> DeclarationSeqOpt;
+}
+
+// repeated in spec
+//nonterm NamespaceAlias {
+//  -> Identifier;
+//} 
+
+nonterm NamespaceAliasDefinition {
+  -> "namespace" Identifier "=" QualifiedNamespaceSpecifier ";";
+}
+
+nonterm QualifiedNamespaceSpecifier {
+  -> ColonColonOpt NestedNameSpecifierOpt NamespaceName;
+}
+
+nonterm TypenameOpt {
+  -> empty;
+  -> "typename";
+}
+
+nonterm UsingDeclaration {
+  -> "using" TypenameOpt ColonColonOpt NestedNameSpecifier UnqualifiedId ";";
+  -> "using" "::" UnqualifiedId ";";
+}
+
+nonterm UsingDirective {
+  -> "using" "namespace" ColonColonOpt NestedNameSpecifierOpt NamespaceName ";";
+}
+
+nonterm AsmDefinition {
+  -> "asm" "(" StringLiteral ")" ";";
+}
+
+nonterm LinkageSpecification {
+  -> "extern" StringLiteral "{" DeclarationSeqOpt "}";
+  -> "extern" StringLiteral Declaration;
+}
+
+
+// -------------------- A.7 Declarators --------------------
+
+nonterm InitDeclaratorList {
+  -> InitDeclarator;
+  -> InitDeclaratorList "," InitDeclarator;
+}
+
+nonterm InitializerOpt {
+  -> empty;
+  -> Initializer;
+}
+
+nonterm InitDeclarator {
+  fun merge(l,r) [ l ]
+
+  -> Declarator InitializerOpt;
+}
+
+nonterm Declarator {
+  -> DirectDeclarator;
+  -> PtrOperator Declarator;
+}
+
+nonterm CvQualifierSeqOpt {
+  -> empty;
+  -> CvQualifierSeq;
+}
+
+nonterm ExceptionSpecificationOpt {
+  -> empty;
+  -> ExceptionSpecification;
+}
+
+nonterm ConstantExpressionOpt {
+  -> empty;
+  -> ConstantExpression;
+}
+
+nonterm DirectDeclarator {
+  -> DeclaratorId;
+  -> DirectDeclarator "(" ParameterDeclarationClause ")" CvQualifierSeqOpt ExceptionSpecificationOpt;
+  -> DirectDeclarator "[" ConstantExpressionOpt "]";
+  -> "(" Declarator ")";
+}
+
+nonterm PtrOperator {
+  -> "*" CvQualifierSeqOpt;
+  -> "&";
+  -> ColonColonOpt NestedNameSpecifier "*" CvQualifierSeqOpt;     // pointer to member
+}
+
+nonterm CvQualifierSeq {
+  -> CvQualifier CvQualifierSeqOpt;
+}
+
+nonterm CvQualifier {
+  -> "const";
+  -> "volatile";
+}
+
+nonterm DeclaratorId {
+  fun merge(l,r) [ l ]
+
+  -> IdExpression;
+  -> ColonColonOpt NestedNameSpecifierOpt TypeName;
+}
+
+nonterm AbstractDeclaratorOpt {
+  -> empty;
+  -> AbstractDeclarator;
+}
+
+nonterm TypeId {
+  -> TypeSpecifierSeq AbstractDeclaratorOpt;
+}
+
+nonterm TypeSpecifierSeqOpt {
+  -> empty;
+  -> TypeSpecifierSeq;
+}
+
+nonterm TypeSpecifierSeq {
+  -> TypeSpecifier TypeSpecifierSeqOpt;
+}
+
+nonterm AbstractDeclarator {
+  -> PtrOperator AbstractDeclaratorOpt;
+  -> DirectAbstractDeclarator;
+}
+     
+nonterm DirectAbstractDeclaratorOpt {
+  -> empty;
+  -> DirectAbstractDeclarator;
+}
+
+nonterm DirectAbstractDeclarator {
+  -> DirectAbstractDeclaratorOpt "(" ParameterDeclarationClause ")" CvQualifierSeqOpt ExceptionSpecificationOpt;
+  -> DirectAbstractDeclaratorOpt "[" ConstantExpressionOpt "]";
+  -> "(" AbstractDeclarator ")";
+}
+
+nonterm ParameterDeclarationListOpt {
+  -> empty;
+  -> ParameterDeclarationList;
+}
+
+nonterm EllipsisOpt {
+  -> empty;
+  -> "...";
+}
+
+nonterm ParameterDeclarationClause {
+  -> ParameterDeclarationListOpt EllipsisOpt;
+  -> ParameterDeclarationList "," "...";
+}
+
+nonterm ParameterDeclarationList {
+  -> ParameterDeclaration;
+  -> ParameterDeclarationList "," ParameterDeclaration;
+}
+
+nonterm ParameterDeclaration {
+  fun merge(l,r) [ l ]
+
+  -> DeclSpecifierSeq Declarator;
+  -> DeclSpecifierSeq Declarator "=" AssignmentExpression;
+  -> DeclSpecifierSeq AbstractDeclaratorOpt;
+  -> DeclSpecifierSeq AbstractDeclaratorOpt "=" AssignmentExpression;
+}
+
+nonterm CtorInitializerOpt {
+  -> empty;
+  -> CtorInitializer;
+}
+
+nonterm FunctionDefinition {
+  -> DeclSpecifierSeqOpt Declarator CtorInitializerOpt FunctionBody;
+  -> DeclSpecifierSeqOpt Declarator FunctionTryBlock;
+}
+
+nonterm FunctionBody {
+  -> CompoundStatement;
+}
+
+nonterm Initializer {
+  -> "=" InitializerClause;
+  -> "(" ExpressionList ")";
+}
+
+nonterm CommaOpt {
+  -> empty;
+  -> ",";
+}
+
+nonterm InitializerClause {
+  -> AssignmentExpression;
+  -> "{" InitializerList CommaOpt "}";
+  -> "{" "}";
+}
+
+nonterm InitializerList {
+  -> InitializerClause;
+  -> InitializerList "," InitializerClause;
+}
+
+
+// -------------------- A.8 Classes --------------------
+
+// repeated in spec
+//nonterm ClassName {
+//  -> Identifier;
+//  -> TemplateId;
+//} 
+
+nonterm MemberSpecificationOpt {
+  -> empty;
+  -> MemberSpecification;
+}
+
+nonterm ClassSpecifier {
+  -> ClassHead "{" MemberSpecificationOpt "}";
+}
+
+nonterm BaseClauseOpt {
+  -> empty;
+  -> BaseClause;
+}
+
+nonterm ClassHead {
+  -> ClassKey IdentifierOpt BaseClauseOpt;
+  -> ClassKey NestedNameSpecifier Identifier BaseClauseOpt;
+  -> ClassKey NestedNameSpecifierOpt TemplateId BaseClauseOpt;
+}
+
+nonterm ClassKey {
+  -> "class";
+  -> "struct";
+  -> "union";
+}
+  
+nonterm MemberSpecification {
+  -> MemberDeclaration MemberSpecificationOpt;
+  -> AccessSpecifier ":" MemberSpecificationOpt;
+}
+
+nonterm MemberDeclaratorListOpt {
+  -> empty;
+  -> MemberDeclaratorList;
+}
+  
+nonterm SemicolonOpt {
+  -> empty;
+  -> ";";
+}
+
+nonterm MemberDeclaration {
+  fun merge(l,r) [ l ]
+
+  -> DeclSpecifierSeqOpt MemberDeclaratorListOpt ";";
+  -> FunctionDefinition SemicolonOpt;
+  -> ColonColonOpt NestedNameSpecifier TemplateOpt UnqualifiedId ";";
+  -> UsingDeclaration;
+  -> TemplateDeclaration;
+}
+
+nonterm MemberDeclaratorList {
+  -> MemberDeclarator;
+  -> MemberDeclaratorList "," MemberDeclarator;
+}
+
+nonterm PureSpecifierOpt {
+  -> empty;
+  -> PureSpecifier;
+}
+
+nonterm ConstantInitializerOpt {
+  -> empty;
+  -> ConstantInitializer;
+}
+
+nonterm MemberDeclarator {
+  fun merge(l,r) [ l ]
+
+  -> Declarator PureSpecifierOpt;           // for when declarator is a function type
+  -> Declarator ConstantInitializerOpt;     // for when it is any other type
+  -> IdentifierOpt ":" ConstantExpression;  // bitfield with optional name
+}
+
+nonterm PureSpecifier {
+  -> "=" IntegerLiteral;         // standard says "0" here but that's not one of my tokens..
+}
+
+nonterm ConstantInitializer{ 
+  -> "=" ConstantExpression;
+}
+
+
+// -------------------- A.9 Derived classes --------------------
+
+nonterm BaseClause {
+  -> ":" BaseSpecifierList;
+}
+
+nonterm BaseSpecifierList {
+  -> BaseSpecifier;
+  -> BaseSpecifierList "," BaseSpecifier;
+}
+ 
+// Q: is there a nonterminal called "virtual"?
+// A: no.  the standard uses the wrong font for "virtual" in the base-specifier rules
+nonterm VirtualOpt {
+  -> empty;
+  -> "virtual";
+}
+
+nonterm AccessSpecifierOpt {
+  -> empty;
+  -> AccessSpecifier;
+}
+
+nonterm BaseSpecifier {
+  -> ColonColonOpt NestedNameSpecifierOpt ClassName;
+  -> "virtual" AccessSpecifierOpt ColonColonOpt NestedNameSpecifierOpt ClassName;
+  -> AccessSpecifier VirtualOpt   ColonColonOpt NestedNameSpecifierOpt ClassName;
+}
+
+nonterm AccessSpecifier {
+  -> "private";
+  -> "protected";
+  -> "public";
+}
+
+
+// -------------------- A.10 Special member functions --------------------
+
+nonterm ConversionFunctionId {
+  -> "operator" ConversionTypeId;
+}
+
+nonterm ConversionDeclaratorOpt {
+  -> empty;
+  -> ConversionDeclarator;
+}
+
+nonterm ConversionTypeId {
+  -> TypeSpecifierSeq ConversionDeclaratorOpt;
+}
+
+nonterm ConversionDeclarator {
+  -> PtrOperator ConversionDeclaratorOpt;
+}
+
+nonterm CtorInitializer {
+  -> ":" MemInitializerList;
+}
+
+// Q: why right recursion?
+nonterm MemInitializerList {
+  -> MemInitializer;
+  -> MemInitializer "," MemInitializerList;
+}                                          
+
+// Q: what is a mem-initializer?
+// A: "member initializer", in constructors after the ":" but before "{"
+nonterm MemInitializer {
+  -> MemInitializerId "(" ExpressionListOpt ")";
+}
+
+nonterm MemInitializerId {
+  fun merge(l,r) { l }
+
+  -> ColonColonOpt NestedNameSpecifierOpt ClassName;
+  -> Identifier;
+}
+
+
+// -------------------- A.11 Overloading --------------------
+
+nonterm OperatorFunctionId {
+  -> "operator" Operator;
+}
+
+nonterm Operator {
+  -> "new";
+  -> "delete";
+  -> "new" "[" "]";
+  -> "delete" "[" "]";
+  -> "+";
+  -> "-";
+  -> "*";
+  -> "/";
+  -> "%";
+  -> "^";
+  -> "&";
+  -> "|";
+  -> "~";
+  -> "!";
+  -> "=";
+  -> "<";
+  -> ">";
+  -> "+=";
+  -> "-=";
+  -> "*=";
+  -> "/=";
+  -> "%=";
+  -> "^=";
+  -> "&=";
+  -> "|=";
+  -> "<<";
+  -> ">>";
+  -> ">>=";
+  -> "<<=";
+  -> "==";
+  -> "!=";
+  -> "<=";
+  -> ">=";
+  -> "&&";
+  -> "||";
+  -> "++";
+  -> "--";
+  -> ",";
+  -> "->*";
+  -> "->";
+  -> "(" ")";
+  -> "[" "]";
+}
+
+
+// -------------------- A.12 Templates --------------------
+
+nonterm ExportOpt {
+  -> empty;
+  -> "export";
+}
+
+nonterm TemplateDeclaration {
+  -> ExportOpt "template" "<" TemplateParameterList ">" Declaration;
+}
+
+nonterm TemplateParameterList {
+  -> TemplateParameter;
+  -> TemplateParameterList "," TemplateParameter;
+}
+
+nonterm TemplateParameter {
+  fun merge(l,r) { l }
+
+  -> TypeParameter;
+  -> ParameterDeclaration;
+}
+
+nonterm TypeParameter {
+  -> "class" IdentifierOpt;
+  -> "class" IdentifierOpt "=" TypeId;
+  -> "typename" IdentifierOpt;
+  -> "typename" IdentifierOpt "=" TypeId;
+  -> "template" "<" TemplateParameterList ">" "class" IdentifierOpt;
+  -> "template" "<" TemplateParameterList ">" "class" IdentifierOpt "=" IdExpression;
+}
+
+nonterm TemplateArgumentListOpt {
+  -> empty;
+  -> TemplateArgumentList;
+}
+
+nonterm TemplateId {
+  -> TemplateName "<" TemplateArgumentListOpt ">";
+}
+
+// repeated in spec
+//nonterm TemplateName {
+//  -> Identifier;
+//} 
+
+nonterm TemplateArgumentList {
+  -> TemplateArgument;
+  -> TemplateArgumentList "," TemplateArgument;
+}
+
+nonterm TemplateArgument {
+  fun merge(l,r) [ l ]
+
+  -> AssignmentExpression;
+  -> TypeId;
+  -> IdExpression;
+}
+
+nonterm ExplicitInstantiation {
+  -> "template" Declaration;
+}
+
+nonterm ExplicitSpecialization {
+  -> "template" "<" ">" Declaration;
+}
+
+
+// -------------------- A.13 Exception handling --------------------
+
+nonterm TryBlock {
+  -> "try" CompoundStatement HandlerSeq;
+}
+
+nonterm FunctionTryBlock {
+  -> "try" CtorInitializerOpt FunctionBody HandlerSeq;
+}
+
+nonterm HandlerSeqOpt {
+  -> empty;
+  -> HandlerSeq;
+}
+
+// Q: why did they choose to use right recursion for this one?  all of
+// the other sequences use left recursion..
+nonterm HandlerSeq {
+  -> Handler HandlerSeqOpt;
+}
+
+nonterm Handler {
+  -> "catch" "(" ExceptionDeclaration ")" CompoundStatement;
+}
+
+nonterm ExceptionDeclaration {
+  -> TypeSpecifierSeq Declarator;
+  -> TypeSpecifierSeq AbstractDeclarator;
+  -> TypeSpecifierSeq;
+  -> "...";
+}
+
+nonterm AssignmentExpressionOpt {
+  -> empty;
+  -> AssignmentExpression;
+}
+
+nonterm ThrowExpression {
+  -> "throw" AssignmentExpressionOpt;
+}
+
+nonterm TypeIdListOpt {
+  -> empty;
+  -> TypeIdList;
+}
+
+nonterm ExceptionSpecification {
+  -> "throw" "(" TypeIdListOpt ")";
+}
+
+nonterm TypeIdList {
+  -> TypeId;
+  -> TypeIdList "," TypeId;
+}
+
+
+// A.14 Preprocessing directives: deferring to separate preprocessor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Added: vendor/elsa/current/elkhound/ocaml/occ2/tokens.h
===================================================================
--- vendor/elsa/current/elkhound/ocaml/occ2/tokens.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/occ2/tokens.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,138 @@
+// tokens.h
+// token codes for occ2
+
+#ifndef TOKENS_H
+#define TOKENS_H
+
+enum Token {
+  TOK_EOF,
+  TOK_NAME,
+  TOK_TYPE_NAME,
+  TOK_VARIABLE_NAME,
+  TOK_INT_LITERAL,
+  TOK_FLOAT_LITERAL,
+  TOK_STRING_LITERAL,
+  TOK_CHAR_LITERAL,
+  TOK_UDEF_QUAL,
+  TOK_ASM,                       // "asm"
+  TOK_AUTO,                      // "auto"
+  TOK_BREAK,                     // "break"
+  TOK_BOOL,                      // "bool"
+  TOK_CASE,                      // "case"
+  TOK_CATCH,                     // "catch"
+  TOK_CDECL,                     // "cdecl"
+  TOK_CHAR,                      // "char"
+  TOK_CLASS,                     // "class"
+  TOK_CONST,                     // "const"
+  TOK_CONST_CAST,                // "const_cast"
+  TOK_CONTINUE,                  // "continue"
+  TOK_DEFAULT,                   // "default"
+  TOK_DELETE,                    // "delete"
+  TOK_DO,                        // "do"
+  TOK_DOUBLE,                    // "double"
+  TOK_DYNAMIC_CAST,              // "dynamic_cast"
+  TOK_ELSE,                      // "else"
+  TOK_ENUM,                      // "enum"
+  TOK_EXPLICIT,                  // "explicit"
+  TOK_EXPORT,                    // "export"
+  TOK_EXTERN,                    // "extern"
+  TOK_FALSE,                     // "false"
+  TOK_FLOAT,                     // "float"
+  TOK_FOR,                       // "for"
+  TOK_FRIEND,                    // "friend"
+  TOK_GOTO,                      // "goto"
+  TOK_IF,                        // "if"
+  TOK_INLINE,                    // "inline"
+  TOK_INT,                       // "int"
+  TOK_LONG,                      // "long"
+  TOK_MUTABLE,                   // "mutable"
+  TOK_NAMESPACE,                 // "namespace"
+  TOK_NEW,                       // "new"
+  TOK_OPERATOR,                  // "operator"
+  TOK_PASCAL,                    // "pascal"
+  TOK_PRIVATE,                   // "private"
+  TOK_PROTECTED,                 // "protected"
+  TOK_PUBLIC,                    // "public"
+  TOK_REGISTER,                  // "register"
+  TOK_REINTERPRET_CAST,          // "reinterpret_cast"
+  TOK_RETURN,                    // "return"
+  TOK_SHORT,                     // "short"
+  TOK_SIGNED,                    // "signed"
+  TOK_SIZEOF,                    // "sizeof"
+  TOK_STATIC,                    // "static"
+  TOK_STATIC_CAST,               // "static_cast"
+  TOK_STRUCT,                    // "struct"
+  TOK_SWITCH,                    // "switch"
+  TOK_TEMPLATE,                  // "template"
+  TOK_THIS,                      // "this"
+  TOK_THROW,                     // "throw"
+  TOK_TRUE,                      // "true"
+  TOK_TRY,                       // "try"
+  TOK_TYPEDEF,                   // "typedef"
+  TOK_TYPEID,                    // "typeid"
+  TOK_TYPENAME,                  // "typename"
+  TOK_UNION,                     // "union"
+  TOK_UNSIGNED,                  // "unsigned"
+  TOK_USING,                     // "using"
+  TOK_VIRTUAL,                   // "virtual"
+  TOK_VOID,                      // "void"
+  TOK_VOLATILE,                  // "volatile"
+  TOK_WCHAR_T,                   // "wchar_t"
+  TOK_WHILE,                     // "while"
+  TOK_LPAREN,                    // "("
+  TOK_RPAREN,                    // ")"
+  TOK_LBRACKET,                  // "["
+  TOK_RBRACKET,                  // "]"
+  TOK_ARROW,                     // "->"
+  TOK_COLONCOLON,                // "::"
+  TOK_DOT,                       // "."
+  TOK_BANG,                      // "!"
+  TOK_TILDE,                     // "~"
+  TOK_PLUS,                      // "+"
+  TOK_MINUS,                     // "-"
+  TOK_PLUSPLUS,                  // "++"
+  TOK_MINUSMINUS,                // "--"
+  TOK_AND,                       // "&"
+  TOK_STAR,                      // "*"
+  TOK_DOTSTAR,                   // ".*"
+  TOK_ARROWSTAR,                 // "->*"
+  TOK_SLASH,                     // "/"
+  TOK_PERCENT,                   // "%"
+  TOK_LEFTSHIFT,                 // "<<"
+  TOK_RIGHTSHIFT,                // ">>"
+  TOK_LESSTHAN,                  // "<"
+  TOK_LESSEQ,                    // "<="
+  TOK_GREATERTHAN,               // ">"
+  TOK_GREATEREQ,                 // ">="
+  TOK_EQUALEQUAL,                // "=="
+  TOK_NOTEQUAL,                  // "!="
+  TOK_XOR,                       // "^"
+  TOK_OR,                        // "|"
+  TOK_ANDAND,                    // "&&"
+  TOK_OROR,                      // "||"
+  TOK_QUESTION,                  // "?"
+  TOK_COLON,                     // ":"
+  TOK_EQUAL,                     // "="
+  TOK_STAREQUAL,                 // "*="
+  TOK_SLASHEQUAL,                // "/="
+  TOK_PERCENTEQUAL,              // "%="
+  TOK_PLUSEQUAL,                 // "+="
+  TOK_MINUSEQUAL,                // "-="
+  TOK_ANDEQUAL,                  // "&="
+  TOK_XOREQUAL,                  // "^="
+  TOK_OREQUAL,                   // "|="
+  TOK_LEFTSHIFTEQUAL,            // "<<="
+  TOK_RIGHTSHIFTEQUAL,           // ">>="
+  TOK_COMMA,                     // ","
+  TOK_ELLIPSIS,                  // "..."
+  TOK_SEMICOLON,                 // ";"
+  TOK_LBRACE,                    // "{"
+  TOK_RBRACE,                    // "}"
+  TOK___ATTRIBUTE__,             // "__attribute__"
+  TOK___FUNCTION__,              // "__FUNCTION__"
+  TOK___LABEL__,                 // "__label__"
+  TOK___PRETTY_FUNCTION__,       // "__PRETTY_FUNCTION__"
+  TOK___TYPEOF__,                // "__typeof__"
+};
+
+#endif // TOKENS_H

Added: vendor/elsa/current/elkhound/ocaml/parsetables.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/parsetables.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/parsetables.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,245 @@
+(* parsetables.ml *)
+(* representation of parsing tables *)
+(* based on elkhound/parsetables.h *)
+
+
+(* The C++ implementation is designed so the sizes of the various
+ * table entries can be adjusted.  I'm reflecting that design here,
+ * but I am just using 'int' as the size choice everywhere, since
+ * (I think) OCaml arrays don't get smaller if you use (e.g.) char.
+ *
+ * The way to make array of char efficiently is using strings, but
+ * that's a TODO at best, for now.
+ *)
+
+
+(* for action entries; some places may still be called int *)
+type tActionEntry = int
+
+(* identifier for a state in the finite automaton *)
+type tStateId = int
+let cSTATE_INVALID = -1
+
+(* entry in the goto table *)
+type tGotoEntry = int
+
+(* index for a terminal *)
+type tTermIndex = int
+
+(* index for a nonterminal *)
+type tNtIndex = int
+
+(* index for a production *)
+type tProdIndex = int
+
+(* ErrorBitsEntry goes here *)
+
+
+(* encode a symbol in the 'stateSymbol' map *)
+(*   N+1:  terminal N *)
+(*   0:    no symbol *)
+(*   -N-1: nonterminal N *)
+type tSymbolId = int
+let symIsTerm (id: tSymbolId) : bool =        id > 0
+let symAsTerm (id: tSymbolId) : int =         id-1      (* why not TermIndex? don't know *)
+let symIsNonterm (id: tSymbolId) : bool =     id < 0
+let symAsNonterm (id: tSymbolId) : tNtIndex = -id-1
+
+
+(* collection of data needed for the online parsing algorithm *)
+type tParseTables = {
+  (* grammar counts *)
+  numTerms: int;
+  numNonterms: int;
+  numProds: int;
+
+  (* # of states in LR automaton *)
+  numStates: int;
+
+  (* action table, indexed by (state*actionCols + lookahead) *)
+  actionCols: int;
+  actionTable: tActionEntry array;
+
+  (* goto table, indexed by (state*gotoCols + nontermId) *)
+  gotoCols: int;
+  gotoTable: tGotoEntry array;
+
+  (* production info, indexed by production id *)
+  prodInfo_rhsLen: int array;         (* this is 'unsigned char' array in C++ *)
+  prodInfo_lhsIndex: tNtIndex array;
+
+  (* map state to symbol shifted to arrive at that state *)
+  stateSymbol: tSymbolId array;
+
+  (* ambiguous actions: one big list, for allocation purposes; then
+   * the actions encode indices into this table; the first indexed
+   * entry gives the # of actions, and is followed by that many
+   * actions, each interpreted the same way ordinary 'actionTable'
+   * entries are *)
+  ambigTableSize: int;                (* redudant in OCaml... *)
+  ambigTable: tActionEntry array;
+
+  (* total order on nonterminals; see elkhound/parsetables.h *)
+  nontermOrder: tNtIndex array;
+
+  (* TODO: implement some of the table compression options? *)
+
+  (* start state id (always 0) *)
+  startState: tStateId;
+  
+  (* index of last production to reduce *)
+  finalProductionIndex: int;
+}
+
+
+(* ------------- sample parse tables (from arith.gr.gen.cc) ------------ *)
+let handcoded_arithParseTables:tParseTables = {
+  numTerms = 8;
+  numNonterms = 4;
+  numProds = 8;
+
+  numStates = 16;
+
+  actionCols = 8;
+  actionTable = [|    (* 128 elements *)
+    (* 0*) 0; 3; 0; 0; 0; 0; 8; 0;
+    (* 1*) 0; 0; 0; 0; 0; 0; 0; 0;
+    (* 2*) -6; 0; -6; -6; -6; -6; 0; -6;
+    (* 3*) 0; 3; 0; 0; 0; 0; 8; 0;
+    (* 4*) 0; 3; 0; 0; 0; 0; 8; 0;
+    (* 5*) 0; 3; 0; 0; 0; 0; 8; 0;
+    (* 6*) 0; 3; 0; 0; 0; 0; 8; 0;
+    (* 7*) 0; 3; 0; 0; 0; 0; 8; 0;
+    (* 8*) -8; 0; -8; -8; -8; -8; 0; -8;
+    (* 9*) 2; 0; 4; 5; 6; 7; 0; 0;
+    (*10*) 0; 0; 4; 5; 6; 7; 0; 9;
+    (*11*) -2; 0; -2; -2; 6; 7; 0; -2;
+    (*12*) -3; 0; -3; -3; 6; 7; 0; -3;
+    (*13*) -4; 0; -4; -4; -4; -4; 0; -4;
+    (*14*) -5; 0; -5; -5; -5; -5; 0; -5;
+    (*15*) -7; 0; -7; -7; -7; -7; 0; -7
+  |];
+
+  gotoCols = 4;
+  gotoTable = [|     (* 64 elements *)
+    (* 0*) 65535; 65535; 9; 15;
+    (* 1*) 65535; 65535; 65535; 65535;
+    (* 2*) 65535; 65535; 65535; 65535;
+    (* 3*) 65535; 65535; 11; 15;
+    (* 4*) 65535; 65535; 12; 15;
+    (* 5*) 65535; 65535; 13; 15;
+    (* 6*) 65535; 65535; 14; 15;
+    (* 7*) 65535; 65535; 10; 15;
+    (* 8*) 65535; 65535; 65535; 65535;
+    (* 9*) 65535; 65535; 65535; 65535;
+    (*10*) 65535; 65535; 65535; 65535;
+    (*11*) 65535; 65535; 65535; 65535;
+    (*12*) 65535; 65535; 65535; 65535;
+    (*13*) 65535; 65535; 65535; 65535;
+    (*14*) 65535; 65535; 65535; 65535;
+    (*15*) 65535; 65535; 65535; 65535
+  |];
+
+  prodInfo_rhsLen = [|       (* 8 elements *)
+    (*0*) 2; 3; 3; 3; 3; 1; 1; 3
+  |];
+  prodInfo_lhsIndex = [|     (* 8 elements *)
+    (*0*) 1; 2; 2; 2; 2; 2; 2; 3
+  |];
+
+  stateSymbol = [|           (* 16 elements *)
+    (*0*) 0; 1; 2; 3; 4; 5; 6; 7; 8; -3; -3; -3; -3; -3; -3; -4
+  |];
+
+  ambigTableSize = 0;
+  ambigTable = [| |];        (* 0 elements *)
+
+  nontermOrder = [|          (* 4 elements *)
+    (*0*) 3; 2; 1; 0
+  |];
+
+  startState = 0;
+  finalProductionIndex = 0
+} 
+
+
+(* -------------- ParseTables client access interface -------------- *)
+let getActionEntry (tables: tParseTables) (state: int) (tok: int) : tActionEntry =
+begin
+  tables.actionTable.(state * tables.actionCols + tok)
+end
+
+let getActionEntry_noError (tables: tParseTables) (state: int) (tok: int) : tActionEntry =
+begin
+  (getActionEntry tables state tok)
+end
+
+
+let isShiftAction (tables: tParseTables) (code: tActionEntry) : bool =
+begin
+  code > 0 && code <= tables.numStates
+end
+
+(* needs tables for compression *)
+let decodeShift (code: tActionEntry) (shiftedTerminal: int) : tStateId =
+begin
+  code-1
+end
+
+let isReduceAction (code: tActionEntry) : bool =
+begin
+  code < 0
+end
+
+(* needs tables for compression *)
+let decodeReduce (code: tActionEntry) (inState: tStateId) : int =
+begin
+  -(code+1)
+end
+
+let isErrorAction (*tables*) (code: tActionEntry) : bool =
+begin
+  code = 0
+end
+
+                       
+(* this returns an index into the ambigTable *)
+(* needs tables for compression *)
+let decodeAmbigAction (tables: tParseTables) (code: tActionEntry) 
+                      (inState: tStateId) : int =
+begin
+  code - 1 - tables.numStates
+end
+
+
+let getGotoEntry (tables: tParseTables) (stateId: tStateId)
+                 (nontermId: int) : tGotoEntry =
+begin
+  tables.gotoTable.(stateId * tables.gotoCols + nontermId)
+end
+
+(* needs tables for compression *)
+let decodeGoto (code: tGotoEntry) (shiftNonterminal: int) : tStateId =
+begin
+  code
+end
+
+
+let getProdInfo_rhsLen (tables: tParseTables) (rule: int) : int =
+begin
+  tables.prodInfo_rhsLen.(rule)
+end
+
+let getProdInfo_lhsIndex (tables: tParseTables) (rule: int) : int =
+begin
+  tables.prodInfo_lhsIndex.(rule)
+end
+
+
+let getNontermOrdinal (tables: tParseTables) (idx: int) : int =
+begin
+  tables.nontermOrder.(idx)
+end
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/ptreeact.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/ptreeact.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/ptreeact.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,106 @@
+(* ptreeact.ml *)
+(* given actions for a grammar, wrap them with actions that
+ * just build a parse tree (forsest) *)
+(* based on elkhound/ptreeact *)
+
+
+open Lexerint       (* tLexerInterface *)
+open Parsetables    (* tParseTables *)
+open Useract        (* tUserActions *)
+open Ptreenode      (* tPTreeNode *)
+
+
+(* ------------------------ tParseTreeLexer ------------------------- *)
+(* wrap the lexer with one yielding parse tree leaf nodes *)
+class tParseTreeLexer
+  (underlying: tLexerInterface)        (* underlying lexer *)
+  (actions: tUserActions) =            (* for getting symbol names *)
+object (self)
+  inherit tLexerInterface
+
+  (* underlying lexer is already primed *)
+  initializer (self#copyFields())
+
+  method getToken() : unit =
+  begin
+    (underlying#getToken());           (* get next token *)
+    (self#copyFields());               (* make new leaf *)
+  end
+
+  method private copyFields() : unit =
+  begin
+    tokType <- (underlying#getTokType());
+
+    (* my sval is a tree leaf *)
+    sval <- (Obj.repr (makePTreeNode (actions.terminalName tokType)));
+  end
+
+  method tokenDesc() : string =
+  begin
+    (underlying#tokenDesc())
+  end
+
+  method tokenKindDesc (kind:int) : string =
+  begin
+    (underlying#tokenKindDesc kind)
+  end
+end
+
+
+(* ----------------------- parseTreeActions ------------------------ *)
+let makeParseTreeActions (underlying: tUserActions) (tables: tParseTables) 
+  : tUserActions =
+begin
+  let actions:tUserActions = {
+    (* action to perform upon performing a reduction *)
+    reductionAction = (
+      fun (prodId:int) (svals: tSemanticValue array) -> (
+        (* production info *)
+        let rhsLen:int = (getProdInfo_rhsLen tables prodId) in
+        let lhsIndex:int = (getProdInfo_lhsIndex tables prodId) in
+        
+        (* make a tree node, initially with no children *)
+        let ret:tPTreeNode = (makePTreeNode (underlying.nonterminalName lhsIndex)) in
+
+        (* add the children *)
+        (setNumChildren ret rhsLen);
+        for i=0 to rhsLen-1 do
+          let child:tPTreeNode = (Obj.obj svals.(i) : tPTreeNode) in
+          (setChild ret i child);
+        done;
+        
+        (Obj.repr ret)
+      ));
+      
+    (* duplicate a semantic value: trivial *)
+    duplicateTerminalValue = (fun _ sval -> sval);
+    duplicateNontermValue = (fun _ sval -> sval);
+
+    (* deallocate an sval that didn't get used: trivial *)
+    deallocateTerminalValue = (fun _ _ -> ());
+    deallocateNontermValue = (fun _ _ -> ());
+
+    (* merge svals for alternative derivations of the same nonterminal *)
+    mergeAlternativeParses = (
+      fun (ntIndex:int) (left:tSemanticValue) (right:tSemanticValue) -> (
+        let l:tPTreeNode = ((Obj.obj left) : tPTreeNode) in
+        let r:tPTreeNode = ((Obj.obj right) : tPTreeNode) in
+        
+        (addAlternative l r);
+        (Obj.repr l)
+      ));
+
+    (* choose whether to keep or drop a reduced value: trivial *)
+    keepNontermValue = (fun _ _ -> true);
+
+    terminalDescription = (fun id _ -> (underlying.terminalName id));
+    nonterminalDescription = (fun id _ -> (underlying.nonterminalName id));
+    terminalName = (fun id -> (underlying.terminalName id));
+    nonterminalName = (fun id -> (underlying.nonterminalName id));
+  } in
+  
+  actions
+end
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/ptreenode.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/ptreenode.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/ptreenode.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,255 @@
+(* ptreenode.ml *)
+(* parse tree node for use with ptreeact module *)
+(* based on elkhound/ptreenode *)
+
+
+open Smutil          (* getSome, etc. *)
+open Arraystack      (* tArrayStack *)
+
+
+(* for storing parse tree counts *)
+type tTreeCount = float
+
+
+(* a node in a parse tree *)
+(* (I tried making this a class, but OCaml kicked my ass instead) *)
+type tPTreeNode = {            
+  (* symbol at this node *)
+  symbol: string;          
+  
+  (* list of ambiguous alternatives to this node *)
+  mutable merged: tPTreeNode option;
+
+  (* array of children *)
+  mutable children: tPTreeNode option array;
+
+  (* number of parse trees this node is root of *)
+  mutable count: tTreeCount;
+}
+
+
+let makePTreeNode (sym:string) : tPTreeNode =
+begin
+  {
+    symbol = sym;
+    merged = None;
+    children = (Array.make 0 None);
+    count = 0.0;
+  }
+end
+
+
+let indent (out:out_channel) (n:int) : unit =
+begin
+  for i=0 to n-1 do
+    (output_char out ' ');
+  done;
+end
+
+
+(* this was polymorphic at one point, then OCaml said "thou shalt not" *)
+let childFold (children: tPTreeNode option array) (init: int)
+              (f: tPTreeNode -> int -> int) : int =
+begin
+  (Array.fold_right (fun co v -> (f (getSome co) v)) children init);
+end
+
+let childIter (children: tPTreeNode option array)
+              (f: tPTreeNode -> unit) : unit =
+begin
+  (Array.iter (fun co -> (f (getSome co))) children);
+end
+
+let rec mergedFold (merged: tPTreeNode option) (init: int)
+               (f: tPTreeNode -> int -> int) : int =
+begin
+  match merged with
+  | None -> init
+  | Some(n) -> (mergedFold n.merged (f n init) f)
+end
+
+let mergedIter (self:tPTreeNode) (f: tPTreeNode -> unit) : unit =
+begin
+  ignore (mergedFold (Some self) 0 (fun n (x:int) -> ((f n); x)))
+end
+
+
+(* just the length of the 'merged' list *)
+let countMergedList (self:tPTreeNode) : int =
+begin
+  (mergedFold (Some self) 0 (fun _ v -> (v+1)))
+end
+
+
+(* count trees rooted here *)
+let rec countTrees (self:tPTreeNode) : tTreeCount =
+begin
+  (* memoize *)
+  if (self.count > 0.0) then (
+    self.count
+  )
+
+  else (
+    (* sum over alternatives, product over children *)
+    (* (look at me, functional programming boy) *)
+    (* never mind, I am obviously not functional programming boy *)
+
+    (* sum over children here *)
+    let ct: float ref = ref 1.0 in
+    (childIter self.children (fun c -> (
+      ct := !ct *. (countTrees c);
+    )));
+
+    (* alternatives? *)
+    if (isSome self.merged) then (
+      (* add them too, recursively *)
+      ct := !ct +. (countTrees (getSome self.merged));
+    );
+
+    !ct
+  )
+end
+
+
+(* set number of children, i.e. size of 'children' array *)
+let setNumChildren (self:tPTreeNode) (i:int) : unit =
+begin
+  self.children <- (Array.make i None)
+end
+
+(* set a particular child *)
+let setChild (self:tPTreeNode) (i:int) (c:tPTreeNode) : unit =
+begin
+  self.children.(i) <- (Some c);
+end
+
+(* add an ambiguous alternative *)
+let addAlternative (self:tPTreeNode) (alt:tPTreeNode) : unit =
+begin
+  (* insert as 2nd element *)
+  alt.merged <- self.merged;
+  self.merged <- (Some alt);
+end
+
+
+(* ----------- printTree (a little biotch) ------------ *)
+let printTree (self:tPTreeNode) (out:out_channel) (expand:bool) : unit =
+begin
+  (* indentation per level *)
+  let cINDENT_INC:int = 2 in
+
+  (* for detecting cyclicity *)      
+  let dummyNode: tPTreeNode = ((Obj.magic []) : tPTreeNode) in
+  let path: tPTreeNode tArrayStack = (new tArrayStack dummyNode) in
+  
+  (* turn this on to detect cyclicity; there is a performance penalty *)
+  let checkForCycles: bool = true in
+
+  (* methods cannot be recursive!  what's up with that?! *)
+  let rec innerPrint (self:tPTreeNode) (indentationOrig:int) : unit =
+  begin
+    let indentation: int ref = ref indentationOrig in
+    let alts: int ref = ref 1 in
+    let lhs: string ref = ref "" in
+    let symbol: string = self.symbol in
+    let merged: tPTreeNode option = self.merged in
+      
+    let cyclicSkip: bool = (
+      if (checkForCycles) then (
+        (* does 'self' appear in 'path'? *)
+        let idx:int = (path#findIndex (fun p -> p == self)) in
+        if (idx >= 0) then (
+          (* yes; print a cyclicity reference *)
+          (indent out !indentation);
+          (Printf.fprintf out "[CYCLIC: refers to %d hops up]\n"
+                              ((path#length()) - idx + 1));
+          true   (* return *)
+        )
+        else (
+          (* no; add myself to the path *)
+          (path#push self);
+          false
+        )
+      )
+      else (
+        false
+      )
+    ) in
+
+    if (not cyclicSkip) then (
+      if (isSome merged) then (
+        (* this is an ambiguity node *)
+        alts := (countMergedList self);
+
+        (* get nonterm from first; should all be same *)
+        try
+          (* extract first word *)
+          let firstSpace:int = (String.index symbol ' ') in
+          lhs := (String.sub symbol 0 firstSpace);
+        with
+        | Not_found -> (
+            lhs := symbol    (* no spaces, use whole thing *)
+          );
+
+        indentation := !indentation + cINDENT_INC;
+      );
+
+      (* iterate over interpretations *)
+      let ct: int ref = ref 1 in
+      (mergedIter self (fun (node:tPTreeNode) -> (
+        if (!alts > 1) then (
+          (indent out (!indentation - cINDENT_INC));
+          (Printf.fprintf out "------------- ambiguous %s: %d of %d ------------\n"
+                              !lhs !ct !alts);
+          (flush out);
+        );
+
+        (indent out !indentation);
+
+        let children: tPTreeNode option array = node.children in
+        let numChildren:int = (Array.length children) in
+
+        (Printf.fprintf out "%s" node.symbol);
+
+        if (expand) then (
+          (* symbol is just LHS, write out RHS names after "->" *)
+          if (numChildren > 0) then (
+            (Printf.fprintf out " ->");
+            (childIter node.children (fun c ->
+              (Printf.fprintf out " %s" c.symbol)
+            ));
+          );
+        );
+
+        (Printf.fprintf out "\n");
+        (flush out);
+
+        (* iterate over children and print them *)
+        (childIter node.children (fun c ->
+          (innerPrint c (!indentation + cINDENT_INC))
+        ));
+
+        (incr ct);
+      )));
+
+      if (isSome merged) then (
+        (* close up ambiguity display *)
+        indentation := !indentation - cINDENT_INC;
+        (indent out !indentation);
+        (Printf.fprintf out "----------- end of ambiguous %s -----------\n"
+                            !lhs);
+        (flush out);
+      );
+      
+      if (checkForCycles) then (
+        (* remove myself from the path *)
+        (ignore (path#pop ()));
+      );
+    );
+  end in
+
+  (innerPrint self 0(*indentation*))
+end
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/smutil.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/smutil.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/smutil.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+(* smutil.ml *)
+(* some random utilities I think should be built in to the language *)
+
+let isEmpty (lst: 'a list) : bool =
+begin
+  match lst with
+  | _ :: _ -> false
+  | _ -> true
+end
+
+let isNotEmpty (lst: 'a list) : bool =
+begin
+  (not (isEmpty lst))
+end
+
+let isNone (o: 'a option) : bool =
+begin
+  match o with
+  | None -> true
+  | _ -> false
+end
+
+let isSome (o: 'a option) : bool =
+begin
+  (not (isNone o))
+end
+
+let getSome (o: 'a option) : 'a =
+begin
+  match o with
+  | None -> (failwith "getSome applied to None")
+  | Some(v) -> v
+end
+
+(* true if 'o' is a Some, and it equals (==) 'v' *)
+let someEquals (o: 'a option) (v: 'a) : bool =
+begin
+  match o with
+  | None -> false
+  | Some(v2) -> v2 == v
+end
+
+let xassertdb (b: bool) : unit =
+begin
+  if (not b) then (
+    (failwith "(db) assertion failure")
+  );
+end
+
+let xassert (b: bool) : unit =
+begin
+  if (not b) then (
+    (failwith "assertion failure")
+  );
+end

Added: vendor/elsa/current/elkhound/ocaml/tobjpool.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/tobjpool.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/tobjpool.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+(* tobjpool.ml *)
+(* test program for objpool.ml *)
+
+open Objpool
+                     
+let counter : int ref = ref 0
+   
+(* my "allocator" will just return successive integers, which my testing
+ * harness can then manipulate like I would addresses in C *)
+let allocator() : int =
+begin
+  (incr counter);
+  (!counter - 1);
+end
+
+let main() : unit =
+begin
+  let pool : int tObjectPool = (new tObjectPool allocator) in
+  
+  (* allocate objects 1 through 10 *)
+  for i = 1 to 10 do
+    (Printf.printf "alloc: %d\n" (pool#alloc()));
+  done;
+
+  (* free the even ones *)
+  for i = 1 to 5 do
+    let addr:int = i*2 in
+    (pool#dealloc addr);
+    (Printf.printf "dealloc: %d\n" addr);
+  done;
+
+  (* allocate 10 more; should get the evens again, plus 11-15 *)
+  for i = 1 to 10 do
+    let addr:int = (pool#alloc()) in
+    (Printf.printf "alloc: %d\n" addr);
+    if (addr < 10 && ((addr mod 2) = 1)) then (
+      (* this would mean it had somehow given us one of the low-valued
+       * odd numbers, but those are still in use! *)
+      (failwith "allocator bug");
+    );
+  done;
+
+end
+;;
+
+Printexc.catch main()
+;;
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/ocaml/useract.ml
===================================================================
--- vendor/elsa/current/elkhound/ocaml/useract.ml	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ocaml/useract.ml	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,150 @@
+(* useract.ml *)
+(* interface for user-defined reduction (etc.) actions *)
+(* based on elkhound/useract.h *)
+
+(* for now, some actual user actions *)
+
+
+(* secret to type casting in OCaml: the Obj module *)
+type tSemanticValue = Obj.t
+let cNULL_SVAL = (Obj.repr 0)
+
+
+(* collection of actions for use during parsing *)
+(* again, see elkhound/useract.h for more info *)
+type tUserActions = {
+  (* action to perform upon performing a reduction *)
+  reductionAction:
+    (*context?*)
+    int ->                     (* production being used to reduce *)
+    tSemanticValue array ->    (* array of svals for RHS symbols *)
+    (*loc?*)
+    tSemanticValue;            (* sval for the reduction *)
+
+  (* duplicate a semantic value *)
+  duplicateTerminalValue:
+    (*context?*)
+    int ->                     (* terminal id *)
+    tSemanticValue ->          (* sval being yielded *)
+    tSemanticValue;            (* sval to yield next time *)
+  duplicateNontermValue:
+    (*context?*)
+    int ->                     (* nonterminal id *)
+    tSemanticValue ->          (* sval being yielded *)
+    tSemanticValue;            (* sval to yield next time *)
+
+  (* deallocate an sval that didn't get used *)
+  deallocateTerminalValue:
+    (*context?*)
+    int ->                     (* terminal id *)
+    tSemanticValue ->          (* sval being dropped *)
+    unit;
+  deallocateNontermValue:
+    (*context?*)
+    int ->                     (* nonterminal id *)
+    tSemanticValue ->          (* sval being dropped *)
+    unit;
+
+  (* merge svals for alternative derivations of the same nonterminal *)
+  mergeAlternativeParses:
+    int ->                     (* nonterminal with two derivations *)
+    tSemanticValue ->          (* sval from derivation 1 *)  
+    tSemanticValue ->          (* sval from derivation 2 *)
+    tSemanticValue;            (* merged sval *)
+    
+  (* choose whether to keep or drop a reduced value *)
+  keepNontermValue:
+    int ->                     (* reduced nonterm id *)
+    tSemanticValue ->          (* sval that 'reductionAction' yielded *)
+    bool;                      (* if false, drop the sval on the floor *)
+    
+  (* reclassification goes here *)
+  
+  (* debugging support; see useract.h for more info *)
+  terminalDescription: int -> tSemanticValue -> string;
+  nonterminalDescription: int -> tSemanticValue -> string;
+  terminalName: int -> string;
+  nonterminalName: int -> string;
+} 
+
+
+(* ---------------- sample reduction actions -------------- *)
+let handcoded_arithUserActions = {
+  reductionAction = (fun prodId svals -> (
+    (* this is how ocamlyacc does it, so I assume it's the fastest way *)
+    let actions : (tSemanticValue array -> tSemanticValue) array = [|
+      (fun svals ->
+        let top = (Obj.obj svals.(0) : int) in
+        (Obj.repr (
+          top
+        ))
+      );
+      (fun svals ->
+        let e1 = (Obj.obj svals.(0) : int) in
+        let e2 = (Obj.obj svals.(2) : int) in
+        (Obj.repr (
+          e1 + e2
+        ))
+      );
+      (fun svals ->
+        let e1 = (Obj.obj svals.(0) : int) in
+        let e2 = (Obj.obj svals.(2) : int) in
+        (Obj.repr (
+          e1 - e2
+        ))
+      );
+      (fun svals ->
+        let e1 = (Obj.obj svals.(0) : int) in
+        let e2 = (Obj.obj svals.(2) : int) in
+        (Obj.repr (
+          e1 * e2
+        ))
+      );
+      (fun svals ->
+        let e1 = (Obj.obj svals.(0) : int) in
+        let e2 = (Obj.obj svals.(2) : int) in
+        (Obj.repr (
+          e1 / e2
+        ))
+      );
+      (fun svals ->
+        let n = (Obj.obj svals.(0) : int) in
+        (Obj.repr (
+          n
+        ))
+      );
+      (fun svals ->
+        let p = (Obj.obj svals.(0) : int) in
+        (Obj.repr (
+          p
+        ))
+      );
+      (fun svals ->
+        let e = (Obj.obj svals.(1) : int) in
+        (Obj.repr (
+          e
+        ))
+      )
+    |] in
+    (actions.(prodId) svals)
+  ));
+  
+  duplicateTerminalValue = (fun termId sval -> sval);
+  duplicateNontermValue = (fun termId sval -> sval);
+  
+  deallocateTerminalValue = (fun termId sval -> ());
+  deallocateNontermValue = (fun termId sval -> ());
+  
+  mergeAlternativeParses = (fun nontermId sval1 sval2 -> sval1);
+  
+  keepNontermValue = (fun nontermId sval -> true);
+
+  terminalDescription = (fun termId sval -> "TODO");
+  nonterminalDescription = (fun termId sval -> "TODO");
+
+  terminalName = (fun termId -> "TODO");
+  nonterminalName = (fun termId -> "TODO")
+}
+
+
+(* EOF *)

Added: vendor/elsa/current/elkhound/out/c.out1
===================================================================
--- vendor/elsa/current/elkhound/out/c.out1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/out/c.out1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+%%% parse-tree: 
+  TranslationUnit -> Declaration TranslationUnit   %attr { }
+    Declaration -> FunctionDefinition   %attr { }
+      FunctionDefinition -> DeclSpecifier Declarator FunctionBody   %attr { }
+        DeclSpecifier -> StorageClassOpt TypeSpecifier   %attr { }
+          StorageClassOpt -> empty   %attr { }
+          TypeSpecifier -> SimpleTypeSpecifier   %attr { }
+            SimpleTypeSpecifier -> "int"   %attr { }
+              int
+        Declarator -> DirectDeclarator   %attr { }
+          DirectDeclarator -> DirectDeclarator "(" ParameterDeclarationClause ")" CVQualifierSeqOpt   %attr { }
+            DirectDeclarator -> VariableName   %attr { }
+              VariableName -> L2_NAME   %attr { }
+                NAME(foo)
+            (
+            ParameterDeclarationClause -> empty   %attr { }
+            )
+            CVQualifierSeqOpt -> empty   %attr { }
+        FunctionBody -> CompoundStatement   %attr { }
+          CompoundStatement -> "{" StatementSeqOpt "}"   %attr { }
+            {
+            StatementSeqOpt -> StatementSeqOpt Statement   %attr { }
+              StatementSeqOpt -> empty   %attr { }
+              Statement -> "return" Expression ";"   %attr { }
+                return
+                Expression -> AssignmentExpression   %attr { }
+                  AssignmentExpression -> ConditionalExpression   %attr { }
+                    ConditionalExpression -> BinaryExpression   %attr { }
+                      BinaryExpression -> CastExpression   %attr { prec=100 }
+                        CastExpression -> UnaryExpression   %attr { }
+                          UnaryExpression -> PostfixExpression   %attr { }
+                            PostfixExpression -> PrimaryExpression   %attr { }
+                              PrimaryExpression -> Literal   %attr { }
+                                Literal -> L2_INT_LITERAL   %attr { }
+                                  INT_LITERAL(3)
+                ;
+            }
+    TranslationUnit -> empty   %attr { }

Added: vendor/elsa/current/elkhound/out/c.out2
===================================================================
--- vendor/elsa/current/elkhound/out/c.out2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/out/c.out2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+%%% parse-tree: 
+  TranslationUnit -> Declaration TranslationUnit   %attr { }
+    Declaration -> FunctionDefinition   %attr { }
+      FunctionDefinition -> DeclSpecifier Declarator FunctionBody   %attr { }
+        DeclSpecifier -> StorageClassOpt TypeSpecifier   %attr { }
+          StorageClassOpt -> empty   %attr { }
+          TypeSpecifier -> SimpleTypeSpecifier   %attr { }
+            SimpleTypeSpecifier -> "int"   %attr { }
+              int
+        Declarator -> DirectDeclarator   %attr { }
+          DirectDeclarator -> DirectDeclarator "(" ParameterDeclarationClause ")" CVQualifierSeqOpt   %attr { }
+            DirectDeclarator -> VariableName   %attr { }
+              VariableName -> L2_NAME   %attr { }
+                NAME(foo)
+            (
+            ParameterDeclarationClause -> ParameterDeclarationList   %attr { }
+              ParameterDeclarationList -> ParameterDeclaration   %attr { }
+                2 ALTERNATIVE PARSES for nonterminal ParameterDeclaration:
+                  ---- alternative 1 ----
+                  ParameterDeclaration -> DeclSpecifier Declarator   %attr { }
+                    DeclSpecifier -> StorageClassOpt TypeSpecifier   %attr { }
+                      StorageClassOpt -> empty   %attr { }
+                      TypeSpecifier -> SimpleTypeSpecifier   %attr { }
+                        SimpleTypeSpecifier -> "int"   %attr { }
+                          int
+                    Declarator -> DirectDeclarator   %attr { }
+                      DirectDeclarator -> "(" Declarator ")"   %attr { }
+                        (
+                        Declarator -> DirectDeclarator   %attr { }
+                          DirectDeclarator -> VariableName   %attr { }
+                            VariableName -> L2_NAME   %attr { }
+                              NAME(x)
+                        )
+                  ---- alternative 2 ----
+                  ParameterDeclaration -> DeclSpecifier AbstractDeclarator   %attr { }
+                    DeclSpecifier -> StorageClassOpt TypeSpecifier   %attr { }
+                      StorageClassOpt -> empty   %attr { }
+                      TypeSpecifier -> SimpleTypeSpecifier   %attr { }
+                        SimpleTypeSpecifier -> "int"   %attr { }
+                          int
+                    AbstractDeclarator -> DirectAbstractDeclarator   %attr { }
+                      DirectAbstractDeclarator -> DirectAbstractDeclarator "(" ParameterDeclarationClause ")" CVQualifierSeqOpt   %attr { }
+                        DirectAbstractDeclarator -> empty   %attr { }
+                        (
+                        ParameterDeclarationClause -> ParameterDeclarationList   %attr { }
+                          ParameterDeclarationList -> ParameterDeclaration   %attr { }
+                            ParameterDeclaration -> DeclSpecifier AbstractDeclarator   %attr { }
+                              DeclSpecifier -> StorageClassOpt TypeSpecifier   %attr { }
+                                StorageClassOpt -> empty   %attr { }
+                                TypeSpecifier -> SimpleTypeSpecifier   %attr { }
+                                  SimpleTypeSpecifier -> TypedefName   %attr { }
+                                    TypedefName -> L2_NAME   %attr { }
+                                      NAME(x)
+                              AbstractDeclarator -> DirectAbstractDeclarator   %attr { }
+                                DirectAbstractDeclarator -> empty   %attr { }
+                        )
+                        CVQualifierSeqOpt -> empty   %attr { }
+            )
+            CVQualifierSeqOpt -> empty   %attr { }
+        FunctionBody -> CompoundStatement   %attr { }
+          CompoundStatement -> "{" StatementSeqOpt "}"   %attr { }
+            {
+            StatementSeqOpt -> empty   %attr { }
+            }
+    TranslationUnit -> empty   %attr { }

Added: vendor/elsa/current/elkhound/out/c.out3
===================================================================
--- vendor/elsa/current/elkhound/out/c.out3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/out/c.out3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,176 @@
+%%% parse-tree: 
+  TranslationUnit -> Declaration TranslationUnit   %attr { }
+    Declaration -> FunctionDefinition   %attr { }
+      FunctionDefinition -> DeclSpecifier Declarator FunctionBody   %attr { }
+        DeclSpecifier -> StorageClassOpt TypeSpecifier   %attr { }
+          StorageClassOpt -> empty   %attr { }
+          TypeSpecifier -> SimpleTypeSpecifier   %attr { }
+            SimpleTypeSpecifier -> "int"   %attr { }
+              int
+        Declarator -> DirectDeclarator   %attr { }
+          DirectDeclarator -> DirectDeclarator "(" ParameterDeclarationClause ")" CVQualifierSeqOpt   %attr { }
+            DirectDeclarator -> VariableName   %attr { }
+              VariableName -> L2_NAME   %attr { }
+                NAME(foo)
+            (
+            ParameterDeclarationClause -> empty   %attr { }
+            )
+            CVQualifierSeqOpt -> empty   %attr { }
+        FunctionBody -> CompoundStatement   %attr { }
+          CompoundStatement -> "{" StatementSeqOpt "}"   %attr { }
+            {
+            StatementSeqOpt -> StatementSeqOpt Statement   %attr { }
+              StatementSeqOpt -> StatementSeqOpt Statement   %attr { }
+                StatementSeqOpt -> StatementSeqOpt Statement   %attr { }
+                  StatementSeqOpt -> StatementSeqOpt Statement   %attr { }
+                    StatementSeqOpt -> empty   %attr { }
+                    2 ALTERNATIVE PARSES for nonterminal Statement:
+                      ---- alternative 1 ----
+                      Statement -> ExpressionStatement   %attr { }
+                        ExpressionStatement -> Expression ";"   %attr { }
+                          Expression -> AssignmentExpression   %attr { }
+                            AssignmentExpression -> ConditionalExpression   %attr { }
+                              ConditionalExpression -> BinaryExpression   %attr { }
+                                BinaryExpression -> CastExpression   %attr { prec=100 }
+                                  CastExpression -> UnaryExpression   %attr { }
+                                    UnaryExpression -> PostfixExpression   %attr { }
+                                      PostfixExpression -> PostfixExpression "(" ExpressionList ")"   %attr { }
+                                        PostfixExpression -> PrimaryExpression   %attr { }
+                                          PrimaryExpression -> VariableName   %attr { }
+                                            VariableName -> L2_NAME   %attr { }
+                                              NAME(putc)
+                                        (
+                                        ExpressionList -> AssignmentExpression   %attr { }
+                                          AssignmentExpression -> ConditionalExpression   %attr { }
+                                            ConditionalExpression -> BinaryExpression   %attr { }
+                                              BinaryExpression -> CastExpression   %attr { prec=100 }
+                                                CastExpression -> UnaryExpression   %attr { }
+                                                  UnaryExpression -> PostfixExpression   %attr { }
+                                                    PostfixExpression -> PrimaryExpression   %attr { }
+                                                      PrimaryExpression -> VariableName   %attr { }
+                                                        VariableName -> L2_NAME   %attr { }
+                                                          NAME(EOF)
+                                        )
+                          ;
+                      ---- alternative 2 ----
+                      Statement -> BlockDeclaration   %attr { }
+                        BlockDeclaration -> SimpleDeclaration   %attr { }
+                          SimpleDeclaration -> DeclSpecifier InitDeclaratorListOpt ";"   %attr { }
+                            DeclSpecifier -> StorageClassOpt TypeSpecifier   %attr { }
+                              StorageClassOpt -> empty   %attr { }
+                              TypeSpecifier -> SimpleTypeSpecifier   %attr { }
+                                SimpleTypeSpecifier -> TypedefName   %attr { }
+                                  TypedefName -> L2_NAME   %attr { }
+                                    NAME(putc)
+                            InitDeclaratorListOpt -> InitDeclaratorList   %attr { }
+                              InitDeclaratorList -> InitDeclarator   %attr { }
+                                InitDeclarator -> Declarator   %attr { }
+                                  Declarator -> DirectDeclarator   %attr { }
+                                    DirectDeclarator -> "(" Declarator ")"   %attr { }
+                                      (
+                                      Declarator -> DirectDeclarator   %attr { }
+                                        DirectDeclarator -> VariableName   %attr { }
+                                          VariableName -> L2_NAME   %attr { }
+                                            NAME(EOF)
+                                      )
+                            ;
+                  Statement -> ExpressionStatement   %attr { }
+                    ExpressionStatement -> Expression ";"   %attr { }
+                      Expression -> AssignmentExpression   %attr { }
+                        AssignmentExpression -> ConditionalExpression   %attr { }
+                          ConditionalExpression -> BinaryExpression   %attr { }
+                            BinaryExpression -> CastExpression   %attr { prec=100 }
+                              CastExpression -> UnaryExpression   %attr { }
+                                UnaryExpression -> PostfixExpression   %attr { }
+                                  PostfixExpression -> PostfixExpression "(" ExpressionList ")"   %attr { }
+                                    PostfixExpression -> PrimaryExpression   %attr { }
+                                      PrimaryExpression -> VariableName   %attr { }
+                                        VariableName -> L2_NAME   %attr { }
+                                          NAME(printf)
+                                    (
+                                    ExpressionList -> AssignmentExpression   %attr { }
+                                      AssignmentExpression -> ConditionalExpression   %attr { }
+                                        ConditionalExpression -> BinaryExpression   %attr { }
+                                          BinaryExpression -> CastExpression   %attr { prec=100 }
+                                            CastExpression -> UnaryExpression   %attr { }
+                                              UnaryExpression -> PostfixExpression   %attr { }
+                                                PostfixExpression -> PrimaryExpression   %attr { }
+                                                  PrimaryExpression -> Literal   %attr { }
+                                                    Literal -> L2_STRING_LITERAL   %attr { }
+                                                      STRING_LITERAL("foo\n")
+                                    )
+                      ;
+                Statement -> ExpressionStatement   %attr { }
+                  ExpressionStatement -> Expression ";"   %attr { }
+                    Expression -> AssignmentExpression   %attr { }
+                      AssignmentExpression -> ConditionalExpression   %attr { }
+                        ConditionalExpression -> BinaryExpression   %attr { }
+                          BinaryExpression -> CastExpression   %attr { prec=100 }
+                            CastExpression -> UnaryExpression   %attr { }
+                              2 ALTERNATIVE PARSES for nonterminal UnaryExpression:
+                                ---- alternative 1 ----
+                                UnaryExpression -> "sizeof" "(" TypeId ")"   %attr { }
+                                  sizeof
+                                  (
+                                  TypeId -> TypeSpecifier AbstractDeclarator   %attr { }
+                                    TypeSpecifier -> SimpleTypeSpecifier   %attr { }
+                                      SimpleTypeSpecifier -> TypedefName   %attr { }
+                                        TypedefName -> L2_NAME   %attr { }
+                                          NAME(foo)
+                                    AbstractDeclarator -> DirectAbstractDeclarator   %attr { }
+                                      DirectAbstractDeclarator -> empty   %attr { }
+                                  )
+                                ---- alternative 2 ----
+                                UnaryExpression -> "sizeof" UnaryExpression   %attr { }
+                                  sizeof
+                                  UnaryExpression -> PostfixExpression   %attr { }
+                                    PostfixExpression -> PrimaryExpression   %attr { }
+                                      PrimaryExpression -> "(" Expression ")"   %attr { }
+                                        (
+                                        Expression -> AssignmentExpression   %attr { }
+                                          AssignmentExpression -> ConditionalExpression   %attr { }
+                                            ConditionalExpression -> BinaryExpression   %attr { }
+                                              BinaryExpression -> CastExpression   %attr { prec=100 }
+                                                CastExpression -> UnaryExpression   %attr { }
+                                                  UnaryExpression -> PostfixExpression   %attr { }
+                                                    PostfixExpression -> PrimaryExpression   %attr { }
+                                                      PrimaryExpression -> VariableName   %attr { }
+                                                        VariableName -> L2_NAME   %attr { }
+                                                          NAME(foo)
+                                        )
+                    ;
+              Statement -> "return" Expression ";"   %attr { }
+                return
+                Expression -> AssignmentExpression   %attr { }
+                  AssignmentExpression -> ConditionalExpression   %attr { }
+                    ConditionalExpression -> BinaryExpression   %attr { }
+                      BinaryExpression.result -> BinaryExpression.left BinaryOperator BinaryExpression.right   %attr { prec=56 }
+                        BinaryExpression -> CastExpression   %attr { prec=100 }
+                          CastExpression -> UnaryExpression   %attr { }
+                            UnaryExpression -> PostfixExpression   %attr { }
+                              PostfixExpression -> PrimaryExpression   %attr { }
+                                PrimaryExpression -> Literal   %attr { }
+                                  Literal -> L2_INT_LITERAL   %attr { }
+                                    INT_LITERAL(1)
+                        BinaryOperator -> "+"   %attr { leftAssoc=1, prec=56 }
+                          +
+                        BinaryExpression.result -> BinaryExpression.left BinaryOperator BinaryExpression.right   %attr { prec=60 }
+                          BinaryExpression -> CastExpression   %attr { prec=100 }
+                            CastExpression -> UnaryExpression   %attr { }
+                              UnaryExpression -> PostfixExpression   %attr { }
+                                PostfixExpression -> PrimaryExpression   %attr { }
+                                  PrimaryExpression -> Literal   %attr { }
+                                    Literal -> L2_INT_LITERAL   %attr { }
+                                      INT_LITERAL(2)
+                          BinaryOperator -> "*"   %attr { leftAssoc=1, prec=60 }
+                            *
+                          BinaryExpression -> CastExpression   %attr { prec=100 }
+                            CastExpression -> UnaryExpression   %attr { }
+                              UnaryExpression -> PostfixExpression   %attr { }
+                                PostfixExpression -> PrimaryExpression   %attr { }
+                                  PrimaryExpression -> Literal   %attr { }
+                                    Literal -> L2_INT_LITERAL   %attr { }
+                                      INT_LITERAL(3)
+                ;
+            }
+    TranslationUnit -> empty   %attr { }

Added: vendor/elsa/current/elkhound/out/castprob.out1
===================================================================
--- vendor/elsa/current/elkhound/out/castprob.out1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/out/castprob.out1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+%%% parse-tree: 
+  Expr -> CastExpr
+    2 ALTERNATIVE PARSES for nonterminal CastExpr:
+      ---- alternative 1 ----
+      CastExpr -> AtomExpr
+        AtomExpr -> AtomExpr ( Expr )
+          AtomExpr -> ( Expr )
+            (
+            Expr -> CastExpr
+              CastExpr -> AtomExpr
+                AtomExpr -> x
+                  x
+            )
+          (
+          Expr -> CastExpr
+            CastExpr -> AtomExpr
+              AtomExpr -> x
+                x
+          )
+      ---- alternative 2 ----
+      CastExpr -> ( Type ) CastExpr
+        (
+        Type -> x
+          x
+        )
+        CastExpr -> AtomExpr
+          AtomExpr -> ( Expr )
+            (
+            Expr -> CastExpr
+              CastExpr -> AtomExpr
+                AtomExpr -> x
+                  x
+            )

Added: vendor/elsa/current/elkhound/out/cdecl.out1
===================================================================
--- vendor/elsa/current/elkhound/out/cdecl.out1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/out/cdecl.out1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+%%% cdecl: entering scope
+%%% cdecl: declaration of x, type int
+%%% cdecl: call of foo with arg y
+%%% cdecl: entering scope
+%%% cdecl: declaration of x, type int
+%%% cdecl: typedef of integer as type int
+%%% cdecl: declaration of y, type integer
+%%% cdecl: declaration of q, type integer
+%%% cdecl: exiting scope
+%%% cdecl: call of integer with arg z
+%%% cdecl: call of integer with arg w
+%%% cdecl: exiting scope
+final parse result: (nil)

Added: vendor/elsa/current/elkhound/out/expr.out1
===================================================================
--- vendor/elsa/current/elkhound/out/expr.out1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/out/expr.out1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+%%% parse-tree: 
+  2 ALTERNATIVE PARSES for nonterminal E:
+    ---- alternative 1 ----
+    E -> E Op E
+      E -> x
+        x
+      Op -> +
+        +
+      E -> E Op E
+        E -> x
+          x
+        Op -> *
+          *
+        E -> x
+          x
+    ---- alternative 2 ----
+    E -> E Op E
+      E -> E Op E
+        E -> x
+          x
+        Op -> +
+          +
+        E -> x
+          x
+      Op -> *
+        *
+      E -> x
+        x

Added: vendor/elsa/current/elkhound/out/ffollow.out1
===================================================================
--- vendor/elsa/current/elkhound/out/ffollow.out1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/out/ffollow.out1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+%%% terminals: Terminals:
+  [0] $: isTerm=1
+  [1] +: isTerm=1
+  [2] *: isTerm=1
+  [3] (: isTerm=1
+  [4] ): isTerm=1
+  [5] id: isTerm=1
+%%% nonterminals: Nonterminals:
+  [0] empty: isTerm=0 first={} follow={}
+  [1] S: isTerm=0 first={id, (} follow={}
+  [2] E: isTerm=0 first={id, (} follow={), $}
+  [3] T: isTerm=0 first={id, (} follow={), $, +}
+  [4] E': isTerm=0 first={+} follow={), $}
+  [5] F: isTerm=0 first={id, (} follow={), +, $, *}
+  [6] T': isTerm=0 first={*} follow={), +, $}
+    0 1 2 3 4 5 6 
+0 [ 1 0 0 0 1 0 1 ]
+1 [ 0 1 0 0 0 0 0 ]
+2 [ 0 0 1 0 0 0 0 ]
+3 [ 0 0 0 1 0 0 0 ]
+4 [ 0 0 0 0 1 0 0 ]
+5 [ 0 0 0 0 0 1 0 ]
+6 [ 0 0 0 0 0 0 1 ]

Added: vendor/elsa/current/elkhound/ownerspec.h
===================================================================
--- vendor/elsa/current/elkhound/ownerspec.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ownerspec.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,74 @@
+// ownerspec.h            see license.txt for copyright and terms of use
+// specification of "owner pointer", as a C++ template class
+
+// I made this as an experiment.. it's really part of the
+// verifier project...
+#error This is not intended to be used
+
+template <class T>
+class OwnerPtr {
+private:
+  T *ptr;
+  
+  enum State { OP_NULL, OP_DEAD, OP_OWNING };
+  State state;
+  
+public:
+  OwnerPtr() : ptr(NULL), state(OP_NULL) {}
+
+  OwnerPtr(T *src) : ptr(src), state(src? OP_OWNING : OP_NULL) {}
+
+  OwnerPtr(OwnerPtr &src) {
+    ptr = src.ptr;
+    state = src.state;
+    src.state = OP_DEAD;
+  }
+
+  ~OwnerPtr() {
+    assert(state != OP_OWNING);
+  }
+
+  OwnerPtr& operator= (OwnerPtr &src) {
+    if (this != &src) {
+      assert(state != OP_OWNING);
+      ptr = src.ptr;
+      state = src.state;
+      src.state = OP_DEAD;
+    }
+    return *this;
+  }
+
+  OwnerPtr& operator= (T *src) {
+    assert(state != OP_OWNING);
+    ptr = src;
+    state = src? OP_OWNING : OP_NULL;
+    return *this;
+  }
+
+  bool operator== (T *p) {
+    assert(state != OP_DEAD);
+    return ptr == p;
+  }
+
+  // yield serf for possible further use
+  operator T* () {
+    assert(state != OP_DEAD);
+    return ptr;
+  }
+
+  // use directly
+  T& operator* () {
+    assert(state == OP_OWNING);
+    return *ptr;
+  }
+  T* operator-> () {
+    assert(state == OP_OWNING);
+    return ptr;
+  }
+};
+
+
+
+
+
+

Added: vendor/elsa/current/elkhound/parse-linux
===================================================================
--- vendor/elsa/current/elkhound/parse-linux	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/parse-linux	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+#!/bin/sh
+# parse the linux testcases
+
+cd testcases/linux
+
+for fname in *.cpp ; do
+  echo "------------ $fname -------------"
+  ../../ccgr -tr sizeof ../../cc.bin $fname 2>&1 | tee out/$fname.out
+done
+


Property changes on: vendor/elsa/current/elkhound/parse-linux
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/parse-tests
===================================================================
--- vendor/elsa/current/elkhound/parse-tests	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/parse-tests	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+#!/bin/sh
+# parse my testcases suite
+
+cd testcases/good
+
+for fname in * ; do
+  echo "$fname ..."
+  ../../ccgr ../../cc.bin $fname > tmp || exit
+  if grep '^Error' tmp; then
+    echo "$fname has some errors"
+    exit
+  fi
+  if grep 'nodes:' tmp; then
+    echo "$fname has some leaks"
+    exit
+  fi
+done
+
+rm tmp
+


Property changes on: vendor/elsa/current/elkhound/parse-tests
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/parser.files
===================================================================
--- vendor/elsa/current/elkhound/parser.files	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/parser.files	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+arraymap.h
+ccwrite.cc
+ccwrite.h
+emitcode.cc
+emitcode.h
+flatutil.h
+glr.cc
+glr.h
+glrmain.cc
+glrtree.cc
+glrtree.h
+gramanl.cc
+gramanl.h
+gramast.cc
+gramast.h
+grammar.cc
+grammar.h
+grampar.cc
+grampar.codes.h
+grampar.h
+lexer1.cc
+lexer1.h
+lexer1yy.cc
+lexer2.cc
+lexer2.h
+lexer2stub.cc
+litcode.cc
+litcode.h
+parssppt.cc
+parssppt.h
+parsstub.cc
+rcptr.h
+useract.cc
+useract.h
+util.h
+cc.gr
+c.ast
+gramast.ast
+grampar.y

Added: vendor/elsa/current/elkhound/parsetables.cc
===================================================================
--- vendor/elsa/current/elkhound/parsetables.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/parsetables.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1329 @@
+// parsetables.cc            see license.txt for copyright and terms of use
+// code for parsetables.h
+
+#include "parsetables.h"    // this module
+#include "bflatten.h"       // BFlatten
+#include "trace.h"          // traceProgress
+#include "crc.h"            // crc32
+#include "emitcode.h"       // EmitCode
+#include "bit2d.h"          // Bit2d
+
+#include <string.h>         // memset
+#include <stdlib.h>         // qsort, system
+
+
+// array index code
+enum { UNASSIGNED = -1 };
+
+               
+// fwd
+template <class EltType>
+void printTable(EltType const *table, int size, int rowLength,
+                rostring typeName, rostring tableName);
+
+
+ParseTables::ParseTables(int t, int nt, int s, int p, StateId start, int final)
+{
+  alloc(t, nt, s, p, start, final);
+}
+    
+template <class T>
+void allocInitArray(T *&arr, int size, T init)
+{
+  arr = new T[size];
+  for (int i=0; i<size; i++) {
+    arr[i] = init;
+  }
+}
+
+template <class T>
+void allocZeroArray(T *&arr, int size)
+{
+  arr = new T[size];
+  memset(arr, 0, sizeof(arr[0]) * size);
+}
+
+void ParseTables::alloc(int t, int nt, int s, int p, StateId start, int final)
+{
+  owning = true;
+
+  temp = new TempData(s);
+
+  numTerms = t;
+  numNonterms = nt;
+  numStates = s;
+  numProds = p;
+
+  actionCols = numTerms;
+  actionRows = numStates;
+
+  gotoCols = numNonterms;
+  gotoRows = numStates;
+
+  allocZeroArray(actionTable, actionTableSize());
+
+  allocZeroArray(gotoTable, gotoTableSize());
+
+  allocZeroArray(prodInfo, numProds);
+
+  allocZeroArray(stateSymbol, numStates);
+
+  // table of ambiguous actions is NULL until someone fills in the
+  // whole thing; since we don't know how many there might be, we
+  // can't even allocate the storage now
+  ambigTableSize = 0;
+  ambigTable = NULL;
+
+  startState = start;
+  finalProductionIndex = final;
+
+  allocZeroArray(nontermOrder, nontermOrderSize());
+
+  if (ENABLE_CRS_COMPRESSION) {
+    allocZeroArray(firstWithTerminal, numTerms);
+    allocZeroArray(firstWithNonterminal, numNonterms);
+  }
+  else {
+    firstWithTerminal = NULL;
+    firstWithNonterminal = NULL;
+  }
+
+  bigProductionListSize = 0;
+  bigProductionList = NULL;
+  if (ENABLE_CRS_COMPRESSION) {
+    allocZeroArray(productionsForState, numStates);
+  }
+  else {
+    productionsForState = NULL;
+  }
+
+  if (ENABLE_CRS_COMPRESSION) {
+    allocZeroArray(ambigStateTable, numStates);
+  }
+  else {
+    ambigStateTable = NULL;
+  }
+
+  // # of bytes, but rounded up to nearest 32-bit boundary
+  errorBitsRowSize = ((numTerms+31) >> 5) * 4;
+
+  // no compressed info
+  uniqueErrorRows = 0;
+  errorBits = NULL;
+  errorBitsPointers = NULL;
+
+  actionIndexMap = NULL;
+  actionRowPointers = NULL;
+
+  gotoIndexMap = NULL;
+  gotoRowPointers = NULL;
+}
+
+
+ParseTables::~ParseTables()
+{
+  if (temp) {
+    delete temp;
+  }
+
+  if (owning) {
+    delete[] actionTable;
+    delete[] gotoTable;
+    delete[] prodInfo;
+    delete[] stateSymbol;
+
+    if (ambigTable) {
+      delete[] ambigTable;
+    }
+
+    delete[] nontermOrder;
+
+    if (firstWithTerminal) {
+      delete[] firstWithTerminal;
+    }
+    if (firstWithNonterminal) {
+      delete[] firstWithNonterminal;
+    }
+    
+    if (bigProductionList) {
+      delete[] bigProductionList;
+    }
+
+    if (errorBits) {
+      delete[] errorBits;
+    }
+    if (actionIndexMap) {
+      delete[] actionIndexMap;
+    }
+    if (gotoIndexMap) {
+      delete[] gotoIndexMap;
+    }
+  }
+
+  // these are always owned
+  if (productionsForState) {
+    delete[] productionsForState;
+  }
+  if (ambigStateTable) {
+    delete[] ambigStateTable;
+  }
+  if (errorBitsPointers) {
+    delete[] errorBitsPointers;
+  }
+  if (actionRowPointers) {
+    delete[] actionRowPointers;
+  }
+  if (gotoRowPointers) {
+    delete[] gotoRowPointers;
+  }
+}
+
+
+ParseTables::TempData::TempData(int numStates)
+  : ambigTable(),
+    bigProductionList(),
+    productionsForState(numStates),
+    ambigStateTable(numStates)
+{
+  productionsForState.setAll(UNASSIGNED);
+  ambigStateTable.setAll(UNASSIGNED);
+}
+
+ParseTables::TempData::~TempData()
+{}
+
+
+ActionEntry ParseTables::validateAction(int code) const
+{
+  // make sure that 'code' is representable; if this fails, most likely
+  // there are more than 32k states or productions; in turn, the most
+  // likely cause of *that* would be the grammar is being generated
+  // automatically from some other specification; you can change the
+  // typedefs of ActionEntry and GotoEntry in gramanl.h to get more
+  // capacity
+  ActionEntry ret = (ActionEntry)code;
+  xassert((int)ret == code);
+  return ret;
+}
+
+GotoEntry ParseTables::validateGoto(int code) const
+{
+  // see above
+  GotoEntry ret = (GotoEntry)code;
+  xassert((int)ret == code);
+  xassert(ret != errorGotoEntry);    // otherwise collision with error code
+  return ret;
+}
+
+
+// doesn't init anything; for use by emitConstructionCode's emitted code
+ParseTables::ParseTables(bool o)
+  : owning(o),
+    temp(NULL)
+{
+  xassert(owning == false);
+}
+
+
+#if ENABLE_CRS_COMPRESSION
+ActionEntry makeAE(ActionEntryKind k, int index)
+{                                      
+  // must fit into 6 bits for my encoding
+  if ((unsigned)index <= AE_MAXINDEX) {
+    // ok
+  }
+  else {                     
+    xfailure(stringc << "index " << index << " truncated!");
+  }
+  
+  if (k == AE_ERROR) {
+    xassert(index == 0);
+  }
+
+  return k | index;
+}
+#endif
+
+
+ActionEntry ParseTables::encodeShift(StateId destState, int shiftedTermId)
+{
+  #if ENABLE_CRS_COMPRESSION
+    int delta = destState - firstWithTerminal[shiftedTermId];
+    return makeAE(AE_SHIFT, delta);
+  #else
+    return validateAction(+destState+1);
+  #endif
+}
+
+
+ActionEntry ParseTables::encodeReduce(int prodId, StateId inWhatState)
+{
+  #if ENABLE_CRS_COMPRESSION
+    int begin = temp->productionsForState[inWhatState];
+    int end = temp->bigProductionList.length();
+    if (begin == UNASSIGNED) {
+      // starting a new set of per-state productions
+      temp->productionsForState[inWhatState] = end;
+      temp->bigProductionList.push(prodId);
+      return AE_REDUCE | 0 /*first in set*/;
+    }
+    else {
+      // continuing a set; search for existing 'prodId' in that set
+      int delta;
+      for (int i=begin; i<end; i++) {
+        if (temp->bigProductionList[i] == prodId) {
+          // re-use this offset
+          delta = i-begin;
+          goto encode;
+        }
+      }
+
+      // not found: add another production id to this set
+      temp->bigProductionList.push(prodId);
+      delta = end-begin;
+
+    encode:
+      return makeAE(AE_REDUCE, delta);
+    }
+
+  #else
+    return validateAction(-prodId-1);
+  #endif
+}
+
+
+ActionEntry ParseTables::encodeAmbig
+  (ArrayStack<ActionEntry> const &set, StateId inWhatState)
+{
+  #if ENABLE_CRS_COMPRESSION
+    int begin = temp->ambigStateTable[inWhatState];
+    int end = temp->ambigTable.length();
+    if (begin == UNASSIGNED) {
+      // starting a new set of per-state ambiguous actions
+      temp->ambigStateTable[inWhatState] = end;
+      appendAmbig(set);
+      return makeAE(AE_AMBIGUOUS, 0 /*first in set*/);
+    }
+    else {
+      // continuing a set: Look for another ambiguous action set in
+      // the same line that has identical contents.  Due to the way
+      // sets are constructed, their representation is canonical.
+      // This is important because some grammars (cc2) have many
+      // ambiguous entries, but they're all the same set of actions;
+      // were we to not consolidate like this, the 6-bit cell encoding
+      // would not be enough.
+
+      // # of big-table entries that will be used
+      int encodeLen = set.length()+1;
+
+      for (int i=begin; i+encodeLen <= end; i++) {
+        // does this offset contain the same set of actions?
+        if (compareAmbig(set, i)) {
+          return makeAE(AE_AMBIGUOUS, i-begin /*delta*/);
+        }
+      }
+
+      // no match
+      appendAmbig(set);
+      return makeAE(AE_AMBIGUOUS, end-begin /*delta*/);
+    }
+
+  #else
+    int end = temp->ambigTable.length();
+    appendAmbig(set);
+    return validateAction(numStates+end+1);
+  #endif
+}
+
+
+void ParseTables::appendAmbig(ArrayStack<ActionEntry> const &set)
+{
+  temp->ambigTable.push(set.length());
+  for (int j=0; j < set.length(); j++) {
+    temp->ambigTable.push(set[j]);
+  }
+}
+
+bool ParseTables::compareAmbig(ArrayStack<ActionEntry> const &set,
+                               int startIndex)
+{
+  if (temp->ambigTable[startIndex] != set.length()) {
+    return false;           // mismatch in 1st entry
+  }
+  for (int j=0; j < set.length(); j++) {
+    if (temp->ambigTable[startIndex+1+j] != set[j]) {
+      return false;         // mismatch in j+2nd entry
+    }
+  }
+  return true;              // match!
+}
+
+
+ActionEntry ParseTables::encodeError() const
+{
+  #if ENABLE_CRS_COMPRESSION
+    return makeAE(AE_ERROR, 0);
+  #else
+    return validateAction(0);
+  #endif
+}
+
+
+GotoEntry ParseTables::encodeGoto(StateId destState, int shiftedNontermId) const
+{
+  #if ENABLE_CRS_COMPRESSION
+    xassert(0 <= shiftedNontermId && shiftedNontermId < numNonterms);
+    int delta = destState - firstWithNonterminal[shiftedNontermId];
+    return validateGoto(delta);
+  #else
+    return validateGoto(destState);
+  #endif
+}
+
+
+// simple alloc + copy
+template <class T>
+void copyArray(int &len, T *&dest, ArrayStack<T> const &src)
+{
+  len = src.length();
+  dest = new T[len];
+  memcpy(dest, src.getArray(), sizeof(T) * len);
+}
+
+// given an array 'src' of indices relative to 'base', allocate the
+// array 'dest' and fill it in with actual pointers into 'base'
+template <class T>
+void copyIndexPtrArray(int len, T **&dest, T *base, ArrayStack<int> const &src)
+{
+  dest = new T* [len];
+  for (int i=0; i<len; i++) {          
+    if (src[i] != UNASSIGNED) {
+      dest[i] = base + src[i];
+    }
+    else {
+      dest[i] = NULL;      // so segfault if deref unassigned entry
+    }
+  }
+}
+
+void ParseTables::finishTables()
+{
+  // copy the ambiguous actions
+  copyArray(ambigTableSize, ambigTable, temp->ambigTable);
+
+  if (ENABLE_CRS_COMPRESSION) {
+    // transfer bigProductionList
+    copyArray(bigProductionListSize, bigProductionList, temp->bigProductionList);
+
+    // transfer productionsForState, translating indices into pointers
+    copyIndexPtrArray(numStates, productionsForState, bigProductionList,
+                      temp->productionsForState);
+
+    // ambigStateTable
+    copyIndexPtrArray(numStates, ambigStateTable, ambigTable,
+                      temp->ambigStateTable);
+  }
+
+  delete temp;
+  temp = NULL;
+}
+
+
+// -------------------- table compression --------------------
+void ParseTables::computeErrorBits()
+{                     
+  traceProgress() << "computing errorBits[]\n";
+
+  // should only be done once
+  xassert(!errorBits);       
+
+  // allocate and clear it
+  int rowSize = ((numTerms+31) >> 5) * 4;
+  allocZeroArray(errorBits, numStates * rowSize);
+
+  // build the pointer table
+  allocZeroArray(errorBitsPointers, numStates);
+
+  // find and set the error bits
+  fillInErrorBits(true /*setPointers*/);
+
+  // compute which rows are identical; I only compress the rows (and
+  // not the columns) because I can fold the former's compression into
+  // the errorBitsPointers[] access, whereas the latter would require
+  // yet another table
+  int *compressed = new int[numStates];   // row -> new location in errorBits[]
+  uniqueErrorRows = 0;
+  int s;
+  for (s=0; s < numStates; s++) {
+    // is 's' the same as any rows that preceded it?
+    for (int t=0; t < s; t++) {
+      // do 's' and 't' have the same contents?
+      if (0==memcmp(errorBitsPointers[s],
+                    errorBitsPointers[t],
+                    sizeof(ErrorBitsEntry) * errorBitsRowSize)) {
+        // yes, map 's' to 't' instead
+        compressed[s] = compressed[t];
+        goto next_s;
+      }
+    }
+
+    // not the same as any
+    compressed[s] = uniqueErrorRows;
+    uniqueErrorRows++;
+
+  next_s:
+    ;
+  }
+
+  // make a smaller 'errorBits' array
+  delete[] errorBits;
+  allocZeroArray(errorBits, uniqueErrorRows * rowSize);
+
+  // rebuild 'errorBitsPointers' according to 'compressed'
+  for (s=0; s < numStates; s++) {
+    errorBitsPointers[s] = errorBits + (compressed[s] * errorBitsRowSize);
+  }
+  delete[] compressed;
+
+  // fill in the bits again, using the new pointers map
+  fillInErrorBits(false /*setPointers*/);
+}
+
+
+void ParseTables::fillInErrorBits(bool setPointers)
+{
+  for (int s=0; s < numStates; s++) {
+    if (setPointers) {
+      errorBitsPointers[s] = errorBits + (s * errorBitsRowSize);
+    }
+
+    for (int t=0; t < numTerms; t++) {
+      if (isErrorAction(actionEntry((StateId)s, t))) {
+        ErrorBitsEntry &b = errorBitsPointers[s][t >> 3];
+        b |= 1 << (t & 7);
+      }
+    }
+  }
+}
+
+
+void ParseTables::mergeActionColumns()
+{
+  traceProgress() << "merging action columns\n";
+
+  // can only do this if we've already pulled out the errors
+  xassert(errorBits);
+
+  // for now I assume we don't have a map yet
+  xassert(!actionIndexMap);
+
+  if (tracingSys("mergeActionColumnsPre")) {
+    // print the action table before compression
+    printTable(actionTable, actionTableSize(), actionCols,
+               "ActionEntry", "actionTable");
+  }
+
+  // compute graph of conflicting 'action' columns
+  // (will be symmetric)
+  Bit2d graph(point(numTerms, numTerms));
+  graph.setall(0);
+
+  // fill it in
+  for (int t1=0; t1 < numTerms; t1++) {
+    for (int t2=0; t2 < t1; t2++) {
+      // does column 't1' conflict with column 't2'?
+      for (int s=0; s < numStates; s++) {
+        ActionEntry a1 = actionEntry((StateId)s, t1);
+        ActionEntry a2 = actionEntry((StateId)s, t2);
+
+        if (isErrorAction(a1) ||
+            isErrorAction(a2) ||
+            a1 == a2) {
+          // no problem
+        }
+        else {
+          // conflict!
+          graph.set(point(t1, t2));
+          graph.set(point(t2, t1));
+          break;
+        }
+      }
+    }
+  }
+  
+  // color the graph
+  Array<int> color(numTerms);      // terminal -> color
+  int numColors = colorTheGraph(color, graph);
+  
+  // build a new, compressed action table; the entries are initialized
+  // to 'error', meaning every cell starts as don't-care
+  ActionEntry *newTable;
+  allocInitArray(newTable, numStates * numColors, errorActionEntry);
+
+  // merge columns in 'actionTable' into those in 'newTable'
+  // according to the 'color' map
+  actionIndexMap = new TermIndex[numTerms];
+  for (int t=0; t<numTerms; t++) {
+    int c = color[t];
+
+    // merge actionTable[t] into newTable[c]
+    for (int s=0; s<numStates; s++) {
+      ActionEntry &dest = newTable[s*numColors + c];
+
+      ActionEntry src = actionEntry((StateId)s, t);
+      if (!isErrorAction(src)) {
+        // make sure there's no conflict (otherwise the graph
+        // coloring algorithm screwed up)
+        xassert(isErrorAction(dest) ||
+                dest == src);
+
+        // merge the entry
+        dest = src;
+      }
+    }
+
+    // fill in the action index map
+    TermIndex ti = (TermIndex)c;
+    xassert(ti == c);     // otherwise value truncation happened
+    actionIndexMap[t] = ti;
+  }
+
+  trace("compression")
+    << "action table: from " << (actionTableSize() * sizeof(ActionEntry))
+    << " down to " << (numStates * numColors * sizeof(ActionEntry))
+    << " bytes\n";
+
+  // replace the existing table with the compressed one
+  delete[] actionTable;
+  actionTable = newTable;
+  actionCols = numColors;
+}
+
+
+// unsurprisingly, this function has considerable structure in common
+// with 'mergeActionColumns'; however, my attempts to consolidate them
+// have led to code that is harder to understand and debug, so they
+// remain separate (at least for now)
+void ParseTables::mergeActionRows()
+{
+  traceProgress() << "merging action rows\n";
+
+  // can only do this if we've already pulled out the errors
+  xassert(errorBits);
+
+  // for now I assume we don't have a map yet
+  xassert(!actionRowPointers);
+
+  // compute graph of conflicting 'action' rows
+  // (will be symmetric)
+  Bit2d graph(point(numStates, numStates));
+  graph.setall(0);
+
+  // fill it in
+  for (int s1=0; s1 < numStates; s1++) {
+    for (int s2=0; s2 < s1; s2++) {
+      // does row 's1' conflict with row 's2'?
+      for (int t=0; t < actionCols; t++) {    // t is an equivalence class of terminals
+        ActionEntry a1 = actionTable[s1*actionCols + t];
+        ActionEntry a2 = actionTable[s2*actionCols + t];
+
+        if (isErrorAction(a1) ||
+            isErrorAction(a2) ||
+            a1 == a2) {
+          // no problem
+        }
+        else {
+          // conflict!
+          graph.set(point(s1, s2));
+          graph.set(point(s2, s1));
+          break;
+        }
+      }
+    }
+  }
+
+  // color the graph
+  Array<int> color(numStates);      // state -> color (equivalence class)
+  int numColors = colorTheGraph(color, graph);
+
+  // build a new, compressed action table
+  ActionEntry *newTable;
+  allocInitArray(newTable, numColors * actionCols, errorActionEntry);
+
+  // merge rows in 'actionTable' into those in 'newTable'
+  // according to the 'color' map
+  
+  // actionTable[]:
+  //
+  //             t0    t1    t2    t3      // terminal equivalence classes
+  //   s0
+  //   s1
+  //   s2
+  //    ...
+  //   /*states*/
+
+  // newTable[]:
+  //
+  //             t0    t1    t2    t3      // terminal equivalence classes
+  //   c0
+  //   c1
+  //   c2    < e.g., union of state1 and state4 (color[1]==color[4]==2) >
+  //    ...
+  //   /*state equivalence classes (colors)*/
+
+  actionRowPointers = new ActionEntry* [numStates];
+  for (int s=0; s<numStates; s++) {
+    int c = color[s];
+
+    // merge actionTable row 's' into newTable row 'c'
+    for (int t=0; t<actionCols; t++) {
+      ActionEntry &dest = newTable[c*actionCols + t];
+
+      ActionEntry src = actionTable[s*actionCols + t];
+      if (!isErrorAction(src)) {
+        // make sure there's no conflict (otherwise the graph
+        // coloring algorithm screwed up)
+        xassert(isErrorAction(dest) ||
+                dest == src);
+
+        // merge the entry
+        dest = src;
+      }
+    }
+
+    // fill in the row pointer map
+    actionRowPointers[s] = newTable + c*actionCols;
+  }
+
+  trace("compression")
+    << "action table: from " << (numStates * actionCols * sizeof(ActionEntry))
+    << " down to " << (numColors * actionCols * sizeof(ActionEntry))
+    << " bytes\n";
+
+  // replace the existing table with the compressed one
+  delete[] actionTable;
+  actionTable = newTable;
+  actionRows = numColors;
+
+  // how many single-value rows?  I'm investigating some other options
+  // for further compression...
+  {
+    int ct=0;
+    for (int s=0; s<actionRows; s++) {
+      int val = 0;
+      for (int t=0; t<actionCols; t++) {
+        int entry = actionRowPointers[s][t];
+        if (val==0) {
+          val = entry;
+        }
+        else if (entry != 0 && entry != val) {
+          // not all the same
+          goto next_s;
+        }
+      }
+
+      // all same
+      ct++;
+
+    next_s:
+      ;
+    }
+    trace("compression") << ct << " same-valued action rows\n";
+  }
+}
+
+
+// created by copying 'mergeGotoRows' and replacing 'action'
+// with 'goto', etc.
+void ParseTables::mergeGotoColumns()
+{
+  traceProgress() << "merging goto columns\n";
+
+  // can only do this if we've already pulled out the errors
+  xassert(errorBits);
+
+  // for now I assume we don't have a map yet
+  xassert(!gotoIndexMap);
+
+  // compute graph of conflicting 'goto' columns
+  Bit2d graph(point(numNonterms, numNonterms));
+  graph.setall(0);
+
+  // fill it in
+  for (int nt1=0; nt1 < numNonterms; nt1++) {
+    for (int nt2=0; nt2 < nt1; nt2++) {
+      // does column 't1' conflict with column 't2'?
+      for (int s=0; s < numStates; s++) {
+        GotoEntry g1 = gotoEntry((StateId)s, nt1);
+        GotoEntry g2 = gotoEntry((StateId)s, nt2);
+
+        if (isErrorGoto(g1) ||
+            isErrorGoto(g2) ||
+            g1 == g2) {
+          // no problem
+        }
+        else {
+          // conflict!
+          graph.set(point(nt1, nt2));
+          graph.set(point(nt2, nt1));
+          break;
+        }
+      }
+    }
+  }
+
+  // color the graph
+  Array<int> color(numNonterms);      // nonterminal -> color
+  int numColors = colorTheGraph(color, graph);
+
+  // build a new, compressed goto table; the entries are initialized
+  // to 'error', meaning every cell starts as don't-care
+  GotoEntry *newTable;
+  allocInitArray(newTable, numStates * numColors, encodeGotoError());
+
+  // merge columns in 'gotoTable' into those in 'newTable'
+  // according to the 'color' map
+  gotoIndexMap = new NtIndex[numNonterms];
+  for (int nt=0; nt<numNonterms; nt++) {
+    int c = color[nt];
+
+    // merge gotoTable[nt] into newTable[c]
+    for (int s=0; s<numStates; s++) {
+      GotoEntry &dest = newTable[s*numColors + c];
+
+      GotoEntry src = gotoEntry((StateId)s, nt);
+      if (!isErrorGoto(src)) {
+        // make sure there's no conflict (otherwise the graph
+        // coloring and/or conflict map algorithms screwed up)
+        xassert(isErrorGoto(dest) ||
+                dest == src);
+
+        // merge the entry
+        dest = src;
+      }
+    }
+
+    // fill in the goto index map
+    NtIndex nti = (NtIndex)c;
+    xassert(nti == c);     // otherwise value truncation happened
+    gotoIndexMap[nt] = nti;
+  }
+
+  trace("compression")
+    << "goto table: from " << (gotoTableSize() * sizeof(GotoEntry))
+    << " down to " << (numStates * numColors * sizeof(GotoEntry))
+    << " bytes\n";
+
+  // replace the existing table with the compressed one
+  delete[] gotoTable;
+  gotoTable = newTable;
+  gotoCols = numColors;
+}
+
+
+// created by copying 'mergeActionRows' and replacing 'action'
+// with 'goto', etc.
+void ParseTables::mergeGotoRows()
+{
+  traceProgress() << "merging goto rows\n";
+
+  // can only do this if we've already pulled out the errors
+  xassert(errorBits);
+
+  // for now I assume we don't have a map yet
+  xassert(!gotoRowPointers);
+
+  // compute graph of conflicting 'goto' rows
+  Bit2d graph(point(numStates, numStates));
+  graph.setall(0);
+
+  // fill it in
+  for (int s1=0; s1 < numStates; s1++) {
+    for (int s2=0; s2 < s1; s2++) {
+      // does row 's1' conflict with row 's2'?
+      for (int nt=0; nt < gotoCols; nt++) {    // nt is an equivalence class of nonterminals
+        GotoEntry g1 = gotoTable[s1*gotoCols + nt];
+        GotoEntry g2 = gotoTable[s2*gotoCols + nt];
+
+        if (isErrorGoto(g1) ||
+            isErrorGoto(g2) ||
+            g1 == g2) {
+          // no problem
+        }
+        else {
+          // conflict!
+          graph.set(point(s1, s2));
+          graph.set(point(s2, s1));
+          break;
+        }
+      }
+    }
+  }
+
+  // color the graph
+  Array<int> color(numStates);      // state -> color (equivalence class)
+  int numColors = colorTheGraph(color, graph);
+
+  // build a new, compressed goto table
+  GotoEntry *newTable;
+  allocInitArray(newTable, numColors * gotoCols, encodeGotoError());
+
+  // merge rows in 'gotoTable' into those in 'newTable'
+  // according to the 'color' map
+
+  // gotoTable[]:
+  //
+  //             t0    t1    t2    t3      // nonterminal equivalence classes
+  //   s0
+  //   s1
+  //   s2
+  //    ...
+  //   /*states*/
+
+  // newTable[]:
+  //
+  //             t0    t1    t2    t3      // nonterminal equivalence classes
+  //   c0
+  //   c1
+  //   c2    < e.g., union of state1 and state4 (color[1]==color[4]==2) >
+  //    ...
+  //   /*state equivalence classes (colors)*/
+
+  gotoRowPointers = new GotoEntry* [numStates];
+  for (int s=0; s<numStates; s++) {
+    int c = color[s];
+
+    // merge gotoTable row 's' into newTable row 'c'
+    for (int nt=0; nt<gotoCols; nt++) {
+      GotoEntry &dest = newTable[c*gotoCols + nt];
+
+      GotoEntry src = gotoTable[s*gotoCols + nt];
+      if (!isErrorGoto(src)) {
+        // make sure there's no conflict (otherwise the graph
+        // coloring algorithm screwed up)
+        xassert(isErrorGoto(dest) ||
+                dest == src);
+
+        // merge the entry
+        dest = src;
+      }
+    }
+
+    // fill in the row pointer map
+    gotoRowPointers[s] = newTable + c*gotoCols;
+  }
+
+  trace("compression")
+    << "goto table: from " << (numStates * gotoCols * sizeof(GotoEntry))
+    << " down to " << (numColors * gotoCols * sizeof(GotoEntry))
+    << " bytes\n";
+
+  // replace the existing table with the compressed one
+  delete[] gotoTable;
+  gotoTable = newTable;
+  gotoRows = numColors;
+}
+
+
+static int intCompare(void const *left, void const *right)
+{
+  return *((int const*)left) - *((int const*)right);
+}
+
+int ParseTables::colorTheGraph(int *color, Bit2d &graph)
+{
+  int n = graph.Size().x;  // same as y
+
+  if (tracingSys("graphColor") && n < 20) {
+    graph.print();
+  }
+
+  // node -> # of adjacent nodes
+  Array<int> degree(n);
+  memset((int*)degree, 0, n * sizeof(int));
+
+  // node -> # of adjacent nodes that have colors already
+  Array<int> blocked(n);
+
+  // initialize some arrays
+  enum { UNASSIGNED = -1 };
+  {
+    for (int i=0; i<n; i++) {
+      // clear the color map
+      color[i] = UNASSIGNED;
+      blocked[i] = 0;
+
+      for (int j=0; j<n; j++) {
+        if (graph.get(point(i,j))) {
+          degree[i]++;
+        }
+      }
+    }
+  }
+
+  // # of colors used
+  int usedColors = 0;
+
+  for (int numColored=0; numColored < n; numColored++) {
+    // Find a vertex to color.  Prefer nodes that are more constrained
+    // (have more blocked colors) to those that are less constrained.
+    // Then, prefer those that are least constraining (heave least
+    // uncolored neighbors) to those that are more constraining.  If
+    // ties remain, choose arbitrarily.
+    int best = -1;
+    int bestBlocked = 0;
+    int bestUnblocked = 0;
+
+    for (int choice = 0; choice < n; choice++) {
+      if (color[choice] != UNASSIGNED) continue;
+
+      int chBlocked = blocked[choice];
+      int chUnblocked = degree[choice] - blocked[choice];
+      if (best == -1 ||                          // no choice yet
+          chBlocked > bestBlocked ||             // more constrained
+          (chBlocked == bestBlocked &&
+           chUnblocked < bestUnblocked)) {       // least constraining
+        // new best
+        best = choice;
+        bestBlocked = chBlocked;
+        bestUnblocked = chUnblocked;
+      }
+    }
+
+    // get the assigned colors of the adjacent vertices
+    Array<int> adjColor(bestBlocked);
+    int adjIndex = 0;
+    for (int i=0; i<n; i++) {
+      if (graph.get(point(best,i)) &&
+          color[i] != UNASSIGNED) {
+        adjColor[adjIndex++] = color[i];
+      }
+    }
+    xassert(adjIndex == bestBlocked);
+
+    // sort them
+    qsort((int*)adjColor, bestBlocked, sizeof(int), intCompare);
+
+    // select the lowest-numbered color that won't conflict
+    int selColor = 0;
+    for (int j=0; j<bestBlocked; j++) {
+      if (selColor == adjColor[j]) {
+        selColor++;
+      }
+      else if (selColor < adjColor[j]) {
+        // found one that doesn't conflict
+        break;
+      }
+      else {
+        // happens when we have two neighbors that have the same color;
+        // that's fine, we'll go around the loop again to see what the
+        // next neighbor has to say
+      }
+    }
+
+    // assign 'selColor' to 'best'
+    color[best] = selColor;
+    if (selColor+1 > usedColors) {
+      usedColors = selColor+1;
+    }
+
+    // update 'blocked[]'
+    for (int k=0; k<n; k++) {
+      if (graph.get(point(best,k))) {
+        // every neighbor of 'k' now has one more blocked color
+        blocked[k]++;
+      }
+    }
+  }
+
+  ostream &os = trace("graphColor") << "colors[]:";
+
+  for (int i=0; i<n; i++) {
+    // every node should now have blocked == degree
+    xassert(blocked[i] == degree[i]);
+
+    // and have a color assigned
+    xassert(color[i] != UNASSIGNED);
+    os << " " << color[i];
+  }
+
+  os << "\n";
+
+  return usedColors;
+}
+
+
+// --------------------- table emission -------------------
+// create literal tables
+template <class EltType>
+void emitTable(EmitCode &out, EltType const *table, int size, int rowLength,
+               rostring typeName, rostring tableName)
+{
+  if (!table || !size) {
+    out << "  " << typeName << " *" << tableName << " = NULL;\n";
+    return;
+  }
+
+  bool printHex = 0==strcmp(typeName, "ErrorBitsEntry") ||
+                  (ENABLE_CRS_COMPRESSION && 0==strcmp(typeName, "ActionEntry")) ||
+                  (ENABLE_CRS_COMPRESSION && 0==strcmp(typeName, "GotoEntry")) ;
+  bool needCast = 0==strcmp(typeName, "StateId");
+
+  if (size * sizeof(*table) > 50) {    // suppress small ones
+    out << "  // storage size: " << size * sizeof(*table) << " bytes\n";
+    if (size % rowLength == 0) {
+      out << "  // rows: " << (size/rowLength) << "  cols: " << rowLength << "\n";
+    }
+  }
+
+  int rowNumWidth = stringf("%d", size / rowLength /*round down*/).length();
+
+  // I make tables 'const' because that way the OS loader might be
+  // smart enough to share them (on a read-only basis) across multiple
+  // processes started from the same executable.  But I immediately
+  // cast them to non-const, since ParseTables doesn't declare
+  // pointers-to-const (since it also has methods to modify the tables
+  // at parser generation time).
+
+  out << "  static " << typeName << " const " << tableName << "[" << size << "] = {";
+  int row = 0;
+  for (int i=0; i<size; i++) {
+    if (i % rowLength == 0) {    // one row per state
+      out << stringf("\n    /""*%*d*""/ ", rowNumWidth, row++);
+    }
+
+    if (needCast) {
+      out << "(" << typeName << ")";
+    }
+
+    if (printHex) {
+      out << stringf("0x%02X, ", table[i]);
+    }
+    else if (sizeof(table[i]) == 1) {
+      // little bit of a hack to make sure 'unsigned char' gets
+      // printed as an int; the casts are necessary because this
+      // code gets compiled even when EltType is ProdInfo
+      out << (int)(*((unsigned char*)(table+i))) << ", ";
+    }
+    else {
+      // print the other int-sized things, or ProdInfo using
+      // the overloaded '<<' below
+      out << table[i] << ", ";
+    }
+  }
+  out << "\n"
+      << "  };\n";
+}
+
+// used to emit the elements of the prodInfo table
+stringBuilder& operator<< (stringBuilder &sb, ParseTables::ProdInfo const &info)
+{
+  sb << "{" << (int)info.rhsLen << "," << (int)info.lhsIndex << "}";
+  return sb;
+}
+
+
+// like 'emitTable', but also set a local called 'tableName'
+template <class EltType>
+void emitTable2(EmitCode &out, EltType const *table, int size, int rowLength,
+                rostring typeName, rostring tableName)
+{
+  string tempName = stringc << tableName << "_static";
+  emitTable(out, table, size, rowLength, typeName, tempName);
+  out << "  " << tableName << " = const_cast<" << typeName << "*>(" 
+      << tempName << ");\n\n";
+}
+
+
+template <class EltType>
+void emitOffsetTable(EmitCode &out, EltType **table, EltType *base, int size,
+                     rostring typeName, rostring tableName, rostring baseName)
+{
+  if (!table) {
+    out << "  " << tableName << " = NULL;\n\n";
+    return;
+  }
+
+  // make the pointers persist by storing a table of offsets
+  Array<int> offsets(size);
+  bool allUnassigned = true;
+  for (int i=0; i < size; i++) {
+    if (table[i]) {
+      offsets[i] = table[i] - base;
+      allUnassigned = false;
+    }
+    else {
+      offsets[i] = UNASSIGNED;    // codes for a NULL entry
+    }
+  }
+
+  if (allUnassigned) {
+    // for example, an LALR(1) grammar has no ambiguous entries in its tables
+    size = 0;
+  }
+
+  if (size > 0) {
+    out << "  " << tableName << " = new " << typeName << " [" << size << "];\n";
+
+    emitTable(out, (int*)offsets, size, 16, "int", stringc << tableName << "_offsets");
+
+    // at run time, interpret the offsets table
+    out << "  for (int i=0; i < " << size << "; i++) {\n"
+        << "    int ofs = " << tableName << "_offsets[i];\n"
+        << "    if (ofs >= 0) {\n"
+        << "      " << tableName << "[i] = " << baseName << " + ofs;\n"
+        << "    }\n"
+        << "    else {\n"
+        << "      " << tableName << "[i] = NULL;\n"
+        << "    }\n"
+        << "  }\n\n";
+  }
+  else {
+    out << "  // offset table is empty\n"
+        << "  " << tableName << " = NULL;\n\n";
+  }
+}
+
+                
+// for debugging
+template <class EltType>
+void printTable(EltType const *table, int size, int rowLength,
+                rostring typeName, rostring tableName)
+{            
+  // disabled for now since I don't need it anymore, and it adds
+  // a link dependency on emitcode.cc ...
+  #if 0
+  {
+    EmitCode out("printTable.tmp");
+    emitTable(out, table, size, rowLength, typeName, tableName);
+  }
+
+  system("cat printTable.tmp; rm printTable.tmp");
+  #endif // 0
+}
+
+
+// emit code for a function which, when compiled and executed, will
+// construct this same table (except the constructed table won't own
+// the table data, since it will point to static program data)
+void ParseTables::emitConstructionCode(EmitCode &out,
+  rostring className, rostring funcName)
+{
+  // must have already called 'finishTables'
+  xassert(!temp);
+
+  out << "// this makes a ParseTables from some literal data;\n"
+      << "// the code is written by ParseTables::emitConstructionCode()\n"
+      << "// in " << __FILE__ << "\n"
+      << "class " << className << "_ParseTables : public ParseTables {\n"
+      << "public:\n"
+      << "  " << className << "_ParseTables();\n"
+      << "};\n"
+      << "\n"
+      << className << "_ParseTables::" << className << "_ParseTables()\n"
+      << "  : ParseTables(false /*owning*/)\n"
+      << "{\n"
+      ;
+
+  // set all the integer-like variables
+  #define SET_VAR(var) \
+    out << "  " #var " = " << var << ";\n";
+  SET_VAR(numTerms);
+  SET_VAR(numNonterms);
+  SET_VAR(numStates);
+  SET_VAR(numProds);
+  SET_VAR(actionCols);
+  SET_VAR(actionRows);
+  SET_VAR(gotoCols);
+  SET_VAR(gotoRows);
+  SET_VAR(ambigTableSize);
+  out << "  startState = (StateId)" << (int)startState << ";\n";
+  SET_VAR(finalProductionIndex);
+  SET_VAR(bigProductionListSize);
+  SET_VAR(errorBitsRowSize);
+  SET_VAR(uniqueErrorRows);
+  #undef SET_VAR
+  out << "\n";
+
+  // action table, one row per state
+  emitTable2(out, actionTable, actionTableSize(), actionCols,
+             "ActionEntry", "actionTable");
+
+  // goto table, one row per state
+  emitTable2(out, gotoTable, gotoTableSize(), gotoCols,
+             "GotoEntry", "gotoTable");
+
+  // production info, arbitrarily 16 per row
+  emitTable2(out, prodInfo, numProds, 16, "ParseTables::ProdInfo", "prodInfo");
+
+  // state symbol map, arbitrarily 16 per row
+  emitTable2(out, stateSymbol, numStates, 16, "SymbolId", "stateSymbol");
+
+  // ambigTable
+  emitTable2(out, ambigTable, ambigTableSize, 16, "ActionEntry", "ambigTable");
+
+  // nonterminal order
+  emitTable2(out, nontermOrder, nontermOrderSize(), 16,
+             "NtIndex", "nontermOrder");
+
+  // errorBits
+  emitTable2(out, errorBits, uniqueErrorRows * errorBitsRowSize, errorBitsRowSize,
+             "ErrorBitsEntry", "errorBits");
+
+  emitOffsetTable(out, errorBitsPointers, errorBits, numStates,
+                  "ErrorBitsEntry*", "errorBitsPointers", "errorBits");
+
+  // actionIndexMap
+  emitTable2(out, actionIndexMap, numTerms, 16,
+             "TermIndex", "actionIndexMap");
+
+  // actionRowPointers
+  emitOffsetTable(out, actionRowPointers, actionTable, numStates,
+                  "ActionEntry*", "actionRowPointers", "actionTable");
+
+  // gotoIndexMap
+  emitTable2(out, gotoIndexMap, numNonterms, 16,
+             "NtIndex", "gotoIndexMap");
+
+  // gotoRowPointers
+  emitOffsetTable(out, gotoRowPointers, gotoTable, numStates,
+                  "GotoEntry*", "gotoRowPointers", "gotoTable");
+
+  if (ENABLE_CRS_COMPRESSION) {
+    emitTable2(out, firstWithTerminal, numTerms, 16,
+               "StateId", "firstWithTerminal");
+
+    emitTable2(out, firstWithNonterminal, numNonterms, 16,
+               "StateId", "firstWithNonterminal");
+
+    emitTable2(out, bigProductionList, bigProductionListSize, 16,
+               "ProdIndex", "bigProductionList");
+
+    emitOffsetTable(out, productionsForState, bigProductionList, numStates,
+                    "ProdIndex*", "productionsForState", "bigProductionList");
+                    
+    emitOffsetTable(out, ambigStateTable, ambigTable, numStates,
+                    "ActionEntry*", "ambigStateTable", "ambigTable");
+  }
+  else {
+    out << "  firstWithTerminal = NULL;\n"
+        << "  firstWithNonterminal = NULL;\n"
+        << "  bigProductionList = NULL;\n"
+        << "  productionsForState = NULL;\n"
+        << "  ambigStateTable = NULL;\n"
+        ;
+  }
+
+  out << "}\n"
+      << "\n"
+      << "\n"
+      << "ParseTables *" << className << "::" << funcName << "()\n"
+      << "{\n"
+      << "  return new " << className << "_ParseTables;\n"
+      << "}\n"
+      << "\n"
+      ;
+}
+
+
+// EOF

Added: vendor/elsa/current/elkhound/parsetables.h
===================================================================
--- vendor/elsa/current/elkhound/parsetables.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/parsetables.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,519 @@
+// parsetables.h            see license.txt for copyright and terms of use
+// ParseTables, a class to contain the tables need by the
+// LR/GLR parsing algorithm
+
+#ifndef PARSETABLES_H
+#define PARSETABLES_H
+
+#include "array.h"        // ArrayStack
+#include "glrconfig.h"    // compression options
+#include "str.h"          // string
+#include <iostream.h>     // ostream
+
+class Flatten;            // flatten.h
+class EmitCode;           // emitcode.h
+class Symbol;             // grammar.h
+class Bit2d;              // bit2d.h
+
+
+// integer id for an item-set DFA state; I'm using an 'enum' to
+// prevent any other integers from silently flowing into it
+enum StateId { STATE_INVALID=-1 };
+
+inline ostream& operator<< (ostream &os, StateId id)
+  { return os << (int)id; }
+
+
+// encodes an action in 'action' table; see 'actionTable'
+#if ENABLE_CRS_COMPRESSION
+  // high bits encoding
+  enum ActionEntryKind {
+    AE_MASK      = 0xC0,    // selection mask
+    AE_SHIFT     = 0x00,    // 00 = shift
+    AE_REDUCE    = 0x40,    // 01 = reduce
+    AE_AMBIGUOUS = 0x80,    // 10 = ambiguous
+    AE_ERROR     = 0xC0,    // 11 = error (if EEF is off)
+    AE_MAXINDEX  = 63       // maximum value of lower bits
+  };
+
+  // remaining 6 bits:
+  //
+  //   shift: desination state, encoded as an offset from the
+  //   first state that that terminal can reach
+  //
+  //   reduce: production, encoded as an index into a per-state
+  //   array of distinct production indices
+  //
+  //   ambiguous: for each state, have an array of ActionEntries.
+  //   ambiguous entries index into this array.  first indexed
+  //   entry is the count of how many actions follow
+  typedef unsigned char ActionEntry;
+  ActionEntry makeAE(ActionEntryKind k, int index);
+  #define errorActionEntry ((ActionEntry)AE_ERROR)
+#else
+  // each entry is one of:
+  //   +N+1, 0 <= N < numStates:         shift, and go to state N
+  //   -N-1, 0 <= N < numProds:          reduce using production N
+  //   numStates+N+1, 0 <= N < numAmbig: ambiguous, use ambigAction N
+  //   0:                                error
+  // (there is no 'accept', acceptance is handled outside this table)
+  typedef signed short ActionEntry;
+  #define errorActionEntry ((ActionEntry)0)
+#endif
+
+
+// encodes a destination state in 'gotoTable'
+#if ENABLE_CRS_COMPRESSION
+  // entry is an offset from the first state that can be reached
+  // by shifting the nonterminal
+  typedef unsigned char GotoEntry;
+#else
+  // entry is the to go to after shifting the nonterminal
+  typedef unsigned short GotoEntry;
+#endif
+#define errorGotoEntry ((GotoEntry)~0)
+
+
+// name a terminal using an index
+typedef unsigned char TermIndex;
+
+// name a nonterminal using an index
+typedef unsigned short NtIndex;
+
+// name a production using an index
+typedef unsigned short ProdIndex;
+
+// an addressed cell in the 'errorBits' table
+typedef unsigned char ErrorBitsEntry;
+
+
+// encodes either terminal index N (as N+1) or
+// nonterminal index N (as -N-1), or 0 for no-symbol
+typedef signed short SymbolId;
+inline bool symIsTerm(SymbolId id) { return id > 0; }
+inline int symAsTerm(SymbolId id) { return id-1; }
+inline bool symIsNonterm(SymbolId id) { return id < 0; }
+inline NtIndex symAsNonterm(SymbolId id) { return (NtIndex)(-(id+1)); }
+SymbolId encodeSymbolId(Symbol const *sym);       // gramanl.cc
+
+
+// assign, but check for truncation
+template <class DEST, class SRC>
+inline void checkAssign(DEST &d, SRC s)
+{
+  d = (DEST)s;
+  xassert(d == s);
+}
+
+
+// the parse tables are the traditional action/goto, plus the list
+// of ambiguous actions, plus any more auxilliary tables useful during
+// run-time parsing
+class ParseTables {
+private:    // types
+  // data about an intermediate state of parse table construction;
+  // once the table is finished, this data gets consolidated into the
+  // actual tables, and then thrown away
+  class TempData {
+  public:   // data
+    // nascent ambigTable
+    ArrayStack<ActionEntry> ambigTable;
+
+    // nascent bigProductionList
+    ArrayStack<ProdIndex> bigProductionList;
+    
+    // nascent productionsForState, except using integer offsets from
+    // start of 'bigProductionList' instead of direct pointers into it
+    ArrayStack<int> productionsForState;
+
+    // nascent versions of ambig tables, again with integer offsets
+    ArrayStack<int> ambigStateTable;
+
+  public:   // funcs
+    TempData(int numStates);
+    ~TempData();
+  };
+
+public:     // types
+  // per-production info
+  struct ProdInfo {
+    unsigned char rhsLen;                // # of RHS symbols
+    NtIndex lhsIndex;                    // 'ntIndex' of LHS
+  };
+
+protected:  // data
+  // when this is false, all of the below "(owner*)" annotations are
+  // actually "(serf)", i.e. this object does *not* own any of the
+  // tables (see emitConstructionCode())
+  bool owning;
+
+  // non-NULL during construction
+  TempData *temp;                        // (nullable owner)
+
+  // # terminals, nonterminals in grammar
+  int numTerms;
+  int numNonterms;
+
+  // # of parse states
+  int numStates;
+
+  // # of productions in the grammar
+  int numProds;
+
+  // action table, indexed by (state*actionCols + lookahead)
+  int actionCols;
+  ActionEntry *actionTable;              // (owner*)
+
+  // goto table, indexed by (state*gotoCols + nontermId)
+  int gotoCols;
+  GotoEntry *gotoTable;                  // (owner*)
+
+  // map production id to information about that production
+  ProdInfo *prodInfo;                    // (owner*)
+
+  // map a state id to the symbol (terminal or nonterminal) which is
+  // shifted to arrive at that state
+  SymbolId *stateSymbol;                 // (owner*)
+
+  // ambiguous actions: one big list, for allocation purposes; then
+  // the actions encode indices into this table; the first indexed
+  // entry gives the # of actions, and is followed by that many
+  // actions, each interpreted the same way ordinary 'actionTable'
+  // entries are
+  int ambigTableSize;
+  ActionEntry *ambigTable;               // (nullable owner*)
+
+  // total order on nonterminals for use in choosing which to
+  // reduce to in the RWL algorithm; index into this using a
+  // nonterminal index, and it yields the ordinal for that
+  // nonterminal (so these aren't really NtIndex's, but they're
+  // exactly as wide, so I use NtIndex anyway)
+  //
+  // The order is consistent with the requirement that if
+  //   A ->+ B
+  // then B will be earlier in the order (assuming acyclicity).
+  // That way, we'll do all reductions to B before any to A (for
+  // reductions spanning the same set of ground terminals), and
+  // therefore will merge all alternatives for B before reducing
+  // any of them to A.
+  NtIndex *nontermOrder;                 // (owner*)
+
+  // --------------------- table compression ----------------------
+
+  // table compression techniques taken from:
+  //   [DDH] Peter Dencker, Karl Dürre, and Johannes Heuft.
+  //   Optimization of Parser Tables for Portable Compilers.
+  //   In ACM TOPLAS, 6, 4 (1984) 546-572.
+  //   http://citeseer.nj.nec.com/context/27540/0 (not in database)
+  //   ~/doc/papers/p546-dencker.pdf (from ACM DL)
+
+  // Code Reduction Scheme (CRS):
+  //
+  // Part (a):  The states are numbered such that all states that
+  // are reached by transitions on a given symbol are contiguous.
+  // See gramanl.cc, GrammarAnalysis::renumberStates().  Then, we
+  // simply need a map from the symbol index to the first state
+  // that is reached along that symbol.
+  StateId *firstWithTerminal;            // (nullable owner*) termIndex -> state
+  StateId *firstWithNonterminal;         // (nullable owner*) ntIndex -> state
+  //
+  // Part (b):  The production indices that appear on a given row
+  // are collected together.  (This is called (c) by [DDH]; I don't
+  // have a counterpart to their (b).)
+  int bigProductionListSize;
+  ProdIndex *bigProductionList;          // (nullable owner*) array into which 'productionsForState' points
+  ProdIndex **productionsForState;       // (nullable owner to serf) state -> stateProdIndex -> prodIndex
+  //
+  // Part (c):  Pointers into 'ambigTable' are are collected together in
+  // per-state lists as well.
+  ActionEntry **ambigStateTable;         // (nullable owner) state -> (+ambigStateTableIndex -> ActionEntry*)
+
+  // Error Entry Factoring (EEF):
+  //
+  // Factor out all the error entries into their own bitmap.  Then
+  // regard error entries in the original tables as "insignificant".
+  //
+  // 'errorBits' is a map of where the error actions are in the action
+  // table.  It is indexed through 'errorBitsPointers':
+  //   byte = errorBitsPointers[stateId][lookahead >> 3];
+  //   if ((byte >> (lookahead & 7)) & 1) then ERROR
+  int errorBitsRowSize;                  // bytes per row
+  int uniqueErrorRows;                   // distinct rows
+  ErrorBitsEntry *errorBits;             // (nullable owner*)
+  ErrorBitsEntry **errorBitsPointers;    // (nullable owner ptr to serfs)
+
+  // Graph Coloring Scheme (GCS):
+  //
+  // Merge lines and columns that have identical significant entries.
+  // This is done as two-pass graph coloring.  They give a specific
+  // heuristic.
+  //
+  // this is a map to be applied to terminal indices before being
+  // used to access the compressed action table; it maps the terminal
+  // id (as reported by the lexer) to the proper action table column
+  TermIndex *actionIndexMap;             // (nullable owner*)
+  //
+  // this is a map from states to the beginning of the action table
+  // row that pertains to that state; it effectively factors the
+  // states into equivalence classes
+  int actionRows;                        // rows in actionTable[]
+  ActionEntry **actionRowPointers;       // (nullable owner ptr to serfs)
+  //
+  // index map for the goto table
+  NtIndex *gotoIndexMap;                 // (nullable owner*)
+  //
+  // row map for the goto table
+  int gotoRows;
+  GotoEntry **gotoRowPointers;           // (nullable owner ptr to serfs)
+
+public:     // data
+  // These are public because if they weren't, I'd just have a stupid
+  // getter/setter pattern that exposes them anyway.
+
+  // start state id
+  StateId startState;
+
+  // index of the production which will finish a parse; it's the
+  // final reduction executed
+  int finalProductionIndex;
+
+private:    // funcs
+  void alloc(int numTerms, int numNonterms, int numStates, int numProds,
+             StateId start, int finalProd);
+
+  // index tables
+  ActionEntry &actionEntry(StateId stateId, int termId)
+    { return actionTable[stateId*actionCols + termId]; }
+  int actionTableSize() const
+    { return actionRows * actionCols; }
+
+  GotoEntry &gotoEntry(StateId stateId, int nontermId)
+    { return gotoTable[stateId*gotoCols + nontermId]; }
+  int gotoTableSize() const
+    { return gotoRows * gotoCols; }
+
+  void appendAmbig(ArrayStack<ActionEntry> const &set);
+  bool compareAmbig(ArrayStack<ActionEntry> const &set, int startIndex);
+
+  void fillInErrorBits(bool setPointers);
+  int colorTheGraph(int *color, Bit2d &graph);
+
+protected:  // funcs
+  // the idea is that 'emitConstructionCode' will emit code that
+  // defines a subclass of 'ParseTables'; that's why so many of the
+  // data members are protected: the subclass can then access them
+  // directly, which is very convenient when trying to construct the
+  // tables from static data
+  ParseTables(bool owning);    // only legal when owning==false
+
+public:     // funcs
+  ParseTables(int numTerms, int numNonterms, int numStates, int numProds,
+              StateId start, int finalProd);
+  ~ParseTables();
+
+  // simple queries
+  int getNumTerms() const { return numTerms; }
+  int getNumNonterms() const { return numNonterms; }
+  int getNumStates() const { return numStates; }
+  int getNumProds() const { return numProds; }
+
+  // finish construction; do this before emitting code
+  void finishTables();
+
+  // write the tables out as C++ source that can be compiled into
+  // the program that will ultimately do the parsing
+  void emitConstructionCode(EmitCode &out, rostring className, rostring funcName);
+
+  // this does the same thing for ML, and is implemented in genml.cc
+  void emitMLConstructionCode(EmitCode &out, rostring className, rostring funcName);
+
+
+  // -------------------- table construction ------------------------
+  // CRS dest-state origin tables
+  void setFirstWithTerminal(int termId, StateId s) {
+    xassert((unsigned)termId < (unsigned)numTerms);
+    firstWithTerminal[termId] = s;
+  }
+  void setFirstWithNonterminal(int nontermId, StateId s) {
+    xassert((unsigned)nontermId < (unsigned)numNonterms);
+    firstWithNonterminal[nontermId] = s;
+  }
+
+  void setActionEntry(StateId stateId, int termId, ActionEntry act)
+    { actionEntry(stateId, termId) = act; }
+  void setGotoEntry(StateId stateId, int nontermId, GotoEntry got)
+    { gotoEntry(stateId, nontermId) = got; }
+
+  // encode actions
+  ActionEntry encodeShift(StateId destState, int shiftedTermId);
+  ActionEntry encodeReduce(int prodId, StateId inWhatState);
+  ActionEntry encodeAmbig(ArrayStack<ActionEntry> const &set,
+                          StateId inWhatState);
+  ActionEntry encodeError() const;
+  ActionEntry validateAction(int code) const;
+
+  // encode gotos
+  GotoEntry encodeGoto(StateId stateId, int shiftedNontermId) const;
+  GotoEntry encodeGotoError() const
+    { return errorGotoEntry; }
+  GotoEntry validateGoto(int code) const;
+
+  // misc
+  void setProdInfo(int prodId, int rhsLen, int ntIndex) {
+    checkAssign(prodInfo[prodId].rhsLen, rhsLen);
+    checkAssign(prodInfo[prodId].lhsIndex, ntIndex);
+  }
+  void setStateSymbol(StateId state, SymbolId sym) {
+    stateSymbol[state] = sym;
+  }
+  NtIndex *getWritableNontermOrder() {
+    // expose this directly, due to the way the algorithm that
+    // computes it is written
+    return nontermOrder;
+  }
+
+  // table compressors
+  void computeErrorBits();
+  void mergeActionColumns();
+  void mergeActionRows();
+  void mergeGotoColumns();
+  void mergeGotoRows();
+
+
+  // -------------------- table queries ---------------------------
+  // return true if the action is an error
+  bool actionEntryIsError(StateId stateId, int termId) {
+    #if ENABLE_EEF_COMPRESSION
+      // check with the error table
+      return ( errorBitsPointers[stateId][termId >> 3]
+                 >> (termId & 7) ) & 1;
+    #else
+      return isErrorAction(actionEntry(stateId, termId));
+    #endif
+  }
+
+  // query action table, without checking the error bitmap
+  ActionEntry getActionEntry_noError(StateId stateId, int termId) {
+    #if ENABLE_GCS_COMPRESSION
+      #if ENABLE_GCS_COLUMN_COMPRESSION
+        return actionRowPointers[stateId][actionIndexMap[termId]];
+      #else
+        return actionRowPointers[stateId][termId];
+      #endif
+    #else
+      return actionEntry(stateId, termId);
+    #endif
+  }
+
+  // query the action table, yielding an action that might be
+  // an error action
+  ActionEntry getActionEntry(StateId stateId, int termId) {
+    #if ENABLE_EEF_COMPRESSION
+      if (actionEntryIsError(stateId, termId)) {
+        return errorActionEntry;
+      }
+    #endif
+
+    return getActionEntry_noError(stateId, termId);
+  }
+
+  // decode actions
+  #if !ENABLE_CRS_COMPRESSION
+    bool isShiftAction(ActionEntry code) const
+      { return code > 0 && code <= numStates; }
+    static StateId decodeShift(ActionEntry code, int /*shiftedTerminal*/)
+      { return (StateId)(code-1); }
+    static bool isReduceAction(ActionEntry code)
+      { return code < 0; }
+    static int decodeReduce(ActionEntry code, StateId /*inState*/)
+      { return -(code+1); }
+    static bool isErrorAction(ActionEntry code)
+      { return code == 0; }
+
+    // ambigAction is only other choice; this yields a pointer to
+    // an array of actions, the first of which says how many actions
+    // there are
+    ActionEntry *decodeAmbigAction(ActionEntry code, StateId /*inState*/) const
+      { return ambigTable + (code-1-numStates); }
+
+  #else
+    static bool isShiftAction(ActionEntry code) {
+      return (code & AE_MASK) == AE_SHIFT;
+    }
+    StateId decodeShift(ActionEntry code, int shiftedTerminal) {
+      return (StateId)(firstWithTerminal[shiftedTerminal] + (code & AE_MAXINDEX));
+    }
+    static bool isReduceAction(ActionEntry code) {
+      return (code & AE_MASK) == AE_REDUCE;
+    }
+    int decodeReduce(ActionEntry code, StateId inState) {
+      return productionsForState[inState][code & AE_MAXINDEX];
+    }
+    static bool isErrorAction(ActionEntry code) {
+      return code == AE_ERROR;
+    }
+
+    ActionEntry *decodeAmbigAction(ActionEntry code, StateId inState) const {
+      return ambigStateTable[inState] + (code & AE_MAXINDEX);
+    }
+  #endif
+
+  // decode gotos
+  GotoEntry getGotoEntry(StateId stateId, int nontermId) {
+    #if ENABLE_GCS_COMPRESSION
+      #if ENABLE_GCS_COLUMN_COMPRESSION
+        return gotoRowPointers[stateId][gotoIndexMap[nontermId]];
+      #else
+        return gotoRowPointers[stateId][nontermId];
+      #endif
+    #else
+      return gotoEntry(stateId, nontermId);
+    #endif
+  }
+
+  bool isErrorGoto(GotoEntry code)
+    { return code == errorGotoEntry; }
+
+  StateId decodeGoto(GotoEntry code, int shiftedNonterminal) {
+    #if ENABLE_CRS_COMPRESSION
+      return (StateId)(firstWithNonterminal[shiftedNonterminal] + code);
+    #else
+      return (StateId)code;
+    #endif
+  }
+
+  // nonterminal order
+  int nontermOrderSize() const
+    { return numNonterms; }
+  NtIndex getNontermOrdinal(NtIndex idx) const
+    { return nontermOrder[idx]; }
+
+  // misc
+  ProdInfo const &getProdInfo(int prodIndex) const
+    { return prodInfo[prodIndex]; }
+  int getStateSymbol(StateId id) const
+    { return stateSymbol[id]; }
+
+  // query compression options based on which fields are not NULL; do
+  // *not* use the compile-time flags, because we're trying to detect
+  // mismatch between compiler flags used at different times
+  bool eef_enabled() const
+    { return !!errorBits; }
+  bool gcs_enabled() const
+    { return !!actionRowPointers; }
+  bool gcsc_enabled() const
+    { return !!actionIndexMap; }
+  bool crs_enabled() const
+    { return !!firstWithTerminal; }
+};
+
+
+// NOTE: At one point (before 7/27/03), I had the ability to read and
+// write parse tables to files, *not* using the C++ compiler to store
+// tables as static data.  I removed it because I wasn't using it, and
+// it was hindering table evolution.  But as the tables stabilize
+// again, if the need arises, one could go get (from CVS) the code
+// that did it and fix it up to work again.
+
+
+#endif // PARSETABLES_H

Added: vendor/elsa/current/elkhound/parsgen.txt
===================================================================
--- vendor/elsa/current/elkhound/parsgen.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/parsgen.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,43 @@
+
+tracing strings for gramanl and GLR parser:
+
+  parse:         details of the parsing actions
+  parse-tree:    the parse tree itself
+  parse-graph:   when set, print the parse graph to a .g file
+  grammar:       echoing the grammar
+  terminals:     list of terminals
+  nonterminals:	 list of nonterminals
+  derivable:     mechanics of the derivability relation computation
+  pred-table:    predictive parsing table
+  item-sets:     the LR parsing table (item sets)
+  progress:      poor-man's profiler (prints at each major phase)
+  profiling:     slightly more detailed profiling info
+  conflict:      SLR conflict printout
+  debug:         general temporary-printf kinds of things, meant to be removed shortly
+  conditions:    results of processing %condition directives
+  follow-sym:    computing Follow of symbol-of-interest
+  rewrite:       details of rewriteSingleNTAsTerminals
+  ambiguities:   print ambiguities in present parse
+  lexer1:        results of L1 analysis
+  lexer2:        results of L2 analysis
+  ast:           print AST of grammar file
+  lex:           print each token of grammar file
+  sem-fns:       print names of semantic functions as they're called
+  tree-merge:    print when we don't merge trees because of attr mismatch
+  disamb:        disambiguation mechanisms
+  compounds:     print declarations of compounds
+  typeCheck:     print something just before typechecking each toplevel form
+  refct:         environment reference count ops
+  cil-tree:      print the Cil tree
+  eh:            print when exceptions are thrown
+  alloc-stats:   print stats about allocated nodes, total mem usage
+  cil-bb:        print the Cil basic blocks
+  print-tree-before:   parse tree print before type checking
+  type-ids:      print the type ids when types are printed
+  initializer:   print details of declaration initializer processing  
+  closure:       details of item-set closure algorithm
+  lrtable:       print the LR item sets
+  nonkernel:     print nonkernel items when printing LR item sets
+
+
+

Added: vendor/elsa/current/elkhound/parsstub.cc
===================================================================
--- vendor/elsa/current/elkhound/parsstub.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/parsstub.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// parsstub.cc            see license.txt for copyright and terms of use
+// stub implementations of code that is expected to be
+// generated and emitted, but sometimes I want to not have
+
+#include "parssppt.h"     // decls
+
+NonterminalInfo nontermMap[] = {};
+
+int nontermMapLength = 0;

Added: vendor/elsa/current/elkhound/perf
===================================================================
--- vendor/elsa/current/elkhound/perf	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/perf	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,192 @@
+#!/usr/bin/perl -w
+# perf: run performance tests on Elkhound
+
+use strict 'subs';
+
+# number of iterations to do, and take the median
+$iters = 1;
+
+# for the C test, whether to run bison
+$runBison = 1;
+
+# which tests to run
+ at tests = ("mozilla", "c");
+
+
+# process arguments
+while (@ARGV) {
+  my $arg = $ARGV[0];
+  if ($arg eq "-iters") {
+    $iters = $ARGV[1];
+    shift @ARGV;
+  }
+  elsif ($arg eq "-tests") {
+    @tests = split(',', $ARGV[1]);
+    shift @ARGV;
+  }
+  elsif ($arg eq "-nobison") {
+    $runBison = 0;
+  }
+  elsif ($arg eq "-help") {
+    usage();
+    exit(0);
+  }
+  else {
+    print STDERR ("unknown argument: $arg\n");
+    usage();
+    exit(2);
+  }
+  shift @ARGV;
+}
+
+sub usage {
+  print(<<"EOF");
+usage: $0 [options]
+
+This script runs the Elkhound performance tests.
+
+options:
+  -iters <n>     : run each test n times, taking medians
+  -nobison       : do not run Bison for the C test
+  -tests <list>  : comma-separated list of test to run, selected from:
+                     @tests
+  -help          : print this message
+EOF
+}
+
+
+# run the tests
+for my $t (@tests) {
+  if ($t eq "mozilla") {
+    testMozilla();
+  }
+  elsif ($t eq "c") {
+    testC();
+  }
+  else {
+    print STDERR ("unknown test: $t\n");
+    exit(2);
+  }
+}
+
+
+
+# ----------------------- particular tests ----------------------
+# mozilla tests
+sub testMozilla {
+  # make sure the files are there
+  run("make cc.in/big >/dev/null");
+
+  print("C++ parser, mozilla input:\n");
+
+  my $format = "  %-30s %6s %6s %6s\n";
+  printf($format, "module", "lines", "parse", "tcheck");
+  printf($format, "-" x 30, "-" x 6, "-" x 6, "-" x 6);
+
+  my @modules = (
+    'nsUnicodeToTeXCMRt1.i',
+    'nsAtomTable.i',
+    'nsCLiveconnectFactory.i',
+    'nsSOAPPropertyBag.i',
+    'nsMsgServiceProvider.i',
+    'nsHTMLEditRules.i'
+  );
+  foreach my $fn (@modules) {
+    my $lines = linesInFile("cc.in/big/$fn");
+
+    my @parse = ();
+    my @tcheck = ();
+
+    for (my $run=0; $run < $iters; $run++) {
+      my @output = run("cc/ccparse cc.in/big/$fn");
+      #print(@output);
+      for $line (@output) {
+        if (($tmp) = ($line =~ m/done parsing \((\d+) ms/)) {
+          push @parse, $tmp;
+        }
+        if (($tmp) = ($line =~ m/done type checking \((\d+) ms/)) {
+          push @tcheck, $tmp;
+        }
+      }
+    }
+
+    printf($format, $fn, $lines, median(@parse), median(@tcheck));
+  }
+}
+
+
+# C parser performance
+sub testC {
+  print("C parser, c.in/c.in4d input:\n");
+
+  # bccgr, the bison-based C parser (can't handle typedefs)
+  my @parse = ();
+  if ($runBison) {
+    for (my $run=0; $run < $iters; $run++) {
+      my @output = run("c/bcparse c.in/c.in4d");
+      for $line (@output) {
+        if (($tmp) = ($line =~ m/finished parse \((\d+) ms/)) {
+          push @parse, $tmp;
+        }
+      }
+    }
+    printf("  bison: %d  (%s)\n", median(@parse), join(',', @parse));
+  }
+
+  # cparse, the Elkhound-based C parser, with typedef support disabled
+  # to allow completely-deterministic parsing
+  @parse = ();
+  for (my $run=0; $run < $iters; $run++) {
+    my @output = run("c/cparse -tr trivialActions,stopAfterParse,yieldVariableName c.in/c.in4d");
+    for $line (@output) {
+      if (($tmp) = ($line =~ m/done parsing \((\d+) ms/)) {
+        push @parse, $tmp;
+      }
+    }
+  }
+  printf("  Elkhound: %d  (%s)\n", median(@parse),  join(',', @parse));
+}
+
+
+# ---------------------- utilities --------------------
+sub run {
+  my ($cmd) = @_;
+  @ret = `$cmd`;
+  my $code = $?;
+  if ($code != 0) {
+    print STDERR ("failed: $cmd\n");
+    exit(2);
+  }
+  return @ret;
+}
+
+
+#print("median: ", median(1,2,35,2,1), "\n");
+#print("median: ", median(5,4,3,2,1), "\n");
+#exit(0);
+
+sub median {
+  my (@vals) = @_;
+
+  # sort in numerically ascending order
+  my @sorted = sort {$a <=> $b} @vals;
+  #print("sorted: ", join(',', @sorted), "\n");
+  my $len = @vals;
+  #print("len: $len\n");
+
+  my $index = int(($len-1) / 2);
+  #print("index: $index\n");
+  return $sorted[$index];
+}
+
+
+sub linesInFile {
+  my ($fname) = @_;
+  open(IN, "<$fname") or die("can't open $fname: $!\n");
+  my $ret = 0;
+  while (<IN>) {
+    $ret++;
+  }
+  close(IN) or die;
+  return $ret;
+}


Property changes on: vendor/elsa/current/elkhound/perf
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/perftest/history
===================================================================
--- vendor/elsa/current/elkhound/perftest/history	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/perftest/history	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,496 @@
+------------ table generation ------------
+
+2002-03-22 22:43 -0700    scott
+got treeadd-merged to parse
+  modified: .gdbinit (1.84)
+  modified: cc_env.cc (1.57)
+  modified: tcheck.cc (1.52)
+  added:    vcgen/treeadd-merged.c (1.1)
+
+2002-03-23 00:57 -0700    scott
+fixed the "cannot reduce" errors in the sample inputs
+  modified: cc.gr (1.124)
+  modified: gramanl.cc (1.51)
+  modified: gramanl.h (1.24)
+
+2002-03-24 01:15 -0700    scott
+bison-compatible output now generates output that causes bison to
+agree with me, for cc.gr, on:
+  - unreachable nonterminals
+  - number of S/R and R/R conflicts
+  - number of states (except Bison is always 3 higher)
+  modified: .cvsignore (1.55)
+  modified: cc.gr (1.125)
+  modified: gramanl.cc (1.54)
+  modified: gramanl.h (1.26)
+  modified: grammar.cc (1.54)
+  modified: grammar.h (1.57)
+
+2002-03-24 01:58 -0700    scott
+modified dottedproduction comparison, resulting in speed improvement
+  modified: .gdbinit (1.85)
+  modified: Makefile.in (1.60)
+  modified: gramanl.cc (1.55)
+  modified: gramanl.h (1.27)
+
+2002-03-24 02:10 -0700    scott
+small improvement by adjusting the way moveDotNoClosure accesses items
+  modified: gramanl.cc (1.56)
+
+2002-03-24 02:18 -0700    scott
+small optimization of symbolAfterDot()
+  modified: gramanl.cc (1.57)
+  modified: gramanl.h (1.28)
+
+2002-03-24 02:41 -0700    scott
+substantial improvement by moving from quadratic to linear closure alg.
+  modified: .gdbinit (1.86)
+  modified: gramanl.cc (1.58)
+  modified: gramanl.h (1.29)
+
+2002-03-24 03:11 -0700    scott
+repaired a bug introduced in the last commit; performance is getting
+better
+  modified: .cvsignore (1.56)
+  modified: Makefile.in (1.61)
+  modified: gramanl.cc (1.59)
+  modified: gramanl.h (1.30)
+
+2002-03-24 05:21 -0700    scott
+coded an implementation of itemset closure which uses hashtables, but
+its performance isn't much better, so I've left it off by default with
+a #define (HASHCLOSURE) to switch to it
+  modified: gramanl.cc (1.60)
+  modified: gramanl.h (1.31)
+
+2002-03-24 20:57 -0700    scott
+implemented an outer hashtable, significant performance improvement
+  modified: Makefile.in (1.62)
+  modified: gramanl.cc (1.61)
+  modified: gramanl.h (1.32)
+  modified: grammar.cc (1.55)
+  modified: grammar.h (1.58)
+
+2002-03-24 21:44 -0700    scott
+abstracted TerminalSet from DottedProduction::lookahead
+  modified: gramanl.cc (1.62)
+  modified: gramanl.h (1.33)
+  modified: grammar.cc (1.56)
+  modified: grammar.h (1.59)
+
+2002-03-25 00:02 -0700    scott
+rewrote analysis algorithms to use TerminalSet
+  modified: .gdbinit (1.87)
+  modified: Makefile.in (1.63)
+  modified: gramanl.cc (1.63)
+  modified: gramanl.h (1.34)
+  modified: grammar.cc (1.57)
+  modified: grammar.h (1.60)
+
+2002-03-25 00:20 -0700    scott
+tweaks
+  modified: Makefile.in (1.64)
+  modified: gramanl.cc (1.64)
+
+2002-03-25 03:12 -0700    scott
+separated DottedProduction into DP and LRItem, a fairly substantial
+overhaul of the GrammarAnalysis module; resulted in significant
+performance improvement by itself, probably due to less overhead
+of speculatively creating LRItems
+  modified: .cvsignore (1.57)
+  modified: .gdbinit (1.88)
+  modified: Makefile.in (1.65)
+  modified: cexp3.gr (1.12)
+  modified: cexp3mrg.cc (1.5)
+  modified: gramanl.cc (1.65)
+  modified: gramanl.h (1.35)
+  modified: regrtest (1.23)
+
+2002-03-25 03:46 -0700    scott
+delayed construction of LRItems in singleItemClosure; small gain
+  modified: gramanl.cc (1.66)
+  modified: gramanl.h (1.36)
+
+2002-03-25 04:37 -0700    scott
+small tweak to allocation in singleItemClosure, 10% improvement
+  modified: Makefile.in (1.66)
+  modified: aenv.cc (1.34)
+  modified: gramanl.cc (1.67)
+  modified: grammar.cc (1.58)
+  modified: grammar.h (1.61)
+
+2002-03-26 02:42 -0700    scott
+some small tweaks before a major planned change
+  modified: .gdbinit (1.89)
+  modified: Makefile.in (1.67)
+  modified: gramanl.cc (1.68)
+
+2002-03-26 03:57 -0700    scott
+implemented delayed allocation of new states; cut analyis time in half
+  modified: .gdbinit (1.90)
+  modified: Makefile.in (1.68)
+  modified: gramanl.cc (1.69)
+  modified: gramanl.h (1.37)
+  modified: grammar.h (1.62)
+
+2002-03-26 04:03 -0700    scott
+removed the defunct list-based implementations of my inner loops
+  modified: gramanl.cc (1.70)
+  modified: gramanl.h (1.38)
+
+2002-03-26 04:05 -0700    scott
+bugfixes to the EXTRA_CHECKS sections
+  modified: Makefile.in (1.69)
+  modified: gramanl.cc (1.71)
+
+2002-03-26 05:12 -0700    scott
+removed allocation due to changedItem in inner loop
+  modified: Makefile.in (1.70)
+  modified: gramanl.cc (1.72)
+  modified: gramanl.h (1.39)
+
+2002-03-26 05:21 -0700    scott
+replaced 'getAllItems' with explicit kernel/nonkernel iteration
+in constructLRItemSets
+  modified: gramanl.cc (1.73)
+
+2002-03-26 05:50 -0700    scott
+added code to count the # of malloc calls in some code
+switched to array for 'pendingList' in constructLRItemSets
+  modified: gramanl.cc (1.74)
+
+2002-03-26 06:13 -0700    scott
+removed all unauthorized mallocs from constructLRItemSets
+  modified: .gdbinit (1.91)
+  modified: gramanl.cc (1.75)
+
+2002-03-26 06:32 -0700    scott
+a little NDEBUG tweaking
+  modified: Makefile.in (1.71)
+  modified: gramanl.cc (1.76)
+  modified: grampar.cc (1.53)
+
+2002-03-26 06:49 -0700    scott
+switched to ArrayStack
+  modified: gramanl.cc (1.77)
+
+2002-03-26 06:56 -0700    scott
+switched to key-type-safe hashes everywhere
+  modified: gramanl.cc (1.78)
+  modified: gramanl.h (1.40)
+
+2002-03-26 07:27 -0700    scott
+switched to OwnerKHashArray
+  modified: gramanl.cc (1.79)
+
+2002-03-26 07:37 -0700    scott
+further refined, abstracted the OwnerKHashArray interface
+  modified: gramanl.cc (1.80)
+  modified: gramanl.h (1.41)
+
+2002-03-26 07:50 -0700    scott
+pinned down allocation in itemSetClosure
+  modified: gramanl.cc (1.81)
+  modified: gramanl.h (1.42)
+
+2002-03-26 08:14 -0700    scott
+moved to precomputed dprod firsts
+  modified: .gdbinit (1.92)
+  modified: gramanl.cc (1.82)
+  modified: gramanl.h (1.43)
+  modified: grammar.h (1.63)
+
+2002-03-26 08:27 -0700    scott
+committing a version which exposes a compiler bug
+  modified: .gdbinit (1.93)
+  modified: Makefile.in (1.72)
+  modified: gramanl.cc (1.83)
+
+2002-03-26 08:58 -0700    scott
+replaced one hashtable with a backpointer; regrtest goes through if
+I remove '-tr conflict' from gramanl command line; I think I have a
+memory safety violation!
+  modified: .gdbinit (1.94)
+  modified: Makefile.in (1.73)
+  modified: gramanl.cc (1.84)
+  modified: gramanl.h (1.44)
+
+2002-03-26 11:27 -0700    scott
+found my evil hiesenbug, committing before removing instrumentation
+aparatus
+  modified: .gdbinit (1.95)
+  modified: Makefile.in (1.74)
+  modified: gramanl.cc (1.85)
+
+2002-03-26 11:38 -0700    scott
+final fixed code from the evil bug.  instrumentation stripped, allocation
+accounted for
+  modified: gramanl.cc (1.86)
+
+--------------- run-time parsing --------------
+
+2002-03-27 05:33 -0700    scott
+implemented a driver to parse C programs with the bison grammar of cc.gr
+  modified: .cvsignore (1.58)
+  modified: .gdbinit (1.96)
+  modified: Makefile.in (1.75)
+  added:    bccgr.cc (1.1)
+  added:    bccgr.h (1.1)
+  modified: grammar.cc (1.59)
+  [59000]
+  final time for 2002-03-27_05:34_-0700: 58879
+
+2002-03-27 05:40 -0700    scott
+added better error output (line/col info)
+  modified: bccgr.cc (1.2)
+  [59000]
+  final time for 2002-03-27_05:41_-0700: 60523
+
+2002-03-27 06:21 -0700    scott
+have things pretty well setup for bison comparisons
+  modified: .gdbinit (1.97)
+  added:    c.in4b (1.1)
+  added:    c.in4c (1.1)
+  added:    c.in4d (1.1)
+  modified: glr.cc (1.51)
+  modified: parssppt.cc (1.16)
+  modified: useract.cc (1.2)
+  modified: useract.h (1.11)
+  [59000]
+  final time for 2002-03-27_06:22_-0700: 54413
+
+2002-03-28 00:06 -0700    scott
+factor of 2 by avoiding constructing debug strings
+  modified: Makefile.in (1.76)
+  modified: glr.cc (1.52)
+  modified: glr.h (1.34)
+  [54409]
+  final time for 2002-03-28_00:07_-0700: 11748
+
+2002-03-28 06:28 -0700    scott
+implemented action/goto parse table generation; still need to switch
+the GLR parser over to using it
+  modified: .gdbinit (1.98)
+  modified: Makefile.in (1.77)
+  modified: asu419.gr (1.2)
+  added:    asu419.in (1.1)
+  modified: gramanl.cc (1.87)
+  modified: gramanl.h (1.45)
+  modified: grammar.h (1.64)
+  [11749]
+  final time for 2002-03-28_06:29_-0700: 11723
+
+2002-03-28 06:54 -0700    scott
+added code to simply compare my existing actions to the action/goto tables
+  modified: glr.cc (1.53)
+  [?]
+  final time for 2002-03-28_06:55_-0700: 12456
+
+2002-03-28 08:10 -0700    scott
+switched GLR to use action/goto; total opt. over some previous numbers
+is around 5x
+  modified: Makefile.in (1.78)
+  modified: cc_type.cc (1.26)
+  modified: glr.cc (1.54)
+  modified: glr.h (1.35)
+  modified: gramanl.cc (1.88)
+  modified: gramanl.h (1.46)
+  [?]
+  final time for 2002-03-28_08:11_-0700: 10691
+
+2002-03-29 11:37 -0700    scott
+rehabilitated cexp3b, fixed forgotten stateSymbol table
+  modified: .cvsignore (1.59)
+  modified: .gdbinit (1.99)
+  modified: Makefile.in (1.79)
+  modified: cexp3.gr (1.13)
+  modified: cexp3ast.ast (1.4)
+  modified: cexp3mrg.cc (1.6)
+  modified: glr.cc (1.55)
+  modified: gramanl.cc (1.89)
+  modified: gramanl.h (1.47)
+  modified: regrtest (1.24)
+  final time for 2002-03-29_11:38_-0700: 10537
+
+2002-03-29 11:41 -0700    scott
+cleaned up a few loose TODO ends
+  modified: gramanl.cc (1.90)
+  [?]
+  final time for 2002-03-29_11:42_-0700: 10538
+
+2002-04-05 22:57 -0700    scott
+documentation tweaks
+  modified: glr.cc (1.56)
+  [?]
+  final time for 2002-04-05_22:58_-0700: 10556
+
+2002-04-14 03:37 -0700    scott
+few tweaks; committing before switching to parsgen work
+  modified: regrtest (1.25)
+  [10338]
+  final time for 2002-04-14_03:38_-0700: 10317
+
+2002-04-14 04:05 -0700    scott
+migrated pendingShifts to ObjArrayStack
+  modified: glr.cc (1.57)
+  modified: glr.h (1.36)
+  [11204]
+  final time for 2002-04-14_04:06_-0700: 10247
+
+2002-04-14 04:35 -0700    scott
+activeParsers, parserWorklist -> ArrayStack
+  modified: glr.cc (1.58)
+  modified: glr.h (1.37)
+  [10688]
+  final time for 2002-04-14_04:36_-0700: 8419
+
+2002-04-14 04:42 -0700    scott
+PathCollectionState::paths -> ObjArrayStack
+  modified: glr.cc (1.59)
+  modified: glr.h (1.38)
+  [8419]
+  final time for 2002-04-14_04:43_-0700: 7977
+
+2002-04-14 05:11 -0700    scott
+pulled allocation of PathCollectionState out of all loops
+  modified: .gdbinit (1.103)
+  modified: glr.cc (1.60)
+  modified: glr.h (1.39)
+  modified: gramanl.h (1.48)
+  [8004]
+  final time for 2002-04-14_05:12_-0700: 6239
+
+2002-04-14 05:38 -0700    scott
+eliminated allocation of ReductionPath objects (not nearly as much
+improvement as I expected); also, noticed that the analysis of callfind
+is yielding lots of chatter from Simplify, and don't know how long that's
+been going on..
+  modified: glr.cc (1.61)
+  modified: glr.h (1.40)
+  [6214]
+  final time for 2002-04-14_05:39_-0700: 5808
+
+2002-04-14 05:49 -0700    scott
+switched to pushAlt, popAlt for PathCollectionState::paths
+  modified: glr.cc (1.62)
+  modified: glr.h (1.41)
+  [5826]
+  final time for 2002-04-14_05:50_-0700: 5832
+
+2002-04-14 05:56 -0700    scott
+eliminated allocation of PendingShift
+  modified: glr.cc (1.63)
+  modified: glr.h (1.42)
+  [5940]
+  final time for 2002-04-14_05:57_-0700: 5786
+
+2002-04-14 06:15 -0700    scott
+removed allocation of 'toPass' in collectReductionPaths
+  modified: glr.cc (1.64)
+  modified: glr.h (1.43)
+  modified: gramanl.cc (1.92)
+  modified: useract.cc (1.3)
+  modified: useract.h (1.12)
+  [6222]
+  final time for 2002-04-14_06:16_-0700: 5195
+
+2002-04-14 06:17 -0700    scott
+small bugfix: popAlt really wants deinit
+  modified: glr.cc (1.65)
+  [5216]
+  final time for 2002-04-14_06:18_-0700: 5201
+
+2002-04-14 06:51 -0700    scott
+I implemented a parser state index, and it actually made things slower!
+so I'm leaving it as a design decision, defaulting to off
+  modified: glr.cc (1.66)
+  modified: glr.h (1.44)
+  [5251]
+  final time for 2002-04-14_06:52_-0700: 5273
+
+2002-04-15 07:06 -0700    scott
+switched to an object pool for stack nodes.. no improvement in performance
+  modified: glr.cc (1.67)
+  modified: glr.h (1.45)
+  [5227]
+  final time for 2002-04-15_07:07_-0700: 4660
+
+2002-04-18 08:44 -0700    scott
+small tweaks to debugging output
+  modified: .gdbinit (1.104)
+  modified: glr.cc (1.68)
+  modified: gramanl.cc (1.93)
+  modified: grammar.cc (1.60)
+  [4698]
+  final time for 2002-04-18_08:45_-0700: 4779
+
+2002-04-18 11:30 -0700    scott
+added a mini-LR for the deterministic language portions, cut
+parsing time in half!
+  modified: .gdbinit (1.105)
+  modified: glr.cc (1.69)
+  modified: glr.h (1.46)
+  [4972] (but lots of "got here" output)
+  final time for 2002-04-18_11:31_-0700: 3038
+
+2002-04-18 12:18 -0700    scott
+embedded the first sibling link, got *another* factor of 2!
+  modified: glr.cc (1.70)
+  modified: glr.h (1.47)
+  [4882]
+  final time for 2002-04-18_12:19_-0700: 1064
+
+2002-04-18 12:54 -0700    scott
+created option to disable passing of SourceLocation information
+in the parser, which leads to maybe a 10% improvement in performance
+  modified: Makefile.in (1.81)
+  modified: glr.cc (1.71)
+  modified: glr.h (1.48)
+  added:    glrconfig.h (1.1)
+  modified: gramanl.cc (1.94)
+  modified: gramanl.h (1.49)
+  modified: useract.cc (1.4)
+  modified: useract.h (1.13)
+  [1092]
+  final time for 2002-04-18_12:55_-0700: 1041
+
+2002-04-18 12:59 -0700    scott
+dropped tokenColumn and stackNodeId, small improvement
+  modified: glr.cc (1.72)
+  modified: glr.h (1.49)
+  [?]
+  final time for 2002-04-18_13:00_-0700: 1057
+
+2002-04-18 14:50 -0700    scott
+more inlining and performance tuning
+  modified: Makefile.in (1.82)
+  modified: bccgr.cc (1.3)
+  modified: glr.cc (1.73)
+  modified: glr.h (1.50)
+  modified: rcptr.h (1.2)
+  [915]
+  final time for 2002-04-18_14:51_-0700: 515
+
+2002-04-18 15:23 -0700    scott
+tuning, inlining, branch prediction: I am at 1.07x --- simply amazing!
+  modified: Makefile.in (1.83)
+  modified: glr.cc (1.74)
+  [515]
+  final time for 2002-04-18_15:24_-0700: 427
+
+2002-04-18 16:00 -0700    scott
+reordered decode of reductions vs shifts in mini-LR because reductions
+are more common
+  modified: Makefile.in (1.84)
+  modified: glr.cc (1.75)
+  [316]
+  final time for 2002-04-18_16:01_-0700: 296
+
+2002-04-18 16:21 -0700    scott
+fixed YYDEBUG problem; eliminated an assignment in inner loop
+  modified: Makefile.in (1.85)
+  modified: bccgr.cc (1.4)
+  modified: glr.cc (1.76)
+  [295]
+  final time for 2002-04-18_16:22_-0700: 292
+

Added: vendor/elsa/current/elkhound/perftest/test-all
===================================================================
--- vendor/elsa/current/elkhound/perftest/test-all	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/perftest/test-all	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+#!/bin/sh
+# run test-ver on every date on stdin
+
+while read; do
+  ./test-ver "$REPLY" | tee -a results
+done


Property changes on: vendor/elsa/current/elkhound/perftest/test-all
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/perftest/test-ver
===================================================================
--- vendor/elsa/current/elkhound/perftest/test-ver	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/perftest/test-ver	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,169 @@
+#!/bin/sh
+# pull a version from CVS and test its performance
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 cvs-date"
+  exit 0
+fi
+cvsDate="$1"
+directory=`echo "$cvsDate" | sed 's/ /_/g'`
+
+CCFLAGS="-O2 -DNDEBUG -D__LINUX__ -D__UNIX__"
+
+# stop on failure
+set -e
+
+# -------------- checkout --------------
+echo "will work in $directory"
+if [ -d "$directory" ]; then
+  echo "things already checked out, building.."
+  cd "$directory"
+else
+  echo "checking things out of CVS..."
+  mkdir "$directory"
+  cd "$directory"
+  touch RUNNING
+
+  echo "checking things out"
+  cvs export -D "$cvsDate" smbase >checkout.log
+  cvs export -D "$cvsDate" ast >>checkout.log
+  cvs export -D "$cvsDate" parsgen >>checkout.log
+fi
+
+# ------------- build smbase ------------
+echo "moving into smbase.."
+cd smbase
+
+if echo "$directory" | egrep '2002-03-28_06:29_-0700|2002-03-28_06:55_-0700|2002-03-28_08:11_-0700|2002-03-29_11:38_-0700|2002-03-29_11:42_-0700|2002-04-05_22:58_-0700' >/dev/null; then
+  echo "array.h needs to be up-to-date"
+  patch -R <<EOF
+--- array.h     Sat Apr 20 23:13:34 2002
++++ -   Sun Apr 21 02:19:51 2002
+@@ -143,14 +143,10 @@
+     {}
+   ~ArrayStack();
+
+-  void push(T const &val)
++  void push(T &val)
+     { setIndexDoubler(len++, val); }
+   T pop()
+     { return operator[](--len); }
+-  T const &top() const
+-    { return operator[](len-1); }
+-  T &top()
+-    { return operator[](len-1); }
+
+   int length() const
+     { return len; }
+@@ -158,9 +154,6 @@
+     { return len==0; }
+   bool isNotEmpty() const
+     { return !isEmpty(); }
+-
+-  void popMany(int ct)
+-    { len -= ct; xassert(len >= 0); }
+ };
+
+ template <class T>
+EOF
+fi
+
+if [ "$directory" = "2002-04-18_12:55_-0700" ]; then
+  echo "xassert.h needs to be up-to-date"
+  patch -R <<EOF
+--- xassert.h   Sat Apr 20 23:28:14 2002
++++ -   Sun Apr 21 02:21:38 2002
+@@ -19,9 +19,9 @@
+
+ // here's a version which will turn off with ordinary NDEBUG
+ #if !defined(NDEBUG)
+-  #define xassertdb(cond) xassert(cond)
++  #define xassert_debug(cond) xassert(cond)
+ #else
+-  #define xassertdb(cond) ((void)0)
++  #define xassert_debug(cond) ((void)0)
+ #endif
+
+ // call when state is known to be bad; will *not* return (ideal
+EOF
+# '  (fix for emacs syntax highlighting)
+fi
+
+echo "building smbase.."
+make ccflags="$CCFLAGS" >make.out 2>&1
+cd ..
+
+
+# ------------------- build ast ---------------------
+echo "building ast.."
+(cd ast; make SMBASE="../smbase" >make.out 2>&1)
+  
+
+# ------------------ build parsgen -----------------
+echo "building parsgen.."
+cd parsgen
+./configure --nocaml --setupMakefile
+
+if [ "$directory" = "2002-04-18_08:45_-0700" ]; then
+  echo "updating glr.cc to remove got-here message"
+  patch <<EOF
+--- -   Sun Apr 21 02:42:05 2002
++++ glr.cc      Sun Apr 21 00:30:29 2002
+@@ -1092,7 +1092,7 @@
+     // added link
+
+     // TODO: I think this code path is unusual; confirm by measurement
+-    cout << "got here\n";
++    //cout << "got here\n";
+
+     // for each 'finished' parser (i.e. those not still on
+     // the worklist)
+EOF
+fi
+
+make SMBASE="../smbase" AST="../ast" ccflags="$CCFLAGS" ccgr >make.out 2>&1
+
+
+# ---------------- performance testing --------------
+for n in 1 2 3 4 5; do
+  echo "running test $n.."
+  (time ./ccgr -tr trivialActions,stopAfterParse cc.bin ../../../c.in4d) 2>&1 \
+    | tee test.out
+    
+  parseStart=`grep 'parsing\.\.\.' test.out | awk '{ print $3 }' | sed 's/ms://'`
+  parseDone=`grep 'done parsing' test.out | awk '{ print $3 }' | sed 's/ms://'`
+  realTime=`grep '^real' test.out | awk '{ print $2 }' | sed 's/s//'`
+  
+  if [ x$parseDone == x ]; then
+    # use realTime as an estimate of parsing-done time
+    mins=`echo $realTime | sed 's/m.*//'`
+    msecsPart=`echo $realTime | sed 's/.*m//' | sed 's/\.//'`
+    msecs=$[ $msecsPart + $mins * 60000 - $parseStart]
+  else
+    # use parseDone
+    msecs=$[ $parseDone - $parseStart ]
+  fi
+
+  echo "msecs: $msecs"
+
+  # make a list
+  allTimes="$allTimes $msecs"
+
+  # if the time is really big, don't bother with the iterations
+  if [ $msecs -gt 20000 ]; then
+    echo "aborting tests because that's more than 20s"
+    echo "final time for $directory: $msecs"
+    exit 0
+  fi
+done
+
+# compute median of allTimes: sort, take 3rd one
+echo "allTimes: $allTimes"
+median=`echo $allTimes | fmt -1 | sort | head -3 | tail -1`
+echo "final time for $directory: $median"
+
+cd ..
+if [ -f RUNNING ]; then
+  rm RUNNING
+fi
+touch SUCCESS


Property changes on: vendor/elsa/current/elkhound/perftest/test-ver
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/ptreeact.cc
===================================================================
--- vendor/elsa/current/elkhound/ptreeact.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ptreeact.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,105 @@
+// ptreeact.cc            see license.txt for copyright and terms of use
+// code for ptreeact.h
+
+#include "ptreeact.h"        // this module
+#include "ptreenode.h"       // PTreeNode
+#include "parsetables.h"     // ParseTables
+#include "trace.h"           // trace
+
+
+// ------------------- ParseTreeLexer -------------------
+ParseTreeLexer::ParseTreeLexer(LexerInterface *u, UserActions *a)
+  : underlying(u),
+    underToken(u->getTokenFunc()),
+    actions(a)
+{
+  // the underlying lexer is already primed
+  copyFields();
+}
+
+STATICDEF void ParseTreeLexer::nextToken(LexerInterface *lex)
+{
+  ParseTreeLexer *ths = static_cast<ParseTreeLexer*>(lex);
+
+  // call underlying token function
+  ths->underToken(ths->underlying);
+
+  // grab its fields
+  ths->copyFields();
+}
+
+void ParseTreeLexer::copyFields()
+{
+  type = underlying->type;
+  loc = underlying->loc;
+
+  // leak underlying's 'sval'.. we'll just assume it doesn't matter
+
+  // my sval is always a newly-allocated PTreeNode, with no children,
+  // and named according to the name of the token yielded
+  PTreeNode *ret = new PTreeNode(actions->terminalName(type));
+  sval = (SemanticValue)ret;
+}
+
+
+string ParseTreeLexer::tokenDesc() const
+{
+  return underlying->tokenDesc();
+}
+
+string ParseTreeLexer::tokenKindDesc(int kind) const
+{
+  return underlying->tokenKindDesc(kind);
+}
+
+
+// ---------------------- ParseTreeActions -------------------
+STATICDEF SemanticValue ParseTreeActions::reduce(
+  UserActions *context,
+  int productionId,
+  SemanticValue const *svals
+  SOURCELOCARG( SourceLoc loc ) )
+{
+  ParseTreeActions *ths = static_cast<ParseTreeActions*>(context);
+
+  // get info about this production
+  ParseTables::ProdInfo const &info = ths->tables->getProdInfo(productionId);
+  xassert(info.rhsLen <= PTreeNode::MAXCHILDREN);
+
+  // make a bare PTreeNode, labeled with the LHS nonterminal name
+  PTreeNode *ret = new PTreeNode(ths->underlying->nonterminalName(info.lhsIndex));
+
+  // add the children
+  for (int i=0; i < info.rhsLen; i++) {
+    ret->children[i] = (PTreeNode*)svals[i];
+  }
+  ret->numChildren = info.rhsLen;
+
+  return (SemanticValue)ret;
+}
+
+
+SemanticValue ParseTreeActions::mergeAlternativeParses(
+  int ntIndex, SemanticValue left, SemanticValue right
+  SOURCELOCARG( SourceLoc loc ) )
+{
+  trace("ptreeactMerge") << underlying->nonterminalName(ntIndex) << "\n";
+
+  // link the ambiguities together in the usual way
+  PTreeNode *L = (PTreeNode*)left;
+  PTreeNode *R = (PTreeNode*)right;
+
+  L->addAlternative(R);
+  return left;
+}
+
+
+char const *ParseTreeActions::terminalName(int termId)
+{
+  return underlying->terminalName(termId);
+}
+
+char const *ParseTreeActions::nonterminalName(int termId)
+{
+  return underlying->nonterminalName(termId);
+}

Added: vendor/elsa/current/elkhound/ptreeact.h
===================================================================
--- vendor/elsa/current/elkhound/ptreeact.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ptreeact.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+// ptreeact.h            see license.txt for copyright and terms of use
+// a generic set of user actions that build parse trees for any grammar
+
+#ifndef PTREEACT_H
+#define PTREEACT_H
+
+#include "lexerint.h"      // LexerInterface
+#include "useract.h"       // UserActions
+
+class ParseTables;         // parsetables.h
+
+
+// lexer to yield PTreeNodes for tokens
+class ParseTreeLexer : public LexerInterface {
+private:
+  LexerInterface *underlying;   // for getting token descriptions
+  NextTokenFunc underToken;     // for getting tokens
+  UserActions *actions;         // for getting symbol names
+
+private:
+  void copyFields();
+
+public:
+  ParseTreeLexer(LexerInterface *u, UserActions *a);
+
+  static void nextToken(LexerInterface *lex);
+  virtual NextTokenFunc getTokenFunc() const
+    { return &ParseTreeLexer::nextToken; }
+
+  virtual string tokenDesc() const;
+  virtual string tokenKindDesc(int kind) const;
+};
+
+
+// layer these actions on top of the generated actions to
+// build parse trees for the reductions
+class ParseTreeActions : public TrivialUserActions {
+private:
+  UserActions *underlying;   // for getting symbol names
+  ParseTables *tables;       // for finding out production lengths
+
+public:
+  ParseTreeActions(UserActions *u, ParseTables *t)
+    : underlying(u), tables(t) {}
+
+  static SemanticValue reduce(
+    UserActions *context,
+    int productionId,
+    SemanticValue const *svals
+    SOURCELOCARG( SourceLoc loc ) );
+  virtual ReductionActionFunc getReductionAction()
+    { return &ParseTreeActions::reduce; }
+
+  virtual SemanticValue mergeAlternativeParses(
+    int ntIndex, SemanticValue left, SemanticValue right
+    SOURCELOCARG( SourceLoc loc ) );
+
+  virtual char const *terminalName(int termId);
+  virtual char const *nonterminalName(int termId);
+  
+  ParseTables *getTables() { return tables; }
+};
+
+
+#endif // PTREEACT_H

Added: vendor/elsa/current/elkhound/ptreenode.cc
===================================================================
--- vendor/elsa/current/elkhound/ptreenode.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ptreenode.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,155 @@
+// ptreenode.cc            see license.txt for copyright and terms of use
+// code for ptreenode.h
+
+#include "ptreenode.h"      // this module
+#include "typ.h"            // STATICDEF
+#include "str.h"            // string
+#include "trace.h"          // tracingSys
+
+#include <string.h>         // strchr
+
+int PTreeNode::allocCount = 0;
+int PTreeNode::alternativeCount = 0;
+
+
+void PTreeNode::init()
+{ 
+  merged = NULL;
+  allocCount++;
+}
+
+
+TreeCount PTreeNode::countTrees()
+{
+  // memoize to avoid exponential blowup
+  if (count != 0) {
+    return count;
+  }
+  
+  else {
+    // a single tree can have any possibility for each of
+    // its children, so the result is their product
+    count = 1;
+    for (int i=0; i<numChildren; i++) {
+      count *= children[i]->countTrees();
+    }
+    
+    // are there alternatives?
+    if (merged) {
+      // add them too (recurse down the list of alts)
+      count += merged->countTrees();
+    }
+  }
+
+  return count;
+}
+
+
+void PTreeNode::printTree(ostream &out, PrintFlags pf) const
+{
+  if (tracingSys("ptreeAddrs")) {
+    pf = (PrintFlags)(pf | PF_ADDRS);
+  }
+  innerPrintTree(out, 0 /*indentation*/, pf);
+}
+
+
+// amount to indent per level
+enum { INDENT_INC = 2 };
+
+void PTreeNode::innerPrintTree(ostream &out, int indentation, 
+                               PrintFlags pf) const
+{
+  int alts = 1;
+  string LHS;
+
+  if (merged) {
+    // this is an ambiguity node
+    alts = countMergedList();
+
+    // since all of the alternatives should rewrite the same LHS
+    // nonterminal, extract it from the first one
+    char const *firstSpace = strchr(type, ' ');
+    if (!firstSpace) {
+      LHS = type;     // no space, use whole thing
+    }
+    else {
+      LHS = substring(type, firstSpace-type);
+    }
+
+    indentation += INDENT_INC;
+  }
+
+  // iterate over interpretations
+  int ct=1;
+  for (PTreeNode const *n = this; n != NULL; n = n->merged) {
+    if (alts > 1) {
+      indent(out, indentation - INDENT_INC);
+      out << "--------- ambiguous " << LHS << ": "
+          << ct << " of " << alts << " ---------\n";
+    }
+
+    indent(out, indentation);
+
+    out << n->type;
+    if (pf & PF_EXPAND) {
+      // the type is just the LHS name; write out the RHS names
+      // after an "->"
+      if (n->numChildren) {
+        out << " ->";
+        for (int c=0; c < n->numChildren; c++) {
+          out << " " << n->children[c]->type;
+        }
+      }
+    }
+
+    if (pf & PF_ADDRS) {
+      // print the parse tree node address, so I can verify proper sharing
+      out << " (" << ((void*)n) << ")";
+    }
+    out << "\n";
+
+    // iterate over children
+    for (int c=0; c < n->numChildren; c++) {
+      // recursively print children
+      n->children[c]->innerPrintTree(out, indentation + INDENT_INC, pf);
+    }
+
+    ct++;
+  }
+
+  if (merged) {
+    // close up ambiguity display
+    indentation -= INDENT_INC;
+    indent(out, indentation);
+    out << "--------- end of ambiguous " << LHS << " ---------\n";
+  }
+}
+
+STATICDEF void PTreeNode::indent(ostream &out, int n)
+{
+  for (int i=0; i<n; i++) {
+    out << " ";
+  }
+}
+
+// # of nodes on the 'merged' list; always at least 1 since
+// 'this' is considered to be in that list
+int PTreeNode::countMergedList() const
+{
+  int ct = 1;
+  for (PTreeNode const *n = merged; n != NULL; n = n->merged) {
+    ct++;
+  }
+  return ct;
+}
+
+
+void PTreeNode::addAlternative(PTreeNode *alt)
+{
+  // insert as 2nd element
+  alt->merged = this->merged;
+  this->merged = alt;
+  
+  alternativeCount++;
+}

Added: vendor/elsa/current/elkhound/ptreenode.h
===================================================================
--- vendor/elsa/current/elkhound/ptreenode.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ptreenode.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,105 @@
+// ptreenode.h            see license.txt for copyright and terms of use
+// parse tree node for experimental grammars (this isn't somthing
+// Elkhound as a whole knows about--it doesn't make trees unless
+// the user actions do)
+
+#ifndef PTREENODE_H
+#define PTREENODE_H
+
+#include <stddef.h>     // NULL
+#include <iostream.h>   // ostream
+
+// for storing counts of parse trees; I try to make the code work for
+// either 'int' or 'double' in this spot (e.g. I assign 0 to it
+// instead of 0.0), even though 'int' overflows quickly for the highly
+// ambiguous grammars
+typedef double TreeCount;
+
+class PTreeNode {
+public:    // types
+  // max # of children (when this is increased, more constructors
+  // for PTreeNode should be added)
+  enum { MAXCHILDREN = 10 };
+  
+  // printing options
+  enum PrintFlags {
+    PF_NONE    = 0,       // default, print types as-is
+    PF_EXPAND  = 1,       // types are just LHS, dig down to find RHSs
+    PF_ADDRS   = 2,       // print node virtual addresses to see sharing
+  };
+
+public:    // data
+  // textual repr. of the production applied; possibly useful for
+  // printing the tree, or during debugging
+  char const *type;
+
+  // instead of making explicit merge nodes (which runs afoul of the
+  // yield-then-merge problem), just link alternatives together using
+  // this link; this is NULL when there are no alternatives, or for
+  // the last node in a list of alts
+  PTreeNode *merged;
+
+  // array of children; these aren't owner pointers because
+  // we might have arbitrary sharing for some grammars
+  int numChildren;
+  PTreeNode *children[MAXCHILDREN];
+
+  // # of parse trees of which this is the root; effectively this
+  // memoizes the result to avoid an exponential blowup counting
+  // the trees; when this value is 0, it means the count has not
+  // yet been computed (any count must be positive)
+  TreeCount count;
+
+  // count of # of allocated nodes; useful for identifying when
+  // we're making too many
+  static int allocCount;
+
+  // count # of times addAlternative is called; this will tell
+  // the total number of local ambiguities that need to be resolved
+  static int alternativeCount;
+
+private:     // funcs
+  // init fields which don't depend on ctor args
+  void init();
+
+  // helpers
+  static void indent(ostream &out, int n);
+  void innerPrintTree(ostream &out, int indentation, PrintFlags pf) const;
+  int countMergedList() const;
+
+public:      // funcs
+  // now lots of constructors so we have one for each possible
+  // number of children; the calls are automatically inserted
+  // by a perl script ('make-trivparser.pl') or by the grammar
+  // transformation GrammarAnalysis::addTreebuildingActions()
+  PTreeNode(char const *t)
+    : type(t), numChildren(0), count(0) { init(); }
+  PTreeNode(char const *t, PTreeNode *ch0)
+    : type(t), numChildren(1), count(0) { init(); children[0] = ch0; }
+  PTreeNode(char const *t, PTreeNode *ch0, PTreeNode *ch1)
+    : type(t), numChildren(2), count(0) { init(); children[0] = ch0; children[1] = ch1; }
+  PTreeNode(char const *t, PTreeNode *ch0, PTreeNode *ch1, PTreeNode *ch2)
+    : type(t), numChildren(3), count(0) { init(); children[0] = ch0; children[1] = ch1; children[2] = ch2; }
+  PTreeNode(char const *t, PTreeNode *ch0, PTreeNode *ch1, PTreeNode *ch2, PTreeNode *ch3)
+    : type(t), numChildren(4), count(0) { init(); children[0] = ch0; children[1] = ch1; children[2] = ch2; children[3] = ch3; }
+  PTreeNode(char const *t, PTreeNode *ch0, PTreeNode *ch1, PTreeNode *ch2, PTreeNode *ch3, PTreeNode *ch4)
+    : type(t), numChildren(5), count(0) { init(); children[0] = ch0; children[1] = ch1; children[2] = ch2; children[3] = ch3; children[4] = ch4; }
+  // be sure to update MAXCHILDREN, above, if you add constructors
+  // which accept more children
+
+  ~PTreeNode() { allocCount--; }
+
+  // count the number of trees encoded (taking merge nodes into
+  // account) in the tree rooted at 'this'
+  TreeCount countTrees();
+
+  // print the entire parse forest using indentation to represent
+  // nesting, and duplicating printing of shared subtrees within
+  // ambiguous regions
+  void printTree(ostream &out, PrintFlags pf = PF_NONE) const;
+
+  // add an alternative to the current 'merged' list
+  void addAlternative(PTreeNode *alt);
+};
+
+#endif // PTREENODE_H

Added: vendor/elsa/current/elkhound/rcptr.h
===================================================================
--- vendor/elsa/current/elkhound/rcptr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/rcptr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,70 @@
+// rcptr.h            see license.txt for copyright and terms of use
+// a stab at a reference-counting pointer
+
+// the object pointed-at must support this interface:
+//   // increment reference count
+//   void incRefCt();
+//   
+//   // decrement refcount, and if it becomes 0, delete yourself
+//   void decRefCt();
+
+#ifndef __RCPTR_H
+#define __RCPTR_H
+
+#include "typ.h"      // NULL
+
+#if 0
+  #include <stdio.h>    // printf, temporary
+  #define DBG(fn) printf("%s(%p)\n", fn, ptr)
+#else
+  #define DBG(fn)
+#endif
+
+template <class T>
+class RCPtr {
+private:    // data
+  T *ptr;                // the real pointer
+
+private:    // funcs
+  void inc() { DBG("inc"); if (ptr) { ptr->incRefCt(); } }
+  void dec() { DBG("dec"); if (ptr) { ptr->decRefCt(); ptr=NULL; } }
+
+public:     // funcs
+  explicit RCPtr(T *p = NULL) : ptr(p) { DBG("ctor"); inc(); }
+  explicit RCPtr(RCPtr const &obj) : ptr(obj.ptr) { DBG("cctor"); inc(); }
+  ~RCPtr() { DBG("dtor"); dec(); }
+
+  // point at something new (setting to NULL is an option)
+  void operator= (T *p) { DBG("op=ptr"); dec(); ptr=p; inc(); }
+  void operator= (RCPtr<T> const &obj)
+    { DBG("op=obj"); dec(); ptr=obj.ptr; inc(); }
+
+  // some operators that make Owner behave more or less like
+  // a native C++ pointer
+  operator T const * () const { DBG("opcT*"); return ptr; }
+  T const & operator* () const { DBG("opc*"); return *ptr; }
+  T const * operator-> () const { DBG("opc->"); return ptr; }
+
+  bool operator==(T *p) const { return ptr == p; }
+  bool operator!=(T *p) const { return !this->operator==(p); }
+
+  bool operator==(RCPtr<T> const &obj) const { return ptr == obj.ptr; }
+  bool operator!=(RCPtr<T> const &obj) const { return !this->operator==(obj); }
+
+  operator T* () { DBG("opT*"); return ptr; }
+  operator T const * () { DBG("opcT*"); return ptr; }
+  T& operator* () { DBG("op*"); return *ptr; }
+  T* operator-> () { DBG("op->"); return ptr; }
+
+  // escape hatch for when operators flake out on us
+  T *get() { DBG("get"); return ptr; }
+  T const *getC() const { DBG("getC"); return ptr; }
+  
+  // sometimes, in performance-critical code, I need fine control
+  // over the refcount operations; this lets me change 'ptr', the
+  // assumption being I'll update the refct manually
+  void setWithoutUpdateRefct(T *p) { ptr=p; }
+};
+
+
+#endif // __RCPTR_H

Added: vendor/elsa/current/elkhound/readme.txt
===================================================================
--- vendor/elsa/current/elkhound/readme.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/readme.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+This file has been superceded by index.html.

Added: vendor/elsa/current/elkhound/regrtest
===================================================================
--- vendor/elsa/current/elkhound/regrtest	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/regrtest	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,271 @@
+#!/bin/sh
+# regression tests
+
+# default values for user parameters
+skip=0
+big=0
+contin=0
+
+# counters
+curtest=0
+success=0
+failure=0
+unexSuccess=0
+unexFailure=0
+runOneTest=false
+
+usage() {
+cat <<EOF
+usage: $0 [options]
+  -skip <n>    skip the first <n> tests
+  -one <n>     run only test <n>
+  -big         run the big, timeconsuming tests
+  -contin      keep going even after a test fails (or succeeds) unexpectedly
+  -help        print this message
+EOF
+}
+
+# process args
+while [ "$1" != "" ]; do
+  case "$1" in
+    -skip)
+      shift
+      skip="$1"
+      ;;
+
+    -one)
+      shift
+      skip="$1"
+      runOneTest=true
+      ;;
+
+    -big)
+      big=1
+      ;;
+
+    -contin)
+      contin=1
+      ;;
+
+    -help)
+      usage
+      exit 0
+      ;;
+
+    *)
+      echo "unknown arg: $1"
+      usage
+      exit 2
+      ;;
+  esac
+
+  shift
+done
+
+# allow 'gmake' or whatever to be used instead of 'make'
+MAKE=${MAKE:-make}
+
+# clear the logfile
+logfile=regrtest.log
+rm -f $logfile
+
+# write something to terminal and log
+log() {
+  echo "$@"
+  echo "$@" >> $logfile
+}
+
+
+# run a single test, and bail if it fails
+runTest() {
+  if runTestInternal "$@"; then
+    true
+  else
+    if [ $contin = 0 ]; then
+      exit 2
+    fi
+  fi
+}
+
+# run a single test, and return 0 if it succeeds
+runTestInternal() {
+  result=0
+
+  if [ "$curtest" -lt "$skip" ]; then
+    echo "[$curtest]: skipping $*"
+  else
+    # print a visually distinct banner
+    echo "------------ [$curtest] $* ------------"
+    ("$@")
+    result=$?
+    if [ $result -ne 0 ]; then
+      unexFailure=`expr $unexFailure + 1`
+      echo ""
+      log  "[$curtest] A regression test command failed:"
+      log  "  $*"
+    else
+      success=`expr $success + 1`
+    fi
+
+    if $runOneTest; then
+      # exit with code 0 if the test succeeded
+      exit `expr 1 - $success`
+    fi
+  fi
+
+  curtest=`expr $curtest + 1`
+  return $result
+}
+
+# run a big test, only if the user wants to
+bigTest() {
+  if [ $big = 1 ]; then
+    runTest "$@"
+  fi
+}
+
+# run a test that is expected to fail
+failTest() {
+  reason="$1"
+  shift
+  if [ "$curtest" -lt "$skip" ]; then
+    echo "[$curtest]: (fail) skipping $*"
+  else
+    echo "------------ [$curtest] (fail) $* ------------"
+    if "$@"; then
+      unexSuccess=`expr $unexSuccess + 1`
+      echo ""
+      log  "[$curtest] A regression test that used to fail ($reason) now succeeds:"
+      log  "  $*"
+      if [ $contin = 0 ]; then
+        exit 2
+      fi
+    else
+      failure=`expr $failure + 1`
+      echo "Failed as expected: $reason"
+    fi
+
+    if $runOneTest; then
+      # exit with code 0 if the test failed
+      exit `expr 1 - $failure`
+    fi
+  fi
+
+  curtest=`expr $curtest + 1`
+}
+
+# run a failing big test
+bigFail() {
+  if [ $big = 1 ]; then
+    failTest "$@"
+  fi
+}
+
+# grep for lines containing both words, in first argument source file
+grepBoth() {
+  grep -w $2 $1 | grep -w $3
+}
+
+
+# ------------- small test grammars ----------
+# usage: testTrivGrammar <name> [<inputSuffix1> [<inputSuffix2> ...]]
+testTrivGrammar() {
+  name="$1"
+  shift
+  runTest $MAKE "triv/${name}.gr.exe" TRGRAMANL=,lrtable
+
+  while [ "$1" != "" ]; do
+    suffix="$1"
+    shift
+
+    runTest "triv/${name}.gr.exe" "triv/${name}.in${suffix}"
+  done
+}
+
+testTrivGrammar aSEb 1
+testTrivGrammar ite 1 2 3 4
+testTrivGrammar AdB 1
+testTrivGrammar CNI 1
+testTrivGrammar ESb 1
+testTrivGrammar CAdB 1
+testTrivGrammar EEb 1 2 3
+testTrivGrammar angle 1 2 3 4 5
+testTrivGrammar testRR 1 2
+
+#runTest $MAKE aSEb.gr.exe
+#runTest ./aSEb.gr.exe aSEb.in1
+
+#  runTest $MAKE ite.gr.exe
+#  for n in 1 2 3 4; do
+#    runTest ./ite.gr.exe ite.in$n
+#  done
+
+
+# this is a test of the delete/replace feature; it uses a script that
+# (for now) is only in Elsa, so don't try it unless that script is 
+# in a usual place
+if [ -x ../elsa/multitest.pl ]; then
+  runTest perl ../elsa/multitest.pl ./elkhound ffollow.gr ffollow_ext.gr
+fi
+
+
+# make sure Elkhound doesn't segfault on the following
+runTest ./elkhound examples/crash1.gr
+
+
+# ------------ test the C grammar and parser -------------
+for n in 1 2 3 4 5 6 7 8 9 10 11 12; do
+  runTest c/cparse -tr stopAfterTCheck,suppressAddrOfError c.in/c.in$n
+done
+
+
+tcheck() {
+  runTest ./test-bad c/cparse tcheck/$1 -tr stopAfterTCheck
+}
+
+tcheck init.c
+tcheck addrglob.c
+tcheck loops.c
+tcheck exprpath.c
+runTest c/cparse -tr printAnalysisPath tcheck/morepaths.c
+
+
+# --------- test C++ parser using standard grammar ------------
+# no '4' because that uses thmprv_attr ...
+for n in 1 2 3   5 6 7 8 9 10 11 12; do
+  runTest cc2/cc2.exe c.in/c.in$n
+done
+
+
+runTest $MAKE examples
+
+
+# print config info
+runTest c/cparse -tr trivialActions,stopAfterParse,glrConfig,yieldVariableName \
+  c.in/c.in4b
+
+# bison performance test
+runTest $MAKE c.in/c.in4d
+
+# I've disable this one because I don't want to build bcparse
+# in my Elkhound distribution, since that is a dependency on
+# Bison
+#runTest c/bcparse c.in/c.in4d
+
+# this one is my main performance tester for comparison to bison
+runTest c/cparse -tr trivialActions,stopAfterParse,yieldVariableName \
+  c.in/c.in4d
+
+
+# final arithmetic to report result
+echo ""
+echo "Successful tests:      $success"
+echo "Failed as expected:    $failure"
+if [ $contin = 1 ]; then
+  echo "Unexpected success:    $unexSuccess"
+  echo "Unexpected failure:    $unexFailure"
+  if [ -f "$logfile" ]; then
+    cat "$logfile"
+  fi
+fi
+


Property changes on: vendor/elsa/current/elkhound/regrtest
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/skeleton.gr
===================================================================
--- vendor/elsa/current/elkhound/skeleton.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/skeleton.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// skeleton.gr            see license.txt for copyright and terms of use
+// template grammar file
+
+verbatim Skeleton [
+  #include "useract.h"       // UserActions
+
+  class Skeleton : public UserActions {
+    #include "skeleton.gen.h"
+  };
+]
+
+terminals {
+  // ... declare all terminals ...
+}
+
+// ... declare all nonterminals ...

Added: vendor/elsa/current/elkhound/ssxmain.cc
===================================================================
--- vendor/elsa/current/elkhound/ssxmain.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ssxmain.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,134 @@
+// ssxmain.cc            see license.txt for copyright and terms of use
+// main() for use with SSx.tree.gr
+
+#include "trivlex.h"   // trivialLexer
+#include "parssppt.h"  // ParseTreeAndTokens
+#include "test.h"      // ARGS_MAIN
+#include "trace.h"     // TRACE_ARGS
+#include "glr.h"       // GLR
+#include "useract.h"   // UserActions
+#include "ptreenode.h" // PTrdeeNode
+
+
+#if 0     // obsolete, replaced by ptreenode.cc
+TreeCount count(Node *n)
+{
+  // memoize to avoid exponential blowup
+  if (n->count != 0) {
+    return n->count;
+  }
+
+  switch (n->type) {
+    default:
+      xfailure("bad code");
+
+    case Node::MERGE:
+      // a single tree can take either from the left or
+      // the right, but not both simultaneously
+      n->count = count(n->left) + count(n->right);
+      break;
+
+    case Node::SSX:
+      // a single tree can have any possibility from left
+      // and any possibility from right
+      n->count = count(n->left) * count(n->right);
+      break;
+
+    case Node::X:
+      n->count = 1;
+      break;
+  }
+
+  return n->count;
+}
+#endif // 0
+
+
+// compute the sum at the top of SSx.tree.gr
+TreeCount C(int n)
+{
+  static TreeCount *memoized = NULL;
+  if (!memoized) {
+    memoized = new TreeCount[n+1];
+
+    memoized[0] = 1;      // seed value: C(0)=1
+
+    for (int i=1; i<n+1; i++) {
+      memoized[i] = 0;    // entry hasn't been computed yet
+    }
+  }
+
+  if (memoized[n]) {
+    return memoized[n];
+  }
+
+  TreeCount sum = 0;
+  for (int m=0; m<n; m++) {
+    sum += C(m) * C(n-1-m);
+  }
+
+  memoized[n] = sum;
+  return sum;
+}
+
+
+// defined in the grammar file
+UserActions *makeUserActions();
+
+int entry(int argc, char *argv[])
+{
+  char const *progName = argv[0];
+  TRACE_ARGS();
+
+  if (argc < 2) {
+    printf("usage: %s input-file\n", progName);
+    return 0;
+  }
+  char const *inputFname = argv[1];
+
+  // see how long the input is
+  int inputLen;
+  {
+    FILE *input = fopen(inputFname, "r");
+    if (!input) {
+      printf("cannot open file: %s\n", inputFname);
+      return 2;
+    }
+    fseek(input, 0, SEEK_END);
+    inputLen = ftell(input);
+    fclose(input);
+  }
+
+  // lex input
+  Lexer2 lexer;
+  trivialLexer(inputFname, lexer);
+
+  // setup parser
+  UserActions *user = makeUserActions();
+  GLR glr(user);
+  glr.readBinaryGrammar("SSx.tree.bin");
+
+  // parse input
+  SemanticValue treeTop;
+  if (!glr.glrParse(lexer, treeTop)) {
+    // glrParse prints the error itself
+    return 2;
+  }
+
+  // count # of parses
+  PTreeNode *top = (PTreeNode*)treeTop;
+  TreeCount numParses = top->countTrees();
+  cout << "num parses: " << numParses << endl;
+
+  // print what it should be
+  int n = (inputLen - 1) / 2;
+  cout << "input is x^" << inputLen 
+       << "; C(" << n 
+       << ") = " << C(n)
+       << endl;
+
+  return 0;
+}
+
+
+ARGS_MAIN

Added: vendor/elsa/current/elkhound/ssxnode.h
===================================================================
--- vendor/elsa/current/elkhound/ssxnode.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/ssxnode.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// ssxnode.h            see license.txt for copyright and terms of use
+// parse tree node for SSx.tree.gr
+
+#ifndef SSXNODE_H
+#define SSXNODE_H
+                      
+// for storing counts of parse trees
+typedef int TreeCount;
+
+class Node {
+public:
+  enum Type { MERGE, SSX, X } type;
+  Node *left, *right;
+  TreeCount count;       // # of parse trees of which this is the root
+
+public:
+  Node(Type t, Node *L, Node *R)
+    : type(t), left(L), right(R), count(0) {}
+};
+
+#endif // SSXNODE_H

Added: vendor/elsa/current/elkhound/tcheck/addrglob.c
===================================================================
--- vendor/elsa/current/elkhound/tcheck/addrglob.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/tcheck/addrglob.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// addrglob.c
+// NUMERRORS 2
+// verify addr-of-global restrictions
+
+int x;    // fine
+
+int foo()
+{
+  return x;
+}
+
+
+int y;
+
+int bar()
+{
+  int z = 3;
+  {
+    int *p = &y;   // ERROR(1)
+    z = *p;        // ERROR(1)
+  }
+  return z;
+}
+
+
+int q thmprv_attr(addrtaken);
+
+int *zoo()
+{
+  return &q;
+}
+   
+
+int ug thmprv_attr(misspelled);     // ERROR(2)
+

Added: vendor/elsa/current/elkhound/tcheck/exprpath.c
===================================================================
--- vendor/elsa/current/elkhound/tcheck/exprpath.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/tcheck/exprpath.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,83 @@
+// exprpath.c
+// NUMERRORS 0
+// demonstrate a range of expressions with tricky control flow paths
+  
+
+void bar(int a, int b);
+
+void foo()
+{
+  int x,y,z;
+
+  4;
+  4.5;
+  "foo";
+  'f';
+  z;
+ 
+  bar(x,y);
+  bar(x++,y);
+  bar(x,y++);
+  //bar(x++,y++);
+
+  bar(x++ + x++, y);
+  //bar(x++ + x++, y++);
+  
+  !(x++);
+  
+  x && y;
+  x++ || y;
+  x && y++;
+  x++ && y++;
+  (x++ + x++) && (y++ + y++);
+
+  x * y;
+  x++ + y;
+  x * y++;
+  x++ * y++;
+  (x++ + x++) * (y++ + y++);
+
+  x ? y : z;
+
+  x++ ? y : z;
+  x ? y++ : z;
+  x ? y : z++;
+  
+  x++ ? y++ : z;
+  x++ ? y : z++;
+  x ? y++ : z++;
+  
+  x++? y++ : z++;
+  (x++ + x++)? y++ : z++;
+  x++? (y++ + y++) : z++;
+  x++? y++ : (z++ + z++);
+  
+  //x ?: y;
+  //x++ ?: y;
+  //x ?: y++;
+  //x++ ?: y++;
+  
+  x,y;
+  x++, y;
+  x, y++;
+  x++, y++;
+
+  x = y;
+  //(x=y) = z;      // will be illegal once I get lvalue checking..
+  //x = (y=z);
+  //(x=y) = x++;
+
+  x += y;
+  //x++ += y;
+  x += y++;
+  //x++ += y++;
+
+  x ? y++ :
+  y ? z++ :
+  z ? x++ : (x=y);
+
+}
+
+
+
+

Added: vendor/elsa/current/elkhound/tcheck/init.c
===================================================================
--- vendor/elsa/current/elkhound/tcheck/init.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/tcheck/init.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// init.c
+// some tests of the initializer type-checking
+// NUMERRORS 3
+
+int a[3] = { 1,2,3 };
+int b[3] = { 1,2,3,4 };           // ERROR(1)
+
+union U { int i; float f; };
+union U u = { 3 };                // ERROR(2)
+
+struct S { int i; float f; };
+struct S s = { 4, 5.6 };
+struct S t = { 4, 5.6, 8 };       // ERROR(3)
+

Added: vendor/elsa/current/elkhound/tcheck/loops.c
===================================================================
--- vendor/elsa/current/elkhound/tcheck/loops.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/tcheck/loops.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,85 @@
+// loops.c
+// NUMERRORS 0
+// test my CFG extraction
+
+void foo()
+{ 
+  int x,y,z;
+
+  ;       // skip
+
+label1:
+  x=4;
+  
+  switch (y) {
+    case 1: y=6; break;
+    case 2: y=7;
+    case 3: z=9; break;
+    case 4 ... 5: z=3; break;
+    default: x=5;
+  }
+  
+  switch (y) {
+    default: y=9; break;
+  }
+  
+  {
+    x=1;
+    y=2;
+    z=3;
+  }
+  
+  if (x > y) {
+    z=9;
+  }
+  else {
+    z=10;
+  }
+  
+  x=5;
+  
+  while (z<10) {
+    z++;
+  }
+
+  x=6;
+
+  do {
+    x++;
+  } while (x < 8);
+
+  for (y=0; y<5; y++) {
+    z--;
+  }
+
+  while (z<10) {
+    z++;
+    if (y++) {
+      break;
+    }
+    if (x<9) {
+      continue;
+    }
+    x += 5;
+  }
+  
+  if (z > y) {
+    return;
+  }        
+  
+  if (x > y) {
+    goto label1;
+  }
+  else {
+    goto label2;
+  }
+  
+  x=9;
+  
+label2:
+  x=8;
+}
+
+
+
+

Added: vendor/elsa/current/elkhound/tcheck/morepaths.c
===================================================================
--- vendor/elsa/current/elkhound/tcheck/morepaths.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/tcheck/morepaths.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// morepaths.c
+// anomaly with missing paths when function ends with loop construct
+
+struct Node {
+  struct Node *next;
+};
+
+void append(struct Node *head, struct Node *toAdd)
+{
+  struct Node *p = head;
+
+  while (p != (struct Node*)0) {
+    thmprv_invariant(1);
+    p = p;
+  }
+
+  //p = toAdd;
+}

Added: vendor/elsa/current/elkhound/test-all-config
===================================================================
--- vendor/elsa/current/elkhound/test-all-config	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/test-all-config	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+#!/bin/sh
+# test-all-config
+# test all (or a representative subset) of the ./configure options
+
+# bail on error
+set -e
+
+# default config is most important (right now, that's w/no compression)
+./configure && make clean all check
+
+testCompr() {
+  ./configure -eef=$1 -gcs=$2 -gcsc=$3 -crs=$4 && make clean all check
+}
+
+# some options on, others off
+testCompr y y y y
+testCompr y y y n
+testCompr y y n y
+testCompr y y n n
+#testCompr y n y y   # gcsc requires gcs
+#testCompr y n y n
+testCompr y n n y
+testCompr y n n n
+#testCompr n y y y   # gcs requires eef
+#testCompr n y y n
+#testCompr n y n y
+#testCompr n y n n
+#testCompr n n y y
+#testCompr n n y n
+testCompr n n n y
+testCompr n n n n
+


Property changes on: vendor/elsa/current/elkhound/test-all-config
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/test-ambig-perf
===================================================================
--- vendor/elsa/current/elkhound/test-ambig-perf	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/test-ambig-perf	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+#!/bin/sh
+# test performance on ambiguous input
+
+#for fn in bb10.c bb20.c bb50.c bb100.c bb200.c bb500.c bb1000.c; do
+for fn in bb300.c bb400.c; do
+  echo "$fn"
+  results=""
+  #for n in 1 2 3 4 5; do
+  for n in 1; do
+    cycles=`./ccgr -tr trivialActions,stopAfterParse cc.bin $fn \
+              | grep cycles | awk '{ print $8 }' | sed 's/(//'`
+    results="$results $cycles"
+    echo "  $n: $cycles"
+  done
+
+  median=`echo $results | fmt -1 | sort | head -3 | tail -1`
+  echo "  median: $median"
+done
+
+


Property changes on: vendor/elsa/current/elkhound/test-ambig-perf
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/test-bad
===================================================================
--- vendor/elsa/current/elkhound/test-bad	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/test-bad	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,64 @@
+#!/bin/sh
+# run a regression test containing one or more intentional failures
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 ./ccgr source-file.c [args-to-ccgr]"
+  exit 0
+fi
+executable="$1"
+srcfile="$2"
+shift
+shift
+
+# read how many failure cases are in the file; expect line of form
+# "// NUMERRORS n"
+numcases=`grep NUMERRORS "$srcfile" | awk '{ print $3 }'`
+if [ -z "$numcases" ]; then
+  echo "didn't find a string of form NUMERRORS <n> in the file"
+  exit 2
+fi
+echo "there are $numcases failure cases in this file"
+
+# iterate through the cases; first case (0) is where no errors are present
+i=0
+while [ $i -le $numcases ]; do
+  # generate a temporary file; first hide the ERROR tags which identify
+  # the current test, then remove all remaining ERROR lines
+  # (syntax for errors has parentheses so if I have >=10 cases I don't
+  # run into problems where e.g. ERROR1 is a substring of ERROR10)
+  echo "generating test $i"
+  cat "$srcfile" | sed "s/ERROR($i)/(selected: $i)/" | grep -v ERROR > test-bad-tmp.c
+
+  # run this through ccgr
+  echo "$executable" "$@" test-bad-tmp.c
+  if "$executable" "$@" test-bad-tmp.c; then
+    if [ $i = 0 ]; then
+      # expected success on 0th iteration
+      echo "(succeeded as expected)"
+    else
+      # unexpected success on >0th iteration
+      echo "The ${i}th iteration did not fail!  It is supposed to fail."
+      exit 2
+    fi
+  else
+    if [ $i = 0 ]; then
+      # unexpected failure on 0th iteration
+      echo "The 0th iteration failed! It is supposed to succeed."
+      #cat test-bad-tmp.c
+      exit 2
+    else
+      # expected failure on >0th iteration
+      echo "(failed as expected)"
+    fi
+  fi
+
+  # possibly bail after 0th
+  if [ "$TESTBADONCE" != "" ]; then
+    echo "bailing after 0th iteration because TESTBADONCE is set"
+    exit 0
+  fi
+
+  i=`expr $i + 1`
+done
+
+echo "all $numcases cases in $srcfile failed as expected"


Property changes on: vendor/elsa/current/elkhound/test-bad
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/test-mlsstr-on-many
===================================================================
--- vendor/elsa/current/elkhound/test-mlsstr-on-many	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/test-mlsstr-on-many	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+#!/bin/sh
+# run mlsstr on a bunch of ocaml sources lying around
+
+./mlsstr ocaml/*.ml || exit
+
+./mlsstr ../Kettle/ocamlutil/*.ml || exit
+./mlsstr ../Kettle/src/*.ml || exit
+
+./mlsstr ../../safec/cil/src/*.ml || exit
+./mlsstr ../../safec/cil/src/ccured/*.ml || exit
+
+# EOF


Property changes on: vendor/elsa/current/elkhound/test-mlsstr-on-many
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elkhound/toplevel/license.txt
===================================================================
--- vendor/elsa/current/elkhound/toplevel/license.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/toplevel/license.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+The software in this directory is
+Copyright (c) 2002, Regents of the University of California
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above 
+      copyright notice, this list of conditions and the following 
+      disclaimer in the documentation and/or other materials provided 
+      with the distribution.
+
+    * Neither the name of the University of California, Berkeley nor 
+      the names of its contributors may be used to endorse or promote 
+      products derived from this software without specific prior 
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: vendor/elsa/current/elkhound/toplevel/readme.txt
===================================================================
--- vendor/elsa/current/elkhound/toplevel/readme.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/toplevel/readme.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+Please see parsgen/readme.txt.

Added: vendor/elsa/current/elkhound/trcptr.cc
===================================================================
--- vendor/elsa/current/elkhound/trcptr.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/trcptr.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,132 @@
+// trcptr.cc            see license.txt for copyright and terms of use
+// test rcptr module
+
+#include "rcptr.h"        // module to test
+#include <stdio.h>        // printf
+
+// a simple class to play with
+class Foo {
+public:
+  static int count;    // # of Foos there are
+  int x;
+  int refCt;
+
+public:
+  Foo(int a);
+  ~Foo();
+  
+  void incRefCt() { refCt++; }
+  void decRefCt();
+};
+
+int Foo::count = 0;
+
+Foo::Foo(int ax)
+  : x(ax), refCt(0)
+{
+  printf("created Foo at %p\n", this);
+  count++;
+}
+
+Foo::~Foo()
+{
+  printf("destroying Foo at %p (refct=%d)\n", this, refCt);
+  count--;
+}
+
+void Foo::decRefCt()
+{
+  if (--refCt == 0) {
+    delete this;
+  }
+}
+
+
+void printFoo(Foo *f)
+{
+  printf("Foo at %p, x=%d, refct=%d\n",
+         f, f? f->x : 0, f? f->refCt : 0);
+}
+
+void printFooC(Foo const *f)
+{
+  printf("const Foo at %p, x=%d, refct=%d\n", 
+         f, f? f->x : 0, f? f->refCt : 0);
+}
+
+void printInt(int x)
+{
+  printf("int x is %d\n", x);
+}
+
+
+// make it, forget to free it
+void test1()
+{
+  printf("----------- test1 -----------\n");
+  RCPtr<Foo> f;
+  f = new Foo(4);
+}
+
+// access all of the operators as non-const
+void test2()
+{
+  printf("----------- test2 -----------\n");
+  RCPtr<Foo> f(new Foo(6));
+
+  printFoo(f);
+  (*f).x = 9;
+  f->x = 12;
+}
+
+// access all of the operators as const
+void test3()
+{
+  printf("----------- test3 -----------\n");
+  RCPtr<Foo> f(new Foo(8));
+  RCPtr<Foo> const &g = f;
+
+  printFooC(g);
+  printInt((*g).x);      // egcs-1.1.2 allows this for non-const operator fn!!!
+  printInt(g->x);
+}
+
+// test exchange of ownership
+void test4()
+{
+  printf("----------- test4 -----------\n");
+  //RCPtr<Foo> f = new Foo(3);     // egcs-1.1.2 does the wrong thing here
+  RCPtr<Foo> f(new Foo(3));
+  RCPtr<Foo> g;
+  g = f;
+  f = NULL;
+  printFoo(f);    // should be null
+  f = g;
+  g = NULL;
+  printFoo(g);    // should be null
+}
+
+// test several things pointing at same obj
+void test5()
+{
+  printf("----------- test5 -----------\n");
+  RCPtr<Foo> f = new Foo(3);
+  RCPtr<Foo> g = f;
+  printFoo(f);
+  g = NULL;
+  printFoo(f);
+}
+
+
+
+int main()
+{
+  test1();
+  test2();
+  test3();
+  test4();
+  test5();
+  
+  printf("%d Foos leaked\n", Foo::count);
+  return Foo::count;
+}

Added: vendor/elsa/current/elkhound/triv/AdB.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/AdB.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/AdB.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// AdB.gr   -*- c++ -*-
+// cyclic grammar
+
+// A -> d | B
+// B -> A
+
+terminals {
+  68 : d   ;
+}
+
+nonterm A {
+  fun merge(p1, p2) [ cout << "merging nonterminal A\n"; return p1; ]
+
+  -> d;
+  -> B;
+}
+
+nonterm B {
+  -> A;
+}
+
+
+

Added: vendor/elsa/current/elkhound/triv/AdB.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/AdB.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/AdB.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+D
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/CAdB.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/CAdB.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/CAdB.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// CAdB.gr   -*- c++ -*-
+// non cyclic grammar (potentially) exhibiting same merge problem as AdB;
+// it really *does* exhibit the problem, as long as "B -> d" occurs
+// earlier in the file than "A -> d"
+
+// C -> A
+// A -> d | B
+// B -> d
+
+terminals {
+  68 : d   ;
+}
+
+nonterm C {
+  -> A;
+}
+
+nonterm B {
+  -> d;
+}
+
+nonterm A {
+  fun merge(p1, p2) [ cout << "merging nonterminal A\n"; return p1; ]
+
+  -> d;
+  -> B;
+}
+
+
+
+

Added: vendor/elsa/current/elkhound/triv/CAdB.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/CAdB.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/CAdB.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+D
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/CNI.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/CNI.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/CNI.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// CNI.gr.in
+// grammar that Shaban reports Nozohoor-Farshi has trouble with
+
+// turns out Shaban is just saying you have to put the semantic
+// values into the sibling links, not the stack nodes (a lesson
+// I learned very early on)
+
+// C -> N I          (i.e. C -> N N I, language is n?n?v in regexp not'n)
+// I -> N v
+// N -> empty
+// N -> n
+
+terminals {
+  n
+  v
+}
+
+nonterm C {
+  fun merge(p1, p2) [ return p1; ]
+
+  -> N I;
+}
+
+nonterm I {
+  -> N v;
+}
+
+nonterm N {
+  -> empty;
+  -> n;
+}
+
+

Added: vendor/elsa/current/elkhound/triv/CNI.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/CNI.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/CNI.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+NV
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/DeclExpr.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/DeclExpr.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/DeclExpr.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,43 @@
+// DeclExpr.gr.in    -*- c++ -*-
+// declarations vs expressions ambiguity kernel
+
+terminals {
+  a      // identifier
+  b      // another identifier
+  l      // left paren
+  r      // right paren       
+  s      // semicolon
+}
+
+nonterm Body {
+  -> empty;
+  -> Body Stmt;
+}
+
+nonterm Stmt {
+  merge(L,R)  [ cout << "merging Stmt\n"; return L; ]
+  dup(v)      [ return v; ]
+  del(v)      []
+
+  -> Decl s;
+  -> Expr s;
+}
+
+nonterm Decl {
+  -> Id/*type*/ Declarator;
+}
+
+nonterm Id {
+  -> a;
+  -> b;
+}
+
+nonterm Declarator {
+  -> Id;
+  -> l Declarator r;
+}
+
+nonterm Expr {
+  -> Id;
+  -> Expr l Expr r;   // function call
+}

Added: vendor/elsa/current/elkhound/triv/DeclExpr.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/DeclExpr.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/DeclExpr.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ALBRSASBS
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/DeclExpr.in10
===================================================================
--- vendor/elsa/current/elkhound/triv/DeclExpr.in10	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/DeclExpr.in10	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBS
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/DeclExpr.in100
===================================================================
--- vendor/elsa/current/elkhound/triv/DeclExpr.in100	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/DeclExpr.in100	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBS
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/DeclExpr.in1000
===================================================================
--- vendor/elsa/current/elkhound/triv/DeclExpr.in1000	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/DeclExpr.in1000	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBS
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/DeclExpr.in10000
===================================================================
--- vendor/elsa/current/elkhound/triv/DeclExpr.in10000	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/DeclExpr.in10000	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBS
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/DeclExpr.in5
===================================================================
--- vendor/elsa/current/elkhound/triv/DeclExpr.in5	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/DeclExpr.in5	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ALBRSASBSALBRSASBSALBRSASBSALBRSASBSALBRSASBS
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/DeclExpr.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/DeclExpr.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/DeclExpr.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+1: %%% progress: 0ms: lexing...
+1: %%% progress: 0ms: reading parse tables file triv/DeclExpr.bin
+1: %%% progress: 1ms: parsing...
+1: %%% progress: 1ms: done parsing (0 ms, 0_511808 cycles)
+1: stack nodes: 0, max stack nodes: 15
+1: detShift=5, detReduce=11, nondetShift=9, nondetReduce=11
+1: yieldThenMergeCt = 0
+1: totalExtracts = 0
+1: multipleDelayedExtracts = 0
+1: tree nodes: 0
+10: %%% progress: 0ms: lexing...
+10: %%% progress: 0ms: reading parse tables file triv/DeclExpr.bin
+10: %%% progress: 0ms: parsing...
+10: %%% progress: 1ms: done parsing (1 ms, 0_202477 cycles)
+10: stack nodes: 0, max stack nodes: 15
+10: detShift=41, detReduce=101, nondetShift=90, nondetReduce=110
+10: yieldThenMergeCt = 0
+10: totalExtracts = 0
+10: multipleDelayedExtracts = 0
+10: tree nodes: 0
+100: %%% progress: 0ms: lexing...
+100: %%% progress: 1ms: reading parse tables file triv/DeclExpr.bin
+100: %%% progress: 1ms: parsing...
+100: %%% progress: 3ms: done parsing (2 ms, 1_502390 cycles)
+100: stack nodes: 0, max stack nodes: 15
+100: detShift=401, detReduce=1001, nondetShift=900, nondetReduce=1100
+100: yieldThenMergeCt = 0
+100: totalExtracts = 0
+100: multipleDelayedExtracts = 0
+100: tree nodes: 0
+1000: %%% progress: 0ms: lexing...
+1000: %%% progress: 5ms: reading parse tables file triv/DeclExpr.bin
+1000: %%% progress: 5ms: parsing...
+1000: %%% progress: 21ms: done parsing (16 ms, 15_946412 cycles)
+1000: stack nodes: 0, max stack nodes: 15
+1000: detShift=4001, detReduce=10001, nondetShift=9000, nondetReduce=11000
+1000: yieldThenMergeCt = 0
+1000: totalExtracts = 0
+1000: multipleDelayedExtracts = 0
+1000: tree nodes: 0
+10000: %%% progress: 0ms: lexing...
+10000: %%% progress: 60ms: reading parse tables file triv/DeclExpr.bin
+10000: %%% progress: 61ms: parsing...
+10000: %%% progress: 220ms: done parsing (159 ms, 158_793112 cycles)
+10000: stack nodes: 0, max stack nodes: 15
+10000: detShift=40001, detReduce=100001, nondetShift=90000, nondetReduce=110000
+10000: yieldThenMergeCt = 0
+10000: totalExtracts = 0
+10000: multipleDelayedExtracts = 0
+10000: tree nodes: 0

Added: vendor/elsa/current/elkhound/triv/EEb.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/EEb.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/EEb.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// EEb.gr.in   -*- c++ -*-
+// a simple ambiguous arithmetic grammar
+
+// E -> E + E | b
+
+terminals {
+  p        // plus
+  b
+}
+
+nonterm E {
+  fun merge(L,R) [ cout << "merging E\n"; return ++count; ]
+  fun dup(v)     [ return ++count; ]
+  fun del(v)     []
+
+  -> a:E p b:E ;
+  -> b         ; 
+}

Added: vendor/elsa/current/elkhound/triv/EEb.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/EEb.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/EEb.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+BPB
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/EEb.in2
===================================================================
--- vendor/elsa/current/elkhound/triv/EEb.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/EEb.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+BPBPB
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/EEb.in3
===================================================================
--- vendor/elsa/current/elkhound/triv/EEb.in3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/EEb.in3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+BPBPBPB
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/EFa.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/EFa.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/EFa.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// EFa.gr.in   -*- c++ -*-
+// deterministic grammar from even-faster
+
+// S -> E
+// E -> E + F | F
+// F -> a | ( E )
+
+terminals {
+  a     // a
+  p     // +
+  l     // (
+  r     // )
+}
+
+nonterm S {
+  -> e:E;
+}
+
+nonterm E {
+  -> e:E p f:F;
+  -> f:F;
+}
+
+nonterm F {
+  -> a;
+  -> l e:E r;
+}

Added: vendor/elsa/current/elkhound/triv/ESb.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/ESb.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ESb.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// ESb.gr   -*- c++ -*-
+// this grammar causes Tomita's algorithm to loop forever..
+// what does mine do?  it works ok.
+
+// S -> E S b | a
+// E -> /*epsilon*/
+
+terminals {
+  65 : a   ;
+  66 : b   ;
+}
+
+nonterm S {
+  -> E S b;
+  -> a;
+}
+
+nonterm E {
+  -> empty;
+}
+
+
+

Added: vendor/elsa/current/elkhound/triv/ESb.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/ESb.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ESb.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ABBB
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/SSSx.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/SSSx.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/SSSx.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// SSSx.gr.in   -*- c++ -*-
+// second nondeterministic grammar from even-faster
+
+// S -> S S S x | S x | x
+
+// number of parse trees:
+//
+//
+//   C(n) = C(n-1) +  SUM   C(m) * C(p) * C(q)
+//                  0<m,p,q
+//                s.t. m+p+q=n-1
+//   C(1) = 1
+
+
+terminals {
+  x
+}
+
+nonterm S {
+  -> a:S b:S c:S x;
+  -> a:S x;
+  -> x;
+}

Added: vendor/elsa/current/elkhound/triv/SSx.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/SSx.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/SSx.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// SSx.gr.in   -*- c++ -*-
+// first nondeterministic grammar from even-faster
+
+// S -> S S x | x
+
+terminals {
+  x
+}
+
+nonterm S {
+  -> a:S b:S x;
+  -> x;
+}

Added: vendor/elsa/current/elkhound/triv/aSEb.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/aSEb.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/aSEb.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// aSEb.gr
+// this grammar causes GLR to add a second sibling link to a node
+// after that node already has another node pointing to it (which
+// is potentially a problem for my mini-LR detection method)
+
+// S -> a S E | b
+// E -> /*epsilon*/
+
+terminals {
+  65 : a   ;
+  66 : b   ;
+}
+
+nonterm S {
+  -> a S E;
+  -> b;
+}
+
+nonterm E {
+  -> empty;
+}
+
+
+

Added: vendor/elsa/current/elkhound/triv/aSEb.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/aSEb.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/aSEb.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+AAB
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/angle.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/angle.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/angle.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,51 @@
+// angle.gr.in  -*- c++ -*-
+// abstracted problem with templates and angle brackets
+
+terminals {
+  60 : LANGLE "<";
+  61 : EQUAL  "=";
+  62 : RANGLE ">";
+  38 : AND    "&";
+  49 : ONE    "1";
+  59 : SEMI   ";";
+  40 : LPAREN "(";
+  41 : RPAREN ")";
+  43 : PLUS   "+";
+
+  precedence {
+    left 100 "+";
+    //left  80 ">";
+    left  60 "&";
+  }
+}
+
+// declaration
+nonterm D {
+  // main rule of interest
+  -> "<" e:E_low ">" ";";
+
+  // just to test parsing of exprs in another context
+  -> "=" e:E_low ";";
+}
+
+// exprs with higher precedence than ">"
+nonterm E_high {
+  -> "1";
+  -> e1:E_high "+" e2:E_high;
+  -> "(" e:E_low ")";
+}
+
+// exprs with ">"
+nonterm E_mid {
+  -> e:E_high;
+  -> e1:E_mid ">" e2:E_high;
+  -> e1:E_mid "<" e2:E_high;
+}
+
+// exprs with lower precedence than ">"
+nonterm E_low {
+  -> e:E_mid;
+  -> e1:E_low "&" e2:E_mid;
+}
+
+

Added: vendor/elsa/current/elkhound/triv/angle.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/angle.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/angle.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+<1>;
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/angle.in2
===================================================================
--- vendor/elsa/current/elkhound/triv/angle.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/angle.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+<1+1>;
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/angle.in3
===================================================================
--- vendor/elsa/current/elkhound/triv/angle.in3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/angle.in3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+<1&1>;
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/angle.in4
===================================================================
--- vendor/elsa/current/elkhound/triv/angle.in4	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/angle.in4	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+=1>1+1+1>1&1<1>1;
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/angle.in5
===================================================================
--- vendor/elsa/current/elkhound/triv/angle.in5	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/angle.in5	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+<1&1>1>;
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/eeb.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/eeb.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/eeb.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+10: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+10: %%% progress: 2ms: parsing...
+10: %%% progress: 2ms: done parsing (0 ms) (491508 cycles)
+10: stack nodes: 3, max stack nodes: 32
+10: tree nodes: 0
+20: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+20: %%% progress: 2ms: parsing...
+20: %%% progress: 4ms: done parsing (2 ms) (2818079 cycles)
+20: stack nodes: 3, max stack nodes: 62
+20: tree nodes: 0
+50: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+50: %%% progress: 2ms: parsing...
+50: %%% progress: 69ms: done parsing (67 ms) (66833743 cycles)
+50: stack nodes: 3, max stack nodes: 152
+50: tree nodes: 0
+100: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+100: %%% progress: 1ms: parsing...
+100: %%% progress: 886ms: done parsing (885 ms) (883382594 cycles)
+100: stack nodes: 3, max stack nodes: 302
+100: tree nodes: 0
+200: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+200: %%% progress: 2ms: parsing...
+200: %%% progress: 21688ms: done parsing (21686 ms) (21650531698 cycles)
+200: stack nodes: 3, max stack nodes: 602
+200: tree nodes: 0
+300: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+300: %%% progress: 2ms: parsing...
+300: %%% progress: 119230ms: done parsing (119228 ms) (119033931268 cycles)
+300: stack nodes: 3, max stack nodes: 902
+300: tree nodes: 0
+400: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+400: %%% progress: 2ms: parsing...
+400: %%% progress: 377416ms: done parsing (377414 ms) (376800329856 cycles)
+400: stack nodes: 3, max stack nodes: 1202
+400: tree nodes: 0
+500: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+500: %%% progress: 2ms: parsing...
+500: %%% progress: 923513ms: done parsing (923511 ms) (922008238470 cycles)
+500: stack nodes: 3, max stack nodes: 1502
+500: tree nodes: 0

Added: vendor/elsa/current/elkhound/triv/eeb.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/eeb.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/eeb.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,48 @@
+10: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+10: %%% progress: 2ms: parsing...
+10: %%% progress: 3ms: done parsing (1 ms) (1505578 cycles)
+10: stack nodes: 3, max stack nodes: 32
+10: num parses: 16796
+10: tree nodes: 231
+20: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+20: %%% progress: 2ms: parsing...
+20: %%% progress: 6ms: done parsing (4 ms) (4257318 cycles)
+20: stack nodes: 3, max stack nodes: 62
+20: num parses: 6.56412e+09
+20: tree nodes: 1561
+50: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+50: %%% progress: 2ms: parsing...
+50: %%% progress: 88ms: done parsing (86 ms) (85995163 cycles)
+50: stack nodes: 3, max stack nodes: 152
+50: num parses: 1.97826e+27
+50: tree nodes: 22151
+100: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+100: %%% progress: 2ms: parsing...
+100: %%% progress: 1798ms: done parsing (1796 ms) (1793372018 cycles)
+100: stack nodes: 3, max stack nodes: 302
+100: num parses: 8.9652e+56
+100: tree nodes: 171801
+200: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+200: %%% progress: 2ms: parsing...
+200: %%% progress: 48138ms: done parsing (48136 ms) (48057959428 cycles)
+200: stack nodes: 3, max stack nodes: 602
+200: num parses: 5.12201e+116
+200: tree nodes: 1353601
+300: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+300: %%% progress: 2ms: parsing...
+300: %%% progress: 256131ms: done parsing (256129 ms) (255711956383 cycles)
+300: stack nodes: 3, max stack nodes: 902
+300: num parses: 4.48864e+176
+300: tree nodes: 4545401
+400: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+400: %%% progress: 2ms: parsing...
+400: %%% progress: 823036ms: done parsing (823034 ms) (821694785100 cycles)
+400: stack nodes: 3, max stack nodes: 1202
+400: num parses: 4.68934e+236
+400: tree nodes: 10747201
+500: %%% progress: 0ms: reading binary grammar file EEb.tree.bin
+500: %%% progress: 2ms: parsing...
+500: %%% progress: 2040164ms: done parsing (2040162 ms) (2036841762687 cycles)
+500: stack nodes: 3, max stack nodes: 1502
+500: num parses: 5.39497e+296
+500: tree nodes: 20959001

Added: vendor/elsa/current/elkhound/triv/efa.bison.notree.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.bison.notree.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.bison.notree.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 0126532
+0000500, 0125478
+0000500, 0126617
+0000500, 0125822
+0000500, 0126395
+0001000, 0256056
+0001000, 0256962
+0001000, 0255224
+0001000, 0255897
+0001000, 0256022
+0001500, 0380985
+0001500, 0380570
+0001500, 0380983
+0001500, 0381148
+0001500, 0381272
+0002000, 0509838
+0002000, 0508738
+0002000, 0539636
+0002000, 0535969
+0002000, 0511226
+0002500, 0701609
+0002500, 0687091
+0002500, 0755376
+0002500, 1063098
+0002500, 0732213
+0005000, 2586489
+0005000, 2655888
+0005000, 2672733
+0005000, 2567284
+0005000, 2557218
+0010000, 4855776
+0010000, 5246707
+0010000, 5406645
+0010000, 4929066
+0010000, 7223047
+0020000, 9677752
+0020000, 11656237
+0020000, 9587632
+0020000, 9688545
+0020000, 11506215
+0050000, 23144827
+0050000, 23326695
+0050000, 23396685
+0050000, 23357902
+0050000, 23378332
+0100000, 45990682
+0100000, 46757032
+0100000, 46351312
+0100000, 46141477
+0100000, 46660462
+0200000, 93059317
+0200000, 93009832
+0200000, 91784775
+0200000, 92100540
+0200000, 91589040
+0500000, 229622197
+0500000, 246277717
+0500000, 229970902
+0500000, 229859347
+0500000, 231096502
+1000000, 463483342
+1000000, 461323867
+1000000, 480984952
+1000000, 463225762
+1000000, 460732500

Added: vendor/elsa/current/elkhound/triv/efa.bison.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.bison.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.bison.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,260 @@
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 1ms: starting parse...
+efa.in/0000500.in: %%% progress: 1ms: finished parse (0 ms, 0_126532 cycles)
+efa.in/0000500.in: tree nodes: 0
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 1ms: starting parse...
+efa.in/0000500.in: %%% progress: 1ms: finished parse (0 ms, 0_125478 cycles)
+efa.in/0000500.in: tree nodes: 0
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 1ms: starting parse...
+efa.in/0000500.in: %%% progress: 1ms: finished parse (0 ms, 0_126617 cycles)
+efa.in/0000500.in: tree nodes: 0
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 0ms: starting parse...
+efa.in/0000500.in: %%% progress: 0ms: finished parse (0 ms, 0_125822 cycles)
+efa.in/0000500.in: tree nodes: 0
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 1ms: starting parse...
+efa.in/0000500.in: %%% progress: 1ms: finished parse (0 ms, 0_126395 cycles)
+efa.in/0000500.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 3ms: starting parse...
+efa.in/0001000.in: %%% progress: 4ms: finished parse (0 ms, 0_256056 cycles)
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 2ms: starting parse...
+efa.in/0001000.in: %%% progress: 2ms: finished parse (0 ms, 0_256962 cycles)
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 1ms: starting parse...
+efa.in/0001000.in: %%% progress: 2ms: finished parse (1 ms, 0_255224 cycles)
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 1ms: starting parse...
+efa.in/0001000.in: %%% progress: 2ms: finished parse (1 ms, 0_255897 cycles)
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 2ms: starting parse...
+efa.in/0001000.in: %%% progress: 2ms: finished parse (0 ms, 0_256022 cycles)
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 2ms: finished parse (0 ms, 0_380985 cycles)
+efa.in/0001500.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 3ms: finished parse (1 ms, 0_380570 cycles)
+efa.in/0001500.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 2ms: finished parse (0 ms, 0_380983 cycles)
+efa.in/0001500.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 2ms: finished parse (0 ms, 0_381148 cycles)
+efa.in/0001500.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 2ms: finished parse (0 ms, 0_381272 cycles)
+efa.in/0001500.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 3ms: starting parse...
+efa.in/0002000.in: %%% progress: 3ms: finished parse (0 ms, 0_509838 cycles)
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 3ms: starting parse...
+efa.in/0002000.in: %%% progress: 3ms: finished parse (0 ms, 0_508738 cycles)
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 2ms: starting parse...
+efa.in/0002000.in: %%% progress: 3ms: finished parse (1 ms, 0_539636 cycles)
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 2ms: starting parse...
+efa.in/0002000.in: %%% progress: 3ms: finished parse (1 ms, 0_535969 cycles)
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 3ms: starting parse...
+efa.in/0002000.in: %%% progress: 3ms: finished parse (0 ms, 0_511226 cycles)
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 4ms: finished parse (1 ms, 0_701609 cycles)
+efa.in/0002500.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 4ms: finished parse (0 ms, 0_687091 cycles)
+efa.in/0002500.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 4ms: finished parse (1 ms, 0_755376 cycles)
+efa.in/0002500.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 6ms: starting parse...
+efa.in/0002500.in: %%% progress: 7ms: finished parse (1 ms, 1_063098 cycles)
+efa.in/0002500.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 3ms: finished parse (0 ms, 0_732213 cycles)
+efa.in/0002500.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 6ms: starting parse...
+efa.in/0005000.in: %%% progress: 9ms: finished parse (3 ms, 2_586489 cycles)
+efa.in/0005000.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 6ms: starting parse...
+efa.in/0005000.in: %%% progress: 9ms: finished parse (3 ms, 2_655888 cycles)
+efa.in/0005000.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 6ms: starting parse...
+efa.in/0005000.in: %%% progress: 9ms: finished parse (3 ms, 2_672733 cycles)
+efa.in/0005000.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 7ms: starting parse...
+efa.in/0005000.in: %%% progress: 9ms: finished parse (2 ms, 2_567284 cycles)
+efa.in/0005000.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 12ms: starting parse...
+efa.in/0005000.in: %%% progress: 15ms: finished parse (3 ms, 2_557218 cycles)
+efa.in/0005000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 15ms: starting parse...
+efa.in/0010000.in: %%% progress: 19ms: finished parse (4 ms, 4_855776 cycles)
+efa.in/0010000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 12ms: starting parse...
+efa.in/0010000.in: %%% progress: 17ms: finished parse (5 ms, 5_246707 cycles)
+efa.in/0010000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 12ms: starting parse...
+efa.in/0010000.in: %%% progress: 18ms: finished parse (6 ms, 5_406645 cycles)
+efa.in/0010000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 12ms: starting parse...
+efa.in/0010000.in: %%% progress: 17ms: finished parse (4 ms, 4_929066 cycles)
+efa.in/0010000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 14ms: starting parse...
+efa.in/0010000.in: %%% progress: 22ms: finished parse (7 ms, 7_223047 cycles)
+efa.in/0010000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 27ms: starting parse...
+efa.in/0020000.in: %%% progress: 37ms: finished parse (10 ms, 9_677752 cycles)
+efa.in/0020000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 24ms: starting parse...
+efa.in/0020000.in: %%% progress: 35ms: finished parse (11 ms, 11_656237 cycles)
+efa.in/0020000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 26ms: starting parse...
+efa.in/0020000.in: %%% progress: 36ms: finished parse (9 ms, 9_587632 cycles)
+efa.in/0020000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 24ms: starting parse...
+efa.in/0020000.in: %%% progress: 34ms: finished parse (10 ms, 9_688545 cycles)
+efa.in/0020000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 25ms: starting parse...
+efa.in/0020000.in: %%% progress: 36ms: finished parse (11 ms, 11_506215 cycles)
+efa.in/0020000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 65ms: starting parse...
+efa.in/0050000.in: %%% progress: 88ms: finished parse (23 ms, 23_144827 cycles)
+efa.in/0050000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 63ms: starting parse...
+efa.in/0050000.in: %%% progress: 86ms: finished parse (23 ms, 23_326695 cycles)
+efa.in/0050000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 64ms: starting parse...
+efa.in/0050000.in: %%% progress: 87ms: finished parse (23 ms, 23_396685 cycles)
+efa.in/0050000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 63ms: starting parse...
+efa.in/0050000.in: %%% progress: 86ms: finished parse (23 ms, 23_357902 cycles)
+efa.in/0050000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 64ms: starting parse...
+efa.in/0050000.in: %%% progress: 87ms: finished parse (23 ms, 23_378332 cycles)
+efa.in/0050000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 126ms: starting parse...
+efa.in/0100000.in: %%% progress: 172ms: finished parse (46 ms, 45_990682 cycles)
+efa.in/0100000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 130ms: starting parse...
+efa.in/0100000.in: %%% progress: 177ms: finished parse (47 ms, 46_757032 cycles)
+efa.in/0100000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 123ms: starting parse...
+efa.in/0100000.in: %%% progress: 170ms: finished parse (47 ms, 46_351312 cycles)
+efa.in/0100000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 126ms: starting parse...
+efa.in/0100000.in: %%% progress: 173ms: finished parse (47 ms, 46_141477 cycles)
+efa.in/0100000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 122ms: starting parse...
+efa.in/0100000.in: %%% progress: 169ms: finished parse (47 ms, 46_660462 cycles)
+efa.in/0100000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 244ms: starting parse...
+efa.in/0200000.in: %%% progress: 337ms: finished parse (93 ms, 93_059317 cycles)
+efa.in/0200000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 246ms: starting parse...
+efa.in/0200000.in: %%% progress: 339ms: finished parse (93 ms, 93_009832 cycles)
+efa.in/0200000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 244ms: starting parse...
+efa.in/0200000.in: %%% progress: 337ms: finished parse (92 ms, 91_784775 cycles)
+efa.in/0200000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 245ms: starting parse...
+efa.in/0200000.in: %%% progress: 337ms: finished parse (92 ms, 92_100540 cycles)
+efa.in/0200000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 244ms: starting parse...
+efa.in/0200000.in: %%% progress: 336ms: finished parse (92 ms, 91_589040 cycles)
+efa.in/0200000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 605ms: starting parse...
+efa.in/0500000.in: %%% progress: 835ms: finished parse (230 ms, 229_622197 cycles)
+efa.in/0500000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 604ms: starting parse...
+efa.in/0500000.in: %%% progress: 851ms: finished parse (247 ms, 246_277717 cycles)
+efa.in/0500000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 606ms: starting parse...
+efa.in/0500000.in: %%% progress: 837ms: finished parse (230 ms, 229_970902 cycles)
+efa.in/0500000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 605ms: starting parse...
+efa.in/0500000.in: %%% progress: 835ms: finished parse (230 ms, 229_859347 cycles)
+efa.in/0500000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 605ms: starting parse...
+efa.in/0500000.in: %%% progress: 837ms: finished parse (232 ms, 231_096502 cycles)
+efa.in/0500000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1200ms: starting parse...
+efa.in/1000000.in: %%% progress: 1664ms: finished parse (464 ms, 463_483342 cycles)
+efa.in/1000000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1201ms: starting parse...
+efa.in/1000000.in: %%% progress: 1664ms: finished parse (462 ms, 461_323867 cycles)
+efa.in/1000000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1202ms: starting parse...
+efa.in/1000000.in: %%% progress: 1684ms: finished parse (482 ms, 480_984952 cycles)
+efa.in/1000000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1203ms: starting parse...
+efa.in/1000000.in: %%% progress: 1667ms: finished parse (464 ms, 463_225762 cycles)
+efa.in/1000000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1202ms: starting parse...
+efa.in/1000000.in: %%% progress: 1664ms: finished parse (462 ms, 460_732500 cycles)
+efa.in/1000000.in: tree nodes: 0

Added: vendor/elsa/current/elkhound/triv/efa.bison.tree.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.bison.tree.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.bison.tree.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 0409967
+0000500, 0402073
+0000500, 0409427
+0000500, 0406030
+0000500, 0406857
+0001000, 0794551
+0001000, 0831676
+0001000, 0801931
+0001000, 0797899
+0001000, 0795732
+0001500, 1307375
+0001500, 1262901
+0001500, 1275180
+0001500, 1281265
+0001500, 1273859
+0002000, 2567858
+0002000, 1985823
+0002000, 1904870
+0002000, 4452264
+0002000, 1859611
+0002500, 2925418
+0002500, 2758094
+0002500, 2732270
+0002500, 2740833
+0002500, 2710916
+0005000, 5557829
+0005000, 7782870
+0005000, 5530129
+0005000, 7823340
+0005000, 5517343
+0010000, 11135400
+0010000, 11105005
+0010000, 20634900
+0010000, 11215267
+0010000, 11109674
+0020000, 24214252
+0020000, 24377700
+0020000, 21839220
+0020000, 24230497
+0020000, 22159552
+0050000, 55062742
+0050000, 55105912
+0050000, 55359712
+0050000, 54783987
+0050000, 54969537
+0100000, 112180605
+0100000, 111518835
+0100000, 110344584
+0100000, 113764755
+0100000, 112044255
+0200000, 220271287
+0200000, 221184187
+0200000, 219794407
+0200000, 220282825
+0200000, 225149610
+0500000, 557640202
+0500000, 553795852
+0500000, 560650807
+0500000, 553728322
+0500000, 550761030
+1000000, 1124463652
+1000000, 1100841097
+1000000, 1109106217
+1000000, 1112083710
+1000000, 1116926760

Added: vendor/elsa/current/elkhound/triv/efa.bison.tree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.bison.tree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.bison.tree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,260 @@
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 1ms: starting parse...
+efa.in/0000500.in: %%% progress: 2ms: finished parse (1 ms, 0_409967 cycles)
+efa.in/0000500.in: tree nodes: 1002
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 0ms: starting parse...
+efa.in/0000500.in: %%% progress: 1ms: finished parse (1 ms, 0_402073 cycles)
+efa.in/0000500.in: tree nodes: 1002
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 0ms: starting parse...
+efa.in/0000500.in: %%% progress: 1ms: finished parse (1 ms, 0_409427 cycles)
+efa.in/0000500.in: tree nodes: 1002
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 0ms: starting parse...
+efa.in/0000500.in: %%% progress: 1ms: finished parse (0 ms, 0_406030 cycles)
+efa.in/0000500.in: tree nodes: 1002
+efa.in/0000500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0000500.in: %%% progress: 1ms: starting parse...
+efa.in/0000500.in: %%% progress: 1ms: finished parse (0 ms, 0_406857 cycles)
+efa.in/0000500.in: tree nodes: 1002
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 1ms: starting parse...
+efa.in/0001000.in: %%% progress: 2ms: finished parse (1 ms, 0_794551 cycles)
+efa.in/0001000.in: tree nodes: 2002
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 1ms: starting parse...
+efa.in/0001000.in: %%% progress: 2ms: finished parse (0 ms, 0_831676 cycles)
+efa.in/0001000.in: tree nodes: 2002
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 1ms: starting parse...
+efa.in/0001000.in: %%% progress: 2ms: finished parse (1 ms, 0_801931 cycles)
+efa.in/0001000.in: tree nodes: 2002
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 1ms: starting parse...
+efa.in/0001000.in: %%% progress: 2ms: finished parse (1 ms, 0_797899 cycles)
+efa.in/0001000.in: tree nodes: 2002
+efa.in/0001000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001000.in: %%% progress: 2ms: starting parse...
+efa.in/0001000.in: %%% progress: 3ms: finished parse (1 ms, 0_795732 cycles)
+efa.in/0001000.in: tree nodes: 2002
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 3ms: finished parse (1 ms, 1_307375 cycles)
+efa.in/0001500.in: tree nodes: 3002
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 1ms: starting parse...
+efa.in/0001500.in: %%% progress: 3ms: finished parse (2 ms, 1_262901 cycles)
+efa.in/0001500.in: tree nodes: 3002
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 3ms: finished parse (1 ms, 1_275180 cycles)
+efa.in/0001500.in: tree nodes: 3002
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 3ms: finished parse (1 ms, 1_281265 cycles)
+efa.in/0001500.in: tree nodes: 3002
+efa.in/0001500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0001500.in: %%% progress: 2ms: starting parse...
+efa.in/0001500.in: %%% progress: 3ms: finished parse (1 ms, 1_273859 cycles)
+efa.in/0001500.in: tree nodes: 3002
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 2ms: starting parse...
+efa.in/0002000.in: %%% progress: 5ms: finished parse (2 ms, 2_567858 cycles)
+efa.in/0002000.in: tree nodes: 4002
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 3ms: starting parse...
+efa.in/0002000.in: %%% progress: 5ms: finished parse (2 ms, 1_985823 cycles)
+efa.in/0002000.in: tree nodes: 4002
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 3ms: starting parse...
+efa.in/0002000.in: %%% progress: 5ms: finished parse (2 ms, 1_904870 cycles)
+efa.in/0002000.in: tree nodes: 4002
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 2ms: starting parse...
+efa.in/0002000.in: %%% progress: 7ms: finished parse (5 ms, 4_452264 cycles)
+efa.in/0002000.in: tree nodes: 4002
+efa.in/0002000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002000.in: %%% progress: 3ms: starting parse...
+efa.in/0002000.in: %%% progress: 5ms: finished parse (2 ms, 1_859611 cycles)
+efa.in/0002000.in: tree nodes: 4002
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 6ms: finished parse (3 ms, 2_925418 cycles)
+efa.in/0002500.in: tree nodes: 5002
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 6ms: finished parse (3 ms, 2_758094 cycles)
+efa.in/0002500.in: tree nodes: 5002
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 6ms: finished parse (3 ms, 2_732270 cycles)
+efa.in/0002500.in: tree nodes: 5002
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 6ms: finished parse (3 ms, 2_740833 cycles)
+efa.in/0002500.in: tree nodes: 5002
+efa.in/0002500.in: %%% progress: 0ms: lexical analysis...
+efa.in/0002500.in: %%% progress: 3ms: starting parse...
+efa.in/0002500.in: %%% progress: 5ms: finished parse (2 ms, 2_710916 cycles)
+efa.in/0002500.in: tree nodes: 5002
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 7ms: starting parse...
+efa.in/0005000.in: %%% progress: 12ms: finished parse (5 ms, 5_557829 cycles)
+efa.in/0005000.in: tree nodes: 10002
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 6ms: starting parse...
+efa.in/0005000.in: %%% progress: 14ms: finished parse (8 ms, 7_782870 cycles)
+efa.in/0005000.in: tree nodes: 10002
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 7ms: starting parse...
+efa.in/0005000.in: %%% progress: 12ms: finished parse (5 ms, 5_530129 cycles)
+efa.in/0005000.in: tree nodes: 10002
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 6ms: starting parse...
+efa.in/0005000.in: %%% progress: 14ms: finished parse (8 ms, 7_823340 cycles)
+efa.in/0005000.in: tree nodes: 10002
+efa.in/0005000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0005000.in: %%% progress: 6ms: starting parse...
+efa.in/0005000.in: %%% progress: 12ms: finished parse (6 ms, 5_517343 cycles)
+efa.in/0005000.in: tree nodes: 10002
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 12ms: starting parse...
+efa.in/0010000.in: %%% progress: 23ms: finished parse (11 ms, 11_135400 cycles)
+efa.in/0010000.in: tree nodes: 20002
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 12ms: starting parse...
+efa.in/0010000.in: %%% progress: 24ms: finished parse (11 ms, 11_105005 cycles)
+efa.in/0010000.in: tree nodes: 20002
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 12ms: starting parse...
+efa.in/0010000.in: %%% progress: 33ms: finished parse (21 ms, 20_634900 cycles)
+efa.in/0010000.in: tree nodes: 20002
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 15ms: starting parse...
+efa.in/0010000.in: %%% progress: 26ms: finished parse (11 ms, 11_215267 cycles)
+efa.in/0010000.in: tree nodes: 20002
+efa.in/0010000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0010000.in: %%% progress: 12ms: starting parse...
+efa.in/0010000.in: %%% progress: 23ms: finished parse (11 ms, 11_109674 cycles)
+efa.in/0010000.in: tree nodes: 20002
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 24ms: starting parse...
+efa.in/0020000.in: %%% progress: 49ms: finished parse (25 ms, 24_214252 cycles)
+efa.in/0020000.in: tree nodes: 40002
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 25ms: starting parse...
+efa.in/0020000.in: %%% progress: 49ms: finished parse (24 ms, 24_377700 cycles)
+efa.in/0020000.in: tree nodes: 40002
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 26ms: starting parse...
+efa.in/0020000.in: %%% progress: 48ms: finished parse (22 ms, 21_839220 cycles)
+efa.in/0020000.in: tree nodes: 40002
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 24ms: starting parse...
+efa.in/0020000.in: %%% progress: 48ms: finished parse (24 ms, 24_230497 cycles)
+efa.in/0020000.in: tree nodes: 40002
+efa.in/0020000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0020000.in: %%% progress: 26ms: starting parse...
+efa.in/0020000.in: %%% progress: 49ms: finished parse (23 ms, 22_159552 cycles)
+efa.in/0020000.in: tree nodes: 40002
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 66ms: starting parse...
+efa.in/0050000.in: %%% progress: 122ms: finished parse (56 ms, 55_062742 cycles)
+efa.in/0050000.in: tree nodes: 100002
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 64ms: starting parse...
+efa.in/0050000.in: %%% progress: 119ms: finished parse (55 ms, 55_105912 cycles)
+efa.in/0050000.in: tree nodes: 100002
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 64ms: starting parse...
+efa.in/0050000.in: %%% progress: 120ms: finished parse (56 ms, 55_359712 cycles)
+efa.in/0050000.in: tree nodes: 100002
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 65ms: starting parse...
+efa.in/0050000.in: %%% progress: 120ms: finished parse (54 ms, 54_783987 cycles)
+efa.in/0050000.in: tree nodes: 100002
+efa.in/0050000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0050000.in: %%% progress: 65ms: starting parse...
+efa.in/0050000.in: %%% progress: 121ms: finished parse (55 ms, 54_969537 cycles)
+efa.in/0050000.in: tree nodes: 100002
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 123ms: starting parse...
+efa.in/0100000.in: %%% progress: 235ms: finished parse (112 ms, 112_180605 cycles)
+efa.in/0100000.in: tree nodes: 200002
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 124ms: starting parse...
+efa.in/0100000.in: %%% progress: 236ms: finished parse (112 ms, 111_518835 cycles)
+efa.in/0100000.in: tree nodes: 200002
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 125ms: starting parse...
+efa.in/0100000.in: %%% progress: 236ms: finished parse (111 ms, 110_344584 cycles)
+efa.in/0100000.in: tree nodes: 200002
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 123ms: starting parse...
+efa.in/0100000.in: %%% progress: 237ms: finished parse (114 ms, 113_764755 cycles)
+efa.in/0100000.in: tree nodes: 200002
+efa.in/0100000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0100000.in: %%% progress: 123ms: starting parse...
+efa.in/0100000.in: %%% progress: 235ms: finished parse (112 ms, 112_044255 cycles)
+efa.in/0100000.in: tree nodes: 200002
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 251ms: starting parse...
+efa.in/0200000.in: %%% progress: 471ms: finished parse (220 ms, 220_271287 cycles)
+efa.in/0200000.in: tree nodes: 400002
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 245ms: starting parse...
+efa.in/0200000.in: %%% progress: 466ms: finished parse (221 ms, 221_184187 cycles)
+efa.in/0200000.in: tree nodes: 400002
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 245ms: starting parse...
+efa.in/0200000.in: %%% progress: 465ms: finished parse (220 ms, 219_794407 cycles)
+efa.in/0200000.in: tree nodes: 400002
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 252ms: starting parse...
+efa.in/0200000.in: %%% progress: 473ms: finished parse (220 ms, 220_282825 cycles)
+efa.in/0200000.in: tree nodes: 400002
+efa.in/0200000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0200000.in: %%% progress: 244ms: starting parse...
+efa.in/0200000.in: %%% progress: 469ms: finished parse (225 ms, 225_149610 cycles)
+efa.in/0200000.in: tree nodes: 400002
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 601ms: starting parse...
+efa.in/0500000.in: %%% progress: 1159ms: finished parse (558 ms, 557_640202 cycles)
+efa.in/0500000.in: tree nodes: 1000002
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 606ms: starting parse...
+efa.in/0500000.in: %%% progress: 1160ms: finished parse (554 ms, 553_795852 cycles)
+efa.in/0500000.in: tree nodes: 1000002
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 607ms: starting parse...
+efa.in/0500000.in: %%% progress: 1169ms: finished parse (562 ms, 560_650807 cycles)
+efa.in/0500000.in: tree nodes: 1000002
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 603ms: starting parse...
+efa.in/0500000.in: %%% progress: 1158ms: finished parse (555 ms, 553_728322 cycles)
+efa.in/0500000.in: tree nodes: 1000002
+efa.in/0500000.in: %%% progress: 0ms: lexical analysis...
+efa.in/0500000.in: %%% progress: 608ms: starting parse...
+efa.in/0500000.in: %%% progress: 1159ms: finished parse (551 ms, 550_761030 cycles)
+efa.in/0500000.in: tree nodes: 1000002
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1200ms: starting parse...
+efa.in/1000000.in: %%% progress: 2327ms: finished parse (1126 ms, 1124_463652 cycles)
+efa.in/1000000.in: tree nodes: 2000002
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1205ms: starting parse...
+efa.in/1000000.in: %%% progress: 2308ms: finished parse (1103 ms, 1100_841097 cycles)
+efa.in/1000000.in: tree nodes: 2000002
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1210ms: starting parse...
+efa.in/1000000.in: %%% progress: 2321ms: finished parse (1111 ms, 1109_106217 cycles)
+efa.in/1000000.in: tree nodes: 2000002
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1208ms: starting parse...
+efa.in/1000000.in: %%% progress: 2322ms: finished parse (1114 ms, 1112_083710 cycles)
+efa.in/1000000.in: tree nodes: 2000002
+efa.in/1000000.in: %%% progress: 0ms: lexical analysis...
+efa.in/1000000.in: %%% progress: 1206ms: starting parse...
+efa.in/1000000.in: %%% progress: 2325ms: finished parse (1119 ms, 1116_926760 cycles)
+efa.in/1000000.in: tree nodes: 2000002

Added: vendor/elsa/current/elkhound/triv/efa.glronly.notree.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.glronly.notree.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.glronly.notree.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 1020099
+0000500, 1018078
+0000500, 1019708
+0000500, 1016002
+0000500, 1047348
+0001000, 2145881
+0001000, 2035523
+0001000, 2008953
+0001000, 2037247
+0001000, 2009018
+0001500, 3058388
+0001500, 3159908
+0001500, 3058050
+0001500, 3359257
+0001500, 3111083
+0002000, 4324330
+0002000, 4473362
+0002000, 4277655
+0002000, 4338603
+0002000, 6520545
+0002500, 9703959
+0002500, 5642871
+0002500, 5644080
+0002500, 5778277
+0002500, 7953997
+0005000, 11260044
+0005000, 11263037
+0005000, 11327280
+0005000, 11320317
+0005000, 11304336
+0010000, 22612277
+0010000, 22600710
+0010000, 22283968
+0010000, 24362078
+0010000, 22571865
+0020000, 44443175
+0020000, 47361877
+0020000, 46821210
+0020000, 46417425
+0020000, 44968312
+0050000, 112528027
+0050000, 112476405
+0050000, 111941775
+0050000, 112390433
+0050000, 110319765
+0100000, 225154627
+0100000, 229376865
+0100000, 225229815
+0100000, 226239532
+0100000, 225374227
+0200000, 468611812
+0200000, 457837567
+0200000, 467582873
+0200000, 454712152
+0200000, 456526725
+0500000, 1127847412
+0500000, 1140175507
+0500000, 1146785010
+0500000, 1142194492
+0500000, 1245552892
+1000000, 2271503572
+1000000, 2280008295
+1000000, 2260076407
+1000000, 2285263335
+1000000, 2285475097

Added: vendor/elsa/current/elkhound/triv/efa.glronly.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.glronly.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.glronly.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,390 @@
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 4ms: done parsing (1 ms, 1_020099 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 4ms: done parsing (1 ms, 1_018078 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 3ms: done parsing (1 ms, 1_019708 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 0ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 3ms: done parsing (1 ms, 1_016002 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 4ms: done parsing (1 ms, 1_047348 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 6ms: done parsing (2 ms, 2_145881 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (2 ms, 2_035523 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (2 ms, 2_008953 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (2 ms, 2_037247 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (2 ms, 2_009018 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 7ms: done parsing (3 ms, 3_058388 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 7ms: done parsing (3 ms, 3_159908 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 6ms: done parsing (3 ms, 3_058050 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 7ms: done parsing (3 ms, 3_359257 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 7ms: done parsing (3 ms, 3_111083 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 9ms: done parsing (5 ms, 4_324330 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 9ms: done parsing (5 ms, 4_473362 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 9ms: done parsing (5 ms, 4_277655 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 8ms: done parsing (4 ms, 4_338603 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 10ms: done parsing (6 ms, 6_520545 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 15ms: done parsing (10 ms, 9_703959 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 10ms: done parsing (5 ms, 5_642871 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 11ms: done parsing (6 ms, 5_644080 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 11ms: done parsing (6 ms, 5_778277 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (8 ms, 7_953997 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 7ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 9ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 20ms: done parsing (11 ms, 11_260044 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 11ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 22ms: done parsing (11 ms, 11_263037 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 8ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 20ms: done parsing (12 ms, 11_327280 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 8ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 19ms: done parsing (11 ms, 11_320317 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 8ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 19ms: done parsing (11 ms, 11_304336 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 13ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 16ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 38ms: done parsing (22 ms, 22_612277 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 37ms: done parsing (23 ms, 22_600710 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 36ms: done parsing (22 ms, 22_283968 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 14ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 16ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 40ms: done parsing (24 ms, 24_362078 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 37ms: done parsing (23 ms, 22_571865 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 25ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 27ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 71ms: done parsing (44 ms, 44_443175 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 24ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 73ms: done parsing (47 ms, 47_361877 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 24ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 27ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 74ms: done parsing (47 ms, 46_821210 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 24ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 72ms: done parsing (46 ms, 46_417425 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 24ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 71ms: done parsing (45 ms, 44_968312 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 70ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 72ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 185ms: done parsing (113 ms, 112_528027 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 62ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 65ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 177ms: done parsing (112 ms, 112_476405 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 62ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 64ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 176ms: done parsing (112 ms, 111_941775 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 62ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 64ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 176ms: done parsing (112 ms, 112_390433 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 61ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 63ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 174ms: done parsing (111 ms, 110_319765 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 126ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 128ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 353ms: done parsing (225 ms, 225_154627 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 120ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 122ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 352ms: done parsing (230 ms, 229_376865 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 119ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 121ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 347ms: done parsing (226 ms, 225_229815 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 127ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 129ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 356ms: done parsing (227 ms, 226_239532 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 124ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 126ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 351ms: done parsing (225 ms, 225_374227 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 258ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 260ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 729ms: done parsing (469 ms, 468_611812 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 234ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 237ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 695ms: done parsing (458 ms, 457_837567 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 238ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 240ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 709ms: done parsing (469 ms, 467_582873 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 240ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 242ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 698ms: done parsing (456 ms, 454_712152 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 243ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 245ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 702ms: done parsing (457 ms, 456_526725 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 641ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 643ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1773ms: done parsing (1130 ms, 1127_847412 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 594ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 596ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1739ms: done parsing (1143 ms, 1140_175507 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 594ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 596ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1744ms: done parsing (1149 ms, 1146_785010 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 590ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 592ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1736ms: done parsing (1144 ms, 1142_194492 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 602ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 604ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1852ms: done parsing (1248 ms, 1245_552892 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1264ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1266ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3542ms: done parsing (2276 ms, 2271_503572 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1216ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1219ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3502ms: done parsing (2283 ms, 2280_008295 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1191ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1193ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3457ms: done parsing (2264 ms, 2260_076407 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1191ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1193ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3482ms: done parsing (2289 ms, 2285_263335 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1186ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1188ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3477ms: done parsing (2289 ms, 2285_475097 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: tree nodes: 0

Added: vendor/elsa/current/elkhound/triv/efa.glronly.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.glronly.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.glronly.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 1818902
+0000500, 1456547
+0000500, 1463658
+0000500, 1491432
+0000500, 1451844
+0001000, 3533222
+0001000, 2994798
+0001000, 5422200
+0001000, 2992595
+0001000, 4250222
+0001500, 4655607
+0001500, 4683423
+0001500, 4952257
+0001500, 4929542
+0001500, 4645124
+0002000, 6310499
+0002000, 6810220
+0002000, 10551855
+0002000, 6285537
+0002000, 6296416
+0002500, 7963334
+0002500, 8196982
+0002500, 7932165
+0002500, 8171282
+0002500, 7918890
+0005000, 16427835
+0005000, 16099808
+0005000, 18830865
+0005000, 18440340
+0005000, 16256852
+0010000, 34433632
+0010000, 31521584
+0010000, 31497607
+0010000, 34544895
+0010000, 33898687
+0020000, 67147845
+0020000, 66516060
+0020000, 65200575
+0020000, 66149782
+0020000, 67074495
+0050000, 171209407
+0050000, 159231652
+0050000, 170619780
+0050000, 161373952
+0050000, 160806615
+0100000, 329909265
+0100000, 332898277
+0100000, 322539968
+0100000, 335081347
+0100000, 342944745
+0200000, 694641907
+0200000, 682739010
+0200000, 677267437
+0200000, 681761873
+0200000, 677434635
+0500000, 1638870577
+0500000, 1634025915
+0500000, 1637840025
+0500000, 1619840993
+0500000, 1622136398
+1000000, 3217928265
+1000000, 3230965627
+1000000, 3234608213
+1000000, 3247375275
+1000000, 3238480350

Added: vendor/elsa/current/elkhound/triv/efa.glronly.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.glronly.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.glronly.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,425 @@
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 5ms: done parsing (2 ms, 1_818902 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 5ms: done parsing (2 ms, 1_456547 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 4ms: done parsing (1 ms, 1_463658 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 0ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 4ms: done parsing (2 ms, 1_491432 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 4ms: done parsing (2 ms, 1_451844 cycles)
+triv/efa.in/0000500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 6ms: done parsing (3 ms, 3_533222 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 6ms: done parsing (3 ms, 2_994798 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 9ms: done parsing (6 ms, 5_422200 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 6ms: done parsing (3 ms, 2_992595 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 7ms: done parsing (4 ms, 4_250222 cycles)
+triv/efa.in/0001000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 8ms: done parsing (5 ms, 4_655607 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 9ms: done parsing (5 ms, 4_683423 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 8ms: done parsing (5 ms, 4_952257 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 1ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 8ms: done parsing (5 ms, 4_929542 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 9ms: done parsing (5 ms, 4_645124 cycles)
+triv/efa.in/0001500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 10ms: done parsing (6 ms, 6_310499 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 5ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 7ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 14ms: done parsing (7 ms, 6_810220 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 15ms: done parsing (11 ms, 10_551855 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 11ms: done parsing (6 ms, 6_285537 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 10ms: done parsing (6 ms, 6_296416 cycles)
+triv/efa.in/0002000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (8 ms, 7_963334 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (8 ms, 8_196982 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (8 ms, 7_932165 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 5ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 7ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 15ms: done parsing (8 ms, 8_171282 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 5ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (8 ms, 7_918890 cycles)
+triv/efa.in/0002500.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 8ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 25ms: done parsing (17 ms, 16_427835 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 8ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 25ms: done parsing (17 ms, 16_099808 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 7ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 9ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 28ms: done parsing (19 ms, 18_830865 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 8ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 26ms: done parsing (18 ms, 18_440340 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 8ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 24ms: done parsing (16 ms, 16_256852 cycles)
+triv/efa.in/0005000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 13ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 15ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 49ms: done parsing (34 ms, 34_433632 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 45ms: done parsing (31 ms, 31_521584 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 45ms: done parsing (31 ms, 31_497607 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 49ms: done parsing (35 ms, 34_544895 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 48ms: done parsing (34 ms, 33_898687 cycles)
+triv/efa.in/0010000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 23ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 25ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 92ms: done parsing (67 ms, 67_147845 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 23ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 25ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 92ms: done parsing (67 ms, 66_516060 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 24ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 92ms: done parsing (66 ms, 65_200575 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 24ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 92ms: done parsing (66 ms, 66_149782 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 23ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 25ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 92ms: done parsing (67 ms, 67_074495 cycles)
+triv/efa.in/0020000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 58ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 60ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 232ms: done parsing (172 ms, 171_209407 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 61ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 63ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 223ms: done parsing (160 ms, 159_231652 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 65ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 68ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 239ms: done parsing (171 ms, 170_619780 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 72ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 74ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 235ms: done parsing (161 ms, 161_373952 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 62ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 64ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 225ms: done parsing (161 ms, 160_806615 cycles)
+triv/efa.in/0050000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 121ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 123ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 453ms: done parsing (330 ms, 329_909265 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 120ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 122ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 455ms: done parsing (333 ms, 332_898277 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 119ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 121ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 444ms: done parsing (323 ms, 322_539968 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 120ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 122ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 458ms: done parsing (336 ms, 335_081347 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 121ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 123ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 466ms: done parsing (343 ms, 342_944745 cycles)
+triv/efa.in/0100000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 240ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 242ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 938ms: done parsing (696 ms, 694_641907 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 242ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 244ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 928ms: done parsing (684 ms, 682_739010 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 245ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 247ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 925ms: done parsing (678 ms, 677_267437 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 239ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 241ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 924ms: done parsing (683 ms, 681_761873 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 237ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 239ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 917ms: done parsing (678 ms, 677_434635 cycles)
+triv/efa.in/0200000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 592ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 594ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2235ms: done parsing (1641 ms, 1638_870577 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 593ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 597ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2233ms: done parsing (1636 ms, 1634_025915 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 593ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 595ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2235ms: done parsing (1640 ms, 1637_840025 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 594ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 596ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2219ms: done parsing (1623 ms, 1619_840993 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 594ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 597ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2221ms: done parsing (1624 ms, 1622_136398 cycles)
+triv/efa.in/0500000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1178ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1180ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 4403ms: done parsing (3223 ms, 3217_928265 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1191ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1193ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 4429ms: done parsing (3236 ms, 3230_965627 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1182ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1184ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 4424ms: done parsing (3240 ms, 3234_608213 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1185ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1192ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 4445ms: done parsing (3253 ms, 3247_375275 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1186ms: reading binary grammar file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1188ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 4432ms: done parsing (3244 ms, 3238_480350 cycles)
+triv/efa.in/1000000.in: stack nodes: 3, max stack nodes: 7

Added: vendor/elsa/current/elkhound/triv/efa.nohybrid.notree.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.nohybrid.notree.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.nohybrid.notree.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 1186088
+0000500, 1507897
+0000500, 1299515
+0000500, 1186610
+0000500, 1416511
+0001000, 2383251
+0001000, 2345563
+0001000, 5412046
+0001000, 2548121
+0001000, 2759184
+0001500, 3523349
+0001500, 7010724
+0001500, 3537530
+0001500, 3705466
+0001500, 4525876
+0002000, 4881346
+0002000, 4988292
+0002000, 6170617
+0002000, 5126161
+0002000, 4773463
+0002500, 6251143
+0002500, 6124703
+0002500, 6341810
+0002500, 6423958
+0002500, 7469978
+0005000, 16150545
+0005000, 13218262
+0005000, 14210872
+0005000, 16427917
+0005000, 15470535
+0010000, 26189595
+0010000, 35025337
+0010000, 29348850
+0010000, 26069752
+0010000, 27156952
+0020000, 53653260
+0020000, 54950872
+0020000, 62903182
+0020000, 57211897
+0020000, 55358347
+0050000, 132331882
+0050000, 137899042
+0050000, 134728177
+0050000, 133046197
+0050000, 141386542
+0100000, 265049737
+0100000, 263330280
+0100000, 265455802
+0100000, 264166732
+0100000, 263615467
+0200000, 537315247
+0200000, 537821227
+0200000, 532535820
+0200000, 528389752
+0200000, 532367797
+0500000, 1334191177
+0500000, 1334619600
+0500000, 1335230250
+0500000, 1335074542
+0500000, 1341445102
+1000000, 2682556912
+1000000, 2659579687
+1000000, 2659874587
+1000000, 2658354727
+1000000, 2650396087

Added: vendor/elsa/current/elkhound/triv/efa.nohybrid.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.nohybrid.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.nohybrid.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,455 @@
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 0ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 2ms: done parsing (1 ms, 1_186088 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 0ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 0ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 2ms: done parsing (2 ms, 1_507897 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 3ms: done parsing (2 ms, 1_299515 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 2ms: done parsing (1 ms, 1_186610 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 0ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 2ms: done parsing (1 ms, 1_416511 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 1ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 4ms: done parsing (3 ms, 2_383251 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 1ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 4ms: done parsing (3 ms, 2_345563 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 1ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 6ms: done parsing (5 ms, 5_412046 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (3 ms, 2_548121 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 1ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 4ms: done parsing (3 ms, 2_759184 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 5ms: done parsing (3 ms, 3_523349 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 9ms: done parsing (7 ms, 7_010724 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 6ms: done parsing (4 ms, 3_537530 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 6ms: done parsing (4 ms, 3_705466 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 7ms: done parsing (5 ms, 4_525876 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 8ms: done parsing (5 ms, 4_881346 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 2ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 7ms: done parsing (5 ms, 4_988292 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 9ms: done parsing (6 ms, 6_170617 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 2ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 7ms: done parsing (5 ms, 5_126161 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 8ms: done parsing (5 ms, 4_773463 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 9ms: done parsing (6 ms, 6_251143 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 9ms: done parsing (6 ms, 6_124703 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 9ms: done parsing (6 ms, 6_341810 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 10ms: done parsing (6 ms, 6_423958 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 11ms: done parsing (7 ms, 7_469978 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 6ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 22ms: done parsing (16 ms, 16_150545 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 9ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 9ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 22ms: done parsing (13 ms, 13_218262 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 7ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 21ms: done parsing (14 ms, 14_210872 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 6ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 23ms: done parsing (17 ms, 16_427917 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 7ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 7ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 22ms: done parsing (15 ms, 15_470535 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 16ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 16ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 42ms: done parsing (26 ms, 26_189595 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 12ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 48ms: done parsing (36 ms, 35_025337 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 13ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 42ms: done parsing (29 ms, 29_348850 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 14ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 41ms: done parsing (27 ms, 26_069752 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 13ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 40ms: done parsing (27 ms, 27_156952 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 28ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 28ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 82ms: done parsing (54 ms, 53_653260 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 25ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 81ms: done parsing (55 ms, 54_950872 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 25ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 89ms: done parsing (63 ms, 62_903182 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 24ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 24ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 81ms: done parsing (57 ms, 57_211897 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 25ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 25ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 81ms: done parsing (56 ms, 55_358347 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 65ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 66ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 198ms: done parsing (132 ms, 132_331882 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 69ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 69ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 207ms: done parsing (138 ms, 137_899042 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 64ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 65ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 199ms: done parsing (134 ms, 134_728177 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 66ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 66ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 199ms: done parsing (133 ms, 133_046197 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 69ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 69ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 211ms: done parsing (142 ms, 141_386542 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 132ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 133ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 398ms: done parsing (265 ms, 265_049737 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 138ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 138ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 402ms: done parsing (264 ms, 263_330280 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 126ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 126ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 392ms: done parsing (266 ms, 265_455802 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 126ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 127ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 391ms: done parsing (264 ms, 264_166732 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 127ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 127ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 391ms: done parsing (264 ms, 263_615467 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 252ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 252ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 791ms: done parsing (539 ms, 537_315247 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 250ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 251ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 789ms: done parsing (538 ms, 537_821227 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 253ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 254ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 787ms: done parsing (533 ms, 532_535820 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 253ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 253ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 783ms: done parsing (530 ms, 528_389752 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 251ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 252ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 785ms: done parsing (533 ms, 532_367797 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 624ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 625ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1961ms: done parsing (1336 ms, 1334_191177 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 626ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 626ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1963ms: done parsing (1337 ms, 1334_619600 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 640ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 640ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1977ms: done parsing (1337 ms, 1335_230250 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 626ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 627ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1964ms: done parsing (1337 ms, 1335_074542 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 627ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 627ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 1971ms: done parsing (1344 ms, 1341_445102 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1241ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1242ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3929ms: done parsing (2687 ms, 2682_556912 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1244ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1245ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3908ms: done parsing (2664 ms, 2659_579687 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1246ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1247ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3911ms: done parsing (2664 ms, 2659_874587 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1257ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1257ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3920ms: done parsing (2663 ms, 2658_354727 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: tree nodes: 0
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1240ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1240ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 3895ms: done parsing (2655 ms, 2650_396087 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: tree nodes: 0

Added: vendor/elsa/current/elkhound/triv/efa.nohybrid.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.nohybrid.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.nohybrid.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 1670590
+0000500, 1660775
+0000500, 2010755
+0000500, 2467872
+0000500, 1911502
+0001000, 3963433
+0001000, 3328816
+0001000, 3296897
+0001000, 3431078
+0001000, 4117175
+0001500, 5420844
+0001500, 8040446
+0001500, 8084630
+0001500, 5663236
+0001500, 5140152
+0002000, 7113510
+0002000, 7426640
+0002000, 7291508
+0002000, 9784288
+0002000, 7319580
+0002500, 11750910
+0002500, 9347557
+0002500, 9354397
+0002500, 9322005
+0002500, 9900525
+0005000, 20721315
+0005000, 20677365
+0005000, 25846410
+0005000, 21021150
+0005000, 22104630
+0010000, 39795232
+0010000, 39507938
+0010000, 39771562
+0010000, 37363763
+0010000, 39039165
+0020000, 73434082
+0020000, 76136400
+0020000, 75694523
+0020000, 80038883
+0020000, 76562490
+0050000, 190000552
+0050000, 187201447
+0050000, 184280962
+0050000, 191052983
+0050000, 187182690
+0100000, 373089660
+0100000, 370115692
+0100000, 370185577
+0100000, 373269547
+0100000, 372948413
+0200000, 748086030
+0200000, 743002762
+0200000, 742458097
+0200000, 739769017
+0200000, 744837532
+0500000, 1871914980
+0500000, 1865846857
+0500000, 1882869195
+0500000, 1858669815
+0500000, 1865956102
+1000000, 3827139532
+1000000, 3982385580
+1000000, 3740081617
+1000000, 3723388072
+1000000, 3733801852

Added: vendor/elsa/current/elkhound/triv/efa.nohybrid.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.nohybrid.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.nohybrid.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,490 @@
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 3ms: done parsing (2 ms, 1_670590 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 3ms: done parsing (2 ms, 1_660775 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 0ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 3ms: done parsing (2 ms, 2_010755 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 4ms: done parsing (3 ms, 2_467872 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0000500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0000500.in: %%% progress: 0ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0000500.in: %%% progress: 1ms: parsing...
+triv/efa.in/0000500.in: %%% progress: 2ms: done parsing (1 ms, 1_911502 cycles)
+triv/efa.in/0000500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0000500.in: detShift=0, detReduce=0, nondetShift=1002, nondetReduce=1003
+triv/efa.in/0000500.in: num parses: 1
+triv/efa.in/0000500.in: tree nodes: 1003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 1ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (4 ms, 3_963433 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 12ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 12ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 15ms: done parsing (3 ms, 3_328816 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 1ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (4 ms, 3_296897 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (3 ms, 3_431078 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001000.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001000.in: %%% progress: 1ms: parsing...
+triv/efa.in/0001000.in: %%% progress: 5ms: done parsing (4 ms, 4_117175 cycles)
+triv/efa.in/0001000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001000.in: detShift=0, detReduce=0, nondetShift=2002, nondetReduce=2003
+triv/efa.in/0001000.in: num parses: 1
+triv/efa.in/0001000.in: tree nodes: 2003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 7ms: done parsing (5 ms, 5_420844 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 1ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 10ms: done parsing (8 ms, 8_040446 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 10ms: done parsing (8 ms, 8_084630 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 7ms: done parsing (5 ms, 5_663236 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0001500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0001500.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0001500.in: %%% progress: 2ms: parsing...
+triv/efa.in/0001500.in: %%% progress: 7ms: done parsing (5 ms, 5_140152 cycles)
+triv/efa.in/0001500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0001500.in: detShift=0, detReduce=0, nondetShift=3002, nondetReduce=3003
+triv/efa.in/0001500.in: num parses: 1
+triv/efa.in/0001500.in: tree nodes: 3003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 2ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 10ms: done parsing (8 ms, 7_113510 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 2ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 10ms: done parsing (8 ms, 7_426640 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 2ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 10ms: done parsing (8 ms, 7_291508 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 2ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 2ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 12ms: done parsing (10 ms, 9_784288 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002000.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002000.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002000.in: %%% progress: 10ms: done parsing (7 ms, 7_319580 cycles)
+triv/efa.in/0002000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002000.in: detShift=0, detReduce=0, nondetShift=4002, nondetReduce=4003
+triv/efa.in/0002000.in: num parses: 1
+triv/efa.in/0002000.in: tree nodes: 4003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 15ms: done parsing (12 ms, 11_750910 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (10 ms, 9_347557 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 4ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (9 ms, 9_354397 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (10 ms, 9_322005 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0002500.in: %%% progress: 0ms: lexing...
+triv/efa.in/0002500.in: %%% progress: 3ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0002500.in: %%% progress: 3ms: parsing...
+triv/efa.in/0002500.in: %%% progress: 13ms: done parsing (10 ms, 9_900525 cycles)
+triv/efa.in/0002500.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0002500.in: detShift=0, detReduce=0, nondetShift=5002, nondetReduce=5003
+triv/efa.in/0002500.in: num parses: 1
+triv/efa.in/0002500.in: tree nodes: 5003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 7ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 7ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 28ms: done parsing (21 ms, 20_721315 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 7ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 27ms: done parsing (20 ms, 20_677365 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 6ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 32ms: done parsing (26 ms, 25_846410 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 7ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 28ms: done parsing (21 ms, 21_021150 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0005000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0005000.in: %%% progress: 6ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0005000.in: %%% progress: 6ms: parsing...
+triv/efa.in/0005000.in: %%% progress: 28ms: done parsing (22 ms, 22_104630 cycles)
+triv/efa.in/0005000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0005000.in: detShift=0, detReduce=0, nondetShift=10002, nondetReduce=10003
+triv/efa.in/0005000.in: num parses: 1
+triv/efa.in/0005000.in: tree nodes: 10003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 13ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 13ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 53ms: done parsing (40 ms, 39_795232 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 13ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 14ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 53ms: done parsing (39 ms, 39_507938 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 13ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 53ms: done parsing (40 ms, 39_771562 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 15ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 15ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 52ms: done parsing (38 ms, 37_363763 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0010000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0010000.in: %%% progress: 12ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0010000.in: %%% progress: 13ms: parsing...
+triv/efa.in/0010000.in: %%% progress: 52ms: done parsing (39 ms, 39_039165 cycles)
+triv/efa.in/0010000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0010000.in: detShift=0, detReduce=0, nondetShift=20002, nondetReduce=20003
+triv/efa.in/0010000.in: num parses: 1
+triv/efa.in/0010000.in: tree nodes: 20003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 28ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 28ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 102ms: done parsing (74 ms, 73_434082 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 24ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 25ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 101ms: done parsing (76 ms, 76_136400 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 26ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 102ms: done parsing (76 ms, 75_694523 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 25ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 106ms: done parsing (80 ms, 80_038883 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0020000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0020000.in: %%% progress: 25ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0020000.in: %%% progress: 26ms: parsing...
+triv/efa.in/0020000.in: %%% progress: 102ms: done parsing (76 ms, 76_562490 cycles)
+triv/efa.in/0020000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0020000.in: detShift=0, detReduce=0, nondetShift=40002, nondetReduce=40003
+triv/efa.in/0020000.in: num parses: 1
+triv/efa.in/0020000.in: tree nodes: 40003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 64ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 65ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 255ms: done parsing (190 ms, 190_000552 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 64ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 65ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 252ms: done parsing (187 ms, 187_201447 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 69ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 69ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 254ms: done parsing (185 ms, 184_280962 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 73ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 73ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 264ms: done parsing (191 ms, 191_052983 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0050000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0050000.in: %%% progress: 63ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0050000.in: %%% progress: 64ms: parsing...
+triv/efa.in/0050000.in: %%% progress: 251ms: done parsing (187 ms, 187_182690 cycles)
+triv/efa.in/0050000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0050000.in: detShift=0, detReduce=0, nondetShift=100002, nondetReduce=100003
+triv/efa.in/0050000.in: num parses: 1
+triv/efa.in/0050000.in: tree nodes: 100003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 126ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 126ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 500ms: done parsing (374 ms, 373_089660 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 128ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 129ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 500ms: done parsing (371 ms, 370_115692 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 131ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 132ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 503ms: done parsing (371 ms, 370_185577 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 126ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 126ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 500ms: done parsing (374 ms, 373_269547 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0100000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0100000.in: %%% progress: 126ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0100000.in: %%% progress: 126ms: parsing...
+triv/efa.in/0100000.in: %%% progress: 500ms: done parsing (374 ms, 372_948413 cycles)
+triv/efa.in/0100000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0100000.in: detShift=0, detReduce=0, nondetShift=200002, nondetReduce=200003
+triv/efa.in/0100000.in: num parses: 1
+triv/efa.in/0100000.in: tree nodes: 200003
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 249ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 250ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 999ms: done parsing (749 ms, 748_086030 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 266ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 266ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 1010ms: done parsing (744 ms, 743_002762 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 250ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 251ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 994ms: done parsing (743 ms, 742_458097 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 255ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 256ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 997ms: done parsing (741 ms, 739_769017 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0200000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0200000.in: %%% progress: 253ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0200000.in: %%% progress: 253ms: parsing...
+triv/efa.in/0200000.in: %%% progress: 999ms: done parsing (746 ms, 744_837532 cycles)
+triv/efa.in/0200000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0200000.in: detShift=0, detReduce=0, nondetShift=400002, nondetReduce=400003
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 618ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 619ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2494ms: done parsing (1875 ms, 1871_914980 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 619ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 620ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2489ms: done parsing (1869 ms, 1865_846857 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 622ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 623ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2509ms: done parsing (1886 ms, 1882_869195 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 626ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 626ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2488ms: done parsing (1862 ms, 1858_669815 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/0500000.in: %%% progress: 0ms: lexing...
+triv/efa.in/0500000.in: %%% progress: 622ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/0500000.in: %%% progress: 623ms: parsing...
+triv/efa.in/0500000.in: %%% progress: 2492ms: done parsing (1869 ms, 1865_956102 cycles)
+triv/efa.in/0500000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/0500000.in: detShift=0, detReduce=0, nondetShift=1000002, nondetReduce=1000003
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1226ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1226ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 5060ms: done parsing (3834 ms, 3827_139532 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1245ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1246ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 5235ms: done parsing (3989 ms, 3982_385580 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1241ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1241ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 4987ms: done parsing (3746 ms, 3740_081617 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1266ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1267ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 4996ms: done parsing (3729 ms, 3723_388072 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003
+triv/efa.in/1000000.in: %%% progress: 0ms: lexing...
+triv/efa.in/1000000.in: %%% progress: 1244ms: reading parse tables file triv/EFa.tree.bin
+triv/efa.in/1000000.in: %%% progress: 1244ms: parsing...
+triv/efa.in/1000000.in: %%% progress: 4984ms: done parsing (3740 ms, 3733_801852 cycles)
+triv/efa.in/1000000.in: stack nodes: 0, max stack nodes: 7
+triv/efa.in/1000000.in: detShift=0, detReduce=0, nondetShift=2000002, nondetReduce=2000003

Added: vendor/elsa/current/elkhound/triv/efa.notree.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.notree.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.notree.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 0246440
+0000500, 0216200
+0000500, 0205192
+0000500, 0203191
+0000500, 0202457
+0001000, 0395824
+0001000, 0392991
+0001000, 0393655
+0001000, 0393484
+0001000, 0392977
+0001500, 0814661
+0001500, 0763224
+0001500, 0644215
+0001500, 0645410
+0001500, 0740799
+0002000, 1060095
+0002000, 1018922
+0002000, 1199042
+0002000, 0996050
+0002000, 1177052
+0002500, 1567559
+0002500, 1553567
+0002500, 1582662
+0002500, 1556705
+0002500, 8931030
+0005000, 3138200
+0005000, 3273759
+0005000, 3119183
+0005000, 3121170
+0005000, 5321288
+0010000, 6070980
+0010000, 6044895
+0010000, 5906114
+0010000, 6100758
+0010000, 5938224
+0020000, 11748952
+0020000, 13963530
+0020000, 11875292
+0020000, 14013247
+0020000, 11873595
+0050000, 29108737
+0050000, 28843653
+0050000, 32775630
+0050000, 29743215
+0050000, 29423700
+0100000, 58434180
+0100000, 57145308
+0100000, 58071510
+0100000, 57582270
+0100000, 58070430
+0200000, 117978195
+0200000, 115160985
+0200000, 115105140
+0200000, 114923970
+0200000, 115315560
+0500000, 287648250
+0500000, 293167590
+0500000, 308304825
+0500000, 291110625
+0500000, 286844040
+1000000, 580600050
+1000000, 579623940
+1000000, 588807150
+1000000, 578049375
+1000000, 578054220

Added: vendor/elsa/current/elkhound/triv/efa.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,390 @@
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 3ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (0 ms, 0_246440 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: tree nodes: 0
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 2ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (1 ms, 0_216200 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: tree nodes: 0
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 3ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (0 ms, 0_205192 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: tree nodes: 0
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 3ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (0 ms, 0_203191 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: tree nodes: 0
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 3ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (0 ms, 0_202457 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 3ms: parsing...
+efa.in/0001000.in: %%% progress: 3ms: done parsing (0 ms, 0_395824 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 3ms: parsing...
+efa.in/0001000.in: %%% progress: 3ms: done parsing (0 ms, 0_392991 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 3ms: parsing...
+efa.in/0001000.in: %%% progress: 3ms: done parsing (0 ms, 0_393655 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 3ms: parsing...
+efa.in/0001000.in: %%% progress: 3ms: done parsing (0 ms, 0_393484 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 3ms: parsing...
+efa.in/0001000.in: %%% progress: 4ms: done parsing (1 ms, 0_392977 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 4ms: parsing...
+efa.in/0001500.in: %%% progress: 5ms: done parsing (1 ms, 0_814661 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 4ms: parsing...
+efa.in/0001500.in: %%% progress: 5ms: done parsing (1 ms, 0_763224 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 4ms: parsing...
+efa.in/0001500.in: %%% progress: 5ms: done parsing (1 ms, 0_644215 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 3ms: parsing...
+efa.in/0001500.in: %%% progress: 4ms: done parsing (1 ms, 0_645410 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: tree nodes: 0
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 4ms: parsing...
+efa.in/0001500.in: %%% progress: 4ms: done parsing (0 ms, 0_740799 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 5ms: parsing...
+efa.in/0002000.in: %%% progress: 6ms: done parsing (1 ms, 1_060095 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 5ms: parsing...
+efa.in/0002000.in: %%% progress: 6ms: done parsing (1 ms, 1_018922 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 7ms: parsing...
+efa.in/0002000.in: %%% progress: 8ms: done parsing (1 ms, 1_199042 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 5ms: parsing...
+efa.in/0002000.in: %%% progress: 6ms: done parsing (1 ms, 0_996050 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 5ms: parsing...
+efa.in/0002000.in: %%% progress: 6ms: done parsing (1 ms, 1_177052 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 7ms: done parsing (2 ms, 1_567559 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 7ms: done parsing (2 ms, 1_553567 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 7ms: done parsing (2 ms, 1_582662 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 6ms: done parsing (1 ms, 1_556705 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: tree nodes: 0
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 14ms: done parsing (9 ms, 8_931030 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 11ms: done parsing (3 ms, 3_138200 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 11ms: done parsing (3 ms, 3_273759 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 11ms: done parsing (3 ms, 3_119183 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 11ms: done parsing (3 ms, 3_121170 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: tree nodes: 0
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 14ms: done parsing (5 ms, 5_321288 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 14ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 16ms: parsing...
+efa.in/0010000.in: %%% progress: 22ms: done parsing (6 ms, 6_070980 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 13ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 15ms: parsing...
+efa.in/0010000.in: %%% progress: 21ms: done parsing (6 ms, 6_044895 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 15ms: parsing...
+efa.in/0010000.in: %%% progress: 20ms: done parsing (5 ms, 5_906114 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 14ms: parsing...
+efa.in/0010000.in: %%% progress: 20ms: done parsing (6 ms, 6_100758 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: tree nodes: 0
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 14ms: parsing...
+efa.in/0010000.in: %%% progress: 20ms: done parsing (6 ms, 5_938224 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 27ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 29ms: parsing...
+efa.in/0020000.in: %%% progress: 41ms: done parsing (12 ms, 11_748952 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 24ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 26ms: parsing...
+efa.in/0020000.in: %%% progress: 40ms: done parsing (14 ms, 13_963530 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 26ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 28ms: parsing...
+efa.in/0020000.in: %%% progress: 40ms: done parsing (12 ms, 11_875292 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 26ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 28ms: parsing...
+efa.in/0020000.in: %%% progress: 42ms: done parsing (14 ms, 14_013247 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: tree nodes: 0
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 26ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 28ms: parsing...
+efa.in/0020000.in: %%% progress: 40ms: done parsing (12 ms, 11_873595 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 64ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 66ms: parsing...
+efa.in/0050000.in: %%% progress: 95ms: done parsing (29 ms, 29_108737 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 62ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 64ms: parsing...
+efa.in/0050000.in: %%% progress: 93ms: done parsing (29 ms, 28_843653 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 62ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 65ms: parsing...
+efa.in/0050000.in: %%% progress: 97ms: done parsing (32 ms, 32_775630 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 63ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 65ms: parsing...
+efa.in/0050000.in: %%% progress: 95ms: done parsing (30 ms, 29_743215 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: tree nodes: 0
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 63ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 65ms: parsing...
+efa.in/0050000.in: %%% progress: 94ms: done parsing (29 ms, 29_423700 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 122ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 124ms: parsing...
+efa.in/0100000.in: %%% progress: 183ms: done parsing (59 ms, 58_434180 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 124ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 126ms: parsing...
+efa.in/0100000.in: %%% progress: 184ms: done parsing (58 ms, 57_145308 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 130ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 132ms: parsing...
+efa.in/0100000.in: %%% progress: 190ms: done parsing (58 ms, 58_071510 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 124ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 126ms: parsing...
+efa.in/0100000.in: %%% progress: 184ms: done parsing (58 ms, 57_582270 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: tree nodes: 0
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 127ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 129ms: parsing...
+efa.in/0100000.in: %%% progress: 187ms: done parsing (58 ms, 58_070430 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 245ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 247ms: parsing...
+efa.in/0200000.in: %%% progress: 365ms: done parsing (118 ms, 117_978195 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 250ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 252ms: parsing...
+efa.in/0200000.in: %%% progress: 368ms: done parsing (116 ms, 115_160985 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 246ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 249ms: parsing...
+efa.in/0200000.in: %%% progress: 364ms: done parsing (115 ms, 115_105140 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 248ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 250ms: parsing...
+efa.in/0200000.in: %%% progress: 365ms: done parsing (115 ms, 114_923970 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: tree nodes: 0
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 250ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 252ms: parsing...
+efa.in/0200000.in: %%% progress: 367ms: done parsing (115 ms, 115_315560 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 605ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 607ms: parsing...
+efa.in/0500000.in: %%% progress: 895ms: done parsing (288 ms, 287_648250 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 606ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 608ms: parsing...
+efa.in/0500000.in: %%% progress: 902ms: done parsing (294 ms, 293_167590 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 605ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 607ms: parsing...
+efa.in/0500000.in: %%% progress: 916ms: done parsing (309 ms, 308_304825 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 607ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 609ms: parsing...
+efa.in/0500000.in: %%% progress: 901ms: done parsing (292 ms, 291_110625 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: tree nodes: 0
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 607ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 610ms: parsing...
+efa.in/0500000.in: %%% progress: 897ms: done parsing (287 ms, 286_844040 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1210ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1212ms: parsing...
+efa.in/1000000.in: %%% progress: 1793ms: done parsing (581 ms, 580_600050 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1205ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1207ms: parsing...
+efa.in/1000000.in: %%% progress: 1787ms: done parsing (580 ms, 579_623940 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1201ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1203ms: parsing...
+efa.in/1000000.in: %%% progress: 1793ms: done parsing (590 ms, 588_807150 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1203ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1205ms: parsing...
+efa.in/1000000.in: %%% progress: 1784ms: done parsing (579 ms, 578_049375 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: tree nodes: 0
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1203ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1205ms: parsing...
+efa.in/1000000.in: %%% progress: 1784ms: done parsing (579 ms, 578_054220 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: tree nodes: 0

Added: vendor/elsa/current/elkhound/triv/efa.perf.csv
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.perf.csv	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.perf.csv	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+0000500, 0484681
+0000500, 0483679
+0000500, 0484858
+0000500, 0479284
+0000500, 0480484
+0001000, 1056680
+0001000, 1273629
+0001000, 1180928
+0001000, 1028815
+0001000, 1722457
+0001500, 1768022
+0001500, 2075753
+0001500, 1758794
+0001500, 1699480
+0001500, 1786636
+0002000, 2694543
+0002000, 2530832
+0002000, 2502057
+0002000, 2883542
+0002000, 2503703
+0002500, 3168300
+0002500, 3342494
+0002500, 3338541
+0002500, 3188518
+0002500, 3182902
+0005000, 6300622
+0005000, 6465288
+0005000, 6386574
+0005000, 6499269
+0005000, 6205364
+0010000, 12871218
+0010000, 12950130
+0010000, 12524313
+0010000, 12743005
+0010000, 12634128
+0020000, 25230510
+0020000, 27265358
+0020000, 27172680
+0020000, 25371975
+0020000, 27081262
+0050000, 62847008
+0050000, 62823135
+0050000, 65956815
+0050000, 62887598
+0050000, 64832505
+0100000, 126392588
+0100000, 124731930
+0100000, 125198040
+0100000, 125423663
+0100000, 124804380
+0200000, 250020518
+0200000, 252162510
+0200000, 251786235
+0200000, 255613688
+0200000, 252206992
+0500000, 637390290
+0500000, 625784445
+0500000, 631991700
+0500000, 632909280
+0500000, 632133270
+1000000, 1255622790
+1000000, 1277550848
+1000000, 1250335935
+1000000, 1261381140
+1000000, 1256238945

Added: vendor/elsa/current/elkhound/triv/efa.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/efa.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/efa.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,425 @@
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 3ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (0 ms, 0_484681 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: num parses: 1
+efa.in/0000500.in: tree nodes: 1003
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 0ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 2ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (1 ms, 0_483679 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: num parses: 1
+efa.in/0000500.in: tree nodes: 1003
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 3ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (0 ms, 0_484858 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: num parses: 1
+efa.in/0000500.in: tree nodes: 1003
+efa.in/0000500.in: %%% progress: 1ms: lexing...
+efa.in/0000500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 3ms: parsing...
+efa.in/0000500.in: %%% progress: 4ms: done parsing (1 ms, 0_479284 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: num parses: 1
+efa.in/0000500.in: tree nodes: 1003
+efa.in/0000500.in: %%% progress: 0ms: lexing...
+efa.in/0000500.in: %%% progress: 0ms: reading binary grammar file EFa.tree.bin
+efa.in/0000500.in: %%% progress: 2ms: parsing...
+efa.in/0000500.in: %%% progress: 3ms: done parsing (1 ms, 0_480484 cycles)
+efa.in/0000500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0000500.in: num parses: 1
+efa.in/0000500.in: tree nodes: 1003
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 4ms: parsing...
+efa.in/0001000.in: %%% progress: 5ms: done parsing (1 ms, 1_056680 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: num parses: 1
+efa.in/0001000.in: tree nodes: 2003
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 3ms: parsing...
+efa.in/0001000.in: %%% progress: 5ms: done parsing (2 ms, 1_273629 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: num parses: 1
+efa.in/0001000.in: tree nodes: 2003
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 4ms: parsing...
+efa.in/0001000.in: %%% progress: 5ms: done parsing (1 ms, 1_180928 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: num parses: 1
+efa.in/0001000.in: tree nodes: 2003
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 3ms: parsing...
+efa.in/0001000.in: %%% progress: 4ms: done parsing (1 ms, 1_028815 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: num parses: 1
+efa.in/0001000.in: tree nodes: 2003
+efa.in/0001000.in: %%% progress: 0ms: lexing...
+efa.in/0001000.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001000.in: %%% progress: 3ms: parsing...
+efa.in/0001000.in: %%% progress: 5ms: done parsing (2 ms, 1_722457 cycles)
+efa.in/0001000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001000.in: num parses: 1
+efa.in/0001000.in: tree nodes: 2003
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 4ms: parsing...
+efa.in/0001500.in: %%% progress: 5ms: done parsing (1 ms, 1_768022 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: num parses: 1
+efa.in/0001500.in: tree nodes: 3003
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 1ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 3ms: parsing...
+efa.in/0001500.in: %%% progress: 5ms: done parsing (2 ms, 2_075753 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: num parses: 1
+efa.in/0001500.in: tree nodes: 3003
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 4ms: parsing...
+efa.in/0001500.in: %%% progress: 6ms: done parsing (2 ms, 1_758794 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: num parses: 1
+efa.in/0001500.in: tree nodes: 3003
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 3ms: parsing...
+efa.in/0001500.in: %%% progress: 5ms: done parsing (2 ms, 1_699480 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: num parses: 1
+efa.in/0001500.in: tree nodes: 3003
+efa.in/0001500.in: %%% progress: 0ms: lexing...
+efa.in/0001500.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0001500.in: %%% progress: 4ms: parsing...
+efa.in/0001500.in: %%% progress: 5ms: done parsing (1 ms, 1_786636 cycles)
+efa.in/0001500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0001500.in: num parses: 1
+efa.in/0001500.in: tree nodes: 3003
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 5ms: parsing...
+efa.in/0002000.in: %%% progress: 7ms: done parsing (2 ms, 2_694543 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: num parses: 1
+efa.in/0002000.in: tree nodes: 4003
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 4ms: parsing...
+efa.in/0002000.in: %%% progress: 6ms: done parsing (2 ms, 2_530832 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: num parses: 1
+efa.in/0002000.in: tree nodes: 4003
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 2ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 4ms: parsing...
+efa.in/0002000.in: %%% progress: 7ms: done parsing (3 ms, 2_502057 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: num parses: 1
+efa.in/0002000.in: tree nodes: 4003
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 5ms: parsing...
+efa.in/0002000.in: %%% progress: 8ms: done parsing (3 ms, 2_883542 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: num parses: 1
+efa.in/0002000.in: tree nodes: 4003
+efa.in/0002000.in: %%% progress: 0ms: lexing...
+efa.in/0002000.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002000.in: %%% progress: 5ms: parsing...
+efa.in/0002000.in: %%% progress: 7ms: done parsing (2 ms, 2_503703 cycles)
+efa.in/0002000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002000.in: num parses: 1
+efa.in/0002000.in: tree nodes: 4003
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 9ms: done parsing (4 ms, 3_168300 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: num parses: 1
+efa.in/0002500.in: tree nodes: 5003
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 9ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 11ms: parsing...
+efa.in/0002500.in: %%% progress: 15ms: done parsing (4 ms, 3_342494 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: num parses: 1
+efa.in/0002500.in: tree nodes: 5003
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 9ms: done parsing (4 ms, 3_338541 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: num parses: 1
+efa.in/0002500.in: tree nodes: 5003
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 4ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 9ms: done parsing (4 ms, 3_188518 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: num parses: 1
+efa.in/0002500.in: tree nodes: 5003
+efa.in/0002500.in: %%% progress: 0ms: lexing...
+efa.in/0002500.in: %%% progress: 3ms: reading binary grammar file EFa.tree.bin
+efa.in/0002500.in: %%% progress: 5ms: parsing...
+efa.in/0002500.in: %%% progress: 8ms: done parsing (3 ms, 3_182902 cycles)
+efa.in/0002500.in: stack nodes: 3, max stack nodes: 4
+efa.in/0002500.in: num parses: 1
+efa.in/0002500.in: tree nodes: 5003
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 15ms: done parsing (7 ms, 6_300622 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: num parses: 1
+efa.in/0005000.in: tree nodes: 10003
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 14ms: done parsing (6 ms, 6_465288 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: num parses: 1
+efa.in/0005000.in: tree nodes: 10003
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 15ms: done parsing (7 ms, 6_386574 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: num parses: 1
+efa.in/0005000.in: tree nodes: 10003
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 8ms: parsing...
+efa.in/0005000.in: %%% progress: 14ms: done parsing (6 ms, 6_499269 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: num parses: 1
+efa.in/0005000.in: tree nodes: 10003
+efa.in/0005000.in: %%% progress: 0ms: lexing...
+efa.in/0005000.in: %%% progress: 6ms: reading binary grammar file EFa.tree.bin
+efa.in/0005000.in: %%% progress: 11ms: parsing...
+efa.in/0005000.in: %%% progress: 17ms: done parsing (6 ms, 6_205364 cycles)
+efa.in/0005000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0005000.in: num parses: 1
+efa.in/0005000.in: tree nodes: 10003
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 14ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 16ms: parsing...
+efa.in/0010000.in: %%% progress: 29ms: done parsing (13 ms, 12_871218 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: num parses: 1
+efa.in/0010000.in: tree nodes: 20003
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 14ms: parsing...
+efa.in/0010000.in: %%% progress: 27ms: done parsing (13 ms, 12_950130 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: num parses: 1
+efa.in/0010000.in: tree nodes: 20003
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 17ms: parsing...
+efa.in/0010000.in: %%% progress: 29ms: done parsing (12 ms, 12_524313 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: num parses: 1
+efa.in/0010000.in: tree nodes: 20003
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 13ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 15ms: parsing...
+efa.in/0010000.in: %%% progress: 27ms: done parsing (12 ms, 12_743005 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: num parses: 1
+efa.in/0010000.in: tree nodes: 20003
+efa.in/0010000.in: %%% progress: 0ms: lexing...
+efa.in/0010000.in: %%% progress: 12ms: reading binary grammar file EFa.tree.bin
+efa.in/0010000.in: %%% progress: 14ms: parsing...
+efa.in/0010000.in: %%% progress: 27ms: done parsing (13 ms, 12_634128 cycles)
+efa.in/0010000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0010000.in: num parses: 1
+efa.in/0010000.in: tree nodes: 20003
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 31ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 33ms: parsing...
+efa.in/0020000.in: %%% progress: 58ms: done parsing (25 ms, 25_230510 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: num parses: 1
+efa.in/0020000.in: tree nodes: 40003
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 25ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 27ms: parsing...
+efa.in/0020000.in: %%% progress: 54ms: done parsing (27 ms, 27_265358 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: num parses: 1
+efa.in/0020000.in: tree nodes: 40003
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 24ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 26ms: parsing...
+efa.in/0020000.in: %%% progress: 53ms: done parsing (27 ms, 27_172680 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: num parses: 1
+efa.in/0020000.in: tree nodes: 40003
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 29ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 31ms: parsing...
+efa.in/0020000.in: %%% progress: 57ms: done parsing (25 ms, 25_371975 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: num parses: 1
+efa.in/0020000.in: tree nodes: 40003
+efa.in/0020000.in: %%% progress: 0ms: lexing...
+efa.in/0020000.in: %%% progress: 25ms: reading binary grammar file EFa.tree.bin
+efa.in/0020000.in: %%% progress: 27ms: parsing...
+efa.in/0020000.in: %%% progress: 54ms: done parsing (27 ms, 27_081262 cycles)
+efa.in/0020000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0020000.in: num parses: 1
+efa.in/0020000.in: tree nodes: 40003
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 71ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 74ms: parsing...
+efa.in/0050000.in: %%% progress: 136ms: done parsing (62 ms, 62_847008 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: num parses: 1
+efa.in/0050000.in: tree nodes: 100003
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 63ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 65ms: parsing...
+efa.in/0050000.in: %%% progress: 128ms: done parsing (63 ms, 62_823135 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: num parses: 1
+efa.in/0050000.in: tree nodes: 100003
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 62ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 65ms: parsing...
+efa.in/0050000.in: %%% progress: 131ms: done parsing (66 ms, 65_956815 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: num parses: 1
+efa.in/0050000.in: tree nodes: 100003
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 63ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 65ms: parsing...
+efa.in/0050000.in: %%% progress: 128ms: done parsing (63 ms, 62_887598 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: num parses: 1
+efa.in/0050000.in: tree nodes: 100003
+efa.in/0050000.in: %%% progress: 0ms: lexing...
+efa.in/0050000.in: %%% progress: 62ms: reading binary grammar file EFa.tree.bin
+efa.in/0050000.in: %%% progress: 64ms: parsing...
+efa.in/0050000.in: %%% progress: 129ms: done parsing (65 ms, 64_832505 cycles)
+efa.in/0050000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0050000.in: num parses: 1
+efa.in/0050000.in: tree nodes: 100003
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 124ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 126ms: parsing...
+efa.in/0100000.in: %%% progress: 252ms: done parsing (126 ms, 126_392588 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: num parses: 1
+efa.in/0100000.in: tree nodes: 200003
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 124ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 126ms: parsing...
+efa.in/0100000.in: %%% progress: 251ms: done parsing (125 ms, 124_731930 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: num parses: 1
+efa.in/0100000.in: tree nodes: 200003
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 128ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 131ms: parsing...
+efa.in/0100000.in: %%% progress: 256ms: done parsing (125 ms, 125_198040 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: num parses: 1
+efa.in/0100000.in: tree nodes: 200003
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 128ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 130ms: parsing...
+efa.in/0100000.in: %%% progress: 256ms: done parsing (126 ms, 125_423663 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: num parses: 1
+efa.in/0100000.in: tree nodes: 200003
+efa.in/0100000.in: %%% progress: 0ms: lexing...
+efa.in/0100000.in: %%% progress: 122ms: reading binary grammar file EFa.tree.bin
+efa.in/0100000.in: %%% progress: 124ms: parsing...
+efa.in/0100000.in: %%% progress: 249ms: done parsing (125 ms, 124_804380 cycles)
+efa.in/0100000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0100000.in: num parses: 1
+efa.in/0100000.in: tree nodes: 200003
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 252ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 254ms: parsing...
+efa.in/0200000.in: %%% progress: 504ms: done parsing (250 ms, 250_020518 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 247ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 249ms: parsing...
+efa.in/0200000.in: %%% progress: 501ms: done parsing (252 ms, 252_162510 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 250ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 252ms: parsing...
+efa.in/0200000.in: %%% progress: 505ms: done parsing (253 ms, 251_786235 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 243ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 246ms: parsing...
+efa.in/0200000.in: %%% progress: 502ms: done parsing (256 ms, 255_613688 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0200000.in: %%% progress: 0ms: lexing...
+efa.in/0200000.in: %%% progress: 259ms: reading binary grammar file EFa.tree.bin
+efa.in/0200000.in: %%% progress: 261ms: parsing...
+efa.in/0200000.in: %%% progress: 514ms: done parsing (253 ms, 252_206992 cycles)
+efa.in/0200000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 601ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 604ms: parsing...
+efa.in/0500000.in: %%% progress: 1242ms: done parsing (638 ms, 637_390290 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 603ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 606ms: parsing...
+efa.in/0500000.in: %%% progress: 1232ms: done parsing (626 ms, 625_784445 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 609ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 612ms: parsing...
+efa.in/0500000.in: %%% progress: 1245ms: done parsing (633 ms, 631_991700 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 603ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 605ms: parsing...
+efa.in/0500000.in: %%% progress: 1239ms: done parsing (634 ms, 632_909280 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/0500000.in: %%% progress: 0ms: lexing...
+efa.in/0500000.in: %%% progress: 603ms: reading binary grammar file EFa.tree.bin
+efa.in/0500000.in: %%% progress: 605ms: parsing...
+efa.in/0500000.in: %%% progress: 1238ms: done parsing (633 ms, 632_133270 cycles)
+efa.in/0500000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1201ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1203ms: parsing...
+efa.in/1000000.in: %%% progress: 2461ms: done parsing (1258 ms, 1255_622790 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1200ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1202ms: parsing...
+efa.in/1000000.in: %%% progress: 2482ms: done parsing (1280 ms, 1277_550848 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1199ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1201ms: parsing...
+efa.in/1000000.in: %%% progress: 2454ms: done parsing (1253 ms, 1250_335935 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1197ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1199ms: parsing...
+efa.in/1000000.in: %%% progress: 2463ms: done parsing (1264 ms, 1261_381140 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4
+efa.in/1000000.in: %%% progress: 0ms: lexing...
+efa.in/1000000.in: %%% progress: 1207ms: reading binary grammar file EFa.tree.bin
+efa.in/1000000.in: %%% progress: 1209ms: parsing...
+efa.in/1000000.in: %%% progress: 2467ms: done parsing (1258 ms, 1256_238945 cycles)
+efa.in/1000000.in: stack nodes: 3, max stack nodes: 4

Added: vendor/elsa/current/elkhound/triv/ite.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/ite.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ite.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// ite.gr.in      -*- c++ -*-
+// test if-then-else ambiguity (er, lookahead actually)
+
+terminals {
+  i  // if
+  t  // then
+  e  // else
+  x  // variable, x
+  p  // +
+  k  // sKip
+  c  // collect? do something with an expression
+}
+
+nonterm Stmt {
+  -> i Exp t Stmt;
+  -> i Exp t Stmt e Stmt;
+  -> k;
+  -> c Exp;
+}
+
+nonterm Exp {
+  -> x;
+  -> Exp p x;
+}
+
+
+
+

Added: vendor/elsa/current/elkhound/triv/ite.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/ite.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ite.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+IXTCXECX
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/ite.in2
===================================================================
--- vendor/elsa/current/elkhound/triv/ite.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ite.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+IXTCXPXPXPXPXEK
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/ite.in3
===================================================================
--- vendor/elsa/current/elkhound/triv/ite.in3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ite.in3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+IXTIXTKEKEK
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/ite.in4
===================================================================
--- vendor/elsa/current/elkhound/triv/ite.in4	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ite.in4	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+IXTIXTCXPXPXPXPXPXPXPXPXECXPXPXPXPXECXPXPXPXPX
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/ite.in5
===================================================================
--- vendor/elsa/current/elkhound/triv/ite.in5	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ite.in5	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+IXTIXTIXTKEKEKEK
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/sssx.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/sssx.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/sssx.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+5: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+5: %%% progress: 2ms: parsing...
+5: %%% progress: 2ms: done parsing (0 ms) (167486 cycles)
+5: stack nodes: 3, max stack nodes: 14
+5: tree nodes: 0
+10: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+10: %%% progress: 2ms: parsing...
+10: %%% progress: 3ms: done parsing (1 ms) (1371720 cycles)
+10: stack nodes: 3, max stack nodes: 30
+10: tree nodes: 0
+15: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+15: %%% progress: 2ms: parsing...
+15: %%% progress: 14ms: done parsing (12 ms) (11647020 cycles)
+15: stack nodes: 3, max stack nodes: 45
+15: tree nodes: 0
+20: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+20: %%% progress: 3ms: parsing...
+20: %%% progress: 57ms: done parsing (54 ms) (54040655 cycles)
+20: stack nodes: 3, max stack nodes: 60
+20: tree nodes: 0
+25: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+25: %%% progress: 2ms: parsing...
+25: %%% progress: 177ms: done parsing (175 ms) (174792928 cycles)
+25: stack nodes: 3, max stack nodes: 75
+25: tree nodes: 0
+30: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+30: %%% progress: 2ms: parsing...
+30: %%% progress: 446ms: done parsing (444 ms) (442615858 cycles)
+30: stack nodes: 3, max stack nodes: 90
+30: tree nodes: 0
+35: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+35: %%% progress: 2ms: parsing...
+35: %%% progress: 1000ms: done parsing (998 ms) (996469880 cycles)
+35: stack nodes: 3, max stack nodes: 105
+35: tree nodes: 0
+40: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+40: %%% progress: 2ms: parsing...
+40: %%% progress: 2021ms: done parsing (2019 ms) (2016509090 cycles)
+40: stack nodes: 3, max stack nodes: 120
+40: tree nodes: 0
+45: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+45: %%% progress: 3ms: parsing...
+45: %%% progress: 3688ms: done parsing (3685 ms) (3679133540 cycles)
+45: stack nodes: 3, max stack nodes: 135
+45: tree nodes: 0
+50: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+50: %%% progress: 2ms: parsing...
+50: %%% progress: 6348ms: done parsing (6346 ms) (6335704655 cycles)
+50: stack nodes: 3, max stack nodes: 150
+50: tree nodes: 0

Added: vendor/elsa/current/elkhound/triv/sssx.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/sssx.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/sssx.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,72 @@
+5: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+5: %%% progress: 2ms: parsing...
+5: %%% progress: 2ms: done parsing (0 ms) (160868 cycles)
+5: stack nodes: 3, max stack nodes: 14
+5: num parses: 5
+5: should be: 5
+5: tree nodes: 23
+10: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+10: %%% progress: 2ms: parsing...
+10: %%% progress: 3ms: done parsing (1 ms) (1814097 cycles)
+10: stack nodes: 3, max stack nodes: 30
+10: num parses: 349
+10: should be: 349
+10: tree nodes: 418
+15: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+15: %%% progress: 2ms: parsing...
+15: %%% progress: 15ms: done parsing (13 ms) (13146793 cycles)
+15: stack nodes: 3, max stack nodes: 45
+15: num parses: 38403
+15: should be: 38403
+15: tree nodes: 2838
+20: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+20: %%% progress: 2ms: parsing...
+20: %%% progress: 62ms: done parsing (60 ms) (60250843 cycles)
+20: stack nodes: 3, max stack nodes: 60
+20: num parses: 5.04752e+06
+20: should be: 5.04752e+06
+20: tree nodes: 10783
+25: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+25: %%% progress: 2ms: parsing...
+25: %%% progress: 195ms: done parsing (193 ms) (192032915 cycles)
+25: stack nodes: 3, max stack nodes: 75
+25: num parses: 7.29709e+08
+25: should be: 7.29709e+08
+25: tree nodes: 29628
+30: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+30: %%% progress: 3ms: parsing...
+30: %%% progress: 496ms: done parsing (493 ms) (492175813 cycles)
+30: stack nodes: 3, max stack nodes: 90
+30: num parses: 1.12065e+11
+30: should be: 1.12065e+11
+30: tree nodes: 66623
+35: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+35: %%% progress: 2ms: parsing...
+35: %%% progress: 1107ms: done parsing (1105 ms) (1104077540 cycles)
+35: stack nodes: 3, max stack nodes: 105
+35: num parses: 1.79451e+13
+35: should be: 1.79451e+13
+35: tree nodes: 130893
+40: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+40: %%% progress: 2ms: parsing...
+40: %%% progress: 2201ms: done parsing (2199 ms) (2195373463 cycles)
+40: stack nodes: 3, max stack nodes: 120
+40: num parses: 2.963e+15
+40: should be: 2.963e+15
+40: tree nodes: 233438
+45: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+45: %%% progress: 2ms: parsing...
+45: %%% progress: 3992ms: done parsing (3990 ms) (3983527430 cycles)
+45: stack nodes: 3, max stack nodes: 135
+45: num parses: 5.00836e+17
+45: should be: 5.00836e+17
+45: MISMATCH in number of parse trees
+45: tree nodes: 387133
+50: %%% progress: 0ms: reading binary grammar file SSSx.tree.bin
+50: %%% progress: 2ms: parsing...
+50: %%% progress: 6864ms: done parsing (6862 ms) (6851034380 cycles)
+50: stack nodes: 3, max stack nodes: 150
+50: num parses: 8.62369e+19
+50: should be: 8.62369e+19
+50: MISMATCH in number of parse trees
+50: tree nodes: 606728

Added: vendor/elsa/current/elkhound/triv/ssx.notree.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/ssx.notree.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ssx.notree.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+15: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+15: %%% progress: 15ms: parsing...
+15: %%% progress: 16ms: done parsing (1 ms) (405498 cycles)
+15: stack nodes: 3, max stack nodes: 24
+15: tree nodes: 0
+25: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+25: %%% progress: 2ms: parsing...
+25: %%% progress: 4ms: done parsing (2 ms) (1947487 cycles)
+25: stack nodes: 3, max stack nodes: 39
+25: tree nodes: 0
+35: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+35: %%% progress: 2ms: parsing...
+35: %%% progress: 8ms: done parsing (6 ms) (6396600 cycles)
+35: stack nodes: 3, max stack nodes: 54
+35: tree nodes: 0
+45: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+45: %%% progress: 2ms: parsing...
+45: %%% progress: 17ms: done parsing (15 ms) (15645672 cycles)
+45: stack nodes: 3, max stack nodes: 69
+45: tree nodes: 0
+55: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+55: %%% progress: 2ms: parsing...
+55: %%% progress: 34ms: done parsing (32 ms) (32606687 cycles)
+55: stack nodes: 3, max stack nodes: 84
+55: tree nodes: 0
+65: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+65: %%% progress: 2ms: parsing...
+65: %%% progress: 64ms: done parsing (62 ms) (61240877 cycles)
+65: stack nodes: 3, max stack nodes: 99
+65: tree nodes: 0
+75: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+75: %%% progress: 2ms: parsing...
+75: %%% progress: 117ms: done parsing (115 ms) (114760566 cycles)
+75: stack nodes: 3, max stack nodes: 114
+75: tree nodes: 0
+85: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+85: %%% progress: 2ms: parsing...
+85: %%% progress: 179ms: done parsing (177 ms) (176447263 cycles)
+85: stack nodes: 3, max stack nodes: 129
+85: tree nodes: 0
+99: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+99: %%% progress: 2ms: parsing...
+99: %%% progress: 325ms: done parsing (323 ms) (323189608 cycles)
+99: stack nodes: 3, max stack nodes: 150
+99: tree nodes: 0

Added: vendor/elsa/current/elkhound/triv/ssx.perf.txt
===================================================================
--- vendor/elsa/current/elkhound/triv/ssx.perf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/ssx.perf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,63 @@
+15: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+15: %%% progress: 4ms: parsing...
+15: %%% progress: 4ms: done parsing (0 ms) (575287 cycles)
+15: stack nodes: 3, max stack nodes: 24
+15: num parses: 429
+15: should be: 429
+15: tree nodes: 195
+25: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+25: %%% progress: 2ms: parsing...
+25: %%% progress: 5ms: done parsing (3 ms) (2811074 cycles)
+25: stack nodes: 3, max stack nodes: 39
+25: num parses: 208012
+25: should be: 208012
+25: tree nodes: 905
+35: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+35: %%% progress: 2ms: parsing...
+35: %%% progress: 10ms: done parsing (8 ms) (7857984 cycles)
+35: stack nodes: 3, max stack nodes: 54
+35: num parses: 1.29645e+08
+35: should be: 1.29645e+08
+35: tree nodes: 2515
+45: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+45: %%% progress: 3ms: parsing...
+45: %%% progress: 21ms: done parsing (18 ms) (18318657 cycles)
+45: stack nodes: 3, max stack nodes: 69
+45: num parses: 9.14826e+10
+45: should be: 9.14826e+10
+45: tree nodes: 5400
+55: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+55: %%% progress: 2ms: parsing...
+55: %%% progress: 41ms: done parsing (38 ms) (38492315 cycles)
+55: stack nodes: 3, max stack nodes: 84
+55: num parses: 6.95336e+13
+55: should be: 6.95336e+13
+55: tree nodes: 9935
+65: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+65: %%% progress: 2ms: parsing...
+65: %%% progress: 79ms: done parsing (76 ms) (76793323 cycles)
+65: stack nodes: 3, max stack nodes: 99
+65: num parses: 5.55341e+16
+65: should be: 5.55341e+16
+65: tree nodes: 16495
+75: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+75: %%% progress: 2ms: parsing...
+75: %%% progress: 128ms: done parsing (126 ms) (125952343 cycles)
+75: stack nodes: 3, max stack nodes: 114
+75: num parses: 4.59508e+19
+75: should be: 4.59508e+19
+75: tree nodes: 25455
+85: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+85: %%% progress: 2ms: parsing...
+85: %%% progress: 203ms: done parsing (201 ms) (201079678 cycles)
+85: stack nodes: 3, max stack nodes: 129
+85: num parses: 3.90444e+22
+85: should be: 3.90444e+22
+85: tree nodes: 37190
+99: %%% progress: 0ms: reading binary grammar file SSx.tree.bin
+99: %%% progress: 7ms: parsing...
+99: %%% progress: 366ms: done parsing (359 ms) (357607109 cycles)
+99: stack nodes: 3, max stack nodes: 150
+99: num parses: 5.09552e+26
+99: should be: 5.09552e+26
+99: tree nodes: 58995

Added: vendor/elsa/current/elkhound/triv/testRR.gr.in
===================================================================
--- vendor/elsa/current/elkhound/triv/testRR.gr.in	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/testRR.gr.in	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// testRR.gr.in   -*- c++ -*-
+// test reduce/reduce behavior
+
+// S -> a B1 c d
+// S -> a B2 c e
+// B1 -> b
+// B2 -> b
+
+option useGCDefaults;
+
+terminals {
+  a
+  b
+  c
+  d
+  e
+  
+  precedence {
+    // assign both 'B' productions the same precedence; there was a
+    // bug in Elkhound that would cause it to drop one of the
+    // productions in this case (now it is fixed, as this test
+    // confirms)
+    prec  200 b;
+  }
+}
+
+nonterm S {
+  -> a B1 c d ;
+  -> a B2 c e ;
+}
+
+nonterm B1 {
+  -> b ;
+}
+
+nonterm B2 {
+  -> b ;
+}
+

Added: vendor/elsa/current/elkhound/triv/testRR.in1
===================================================================
--- vendor/elsa/current/elkhound/triv/testRR.in1	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/testRR.in1	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ABCD
\ No newline at end of file

Added: vendor/elsa/current/elkhound/triv/testRR.in2
===================================================================
--- vendor/elsa/current/elkhound/triv/testRR.in2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/triv/testRR.in2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+ABCE
\ No newline at end of file

Added: vendor/elsa/current/elkhound/trivbison.cc
===================================================================
--- vendor/elsa/current/elkhound/trivbison.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/trivbison.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,108 @@
+// trivbison.cc            see license.txt for copyright and terms of use
+// driver file for a Bison-parser with the trivial lexer
+
+#include "trivbison.h"  // this module
+#include "lexer2.h"     // Lexer2
+#include "trivlex.h"    // trivialLexer
+#include "trace.h"      // traceProgress
+#include "syserr.h"     // xsyserror
+#include "ptreenode.h"  // PTreeNode
+#include "cyctimer.h"   // CycleTimer
+
+#include <stdio.h>      // printf
+#include <iostream.h>   // cout, etc.
+
+// global list of L2 tokens for yielding to Bison
+Lexer2 lexer2;
+Lexer2Token const *lastTokenYielded = NULL;
+
+// parsing entry point
+int yyparse();
+
+// returns token types until EOF, at which point L2_EOF is returned
+int yylex()
+{
+  static ObjListIter<Lexer2Token> *iter = NULL;
+
+  if (!iter) {
+    // prepare to return tokens
+    iter = new ObjListIter<Lexer2Token>(lexer2.tokens);
+  }
+
+  if (!iter->isDone()) {
+    // grab type to return
+    lastTokenYielded = iter->data();
+    Lexer2TokenType ret = iter->data()->type;
+
+    // advance to next token
+    iter->adv();
+
+    // return one we just advanced past
+    return ret;
+  }
+  else {
+    // done; don't bother freeing things
+    lastTokenYielded = NULL;
+    return L2_EOF;
+  }
+}
+
+
+void yyerror(char const *s)
+{
+  if (lastTokenYielded) {
+    printf("%s: ", lastTokenYielded->loc.toString().pcharc());
+  }
+  else {
+    printf("<eof>: ");
+  }
+  printf("%s\n", s);
+}
+
+
+int main(int argc, char *argv[])
+{
+  char const *progname = argv[0];
+
+  if (argc >= 2 &&
+      0==strcmp(argv[1], "-d")) {
+    #ifdef YYDEBUG
+      yydebug = 1;
+    #else
+      printf("debugging is disabled because YYDEBUG isn't set\n");
+      return 2;
+    #endif
+
+    argc--;
+    argv++;
+  }
+
+  if (argc < 2) {
+    printf("usage: %s [-d] inputfile\n", progname);
+    printf("  -d: turn on yydebug, so it prints shift/reduce actions\n");
+    return 0;
+  }
+
+  char const *inputFname = argv[1];
+
+  traceAddSys("progress");
+
+  // run lexer
+  traceProgress() << "lexical analysis...\n";
+  trivialLexer(inputFname, lexer2);
+
+  // start Bison-parser
+  traceProgress() << "starting parse..." << endl;
+  CycleTimer timer;
+
+  if (yyparse() != 0) {
+    cout << "yyparse returned with an error\n";
+  }
+
+  traceProgress() << "finished parse (" << timer.elapsed() << ")" << endl;
+
+  cout << "tree nodes: " << PTreeNode::allocCount
+       << endl;
+
+  return 0;
+}

Added: vendor/elsa/current/elkhound/trivbison.h
===================================================================
--- vendor/elsa/current/elkhound/trivbison.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/trivbison.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// trivbison.h            see license.txt for copyright and terms of use
+// decls shared between trivbison.cc and EFa.*tree.y
+// originally created by copying bccgr.h
+
+#ifndef TRIVBISON_H
+#define TRIVBISON_H
+
+#include <stdlib.h>     // free
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// functions called by Bison-parser
+void yyerror();
+int yylex();
+
+// Bison-parser entry
+int yyparse();
+extern int yydebug;
+       
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // TRIVBISON_H

Added: vendor/elsa/current/elkhound/trivlex.cc
===================================================================
--- vendor/elsa/current/elkhound/trivlex.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/trivlex.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// trivlex.cc            see license.txt for copyright and terms of use
+// trivial lexer (returns each character as a token)
+  
+#include "lexer2.h"     // Lexer2
+#include "syserr.h"     // xsyserror
+
+#include <stdio.h>      // FILE stuff
+
+void trivialLexer(char const *fname, Lexer2 &dest)
+{
+  FILE *fp = fopen(fname, "r");
+  if (!fp) {
+    xsyserror("open", fname);
+  }                    
+  SourceLoc loc = sourceLocManager->encodeBegin(fname);
+
+  int ch;
+  while ((ch = fgetc(fp)) != EOF) {
+    // abuse Lexer2 to hold chars
+    Lexer2Token *tok = new Lexer2Token((Lexer2TokenType)ch, loc);
+
+    // add it to list
+    dest.addToken(tok);
+                                         
+    char aChar = ch;
+    loc = sourceLocManager->advText(loc, &aChar, 1);
+  }
+  dest.addEOFToken();
+}

Added: vendor/elsa/current/elkhound/trivlex.h
===================================================================
--- vendor/elsa/current/elkhound/trivlex.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/trivlex.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// trivlex.h            see license.txt for copyright and terms of use
+// decl for trivlex.cc
+
+#ifndef TRIVLEX_H
+#define TRIVLEX_H
+
+class Lexer2;
+void trivialLexer(char const *fname, Lexer2 &dest);
+
+#endif // TRIVLEX_H

Added: vendor/elsa/current/elkhound/trivmain.cc
===================================================================
--- vendor/elsa/current/elkhound/trivmain.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/trivmain.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,185 @@
+// trivmain.cc            see license.txt for copyright and terms of use
+// main() for use with trivlex, and grammars which just test
+// parsing properties
+
+#ifndef GRAMMAR_NAME
+  #error set preprocessor symbol GRAMMAR_NAME to the name of the .bin grammar file
+#endif
+
+#include "trivlex.h"   // trivialLexer
+#include "test.h"      // ARGS_MAIN
+#include "trace.h"     // TRACE_ARGS
+#include "useract.h"   // TrivialUserActions
+#include "lexer2.h"    // Lexer2
+#include "glr.h"       // GLR
+#include "useract.h"   // UserActions
+#include "ptreenode.h" // PTreeNode
+#include "cc_lang.h"   // CCLang
+#include "exc.h"       // throw_XOpen
+
+#include <string.h>    // strcmp
+#include <stdlib.h>    // exit
+
+// no bison-parser present, so need to define this
+Lexer2Token const *yylval = NULL;
+
+
+// compute the sum at the top of SSx.gr.in
+TreeCount ssxCount(int n)
+{
+  static TreeCount *memoized = NULL;
+  if (!memoized) {
+    memoized = new TreeCount[n+1];
+
+    memoized[0] = 1;      // seed value: ssxCount(0)=1
+
+    for (int i=1; i<n+1; i++) {
+      memoized[i] = 0;    // entry hasn't been computed yet
+    }
+  }
+
+  if (memoized[n]) {
+    return memoized[n];
+  }
+
+  TreeCount sum = 0;
+  for (int m=0; m<n; m++) {
+    sum += ssxCount(m) * ssxCount(n-1-m);
+  }
+
+  memoized[n] = sum;
+  return sum;
+}
+
+
+// compute the sum at the top of SSSx.gr.in
+TreeCount sssxCount(int n)
+{
+  static TreeCount *memoized = NULL;
+  if (!memoized) {
+    memoized = new TreeCount[n+1];
+
+    memoized[1] = 1;      // seed value: sssxCount(1)=1
+
+    for (int i=2; i<n+1; i++) {
+      memoized[i] = 0;    // entry hasn't been computed yet
+    }
+  }
+
+  xassert(n > 0);
+
+  if (memoized[n]) {
+    return memoized[n];
+  }
+
+  TreeCount sum = sssxCount(n-1);
+
+  for (int m = 1; m <= n-3; m++) {
+    for (int p = 1; m+p <= n-2; p++) {
+      int q = n-1 - m - p;
+      xassert(q > 0);
+
+      sum += sssxCount(m) * sssxCount(p) * sssxCount(q);
+    }
+  }
+
+  memoized[n] = sum;
+  return sum;
+}
+
+
+// defined in the grammar file
+UserActions *makeUserActions();
+
+void entry(int argc, char *argv[])
+{
+  char const *progName = argv[0];
+  TRACE_ARGS();
+
+  if (argc < 2) {
+    printf("usage: %s [-tr flags] [-count] input-file\n", progName);
+    return;
+  }
+
+  bool count = false;
+  if (0==strcmp(argv[1], "-count")) {
+    count = true;
+    argv++;    // shift
+    argc--;
+  }
+
+  SourceLocManager mgr;
+
+  char const *inputFname = argv[1];
+
+  // see how long the input is
+  int inputLen;
+  {
+    FILE *input = fopen(inputFname, "r");
+    if (!input) {
+      throw_XOpen(inputFname);
+    }
+    fseek(input, 0, SEEK_END);
+    inputLen = ftell(input);
+    fclose(input);
+  }
+
+  // lex input
+  CCLang lang;
+  Lexer2 lexer(lang);
+  traceProgress() << "lexing...\n";
+  trivialLexer(inputFname, lexer);
+  lexer.beginReading();
+
+  // set up parser
+  UserActions *user = makeUserActions();
+  ParseTables *tables = user->makeTables();
+
+  // possibly replace actions with trivial ones
+  if (tracingSys("trivialActions")) {
+    user = new TrivialUserActions();
+    count = false;   // cannot count with trivial actions, because no tree is made
+  }
+
+  // make the parser object
+  GLR glr(user, tables);
+
+  // parse input
+  SemanticValue treeTop;
+  if (!glr.glrParse(lexer, treeTop)) {
+    // glrParse prints the error itself
+    exit(2);
+  }
+
+  PTreeNode *top = (PTreeNode*)treeTop;
+
+  // count # of parses
+  if (count) {
+    TreeCount numParses = top->countTrees();
+    cout << "num parses: " << numParses << endl;
+
+    TreeCount should = 0;    // meaning unknown
+    if (0==strcmp(GRAMMAR_NAME, "triv/SSx.tree.bin")) {
+      should = ssxCount((inputLen-1) / 2);
+    }
+    if (0==strcmp(GRAMMAR_NAME, "triv/SSSx.tree.bin")) {
+      should = sssxCount(inputLen);
+    }
+
+    if (should != 0) {
+      cout << "should be: " << should << endl;
+      if (should != numParses) {
+        cout << "MISMATCH in number of parse trees\n";
+      }
+    }
+  }
+  cout << "tree nodes: " << PTreeNode::allocCount
+       << endl;
+
+  if (tracingSys("printTree")) {
+    top->printTree(cout);
+  }
+}
+
+
+ARGS_MAIN

Added: vendor/elsa/current/elkhound/tutorial.html
===================================================================
--- vendor/elsa/current/elkhound/tutorial.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/tutorial.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1673 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elkhound Tutorial</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+</HEAD>
+
+<body>
+
+<center><h2>
+Elkhound Tutorial
+</h2></center>
+
+<p><center><img src="http://www.castlebarelkhounds.com/puppy111.jpg"></center>
+
+<p>The purpose of this tutorial is to walk through the steps of
+building a parser using Elkhound.  Familiarity with another parser
+generator (such as
+<a href="http://www.gnu.org/manual/bison-1.25/bison.html">Bison</a>) 
+might be helpful but should not be necessary.
+
+<p>The
+<a href="manual.html">Elkhound manual</a> may also be of use, but
+at the moment the manual is far from complete, and this tutorial
+has much more information.
+
+<h3>Contents</h3>
+<ul>
+<li><a href="#sec1">1. The Language to Parse</a>
+<li><a href="#sec2">2. The Lexer</a>
+<li><a href="#sec3">3. A grammar for AExp</a>
+<li><a href="#sec4">4. The parser driver</a>
+<li><a href="#sec5">5. Resolving the ambiguity</a>
+<li><a href="#sec6">6. Parse actions</a>
+<li><a href="#sec7">7. Filling out the language</a>
+<li><a href="#sec8">8. Building an AST</a>
+<li><a href="#sec9">9. Late disambiguation</a>
+<li><a href="#conc">Conclusion</a>
+<li><a href="#refs">References</a>
+</ul>
+
+<a name="sec1"></a>
+<h2>1. The Language to Parse</h2>
+<!-- FILES: gcom1 -->
+
+<p>I'll use Dijkstra's guarded command language as the example language
+to parse <a href="#ref1">[1]</a>.  We can describe the syntax with
+the nonterminals <b>AExp</b> (arithmetic expression), <b>BExp</b> (boolean
+expression), <b>Stmt</b> (statement) and <b>GCom</b> (guarded command):
+
+<pre>
+  AExp ::= n                  // integer literal
+         | x                  // variable name
+         | AExp + AExp        // addition
+         | AExp - AExp        // subtraction
+         | AExp * AExp        // multiplication
+         | (AExp)             // grouping parentheses
+
+  BExp ::= true
+         | false
+         | AExp = AExp        // equality test
+         | AExp &lt; AExp        // less than
+         | !BExp              // boolean negation
+         | BExp /\ BExp       // and
+         | BExp \/ BExp       // or
+         | (BExp)             // grouping
+
+  Stmt ::= skip               // do nothing
+         | abort              // terminate execution unsuccessfully
+         | print x            // print variable value
+         | x := AExp          // variable assignment
+         | Stmt ; Stmt        // sequential execution
+         | if GCom fi         // guarded command
+         | do GCom od         // loop
+
+  GCom ::= BExp -&gt; Stmt       // run command if expression is true
+         | GCom # GCom        // nondeterministic choice (using "#" for "fatbar")
+</pre>
+
+<p>My hope is this example language will illustrate the main tasks of
+parser construction without being yet another "desktop calculator"
+example.  Of course, we'll start with just AExp (since it's the only
+nonterminal that doesn't depend on the others), so initially it
+will be the same old example.
+
+<a name="sec2"></a>
+<h2>2. The Lexer</h2>
+<!-- FILES: gcom1 -->
+
+<p>The first step is to write the lexer.  While it is possible to
+put the lexer definition right into the grammar file (using the
+<tt>verbatim</tt> and <tt>impl_verbatim</tt> directives), and
+doing so might make the example shorter, it would not represent
+very good design.  So the lexer is its own module.
+
+<a name="sec2.1"></a>
+<h3>2.1 &nbsp; lexer.h</h3>
+
+<p>The header <a href="examples/gcom1/lexer.h"><tt>lexer.h</tt></a>
+starts with an enumeration describing the tokens and their
+associated codes:
+
+<pre>
+  // token codes (must agree with the parser)
+  enum TokenCode {
+    TOK_EOF         = 0,     // end of file
+    TOK_LITERAL,             // integer literal
+    TOK_IDENTIFIER,          // identifier like "x"
+    TOK_PLUS,                // "+"
+    TOK_MINUS,               // "-"
+    TOK_TIMES,               // "*"
+    TOK_LPAREN,              // "("
+    TOK_RPAREN,              // ")"
+  };
+</pre>
+
+<p>Next, a class needs to implement <tt>LexerInterface</tt>
+(<a href="lexerint.h"><tt>lexerint.h</tt></a>).  The parser's
+interaction with the lexer is conducted via this interface:
+
+<pre>
+  // read characters from stdin, yield tokens for the parser
+  class Lexer : public LexerInterface {
+  public:
+    // function that retrieves the next token from
+    // the input stream
+    static void nextToken(LexerInterface *lex);
+    virtual NextTokenFunc getTokenFunc() const
+      { return &amp;Lexer::nextToken; }
+
+    // debugging assistance functions
+    string tokenDesc() const;
+    string tokenKindDesc(int kind) const;
+  };
+</pre>
+
+<a name="sec2.2"></a>
+<h3>2.2 &nbsp; lexer.cc</h3>
+
+<p>Typically, one would use a lexer generator such as <a
+href="http://www.gnu.org/software/flex/">flex</a> to help write a fast
+lexer.  However, this tutorial is not about flex, and is not concerned
+with performance, so we'll use a simple hand-coded lexer.  The lexer's
+primary task is to set the <tt>type</tt> field equal to the code of
+the token that is found.  For some tokens (<tt>TOK_LITERAL</tt> and
+<tt>TOK_IDENTIFIER</tt> in our example), it also sets the
+<tt>sval</tt> (semantic value) field.  The meaning of <tt>sval</tt> is
+decided by the person who writes the lexer.
+
+<p>Here is the <tt>Lexer::nextToken</tt> function from
+<a href="examples/gcom1/lexer.cc">lexer.cc</a>:
+
+<pre>
+  void Lexer::nextToken(LexerInterface *lex)
+  {
+    int ch = getchar();
+
+    // skip whitespace
+    while (isspace(ch)) {
+      ch = getchar();
+    }
+
+    // end of file?
+    if (ch == EOF) {
+      lex-&gt;type = TOK_EOF;
+      return;
+    }
+
+    // simple one-character tokens
+    switch (ch) {
+      case '+': lex-&gt;type = TOK_PLUS; return;
+      case '-': lex-&gt;type = TOK_MINUS; return;
+      case '*': lex-&gt;type = TOK_TIMES; return;
+      case '(': lex-&gt;type = TOK_LPAREN; return;
+      case ')': lex-&gt;type = TOK_RPAREN; return;
+    }
+
+    // integer literal
+    if (isdigit(ch)) {
+      int value = 0;
+      while (isdigit(ch)) {
+        value = value*10 + ch-'0';
+        ch = getchar();
+      }
+      ungetc(ch, stdin);      // put back the nondigit
+
+      // semantic value is the integer value of the literal
+      lex-&gt;sval = (SemanticValue)value;
+
+      lex-&gt;type = TOK_LITERAL;
+      return;
+    }
+
+    // identifier
+    if (isalpha(ch)) {        // must start with letter
+      char buf[80];
+      int i=0;
+      while (isalnum(ch)) {   // but allow digits later on
+        buf[i++] = (char)ch;
+        if (i==80) {
+          fprintf(stderr, "identifier is too long\n");
+          abort();
+        }
+        ch = getchar();
+      }
+      buf[i]=0;
+      ungetc(ch, stdin);
+
+      // semantic value is a pointer to an allocated string; it
+      // is simply leaked (never deallocated) for this example
+      lex-&gt;sval = (SemanticValue)strdup(buf);
+
+      lex-&gt;type = TOK_IDENTIFIER;
+      return;
+    }
+
+    fprintf(stderr, "illegal character: %c\n", ch);
+    abort();
+  }
+</pre>
+
+<p>The lexer interface includes functions that return information
+about the tokens, mainly to assist in debugging.  For example,
+when the Elkhound parser is told to print out the actions it is
+taking, it uses these description functions to make that output
+more informative.
+
+<pre>
+  string Lexer::tokenDesc() const
+  {
+    switch (type) {
+      // for two kinds of tokens, interpret their semantic value
+      case TOK_LITERAL:      return stringf("%d", (int)sval);
+      case TOK_IDENTIFIER:   return string((char*)sval);
+
+      // otherwise, just return the token kind description
+      default:               return tokenKindDesc(type);
+    }
+  }
+
+
+  string Lexer::tokenKindDesc(int kind) const
+  {
+    switch (kind) {
+      case TOK_EOF:          return "EOF";
+      case TOK_LITERAL:      return "lit";
+      case TOK_IDENTIFIER:   return "id";
+      default: {
+        static char const map[] = "+-*()";
+        return substring(&amp;map[kind-TOK_PLUS], 1);
+      }
+    }
+  }
+</pre>
+
+<a name="sec2.3"></a>
+<h3>2.3 &nbsp; Test the lexer</h3>
+
+<p>Finally, it's useful to write a simple driver to test the lexer by
+itself.  It also illustrates how the parser will use the lexer
+interface.  This driver will only be used for the lexer test program;
+it's not the <tt>main()</tt> function of the completed parser program.
+
+<pre>
+  #ifdef TEST_LEXER
+  int main()
+  {
+    Lexer lexer;
+    for (;;) {
+      lexer.getTokenFunc()(&amp;lexer);    // first call yields a function pointer
+
+      // print the returned token
+      string desc = lexer.tokenDesc();
+      printf("%s\n", desc.c_str());
+
+      if (lexer.type == TOK_EOF) {
+        break;
+      }
+    }
+
+    return 0;
+  }
+  #endif // TEST_LEXER
+</pre>
+
+<p>We can compile and run this completed lexer test program:
+
+<pre>
+  $ g++ -o lexer -g -Wall -I../.. -I../../../smbase -DTEST_LEXER lexer.cc \
+    ../../libelkhound.a ../../../smbase/libsmbase.a
+  $ echo "5 + myVar * (6 + 7)" | ./lexer
+  5
+  +
+  myVar
+  *
+  (
+  6
+  +
+  7
+  )
+  EOF
+</pre>
+
+<p>The <a href="examples/gcom1/Makefile"><tt>Makefile</tt></a> knows how
+to do the compilation step; just say <tt>make lexer</tt> in the
+<tt>examples/gcom1</tt> directory of Elkhound.
+
+<a name="sec3"></a>
+<h2>3. A grammar for AExp</h2>
+<!-- FILES: gcom1 -->
+
+<a name="sec3.1"></a>
+<h3>3.1 &nbsp; Context class</h3>
+
+<p>All of the parsing actions become methods of a class, called the
+parser context class.  Fields of that class do the job that would
+be done with global variables in other parser generators.  Since
+we don't need any such context yet, we use an empty class.  It
+must implement the <tt>UserActions</tt>
+(<a href="useract.h"><tt>useract.h</tt></a>) interface.
+
+<pre>
+  context_class GCom : public UserActions {
+  public:
+    // empty for now
+  };
+</pre>
+
+<a name="sec3.2"></a>
+<h3>3.2 &nbsp; Terminals</h3>
+
+<p>Next, the tokens or terminal symbols of the grammar must be
+declared, along with their numeric codes.  Tokens can be given
+optional aliases (in quotes) to make the grammar that follows
+more readable.
+
+<pre>
+  terminals {
+    0 : TOK_EOF                        ;
+    1 : TOK_LITERAL                    ;
+    2 : TOK_IDENTIFIER                 "x";
+    3 : TOK_PLUS                       "+";
+    4 : TOK_MINUS                      "-";
+    5 : TOK_TIMES                      "*";
+    6 : TOK_LPAREN                     "(";
+    7 : TOK_RPAREN                     ")";
+  }
+</pre>
+
+<p>Since this information repeats information already in <tt>lexer.h</tt>,
+there is a script, <a href="make-tok"><tt>make-tok</tt></a>, that can
+create it automatically.  Run the script like this:
+
+<pre>
+  $ perl ../../make-tok TokenCode &lt;lexer.h &gt;tokens.tok
+</pre>
+
+and then the terminals section of the grammar becomes simply
+
+<pre>
+  terminals {
+    include("tokens.tok")
+  }
+</pre>
+
+<a name="sec3.3"></a>
+<h3>3.3 &nbsp; The grammar</h3>
+
+<p>Finally, we specify the grammar.  Nonterminals are introduced with
+the <tt>nonterm</tt> keyword, then the name of the nonterminal and an
+open-brace ("<tt>{</tt>").  Inside the braces are a sequence of
+right-hand sides: begin with "<tt>-&gt;</tt>" (pronounced "rewrites
+as"), then a sequence of terminals or nonterminals, then a semicolon
+("<tt>;</tt>").
+
+<pre>
+  nonterm AExp {
+    -> TOK_LITERAL;
+    -> TOK_IDENTIFIER;
+    -> AExp "+" AExp;
+    -> AExp "-" AExp;
+    -> AExp "*" AExp;
+    -> "(" AExp ")";
+  }
+</pre>
+
+<p>The syntax is free-form; all whitespace is equivalent.  The example
+could have been written all on one line, or spread out onto even more
+lines (with blank lines wherever).  You can put comments, either C++-style
+"<tt>//</tt>" or C-style "<tt>/*...*/</tt>", anywhere you can put
+whitespace.
+
+<p>Some optional components have been left out of this example:
+semantic value types, right-hand side (RHS) labels, and parse
+actions.  They will be addressed in subsequent sections.
+
+<a name="sec3.4"></a>
+<h3>3.4 &nbsp; Running elkhound</h3>
+
+<p>The next step is to run <tt>elkhound</tt>, the parser generator
+program.  (Run it without arguments to see a short usage description.)
+
+<pre>
+  $ ../../elkhound gcom.gr
+  9 shift/reduce conflicts
+</pre>
+
+<p>It has some shift/reduce conflicts, because the grammar is
+ambiguous, but we'll deal with them later.
+
+<p><tt>elkhound</tt> wrote output to two files, <tt>gcom.h</tt> and
+<tt>gcom.cc</tt>.  <tt>gcom.h</tt> contains the definition of the
+parser context class, <tt>GCom</tt>.  It consists of whatever appeared
+in the <tt>context_class</tt> declaration in the grammar file, plus
+declarations used during parsing.
+
+<pre>
+  // gcom.h
+  // *** DO NOT EDIT BY HAND ***
+  // automatically generated by elkhound, from gcom.gr
+
+  #ifndef GCOM_H
+  #define GCOM_H
+
+  #include "useract.h"     // UserActions
+
+
+  // parser context class
+  class 
+  #line 6 "gcom.gr"
+   GCom : public UserActions {
+  public:
+    // empty for now
+
+  #line 19 "gcom.h"
+
+
+  private:
+    USER_ACTION_FUNCTIONS      // see useract.h
+
+    // declare the actual action function
+    static SemanticValue doReductionAction(
+      GCom *ths,
+      int productionId, SemanticValue const *semanticValues,
+    SourceLoc loc);
+
+    // declare the classifier function
+    static int reclassifyToken(
+      GCom *ths,
+      int oldTokenType, SemanticValue sval);
+
+    void action0___EarlyStartSymbol(SourceLoc loc, SemanticValue top);
+    void action1_AExp(SourceLoc loc);
+    void action2_AExp(SourceLoc loc);
+    void action3_AExp(SourceLoc loc);
+    void action4_AExp(SourceLoc loc);
+    void action5_AExp(SourceLoc loc);
+    void action6_AExp(SourceLoc loc);
+
+  // the function which makes the parse tables
+  public:
+    virtual ParseTables *makeTables();
+  };
+
+  #endif // GCOM_H
+</pre>
+
+<p><tt>gcom.cc</tt> contains implementations of those functions,
+plus the parse tables themselves as static data.  I don't include
+example output here because the details aren't very important
+right now.
+
+<a name="sec4"></a>
+<h2>4. The parser driver</h2>
+<!-- FILES: gcom1 -->
+
+<p>Finally, we're ready to write a <tt>main()</tt> function to tie it
+all together.  Again, this could have been stuffed into
+<tt>gcom.gr</tt>, but it's better to separate it into another file (<a
+href="examples/gcom1/parser.cc"><tt>parser.cc</tt></a>) for
+maintainability.
+
+<pre>
+  #include "lexer.h"     // Lexer
+  #include "gcom.h"      // GCom
+  #include "glr.h"       // GLR
+
+  int main()
+  {
+    // create and initialize the lexer
+    Lexer lexer;
+    lexer.nextToken(&amp;lexer);
+
+    // create the parser context object
+    GCom gcom;
+
+    // initialize the parser
+    GLR glr(&amp;gcom, gcom.makeTables());
+
+    // parse the input
+    SemanticValue result;
+    if (!glr.glrParse(lexer, result)) {
+      printf("parse error\n");
+      return 2;
+    }
+
+    // print result
+    printf("result: %d\n", (int)result);
+
+    return 0;
+  }
+</pre>
+
+<p>Compile and link this program (can also use the
+<a href="examples/gcom1/Makefile"><tt>Makefile</tt></a>: "<tt>make parser</tt>"):
+
+<pre>
+  $ g++ -c -o lexer.o -g -Wall -I../.. -I../../../smbase lexer.cc
+  $ g++ -c -o parser.o -g -Wall -I../.. -I../../../smbase parser.cc
+  $ g++ -c -o gcom.o -g -Wall -I../.. -I../../../smbase gcom.cc
+  $ g++ -o parser lexer.o parser.o gcom.o -g -Wall ../../libelkhound.a ../../../smbase/libsmbase.a
+</pre>
+
+<p>Right now, it doesn't do much more than recognize the language:
+
+<pre>
+  $ echo "2" | ./parser
+  result: 0
+
+  $ echo "2 + 3" | ./parser
+  result: 0
+
+  $ echo "2 + 3 +" | ./parser
+  WARNING: there is no action to deallocate terminal TOK_PLUS
+  In state 4, I expected one of these tokens:
+    [1] lit
+    [2] id
+    [6] (
+  &lt;noloc&gt;:1:1: Parse error (state 4) at EOF
+  parse error
+
+  $ echo "2 + 3 + 5" | ./parser
+  &lt;noloc&gt;:1:1: WARNING: there is no action to merge nonterm AExp
+  result: 0
+
+  $ echo "2 + 3 + 5 +" | ./parser
+  &lt;noloc&gt;:1:1: WARNING: there is no action to merge nonterm AExp
+  WARNING: there is no action to deallocate terminal TOK_PLUS
+  In state 4, I expected one of these tokens:
+    [1] lit
+    [2] id
+    [6] (
+  &lt;noloc&gt;:1:1: Parse error (state 4) at EOF
+  parse error
+</pre>
+
+<p>The parse error message explains which tokens would have allowed
+the parser to make progress for at least one more token of input.
+Elkhound's error diagnosis and recovery is unfortunately still quite
+primitive; among the TODOs is to improve it.  Anyway,
+the output can be suppressed if desired by adding to <tt>main()</tt>:
+<pre>
+  glr.noisyFailedParse = false;
+</pre>
+
+<p>The complaints about not being able to deallocate terminals mean
+the parser is dropping semantic values on the floor.  Elkhound offers
+a way to specify what should happen in that case, but since we did
+not, the parser prints a warning.  The warning can be suppressed by
+adding at the top of <tt>gcom.gr</tt>:
+<pre>
+  option useGCDefaults;
+</pre>
+
+<p>2005-03-03: I just made it so that terminals with no declared type
+are silently dropped on the floor, so you won't see the above
+warnings about deallocating terminals.
+
+<p>Finally, the warning about merging the nonterminal AExp means that
+the parser discovered an ambiguity, but the grammar did not specify
+how to handle it, so (at least) one of the ambiguous alternatives was
+arbitrarily dropped.  We could suppress that by specifying an empty
+ambiguity resolution procedure, but let's leave it alone for now.
+
+<p>The source files for this point in the tutorial are in the
+<a href="examples/gcom1"><tt>examples/gcom1</tt></a> directory:
+<ul>
+<li><a href="examples/gcom1/lexer.h"><tt>lexer.h</tt></a>
+<li><a href="examples/gcom1/lexer.cc"><tt>lexer.cc</tt></a>
+<li><a href="examples/gcom1/gcom.gr"><tt>gcom.gr</tt></a>
+<li><a href="examples/gcom1/parser.cc"><tt>parser.cc</tt></a>
+<li><a href="examples/gcom1/Makefile"><tt>Makefile</tt></a>
+</ul>
+
+<a name="sec5"></a>
+<h2>5. Resolving the ambiguity</h2>
+<!-- FILES: gcom2 -->
+
+<a name="sec5.1"></a>
+<h3>5.1 &nbsp; Look at the conflicts</h3>
+
+<p>Often, you can tell what the problem is by looking at the parser's
+conflict report.  To do that, run <tt>elkhound</tt> with
+"<tt>-tr conflict</tt>":
+
+<pre>
+  $ ../../elkhound -tr conflict gcom.gr
+  %%% conflict: --------- state 11 ----------
+  left context: AExp + AExp
+  sample input: TOK_LITERAL + TOK_LITERAL
+  %%% conflict: conflict for symbol TOK_PLUS
+  %%% conflict:   shift, and move to state 4
+  %%% conflict:   reduce by rule [3] AExp[void] -> AExp + AExp
+  %%% conflict: conflict for symbol TOK_MINUS
+  %%% conflict:   shift, and move to state 5
+  %%% conflict:   reduce by rule [3] AExp[void] -> AExp + AExp
+  %%% conflict: conflict for symbol TOK_TIMES
+  %%% conflict:   shift, and move to state 6
+  %%% conflict:   reduce by rule [3] AExp[void] -> AExp + AExp
+  (etc.)
+</pre>
+
+<p>What this is saying is that after seeing "AExp + AExp", if
+it sees a "+", "-" or "*" then it has two possible actions:
+<ul>
+<li>reduce using "AExp -> AExp + AExp", or
+<li>shift the symbol, in hopes of reducing that symbol before
+    reducing via the "+" rule
+</ul>
+This information may be enough for you to understand what the
+problem is and how to solve it.  However, it's rather low-level
+information, and sometimes it isn't clear where the problem
+actually lies.  Also, not every conflict leads to an ambiguity.
+
+<p>For those familiar with other parser generators, you may
+find yourself wanting to see the entire LR table.  For that,
+add "<tt>-tr lrtable</tt>" to the <tt>elkhound</tt> command
+line.  It will write another file (<tt>gcom.out</tt>).
+
+<a name="sec5.2"></a>
+<h3>5.2 &nbsp; Print the tree</h3>
+
+<p>If you have an input that demonstrates a geniune ambiguity, you can
+have Elkhound print the parse tree, including ambiguities.  The parse
+tree can then be compared with the input and grammar to decide how to
+proceed.
+
+<p>To print the parse tree, we just need to change the driver
+a little.  Specifically, we wrap the lexer with a version that
+just yields the nonterminal name, and substitute the given actions
+with actions that build a parse tree.  We need two more headers:
+
+<pre>
+  #include "ptreenode.h" // PTreeNode
+  #include "ptreeact.h"  // ParseTreeLexer, ParseTreeActions
+</pre>
+
+Then, run the parser like this:
+
+<pre>
+  // wrap the lexer and actions with versions that make a parse tree
+  ParseTreeLexer ptlexer(&amp;lexer, &amp;gcom);
+  ParseTreeActions ptact(&amp;gcom, gcom.makeTables());
+
+  // initialize the parser
+  GLR glr(&amp;ptact, ptact.getTables());
+
+  // parse the input
+  SemanticValue result;
+  if (!glr.glrParse(ptlexer, result)) {
+    printf("parse error\n");
+    return 2;
+  }
+
+  // print the tree
+  PTreeNode *ptn = (PTreeNode*)result;
+  ptn-&gt;printTree(cout, PTreeNode::PF_EXPAND);
+</pre>
+
+<p>The file <a href="examples/gcom2/parser.cc"><tt>parser.cc</tt></a>
+decides whether to print the tree based on a command-line argument
+"<tt>-tree</tt>".  The new parser gives some interesting output:
+
+<pre>
+  $ echo "2" | ./parser -tree
+  __EarlyStartSymbol -&gt; AExp TOK_EOF
+    AExp -&gt; TOK_LITERAL
+      TOK_LITERAL
+    TOK_EOF
+
+  $ echo "2 + 3" | ./parser -tree
+  __EarlyStartSymbol -&gt; AExp TOK_EOF
+    AExp -&gt; AExp TOK_PLUS AExp
+      AExp -&gt; TOK_LITERAL
+        TOK_LITERAL
+      TOK_PLUS
+      AExp -&gt; TOK_LITERAL
+        TOK_LITERAL
+    TOK_EOF
+
+  $ echo "2 + 3 + 4" | ./parser -tree
+  __EarlyStartSymbol -&gt; AExp TOK_EOF
+    --------- ambiguous AExp: 1 of 2 ---------
+      AExp -&gt; AExp TOK_PLUS AExp
+        AExp -&gt; AExp TOK_PLUS AExp
+          AExp -&gt; TOK_LITERAL
+            TOK_LITERAL
+          TOK_PLUS
+          AExp -&gt; TOK_LITERAL
+            TOK_LITERAL
+        TOK_PLUS
+        AExp -&gt; TOK_LITERAL
+          TOK_LITERAL
+    --------- ambiguous AExp: 2 of 2 ---------
+      AExp -&gt; AExp TOK_PLUS AExp
+        AExp -&gt; TOK_LITERAL
+          TOK_LITERAL
+        TOK_PLUS
+        AExp -&gt; AExp TOK_PLUS AExp
+          AExp -&gt; TOK_LITERAL
+            TOK_LITERAL
+          TOK_PLUS
+          AExp -&gt; TOK_LITERAL
+            TOK_LITERAL
+    --------- end of ambiguous AExp ---------
+    TOK_EOF
+
+</pre>
+
+<p>As one can tell by inspecting the grammar, an ambiguity arises
+because the production
+
+<pre>
+  AExp -&gt; AExp "+" AExp
+</pre>
+
+does not specify an associativity for "<tt>+</tt>".  Moreover, we
+can see that "<tt>-</tt>" and "<tt>*</tt>" have the same problem,
+and that there is no specified precedence among these operators.
+
+<a name="sec5.3"></a>
+<h3>5.3 &nbsp; Precedence and associativity</h3>
+<!-- FILES: gcom3 -->
+
+<p>These problems are easy to fix.  We can just tell Elkhound the
+precedence and associativity of these operators, in the
+<tt>terminals</tt> section of
+<a href="examples/gcom3/gcom.gr"><tt>gcom.gr</tt></a>:
+
+<pre>
+  terminals {
+    include("tokens.tok")
+
+    precedence {
+      left  20 "*";        // high precedence, left associative
+      left  10 "+" "-";    // low precedence, left associative
+    }
+  }
+</pre>
+
+<p>Higher precedence numbers mean higher precedence, i.e. that those
+operators bind more tightly.  The order in which the declarations
+appear is irrelevant; only the numbers matter.  Operators with the
+same precedence are resolved using associativity, typically either
+"<tt>left</tt>" or "<tt>right</tt>".  See the 
+<a href="manual.html">manual</a>
+(Section 7) for more information.
+
+<p>Now, <tt>elkhound</tt> reports no LR conflicts, which implies
+the grammar is unambiguous (though the converse is not true: the
+presence of conflicts does not guarantee ambiguity).  We can see
+that the tree for "<tt>2 + 3 + 4</tt>" no longer contains
+ambiguities:
+
+<pre>
+  $ echo "2 + 3 + 4" | ./parser -tree
+  __EarlyStartSymbol -&gt; AExp TOK_EOF
+    AExp -&gt; AExp TOK_PLUS AExp
+      AExp -&gt; AExp TOK_PLUS AExp
+        AExp -&gt; TOK_LITERAL
+          TOK_LITERAL
+        TOK_PLUS
+        AExp -&gt; TOK_LITERAL
+          TOK_LITERAL
+      TOK_PLUS
+      AExp -&gt; TOK_LITERAL
+        TOK_LITERAL
+    TOK_EOF
+</pre>
+
+<p>Precedence and associativity can only be used when the
+disambiguation criteria is entirely syntactic, and fairly simple at
+that.  One of Elkhound's special features is the ability to tolerate
+ambiguity during parsing, letting the user defer disambiguation until
+it is convenient.  Later on I'll demonstrate how to do this.
+
+
+<a name="sec6"></a>
+<h2>6. Parse actions</h2>
+<!-- FILES: gcom4 -->
+
+<p>To make the program do anything besides simply recognize a
+language, we need to add actions to the grammar productions.  Actions
+are written in C++, inside braces ("<tt>{</tt>" and "<tt>}</tt>")
+after the right-hand side (RHS).  Like the rest of the grammar,
+actions are free-form, and can span many lines if needed.
+
+<p>An action can yield a <i>semantic value</i>, or sval.  Svals
+can have whatever meaning you want.  However, since they are stored
+internally in a single word (typically 32 bits), data that does not
+fit into one word must be referred to with a pointer or some other
+indirection mechanism.  Svals are yielded by simply <tt>return</tt>ing
+them.
+
+<p>Semantic values have a declared type.  When the generated parser is
+compiled by the C++ compiler, it will check that the type matches what
+is actually yielded.  The sval type for a nonterminal is specified by
+enclosing it in parentheses ("<tt>(</tt>" and "<tt>)</tt>") right
+after the <tt>nonterm</tt> keyword at the beginning of the nonterminal
+declaration.  The type for a terminal is declared in the
+<tt>terminals</tt> section with the syntax:
+
+<blockquote>
+  <tt>token(</tt> <i>type</i> <tt>)</tt> <i>tokenName</i> <tt>;</tt>
+</blockquote>
+
+<p>Actions accept svals from the actions that run for productions
+lower in the parse tree.  Specifically, each RHS element of a rule
+will yield some semantic value, and that value can be used by
+referring to the RHS label.  Labels are attached to RHS elements by
+preceding their symbol (terminal or nonterminal) name with an
+identifier and a colon ("<tt>:</tt>").  Within the action body, these
+labels are ordinary C++ variable names, with their proper declared type.
+
+<p>Here is a complete example for AExp which simply evaluates the
+expression in the usual way (from
+<a href="examples/gcom4/gcom.gr"><tt>gcom.gr</tt></a>):
+
+<pre>
+  nonterm(int) AExp {
+    -&gt; n:TOK_LITERAL         { return n; }
+    -&gt; a1:AExp "+" a2:AExp   { return a1 + a2; }
+    -&gt; a1:AExp "-" a2:AExp   { return a1 - a2; }
+    -&gt; a1:AExp "*" a2:AExp   { return a1 * a2; }
+    -&gt; "(" a:AExp ")"        { return a; }
+
+    // interpret identifiers using environment variables; it's
+    // a bit of a hack, and we'll do something better later
+    -&gt; x:TOK_IDENTIFIER {
+         char const *envp = getenv(x);
+         if (envp) {
+           return atoi(envp);
+         }
+         else {
+           return 0;      // not defined, call it 0
+         }
+       }
+  }
+</pre>
+
+<p>I added a <tt>verbatim</tt> section at the top, so the identifier
+action could call two library functions.  This gets emitted directly
+into the generated <tt>gcom.h</tt> file.  In this case it could also
+have been <tt>impl_verbatim</tt>, which is only inserted into 
+<tt>gcom.cc</tt>.
+
+<pre>
+  verbatim {
+    #include &lt;stdlib.h&gt;     // getenv, atoi
+  }
+</pre>
+
+
+<p>Now the parser finally does some useful computation.  (The last two
+examples assume you're using the
+<a href="http://www.gnu.org/software/bash/bash.html">bash</a> shell.
+If not, adjust them to use your shell's syntax for setting environment
+variables.)
+
+<pre>
+  $ echo "2 + 3 * 4" | ./parser
+  result: 14
+
+  $ echo "(2 + 3) * 4" | ./parser
+  result: 20
+
+  $ echo "(2 + 3) * 4 - 72" | ./parser
+  result: -52
+
+  $ echo "(2 + 3) * z - 72" | ./parser
+  result: -72
+
+  $ export a=4; echo "2 + a" | ./parser
+  result: 6
+
+  $ export a=4 b=6; echo "2 + a * b" | ./parser
+  result: 26
+</pre>
+
+<p>The source files for this point in the tutorial are in the
+<a href="examples/gcom4"><tt>examples/gcom4</tt></a> directory:
+<ul>
+<li><a href="examples/gcom4/lexer.h"><tt>lexer.h</tt></a>
+<li><a href="examples/gcom4/lexer.cc"><tt>lexer.cc</tt></a>
+<li><a href="examples/gcom4/gcom.gr"><tt>gcom.gr</tt></a>
+<li><a href="examples/gcom4/parser.cc"><tt>parser.cc</tt></a>
+<li><a href="examples/gcom4/Makefile"><tt>Makefile</tt></a>
+</ul>
+
+<a name="sec7"></a>
+<h2>7. Filling out the language</h2>
+<!-- FILES: gcom5 -->
+
+<p>At this point, let's fill out the lexer and grammar to parse the 
+whole GCom language.  The lexer header gets some new tokens,
+<a href="examples/gcom5/lexer.h"><tt>lexer.h</tt></a>:
+
+<pre>
+  // for BExp
+  TOK_TRUE,                // "true"
+  TOK_FALSE,               // "false"
+  TOK_EQUAL,               // "="
+  TOK_LESS,                // "<"
+  (etc.)
+</pre>
+
+<p>The lexer implementation gets more complicated (just an excerpt),
+<a href="examples/gcom5/lexer.cc"><tt>lexer.cc</tt></a>:
+
+<pre>
+  case '-':
+    // TOK_MINUS or TOK_ARROW?
+    ch = getchar();
+    if (ch == '>') {
+      lex->type = TOK_ARROW;
+    }
+    else {
+      lex->type = TOK_MINUS;
+      ungetc(ch, stdin);
+    }
+    return;
+</pre>
+
+<p>Finally, three new nonterminals are added to the grammar file,
+<a href="examples/gcom5/gcom.gr"><tt>gcom.gr</tt></a>:
+
+<pre>
+  nonterm(bool) BExp {
+    -> "true"                     { return true; }
+    -> "false"                    { return false; }
+    -> a1:AExp "=" a2:AExp        { return a1 == a2; }
+    -> a1:AExp "<" a2:AExp        { return a1 < a2; }
+    -> "!" b:BExp                 { return !b; }
+    -> b1:BExp TOK_AND b2:BExp    { return b1 && b2; }
+    -> b1:BExp TOK_OR  b2:BExp    { return b1 || b2; }
+    -> "(" b:BExp ")"             { return b; }
+  }
+
+
+  nonterm Stmt {
+    -> "skip" {
+         // no-op
+       }
+
+    -> "abort" {
+         printf("abort command executed\n");
+         exit(0);
+       }
+
+    -> "print" x:TOK_IDENTIFIER {
+         char const *envp = getenv(x);
+         printf("%s is %d\n", x, envp? atoi(envp) : 0);
+       }
+
+    -> x:TOK_IDENTIFIER ":=" a:AExp {
+         // like above, use the environment variables
+         putenv(strdup(stringf("%s=%d", x, a).c_str()));
+       }
+
+    -> Stmt ";" Stmt {
+         // sequencing is automatic
+       }
+
+    -> "if" g:GCom "fi" {
+         if (!g) {
+           printf("'if' command had no enabled alternatives; aborting\n");
+           exit(0);
+         }
+       }
+
+    -> "do" GCom "od" {
+         // There's no way to get the parser to loop; that's not its job.
+         // For now, we'll just treat it like an 'if' that doesn't mind
+         // when no alternative is enabled.  Later, we'll build a tree
+         // and do this right.
+       }
+  }
+
+
+  // a guarded command returns true if it found an enabled guard, and
+  // false otherwise
+  nonterm(bool) GCom {
+    -> b:BExp "->" Stmt {
+         // Like for 'do', there is no way to tell the parser not to
+         // parse part of its input, so the statement will be executed
+         // regardless of the value of 'b'.  Again, this will be fixed
+         // in a later version of this example.  For now, we can at
+         // least indicate whether the guard succeeded.
+         return b;
+       }
+
+    -> g1:GCom "#" g2:GCom {
+         return g1 || g2;
+       }
+  }
+</pre>
+
+<p>It behaves reasonably well, except that the control flow doesn't
+quite work, because the parse actions are not capable of causing the
+parser to skip sections of input, nor loop over the input.
+
+<pre>
+  $ echo "x := 2 + 3; print x" | ./parser
+  x is 5
+  result: 0
+
+  $ echo "abort" | ./parser
+  abort command executed
+
+  $ echo "skip" | ./parser
+  result: 0
+
+  $ echo "if true -> skip fi" | ./parser
+  result: 0
+
+  $ echo "if false -> skip fi" | ./parser
+  'if' command had no enabled alternatives; aborting
+
+  $ echo "if false -> skip # true -> skip fi" | ./parser
+  result: 0
+
+  $ echo "do false -> skip od" | ./parser
+  result: 0
+</pre>
+
+<p>The source files for this point in the tutorial are in the
+<a href="examples/gcom5"><tt>examples/gcom5</tt></a> directory:
+<ul>
+<li><a href="examples/gcom5/lexer.h"><tt>lexer.h</tt></a>
+<li><a href="examples/gcom5/lexer.cc"><tt>lexer.cc</tt></a>
+<li><a href="examples/gcom5/gcom.gr"><tt>gcom.gr</tt></a>
+<li><a href="examples/gcom5/parser.cc"><tt>parser.cc</tt></a>
+<li><a href="examples/gcom5/Makefile"><tt>Makefile</tt></a>
+</ul>
+
+<a name="sec8"></a>
+<h2>8. Building an AST</h2>
+<!-- FILES: gcom -->
+
+<p>To demonstrate some of the more sophisticated features of
+disambiguation and semantic-value handling, we need to make the
+example more realistic.  We'll modify the parser to build an abstract
+syntax tree (AST), instead of evaluating the program directly.  This
+will involve the use of another tool, 
+<a href="../ast/index.html"><tt>astgen</tt></a>, which is
+useful in its own right.
+
+<a name="sec8.1"></a>
+<h3>8.1 &nbsp; AST definition</h3>
+
+<p>The input to <tt>astgen</tt> consists of a sequence of class
+declarations.  Inside each class is one or more subclass
+declarations, that will become nodes in the AST.  The file
+<a href="examples/gcom/gcom.ast"><tt>gcom.ast</tt></a> begins
+with a few enumerations, and then has the classes:
+
+<pre>
+  // arithmetic expressions
+  class AExp {
+    pure_virtual int eval(Env &amp;env);
+
+    -&gt; A_lit(int n);
+    -&gt; A_var(string x);
+    -&gt; A_bin(AExp a1, AOp op, AExp a2);
+  }
+
+  // boolean expressions
+  class BExp {
+    pure_virtual bool eval(Env &amp;env);
+
+    -&gt; B_lit(bool b);
+    -&gt; B_pred(AExp a1, BPred op, AExp a2);
+    -&gt; B_not(BExp b);
+    -&gt; B_bin(BExp b1, BOp op, BExp b2);
+  }
+
+  // statements
+  class Stmt {
+    pure_virtual void eval(Env &amp;env);
+
+    -&gt; S_skip();
+    -&gt; S_abort();
+    -&gt; S_print(string x);
+    -&gt; S_assign(string x, AExp a);
+    -&gt; S_seq(Stmt s1, Stmt s2);
+    -&gt; S_if(GCom g);
+    -&gt; S_do(GCom g);
+  }
+
+  // guarded commands
+  class GCom {
+    // returns true if it finds an enabled alternative, false o.w.
+    pure_virtual bool eval(Env &amp;env);
+
+    -&gt; G_stmt(BExp b, Stmt s);
+    -&gt; G_seq(GCom g1, GCom g2);
+  }
+</pre>
+
+<p>Then, <tt>astgen</tt> will produce two files that contain
+full C++ class definitions for the AST nodes.  See
+<a href="../ast/index.html">the ast page</a> for more information.
+
+<pre>
+  $ ../../../ast/astgen -o ast gcom.ast
+  writing ast.h...
+  writing ast.cc...
+</pre>
+
+<a name="sec8.2"></a>
+<h3>8.2 &nbsp; AST-building grammar actions</h3>
+
+<p>Next, we modify the grammar to build these AST components,
+instead of evaluating the program directly; the result is
+<a href="examples/gcom/gcom.gr"><tt>gcom.gr</tt></a>.
+The only slightly tricky part is that we deallocate the strings
+allocated by the lexer when they are consumed.  The rules are
+otherwise straightforward:
+
+<pre>
+  nonterm(AExp*) AExp {
+    -&gt; n:TOK_LITERAL                { return new A_lit(n); }
+    -&gt; x:TOK_IDENTIFIER             { return new A_var(copyAndFree(x)); }
+    -&gt; a1:AExp "+" a2:AExp          { return new A_bin(a1, AO_PLUS, a2); }
+    -&gt; a1:AExp "-" a2:AExp          { return new A_bin(a1, AO_MINUS, a2); }
+    -&gt; a1:AExp "*" a2:AExp          { return new A_bin(a1, AO_TIMES, a2); }
+    -&gt; "(" a:AExp ")"               { return a; }
+  }
+
+
+  nonterm(BExp*) BExp {
+    -&gt; "true"                       { return new B_lit(true); }
+    -&gt; "false"                      { return new B_lit(false); }
+    -&gt; a1:AExp "=" a2:AExp          { return new B_pred(a1, BP_EQUAL, a2); }
+    -&gt; a1:AExp "<" a2:AExp          { return new B_pred(a1, BP_LESS, a2); }
+    -&gt; "!" b:BExp                   { return new B_not(b); }
+    -&gt; b1:BExp TOK_AND b2:BExp      { return new B_bin(b1, BO_AND, b2); }
+    -&gt; b1:BExp TOK_OR  b2:BExp      { return new B_bin(b1, BO_OR, b2); }
+    -&gt; "(" b:BExp ")"               { return b; }
+  }
+
+
+  nonterm(Stmt*) Stmt {
+    -&gt; "skip"                       { return new S_skip; }
+    -&gt; "abort"                      { return new S_abort; }
+    -&gt; "print" x:TOK_IDENTIFIER     { return new S_print(copyAndFree(x)); }
+    -&gt; x:TOK_IDENTIFIER ":=" a:AExp { return new S_assign(copyAndFree(x), a); }
+    -&gt; s1:Stmt ";" s2:Stmt          { return new S_seq(s1, s2); }
+    -&gt; "if" g:GCom "fi"             { return new S_if(g); }
+    -&gt; "do" g:GCom "od"             { return new S_do(g); }
+  }
+
+
+  nonterm(GCom*) GCom {
+    -&gt; b:BExp "-&gt;" s:Stmt           { return new G_stmt(b, s); }
+    -&gt; g1:GCom "#" g2:GCom          { return new G_seq(g1, g2); }
+  }
+</pre>
+
+<p>Do not be confused by the double meaning of names like "AExp".
+Inside the parentheses, they refer to a C++ class name; outside,
+they refer to a grammar nonterminal.  Since grammar nonterminal
+names do not automatically become type names anywhere, there is
+no conflict.
+
+<p>Digression: Notice the difference between a parse tree and an AST.
+In the AST, we do not need nodes for the grouping parentheses (they
+are only an aid to the parser), and we are free to consolidate similar
+nodes like the binary arithmetic expressions.  In general, the AST
+should reflect semantics more than syntax, whereas the parse tree
+necessarily reflects the syntax directly.  A good AST design is a key
+ingredient in a good language analysis program, since it serves as the
+communication medium between the parser and every other analysis that
+follows.
+
+<h3>8.3 &nbsp; Evaluation</h3>
+
+<p>We're ready to write the evaluation rules as methods of the AST
+nodes.  Those methods are declared in 
+<a href="examples/gcom/gcom.ast"><tt>gcom.ast</tt></a> like:
+
+<pre>
+  pure_virtual int eval(Env &amp;env);
+</pre>
+
+<p>This declaration means that in class AExp, <tt>eval</tt> is
+pure (no definition).  Further, <tt>astgen</tt> will insert
+declarations for <tt>eval</tt> into each of the subclasses
+<tt>A_lit</tt>, <tt>A_var</tt> and <tt>A_bin</tt>.  Thus, we
+only need to implement them.
+
+<p><a href="examples/gcom/eval.h"><tt>eval.h</tt></a> declares
+class <tt>Env</tt>, which contains variable bindings; we're not
+using the program's environment variables anymore.
+
+<pre>
+  class Env {
+  private:
+    // map: name -&gt; value
+    TStringHash&lt;Binding&gt; map;
+
+  public:
+    Env();
+    ~Env();
+
+    int get(char const *x);
+    void set(char const *x, int val);
+  };
+</pre>
+
+<p>Then,
+<a href="examples/gcom/eval.cc"><tt>eval.cc</tt></a> has the
+implementations of the <tt>eval</tt> routines.  Here are the
+evaluation rules for AExp; the others are straightforward as
+well:
+
+<pre>
+  int A_lit::eval(Env &amp;env)
+  {
+    return n;
+  }
+
+  int A_var::eval(Env &amp;env)
+  {
+    return env.get(x.c_str());
+  }
+
+  int A_bin::eval(Env &amp;env)
+  {
+    switch (op) {
+      default:       assert(!"bad code");
+      case AO_PLUS:  return a1-&gt;eval(env) + a2-&gt;eval(env);
+      case AO_MINUS: return a1-&gt;eval(env) - a2-&gt;eval(env);
+      case AO_TIMES: return a1-&gt;eval(env) * a2-&gt;eval(env);
+    }
+  }
+</pre>
+
+<a name="#sec8.4"></a>
+<h3>8.4 &nbsp; Modifications to the driver</h3>
+
+<p>We need a few modifications to the driver,
+<a href="examples/gcom/parser.cc"><tt>parser.cc</tt></a>.
+We need two more headers:
+
+<pre>
+  #include "ast.h"       // Stmt, etc.
+  #include "eval.h"      // Env
+</pre>
+
+<p>I've added a command-line option to print the AST (in addition
+to the one already there to print the parse tree):
+
+<pre>
+  bool printAST  = argc==2 &amp;&amp; 0==strcmp(argv[1], "-ast");
+</pre>
+
+<p>I changed the context class name to avoid a clash with an
+AST node name:
+
+<pre>
+  GComContext gcom;
+</pre>
+
+<p>And finally we have the code to print and evaluate the tree.  One
+of <tt>astgen</tt>'s features is that it supplies the <tt>debugPrint</tt>
+method automatically.
+
+<pre>
+  // result is an AST node
+  Stmt *top = (Stmt*)result;
+
+  if (printAST) {
+    top-&gt;debugPrint(cout, 0);
+  }
+
+  // evaluate
+  printf("evaluating...\n");
+  Env env;
+  top-&gt;eval(env);
+  printf("program terminated normally\n");
+
+  // recursively deallocate the tree
+  delete top;
+</pre>
+
+<a name="sec8.5"></a>
+<h3>8.5 &nbsp; A few examples</h3>
+
+<p>Let's try it on a few examples!
+
+<p><a href="examples/gcom/in1"><tt>in1</tt></a> just prints 5
+(here I also told it to print the AST):
+
+<pre>
+  $ cat in1
+  x := 5;
+  print x
+
+  $ ./parser -ast &lt;in1
+  S_seq:
+    S_assign:
+      x = "x"
+      A_lit:
+        n = 5
+    S_print:
+      x = "x"
+  evaluating...
+  x is 5
+  program terminated normally
+</pre>
+
+<p><a href="examples/gcom/in2"><tt>in2</tt></a> counts to 10:
+
+<pre>
+  $ cat in2
+  x := 0;
+  do x &lt; 10 -&gt;
+    print x;
+    x := x + 1
+  od;
+  print x
+
+  $ ./parser &lt;in2
+  evaluating...
+  x is 0
+  x is 1
+  x is 2
+  x is 3
+  x is 4
+  x is 5
+  x is 6
+  x is 7
+  x is 8
+  x is 9
+  x is 10
+  program terminated normally
+</pre>
+
+<p><a href="examples/gcom/in3"><tt>in3</tt></a> computes the greatest
+common divisor of two numbers:
+
+<pre>
+  $ cat in3
+  x := 152;
+  y := 104;
+  do !(x = y) -&gt;
+    print x;
+    print y;
+    if x &lt; y -&gt; y := y - x #
+       y &lt; x -&gt; x := x - y fi
+  od;
+  print x
+
+  $ ./parser &lt;in3
+  evaluating...
+  x is 152
+  y is 104
+  x is 48
+  y is 104
+  x is 48
+  y is 56
+  x is 48
+  y is 8
+  x is 40
+  y is 8
+  x is 32
+  y is 8
+  x is 24
+  y is 8
+  x is 16
+  y is 8
+  x is 8
+  program terminated normally
+</pre>
+
+<p>The source files for this point in the tutorial are in the
+<a href="examples/gcom"><tt>examples/gcom</tt></a> directory:
+<ul>
+<li><a href="examples/gcom/lexer.h"><tt>lexer.h</tt></a>
+<li><a href="examples/gcom/lexer.cc"><tt>lexer.cc</tt></a>
+<li><a href="examples/gcom/gcom.gr"><tt>gcom.gr</tt></a>
+<li><a href="examples/gcom/parser.cc"><tt>parser.cc</tt></a>
+<li><a href="examples/gcom/gcom.ast"><tt>gcom.ast</tt></a>
+<li><a href="examples/gcom/eval.h"><tt>eval.h</tt></a>
+<li><a href="examples/gcom/eval.cc"><tt>eval.cc</tt></a>
+<li><a href="examples/gcom/Makefile"><tt>Makefile</tt></a>
+</ul>
+
+<a name="sec9"></a>
+<h2>9. Late disambiguation</h2>
+<!-- FILES: gcom7 -->
+
+<p>Now that we've got a realistic infrustructure, I can demonstrate
+some of the options for late disambiguation.  Let's imagine that we
+wanted to implement precedence and associativity for AExp sometime
+later than parser generation time.  After removing the precedence and
+associativity declarations for "+", "-" and "*" from <a
+href="examples/gcom7/gcom.gr"><tt>gcom.gr</tt></a>, there are two main
+tasks: specify how to deallocate unused semantic values, and specify
+how to merge ambiguous alternatives.
+
+<a name="sec9.1"></a>
+<h3>9.1 &nbsp; dup and del</h3>
+
+<p>Anytime the grammar contains LR conflicts, the parser will pursue
+all possible alternatives in parallel.  When an alternative fails, it
+tries to "undo" the actions that were executed on the failed parse
+branch by calling the <tt>del()</tt> function associated with the each
+symbol that produced a value that will now be ignored.  Furthermore,
+when a value produced by one action is consumed by more than one
+action, it may be necessary to take additional action (like
+incrementing a reference count).  The <tt>dup()</tt> function makes a
+copy of an sval for later use.
+
+<p>For terminals, dup and del are specified in the <tt>terminals</tt>
+section:
+
+<pre>
+  token(int) TOK_LITERAL {
+    fun dup(n) { return n; }     // nothing special to do for ints
+    fun del(n) {}
+  }
+  token(char*) TOK_IDENTIFIER {
+    fun dup(x) { return strdup(x); }     // make a copy
+    fun del(x) { free(x); }              // delete a copy
+  }
+</pre>
+
+<p>For nonterminals, these functions are included with the
+rest of the <tt>nonterm</tt> info:
+
+<pre>
+  nonterm(AExp*) AExp {
+    fun dup(a) { return a-&gt;clone(); }     // deep copy
+    fun del(a) { delete a; }              // deep delete
+    // ... rest of AExp ...
+  }
+</pre>
+
+<p>During development, you may want to postpone dealing with
+<tt>dup</tt> and <tt>del</tt>.  Or, you might be using a
+garbage collector, and all of your dup and del functions would
+be trivial, like for TOK_LITERAL, above.  In either case, you
+can say
+
+<pre>
+  option useGCDefaults;
+</pre>
+
+at the top of the grammar file.  Then, Elkhound will automatically
+insert trivial dup/del everywhere, to suppress the warning that
+is otherwise printed when such a function is called but not
+implemented.
+
+<a name="sec9.2"></a>
+<h3>9.2 &nbsp; merge</h3>
+
+<p>An ambiguity is a situation where some sequence of terminals
+can be rewritten in more than one way to yield some nonterminal.
+For example, in the ambiguous AExp grammar, we have
+
+<pre>
+  2+3+4 -&gt; (AExp+AExp)+AExp -&gt; AExp+AExp -&gt; AExp
+  2+3+4 -&gt; AExp+(AExp+AExp) -&gt; AExp+AExp -&gt; AExp
+</pre>
+
+<p>When this happens, the parser executes both reduction
+actions for AExp, and then hands the results to the <tt>merge()</tt>
+function associated with AExp.  The merge function must return
+a semantic value to be used in place of the ambiguous alternatives.
+Furthermore, it assumes "ownership" of the original values; if one
+or both are not used in the result, it should deallocate them.
+
+<p>For AExp, we'll look inside the two alternatives, pick the
+one that respects the usual precedence and associativity rules,
+and deallocate the other one:
+
+<pre>
+  fun merge(a1,a2) {
+    if (precedence(a1) &lt; precedence(a2))
+      { delete a2; return a1; }         // lowest precedence goes on top
+    if (precedence(a1) &gt; precedence(a2))
+      { delete a1; return a2; }
+
+    // equal precedence, must be binary operators
+    A_bin *ab1 = a1-&gt;asA_bin();         // cast to A_bin*
+    A_bin *ab2 = a2-&gt;asA_bin();
+
+    // same precedence; associates to the left; that means
+    // that the RHS must use a higher-precedence operator
+    if (precedence(ab1) &lt; precedence(ab1-&gt;a2))
+      { delete ab2; return ab1; }       // high-prec exp on right
+    if (precedence(ab2) &lt; precedence(ab2-&gt;a2))
+      { delete ab1; return ab2; }       // high-prec exp on right
+
+    printf("failed to disambiguate!\n");
+    delete ab2; return ab1;             // pick arbitrarily
+  }
+</pre>
+
+<p>This depends on the <tt>precedence</tt> function:
+
+<pre>
+  static int precedence(AExp *a)
+  {
+    if (!a-&gt;isA_bin())       { return 20; }      // unary
+
+    A_bin *ab = a-&gt;asA_bin();
+    if (ab-&gt;op == AO_TIMES)  { return 10; }      // *
+    else                     { return 0;  }      // +,-
+  }
+</pre>
+
+<p>It also requires that we add an AST node to represent
+parenthetical grouping, since they now must be retained to
+participate in run-time disambiguation; see
+<a href="examples/gcom7/gcom.ast"><tt>gcom.ast</tt></a>,
+<a href="examples/gcom7/gcom.gr"><tt>gcom.gr</tt></a> and
+<a href="examples/gcom7/eval.cc"><tt>eval.cc</tt></a>.
+
+<p>One way to see how this is different from the way it was
+with precedence and associativity implemented at parser generation
+time is to compare the parse tree to the AST: the parse tree
+has the ambiguities, whereas the AST is disambiguated during
+construction by <tt>merge()</tt>:
+
+<pre>
+  $ echo "x := 2+3*4; print x" | ./parser -tree
+  __EarlyStartSymbol -&gt; Start TOK_EOF
+    Start -&gt; Stmt
+      Stmt -&gt; Stmt TOK_SEMI Stmt
+        Stmt -&gt; TOK_IDENTIFIER TOK_ASSIGN AExp
+          TOK_IDENTIFIER
+          TOK_ASSIGN
+          --------- ambiguous AExp: 1 of 2 ---------
+            AExp -&gt; AExp TOK_TIMES AExp
+              AExp -&gt; AExp TOK_PLUS AExp
+                AExp -&gt; TOK_LITERAL
+                  TOK_LITERAL
+                TOK_PLUS
+                AExp -&gt; TOK_LITERAL
+                  TOK_LITERAL
+              TOK_TIMES
+              AExp -&gt; TOK_LITERAL
+                TOK_LITERAL
+          --------- ambiguous AExp: 2 of 2 ---------
+            AExp -&gt; AExp TOK_PLUS AExp
+              AExp -&gt; TOK_LITERAL
+                TOK_LITERAL
+              TOK_PLUS
+              AExp -&gt; AExp TOK_TIMES AExp
+                AExp -&gt; TOK_LITERAL
+                  TOK_LITERAL
+                TOK_TIMES
+                AExp -&gt; TOK_LITERAL
+                  TOK_LITERAL
+          --------- end of ambiguous AExp ---------
+        TOK_SEMI
+        Stmt -&gt; TOK_PRINT TOK_IDENTIFIER
+          TOK_PRINT
+          TOK_IDENTIFIER
+    TOK_EOF
+    
+  $ echo "x := 2+3*4; print x" | ./parser -ast
+  S_seq:
+    S_assign:
+      x = "x"
+      A_bin:
+        A_lit:
+          n = 2
+        op = 0
+        A_bin:
+          A_lit:
+            n = 3
+          op = 2
+          A_lit:
+            n = 4
+    S_print:
+      x = "x"
+  evaluating...
+  x is 14
+  program terminated normally
+</pre>
+
+<p>In this example, the <tt>merge()</tt> function is able to decide
+which alternative to keep based on local (syntactic) information.
+In some situations, this might not be possible.  Another approach
+is to write <tt>merge()</tt> so that it retains <em>both</em>
+alternatives, and then <tt>eval()</tt> could do disambiguation.
+While this tutorial does not have an example of this approach,
+it is used extensively in the 
+<a href="../elsa/index.html">Elsa C++ parser</a>, so you can look
+there for further guidance.
+
+
+<p>The source files for this point in the tutorial are in the
+<a href="examples/gcom7"><tt>examples/gcom7</tt></a> directory:
+<ul>
+<li><a href="examples/gcom7/lexer.h"><tt>lexer.h</tt></a>
+<li><a href="examples/gcom7/lexer.cc"><tt>lexer.cc</tt></a>
+<li><a href="examples/gcom7/gcom.gr"><tt>gcom.gr</tt></a>
+<li><a href="examples/gcom7/parser.cc"><tt>parser.cc</tt></a>
+<li><a href="examples/gcom7/gcom.ast"><tt>gcom.ast</tt></a>
+<li><a href="examples/gcom7/eval.h"><tt>eval.h</tt></a>
+<li><a href="examples/gcom7/eval.cc"><tt>eval.cc</tt></a>
+<li><a href="examples/gcom7/Makefile"><tt>Makefile</tt></a>
+</ul>
+
+
+<a name="conc"></a>
+<h2>Conclusion</h2>
+
+<p>By now you know how to:
+<ul>
+<li>Implement the LexerInterface that Elkhound uses
+<li>Read and write the grammar syntax
+<li>Write a parser driver
+<li>Resolve ambiguities at parser-generation time with
+    precedence and associativity
+<li>Write grammar actions for use at parse time
+<li>Use <tt>astgen</tt> to build an AST
+<li>Manage copying and deallocation of semantic values during
+    nondeterministic parsing with <tt>dup()</tt> and <tt>del()</tt>
+<li>Resolve ambiguities at parse time with <tt>merge()</tt>
+</ul>
+
+<p>It's my hope that, with these skills and the Elkhound tool, you'll
+find it's easy and fun to write language analysis and translation
+programs.  If not, you can always email me (smcpeak <tt>at</tt> cs
+<tt>dot</tt> berkeley <tt>dot</tt> edu) and complain! &nbsp;
+<tt>:)</tt>
+
+
+
+<a name="refs"></a>
+<h2>References</h2>
+
+<p>
+<a name="ref1"></a>
+[1] Edsger W. Dijkstra.  <i>A Discipline of Programming.</i>
+Prentice-Hall, 1976.
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+</html>

Added: vendor/elsa/current/elkhound/useract.cc
===================================================================
--- vendor/elsa/current/elkhound/useract.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/useract.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,77 @@
+// useract.cc            see license.txt for copyright and terms of use
+// code for useract.h
+
+#include "useract.h"     // this module
+#include "typ.h"         // STATICDEF
+#include "xassert.h"     // xfailure
+
+
+UserActions::~UserActions()
+{}
+
+
+ParseTables *UserActions::makeTables()
+{
+  xfailure("this object does not have any tables");
+  return NULL;   // silence warning
+}
+
+
+// ----------------- TrivialUserActions --------------------
+UserActions::ReductionActionFunc TrivialUserActions::getReductionAction()
+{
+  return &TrivialUserActions::doReductionAction;
+}
+
+STATICDEF SemanticValue TrivialUserActions::doReductionAction(
+  UserActions *, int , SemanticValue const *
+  SOURCELOCARG( SourceLoc ) )
+  { return NULL_SVAL; }
+
+SemanticValue TrivialUserActions::duplicateTerminalValue(
+  int , SemanticValue sval)
+  { return sval; }
+
+SemanticValue TrivialUserActions::duplicateNontermValue(
+  int , SemanticValue sval)
+  { return sval; }
+
+
+void TrivialUserActions::deallocateTerminalValue(
+  int , SemanticValue )
+  {}
+
+void TrivialUserActions::deallocateNontermValue(
+  int , SemanticValue )
+  {}
+
+SemanticValue TrivialUserActions::mergeAlternativeParses(
+  int , SemanticValue left, SemanticValue
+  SOURCELOCARG( SourceLoc ) )
+  { return left; }
+
+bool TrivialUserActions::keepNontermValue(int , SemanticValue )
+  { return true; }     // do not cancel
+
+
+UserActions::ReclassifyFunc TrivialUserActions::getReclassifier()
+{
+  return &TrivialUserActions::reclassifyToken;
+}
+
+STATICDEF int TrivialUserActions::reclassifyToken(UserActions *,
+  int oldTokenType, SemanticValue )
+  { return oldTokenType; }
+
+string TrivialUserActions::terminalDescription(int, SemanticValue)
+  { return string(""); }
+
+string TrivialUserActions::nonterminalDescription(int, SemanticValue)
+  { return string(""); }
+  
+char const *TrivialUserActions::terminalName(int)
+  { return ""; }
+char const *TrivialUserActions::nonterminalName(int)
+  { return ""; }
+
+

Added: vendor/elsa/current/elkhound/useract.h
===================================================================
--- vendor/elsa/current/elkhound/useract.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/useract.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,184 @@
+// useract.h            see license.txt for copyright and terms of use
+// interface to an object containing user-defined action functions
+
+// the code appears in the .cc file generated by 'gramanl' from
+// an associated .gr file
+
+// the comments below are guidelines on writing grammar actions, since
+// those grammar actions are composed to form the single-entry
+// functions documented below
+
+#ifndef USERACT_H
+#define USERACT_H
+
+#include "glrconfig.h"     // SOURCELOC
+#include "str.h"           // string
+#include "srcloc.h"        // SourceLoc
+
+class ParseTables;         // parsetables.h
+
+// user-supplied semantic values:
+//  - Semantic values are an arbitrary word, that the user can then
+//    use as a pointer or an integer or whatever.  The parser
+//    generator inserts the appropriate casts, so the actual type
+//    I use here shouldn't ever be visible to the user.
+//  - Usually, SemanticValues that are used as pointers are considered
+//    to be owner pointers, but only in the sense that del() will be
+//    called.  It's up to the user to decide if del() actually does
+//    anything.
+typedef unsigned long SemanticValue;
+
+// name of a null sval; can't use "NULL" because of __null weirdness in gcc-3...
+#define NULL_SVAL 0
+
+
+// package of functions; the user will create an instance of a class
+// derived from this, and the parser will carry it along to invoke
+// the various action functions
+class UserActions {
+public:
+  // allow abstract user to delete
+  virtual ~UserActions();
+
+  // user-supplied reduction actions
+  //  - production 'id' is being used to reduce
+  //  - 'svals' contains an array of semantic values yielded by the RHS
+  //    symbols, such that the 0th element is the leftmost RHS element;
+  //    the pointers in the array are owner pointers (the array ptr itself
+  //    is a serf)
+  //  - 'loc' is the location of the left edge of the parse subtree
+  //  - this fn returns the semantic value for the reduction; this return
+  //    value is an owner pointer
+  typedef SemanticValue (*ReductionActionFunc)(
+    UserActions *context,         // parser context class object
+    int productionId,             // production being used to reduce
+    SemanticValue const *svals    // array of semantic values
+    SOURCELOCARG( SourceLoc loc ) );
+                                                     
+  // get the actual function; two-step to avoid virtual call in inner loop
+  virtual ReductionActionFunc getReductionAction()=0;
+
+  // duplication of semantic values:
+  //  - the given 'sval' is about to be passed to a reduction action
+  //    function.  the user must return a value to be stored in place
+  //    of the old one, in case it is needed to pass to another action
+  //    function in case of local ambiguity; 'sval' is a serf
+  //  - the return value will be yielded (if necessary) to the next
+  //    consumer action function, and is an owner ptr
+  //  - some possible strategies:
+  //    - return NULL, in which case it is probably an error for the
+  //      value to be passed to another action (i.e. the grammar needs
+  //      to be LALR(1) near this semantic value); in this case, 'del'
+  //      will not be called on the NULL value
+  //    - increment a reference count and return 'sval'
+  //    - do nothing, and rely on some higher-level allocation scheme
+  //      such as full GC, or regions
+  virtual SemanticValue duplicateTerminalValue(
+    int termId, SemanticValue sval)=0;
+  virtual SemanticValue duplicateNontermValue(
+    int nontermId, SemanticValue sval)=0;
+
+  // a semantic value didn't get passed to an action function, either
+  // because it was never used at all (e.g. a semantic value for a
+  // punctuator token, which the user can simply ignore), or because we
+  // duplicated it in anticipation of a possible local ambiguity, but
+  // then that parse turned out not to happen, so we're cancelling
+  // the dup now; 'sval' is an owner pointer
+  virtual void deallocateTerminalValue(int termId, SemanticValue sval)=0;
+  virtual void deallocateNontermValue(int nontermId, SemanticValue sval)=0;
+
+  // this is called when there are two interpretations for the same
+  // sequence of ground terminals, culminating in two different reductions
+  // deriving the same left-hand-side nonterminal (identified by 'ntIndex');
+  // it should return a value to be used in the place where they conflict'
+  // both 'left' and 'right' are owner pointers, and the return value
+  // is also an owner pointer
+  //
+  // NOTE: the 'left' value is always the node which came first, and
+  // might even have been yielded to another reduction already
+  // (depending on the grammar), whereas the 'right' value is always a
+  // node which was just created, and has definitely *not* been
+  // yielded to anything (this fact is critical to solving the general
+  // yield-then-merge problem)
+  virtual SemanticValue mergeAlternativeParses(
+    int ntIndex, SemanticValue left, SemanticValue right
+    SOURCELOCARG( SourceLoc loc )
+  )=0;
+
+  // after every reduction, the semantic value is passed to this function,
+  // which returns 'false' if the reduction should be cancelled; if it
+  // does return false, then 'sval' is an owner pointer (the parser engine
+  // will drop the value on the floor)
+  virtual bool keepNontermValue(int nontermId, SemanticValue sval)=0;
+
+  // every time a token is pulled from the lexer, this reclassifier is
+  // used to give the user a chance to reinterpret the token, before it
+  // is used for reduction lookahead comparisons; it returns the
+  // reclassified token type, or 'oldTokenType' to leave it unchanged
+  typedef int (*ReclassifyFunc)(UserActions *ths, int oldTokenType, SemanticValue sval);
+
+  // get the reclassifier
+  virtual ReclassifyFunc getReclassifier()=0;
+
+  // descriptions of symbols with their semantic values; this is useful
+  // for the ACTION_TRACE function of the parser
+  virtual string terminalDescription(int termId, SemanticValue sval)=0;
+  virtual string nonterminalDescription(int nontermId, SemanticValue sval)=0;
+
+  // get static names for all of the symbols
+  virtual char const *terminalName(int termId)=0;
+  virtual char const *nonterminalName(int termId)=0;
+
+  // get the parse tables for this grammar; the default action
+  // complains that no tables are defined
+  virtual ParseTables *makeTables();
+};
+
+
+// for derived classes, the list of functions to be declared
+// (this macro is used by the generated code)
+#define USER_ACTION_FUNCTIONS                                          \
+  virtual ReductionActionFunc getReductionAction();                    \
+                                                                       \
+  virtual SemanticValue duplicateTerminalValue(                        \
+    int termId, SemanticValue sval);                                   \
+  virtual SemanticValue duplicateNontermValue(                         \
+    int nontermId, SemanticValue sval);                                \
+                                                                       \
+  virtual void deallocateTerminalValue(                                \
+    int termId, SemanticValue sval);                                   \
+  virtual void deallocateNontermValue(                                 \
+    int nontermId, SemanticValue sval);                                \
+                                                                       \
+  virtual SemanticValue mergeAlternativeParses(                        \
+    int ntIndex, SemanticValue left, SemanticValue right               \
+    SOURCELOCARG( SourceLoc loc )                                      \
+  );                                                                   \
+                                                                       \
+  virtual bool keepNontermValue(int nontermId, SemanticValue sval);    \
+                                                                       \
+  virtual ReclassifyFunc getReclassifier();                            \
+                                                                       \
+  virtual string terminalDescription(int termId, SemanticValue sval);  \
+  virtual string nonterminalDescription(int nontermId, SemanticValue sval);  \
+                                                                       \
+  virtual char const *terminalName(int termId);                        \
+  virtual char const *nonterminalName(int termId);
+
+
+// a useraction class which has only trivial actions
+class TrivialUserActions : public UserActions {
+public:
+  USER_ACTION_FUNCTIONS
+
+  static SemanticValue doReductionAction(
+    UserActions *ths,
+    int productionId, SemanticValue const *svals
+    SOURCELOCARG( SourceLoc loc ) );
+
+  static int reclassifyToken(UserActions *ths, 
+    int oldTokenType, SemanticValue sval);
+};
+
+
+#endif // USERACT_H

Added: vendor/elsa/current/elkhound/util.h
===================================================================
--- vendor/elsa/current/elkhound/util.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elkhound/util.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// util.h            see license.txt for copyright and terms of use
+// collection of utility macros and functions that are
+// candidates for adding to the smbase library
+
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#include "trace.h"     // trace
+
+// given a method called 'print', define an operator to use it
+#define OSTREAM_OPERATOR(MyClass)                                \
+  friend ostream &operator << (ostream &os, MyClass const &ths)  \
+    { ths.print(os); return os; }
+
+
+// I'm experimenting with the idea of making my control structures
+// more declarative
+#define INTLOOP(var, start, maxPlusOne) \
+  for (int var = start; var < maxPlusOne; var++)
+
+
+// experiment: given (a reference to), an owner pointer, yield the pointer
+// value after nullifying the given pointer
+template <class T>
+inline T *transferOwnership(T *&ptr)
+{
+  T *ret = ptr;
+  ptr = NULL;
+  return ret;
+}
+
+
+// print a value under the debug trace (name: Trace VALue)
+#define TVAL(expr) \
+  trace("debug") << #expr ": " << (expr) << endl
+
+
+#endif // __UTIL_H

Added: vendor/elsa/current/elsa/ast_build.cc
===================================================================
--- vendor/elsa/current/elsa/ast_build.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/ast_build.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// ast_build.h
+// code for ast_build.cc
+
+#include "ast_build.h"      // this module
+
+
+FakeList<ArgExpression> *makeExprList1(Expression *e)
+{
+  return FakeList<ArgExpression>::makeList(new ArgExpression(e));
+}
+
+FakeList<ArgExpression> *makeExprList2(Expression *e1, Expression *e2)
+{
+  return makeExprList1(e2)->prepend(new ArgExpression(e1));
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/ast_build.h
===================================================================
--- vendor/elsa/current/elsa/ast_build.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/ast_build.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// ast_build.h
+// some utilities for constructing fragments of the C++ AST
+
+#ifndef AST_BUILD_H
+#define AST_BUILD_H
+
+#include "cc_ast.h"      // C++ AST
+
+// wrap an expression in a list
+FakeList<ArgExpression> *makeExprList1(Expression *e);
+
+// wrap a pair of expressions in a list
+FakeList<ArgExpression> *makeExprList2(Expression *e1, Expression *e2);
+
+#endif // AST_BUILD_H

Added: vendor/elsa/current/elsa/astvisit.cc
===================================================================
--- vendor/elsa/current/elsa/astvisit.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/astvisit.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,123 @@
+// astvisit.cc
+// code for astvisit.h
+
+#include "astvisit.h"       // this module
+
+
+ASTVisitorEx::ASTVisitorEx()
+  : loc(SL_UNKNOWN)
+{}
+
+
+void ASTVisitorEx::visitFunctionInstantiation(Function *obj)
+{
+  obj->traverse(*this);
+}
+
+
+void ASTVisitorEx::foundAmbiguous(void *obj, void **ambig, char const *kind)
+{}
+
+
+bool ASTVisitorEx::visitFunction(Function *obj)
+{
+  // template with instantiations to visit?
+  if (obj->isTemplate()) {
+    // instantiations are concrete
+    Restorer<bool> r(inTemplate, false);
+
+    TemplateInfo *ti = obj->nameAndParams->var->templateInfo();
+    SFOREACH_OBJLIST(Variable, ti->instantiations, iter) {
+      Variable const *inst = iter.data();
+      if (inst->templateInfo()->instantiatedFunctionBody()) {
+        visitFunctionInstantiation(inst->funcDefn);
+      }
+    }
+  }
+
+  return true;
+}
+
+
+// // wrap the unsafe cast
+// #define CAST_AMBIG(node) ((void**)(&((node)->ambiguity)))
+
+// quarl 2006-11-06
+//     Pass in a pointer to a real void* to avoid type-punning.
+#define CALL_FOUND_AMBIGUOUS(obj, T, node, name)                  \
+  do {                                                            \
+    T *&ambiguity = (node)->ambiguity;                            \
+    void *ambiguity0 = (void*) ambiguity;                         \
+    foundAmbiguous(obj, &ambiguity0, name);                       \
+    ambiguity = (T*) ambiguity0;                                  \
+  } while(0)
+
+bool ASTVisitorEx::visitPQName(PQName *obj)
+{
+  if (obj->loc != SL_UNKNOWN) {
+    loc = obj->loc;
+  }
+  if (obj->isPQ_qualifier() &&
+      obj->asPQ_qualifier()->ambiguity) {
+    CALL_FOUND_AMBIGUOUS(obj, PQName, obj->asPQ_qualifier(), "PQ_qualifier");
+  }
+  return true;
+}
+
+
+// visit a node that has an ambiguity link
+#define VISIT_W_AMBIG(type)                                        \
+  bool ASTVisitorEx::visit##type(type *obj)                        \
+  {                                                                \
+    if (obj->ambiguity) {                                          \
+      CALL_FOUND_AMBIGUOUS(obj, type, obj, obj->kindName());       \
+    }                                                              \
+    return true;                                                   \
+  }
+
+// visit a node that has a source location
+#define VISIT_W_LOC(type)                         \
+  bool ASTVisitorEx::visit##type(type *obj)       \
+  {                                               \
+    if (obj->loc != SL_UNKNOWN) {                 \
+      loc = obj->loc;                             \
+    }                                             \
+    return true;                                  \
+  }
+
+// visit a node that has a source location and an ambiguity link
+#define VISIT_W_LOC_AMBIG(type)                                    \
+  bool ASTVisitorEx::visit##type(type *obj)                        \
+  {                                                                \
+    if (obj->loc != SL_UNKNOWN) {                                  \
+      loc = obj->loc;                                              \
+    }                                                              \
+    if (obj->ambiguity) {                                          \
+      CALL_FOUND_AMBIGUOUS(obj, type, obj, obj->kindName());       \
+    }                                                              \
+    return true;                                                   \
+  }
+
+VISIT_W_AMBIG(ASTTypeId)
+VISIT_W_AMBIG(Declarator)
+VISIT_W_AMBIG(Condition)
+VISIT_W_AMBIG(Expression)
+VISIT_W_AMBIG(ArgExpression)
+VISIT_W_AMBIG(TemplateArgument)
+
+VISIT_W_LOC(TypeSpecifier)
+VISIT_W_LOC(Enumerator)
+VISIT_W_LOC(Member)
+VISIT_W_LOC(IDeclarator)
+VISIT_W_LOC(Initializer)
+
+VISIT_W_LOC_AMBIG(TopForm)
+VISIT_W_LOC_AMBIG(Statement)
+VISIT_W_LOC_AMBIG(TemplateParameter)
+
+#undef VISIT_W_AMBIG
+#undef VISIT_W_LOC
+#undef VISIT_W_LOC_AMBIG
+
+
+// EOF

Added: vendor/elsa/current/elsa/astvisit.h
===================================================================
--- vendor/elsa/current/elsa/astvisit.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/astvisit.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+// astvisit.h
+// extension to the default ASTVisitor; this is an experimental
+// replacement for the visitor classes in cc_ast_aux.h, so for
+// now only I (Scott) will use this
+
+#ifndef ASTVISIT_H
+#define ASTVISIT_H
+
+#include "cc_ast.h"       // ASTVisitor
+
+class ASTVisitorEx : public ASTVisitor {
+public:      // data
+  // the most recent location we've seen
+  SourceLoc loc;
+
+public:      // funcs
+  ASTVisitorEx();
+
+  // 'visitFunction' calls this for template instantiations;
+  // by default, this simply kicks off a traversal of 'obj'.
+  virtual void visitFunctionInstantiation(Function *obj);
+
+  // This is called when a node with a non-NULL ambiguity link is
+  // encountered.  By default it does nothing.  'obj' is a pointer
+  // to the node with the link; you'd have to cast it to do anything
+  // with it.  'ambig' is a pointer to the ambiguity link itself;
+  // this interface is unsound, letting you put any type of pointer
+  // there, so be careful not to.  'kind' is the type of the node;
+  // it's mostly meant for debugging and diagnostics, but in a pinch
+  // it could be used for RTTI.
+  virtual void foundAmbiguous(void *obj, void **ambig, char const *kind);
+
+  // ASTVisitor functions
+  #define DECL(type) \
+    virtual bool visit##type(type *obj) /*user ;*/
+  DECL(TopForm);
+  DECL(Function);
+  DECL(ASTTypeId);
+  DECL(PQName);
+  DECL(TypeSpecifier);
+  DECL(Enumerator);
+  DECL(Member);
+  DECL(Declarator);
+  DECL(IDeclarator);
+  DECL(Statement);
+  DECL(Condition);
+  DECL(Expression);
+  DECL(ArgExpression);
+  DECL(Initializer);
+  DECL(TemplateParameter);
+  DECL(TemplateArgument);
+  #undef DECL
+};
+
+#endif // ASTVISIT_H

Added: vendor/elsa/current/elsa/astxml_check
===================================================================
--- vendor/elsa/current/elsa/astxml_check	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/astxml_check	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,144 @@
+#!/usr/bin/perl -w
+# -*-perl-*-
+use strict;
+
+# Test ast xml rendering and parsing.
+
+# Daniel S. Wilkerson dsw at cs.berkeley.edu
+
+my $parser = "./ccparse";
+die "No executable file: $parser\n" unless -x $parser;
+my @names = ();
+my @outfiles = ();
+my %outfile2command = ();
+
+my $outdir;
+my $verbose = 0;
+
+my $usage=<<END
+Usage: $0 -d <outputdir> <inputlist>...
+END
+    ;
+
+if (+ at ARGV==0) {
+    print $usage;
+    exit 0;
+}
+
+{
+    my $arg = shift @ARGV;
+    last unless defined $arg;
+    if ($arg=~/^-d/) {
+        $outdir = shift @ARGV;
+        die "No argument to -d\n" unless defined $outdir;
+        die "No such dir: $outdir\n" unless -d $outdir;
+    } elsif ($arg=~/^-v/) {
+        $verbose++;
+    } else {
+        push @names, $arg;
+    }
+    redo;
+}
+die "You must specify an out directory with -d\n$usage" unless defined $outdir;
+
+sub run_only ($$) {
+    my ($command, $outfile) = @_;
+    my $realcommand = "$command > $outfile";
+#    print "RUN: $realcommand\n";
+    unlink $outfile;
+    die if -f $outfile;
+    my $res = system "$realcommand";
+#    print "\t$res\n";
+    if ($res!=0) {
+        my $exit_value  = $res >> 8;
+        my $signal_num  = $res & 127;
+        my $dumped_core = $res & 128;
+        system "echo >> $outfile '**** abnormal exit: exit_value $exit_value, " .
+            "signal_num $signal_num, dumped_core $dumped_core'\n";
+        die "Command fails: $realcommand\n";
+    }
+}
+
+sub run_command ($$) {
+    my ($command, $outfile) = @_;
+    my $realcommand = "$command > $outfile";
+    $outfile2command{$outfile} = $realcommand;
+    push @outfiles, $outfile;
+#    print "$command\n";
+    run_only $command, $outfile;
+}
+
+sub dump_outfiles {
+    for my $outfile(@outfiles) {
+        print "STAGE ****************\n";
+        print "$outfile2command{$outfile}\n";
+        system "cat $outfile";
+    }
+}
+
+my $numinputs = 0;
+my $numpass = 0;
+my @failingFiles = ();
+for my $name(@names) {
+    print "$name\n";
+    die "No such file $name\n" unless -f "$name";
+    ++$numinputs;
+
+    my $outname = $name;
+    if ($outname=~m|/|) {$outname=~s|^.*/([^/]+)|$1|;}
+    die "Bad outname:$outname:\n" if $outname=~/^\s*$/;
+    $outname = "$outdir/$outname";
+
+    @outfiles = ();
+    push @outfiles, $name;
+    $outfile2command{$name} = "ORIGINAL: $name";
+    eval {
+        run_command("$parser -tr xmlPrintAST,xmlPrintAST-indent $name | ./chop_out",
+                    "$outname.A1.xml");
+        run_command("$parser -tr parseXml,stopAfterParse $outname.A1.xml",
+                    "$outname.A2.out");
+        die "File should be empty $outname.A2.out" if -s "$outname.A2.out" > 0;
+    };
+    if ($@) {
+        dump_outfiles() if $verbose;
+        push @failingFiles, $name;
+        print "ERROR: $@\n";
+        next;
+    }
+
+    # sm: replaced -u with -c for portability
+    #
+    # sm: 2005-02-12: added -b (ignore blankspace differences)
+    # because on cygwin with DOS line endings in/c99/t0133.c has
+    # a CR vs CRLF difference that I don't want to track down...
+#      my $diff_command = "diff -c -b $outname.2out.cc $outname.4out.cc > $outname.5diff";
+#      $outfile2command{"$outname.5diff"} = $diff_command;
+#      push @outfiles, "$outname.5diff";
+#      my $diff_res = system $diff_command;
+#      if ($diff_res == 0) {
+#          ++$numpass;
+#      } else {
+#          dump_outfiles() if $verbose;
+#          push @failingFiles, $name;
+#      }
+}
+
+print "";
+#  print "Num inputs $numinputs\n";
+#  print "Num pass   $numpass\n";
+if (@failingFiles) {
+    print ("Failing files: ", join(' ', @failingFiles), "\n");
+    print "FAIL\n";
+    exit 1;
+} else {
+    print "PASS\n";
+    exit 0;
+}
+
+#  if ($numinputs==$numpass) {
+#      print "PASS\n";
+#      exit 0;
+#  } else {
+#      print "FAIL\n";
+#      exit 1;
+#  }


Property changes on: vendor/elsa/current/elsa/astxml_check
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/baselexer.cc
===================================================================
--- vendor/elsa/current/elsa/baselexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/baselexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,176 @@
+// baselexer.cc            see license.txt for copyright and terms of use
+// code for baselexer.h
+
+#include "baselexer.h"   // this module
+#include "strtable.h"    // StringTable
+#include "exc.h"         // throw_XOpen
+
+#include <fstream.h>     // ifstream
+
+#if defined(__GNUC__) && (__GNUC__ > 2)
+  // gcc-3 doesn't have istrstream (but it is standard!), so fake it
+  #include <sstream>       // istringstream
+
+  #undef string            // in case the string->mystring definition is active
+
+  inline istream *construct_istrstream(char const *buf, int len)
+  {
+    return new std::istringstream(std::string(buf, len));
+  }
+#else
+  // should work on any compiler that implements the C++98 standard
+  // (istrstream is deprecated but still standard)
+  #include <strstream.h>   // istrstream
+
+  inline istream *construct_istrstream(char const *buf, int len)
+  {
+    return new istrstream(buf, len);
+  }
+#endif
+
+
+// this function effectively lets me initialize one of the
+// members before initing a base class
+istream *BaseLexer::openFile(char const *fname)
+{
+  // 2005-01-17: open in binary mode to coincide with srcloc.cc
+  // doing the same, for cygwin reasons
+  this->inputStream = new ifstream(fname, ios::in | ios::binary);
+  if (!*inputStream) {
+    // destructor won't be called so delete here.
+    delete inputStream; inputStream = NULL;
+    throw_XOpen(fname);
+  }
+  return inputStream;
+}
+
+BaseLexer::BaseLexer(StringTable &s, char const *fname)
+  : yyFlexLexer(openFile(fname)),
+
+    // 'inputStream' is initialized by 'openFile'
+    srcFile(NULL),           // changed below
+
+    nextLoc(SL_UNKNOWN),     // changed below
+    curLine(1),
+
+    strtable(s),
+    errors(0),
+    warnings(0)
+{
+  srcFile = sourceLocManager->getInternalFile(fname);
+
+  loc = sourceLocManager->encodeBegin(fname);
+  nextLoc = loc;
+}
+
+
+istream *BaseLexer::openString(char const *buf, int len)
+{
+  this->inputStream = construct_istrstream(buf, len);
+  return inputStream;
+}
+
+BaseLexer::BaseLexer(StringTable &s, SourceLoc initLoc,
+                     char const *buf, int len)
+  : yyFlexLexer(openString(buf, len)),
+
+    // 'inputStream' is initialized by 'openString'
+    srcFile(NULL),           // changed below
+
+    nextLoc(initLoc),
+    curLine(0),              // changed below
+
+    strtable(s),
+    errors(0),
+    warnings(0)
+{
+  // decode the given location
+  char const *fname;
+  int line, col;
+  sourceLocManager->decodeLineCol(initLoc, fname, line, col);
+
+  // finish initializing data members
+  srcFile = sourceLocManager->getInternalFile(fname);
+  curLine = line;
+
+  loc = initLoc;
+}
+
+
+BaseLexer::~BaseLexer()
+{
+  delete inputStream;
+}
+
+
+StringRef BaseLexer::addString(char *str, int len)
+{
+  // (copied from gramlex.cc, GrammarBaseLexer::addString)
+
+  // write a null terminator temporarily
+  char wasThere = str[len];
+  if (wasThere) {
+    str[len] = 0;
+    StringRef ret = strtable.add(str);
+    str[len] = wasThere;
+    return ret;
+  }
+  else {
+    return strtable.add(str);
+  }
+}
+
+
+void BaseLexer::whitespace()
+{
+  updLoc();
+
+  // scan for newlines
+  char *p = yytext, *endp = yytext+yyleng;
+  for (; p < endp; p++) {
+    if (*p == '\n') {
+      curLine++;
+    }
+  }
+}
+
+
+int BaseLexer::tok(int t)
+{
+  updLoc();
+  sval = NULL_SVAL;     // catch mistaken uses of 'sval' for single-spelling tokens
+  return t;
+}
+
+
+void BaseLexer::err(char const *msg)
+{
+  errors++;
+  cerr << toString(loc) << ": error: " << msg << endl;
+}
+
+
+void BaseLexer::warning(char const *msg)
+{
+  warnings++;
+  cerr << toString(loc) << ": warning: " << msg << endl;
+}
+
+
+STATICDEF void BaseLexer::tokenFunc(LexerInterface *lex)
+{
+  BaseLexer *ths = static_cast<BaseLexer*>(lex);
+
+  // call into the flex lexer; this updates 'loc' and sets
+  // 'sval' as appropriate
+  ths->type = ths->yylex();
+}
+
+
+BaseLexer::NextTokenFunc BaseLexer::getTokenFunc() const
+{
+  return &BaseLexer::tokenFunc;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/baselexer.h
===================================================================
--- vendor/elsa/current/elsa/baselexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/baselexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,100 @@
+// baselexer.h            see license.txt for copyright and terms of use
+// flex-lexer base class; used by C/C++ lexer, among others.
+//
+// The key property that differentiates baselexer from lexer is
+// that the latter knows the details of what tokens exist and
+// what their semantic values mean, whereas the former does not.
+// Therefore, I can re-use baselexer for other languages, and
+// let lexer be the C++-specific one.
+
+#ifndef BASELEXER_H
+#define BASELEXER_H
+
+#include "sm_flexlexer.h"   // yyFlexLexer
+
+#include <iostream.h>       // istream
+#include "lexerint.h"       // LexerInterface
+#include "strtable.h"       // StringRef, StringTable
+
+
+// lexer object
+class BaseLexer : public yyFlexLexer, public LexerInterface {
+protected:  // data
+  istream *inputStream;            // (owner) file from which we're reading
+  SourceLocManager::File *srcFile; // (serf) contains the hash map we update
+
+  SourceLoc nextLoc;               // location of *next* token
+  int curLine;                     // current line number; needed for #line directives
+
+public:     // data
+  StringTable &strtable;           // string table
+  int errors;                      // count of errors encountered
+  int warnings;                    // same for warnings
+
+private:    // funcs
+  BaseLexer(BaseLexer&);           // disallowed
+
+protected:  // funcs
+  // advance source location
+  void updLoc() {
+    loc = nextLoc;                 // location of *this* token
+    nextLoc = advText(nextLoc, yytext, yyleng);
+  }
+
+  // adds a string with only the specified # of chars; writes (but
+  // then restores) a null terminator if necessary, so 'str' isn't const
+  StringRef addString(char *str, int len);
+
+  // updLoc(), then for every newline found in
+  // [yytext,yytext+yyleng-1], increment 'curLine'
+  void whitespace();
+
+  // return the given token code, after updLoc'ing and setting
+  // 'sval' to NULL; suitable for tokens with one spelling (or
+  // otherwise have no semantic value)
+  int tok(int t);
+
+  // report an error
+  void err(char const *msg);
+  void warning(char const *msg);
+
+  // part of the constructor
+  istream *openFile(char const *fname);
+  istream *openString(char const *buf, int len);
+
+  // read the next token and return its code; returns 0 for end of file;
+  // this function is defined in flex's output source code
+  //virtual int yylex();
+  //
+  // since Flex outputs yylex as being a member function of the
+  // final lexer class, the declaration of 'yylex' must be put into
+  // that class, not this one
+
+public:     // funcs
+  // make a lexer to scan the given file
+  BaseLexer(StringTable &strtable, char const *fname);
+  
+  // make a lexer to scan an in-memory string; 'initLoc' is the
+  // location that the first character should be regarded as being at;
+  // the buffer must remain allocated as long as this BaseLexer is
+  BaseLexer(StringTable &strtable, SourceLoc initLoc,
+            char const *buf, int len);
+
+  ~BaseLexer();
+
+  static void tokenFunc(LexerInterface *lex);
+
+  // LexerInterface funcs
+  virtual NextTokenFunc getTokenFunc() const;
+};
+
+
+// this macro declares the methods that flex's output implements
+#define FLEX_OUTPUT_METHOD_DECLS               \
+  virtual int yylex();                         \
+  yy_state_type yy_get_previous_state();       \
+  yy_state_type yy_try_NUL_trans( yy_state_type current_state );
+
+
+
+#endif // BASELEXER_H

Added: vendor/elsa/current/elsa/bitstrmap.h
===================================================================
--- vendor/elsa/current/elsa/bitstrmap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/bitstrmap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,104 @@
+// bitstrmap.h
+// map from finite bitstrings to some object
+
+// This is not a BDD because:
+//   - I want to map to arbitrary objects, not just 0 or 1.
+//   - I do not expect much useful sharing.
+
+#ifndef BITSTRMAP_H
+#define BITSTRMAP_H
+
+template <class T>
+class BitStrMap {
+public:      // types
+  class Node {
+  public:    // data
+    // domain object, or 0 if not mapped
+    T data;
+
+    // child if next bit in string is 0, or NULL if there are
+    // no mapped objects there (owner)
+    Node *zero;
+
+    // similar for 1
+    Node *one;
+
+  public:
+    Node() : data((T)0), zero(NULL), one(NULL) {}
+    ~Node();
+    
+    // get a successor, creating it if necessary
+    Node *getZero();
+    Node *getOne();
+    Node *getSucc(bool which)
+      { return which? getOne() : getZero(); }
+  };
+
+private:     // data
+  // first node in tree, corresponding to empty bitstring
+  // (nullable owner)
+  Node *top;
+
+public:      // funcs
+  BitStrMap() : top(NULL) {}
+  ~BitStrMap();
+  
+  // get or create
+  Node *getTop();
+};
+
+
+// ------------------- Node implementation ----------------------
+template <class T>
+BitStrMap<T>::Node::~Node()
+{
+  if (zero) {
+    delete zero;
+  }
+  if (one) {
+    delete one;
+  }
+}
+
+
+template <class T>
+typename BitStrMap<T>::Node *BitStrMap<T>::Node::getZero()
+{
+  if (!zero) {
+    zero = new Node;
+  }
+  return zero;
+}
+
+
+template <class T>
+typename BitStrMap<T>::Node *BitStrMap<T>::Node::getOne()
+{
+  if (!one) {
+    one = new Node;
+  }
+  return one;
+}
+
+
+// ------------------ BitStrMap implementation ------------------
+template <class T>
+BitStrMap<T>::~BitStrMap()
+{
+  if (top) {
+    delete top;
+  }
+}
+
+
+template <class T>
+typename BitStrMap<T>::Node *BitStrMap<T>::getTop()
+{
+  if (!top) {
+    top = new Node;
+  }
+  return top;
+}
+
+
+#endif // BITSTRMAP_H

Added: vendor/elsa/current/elsa/buildint/extract_section.pl
===================================================================
--- vendor/elsa/current/elsa/buildint/extract_section.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/buildint/extract_section.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,78 @@
+#!/usr/bin/perl -w
+# See License.txt for copyright and terms of use
+
+# Extract a section from an ELF file.
+
+# By Ben Liblit and originally released as part of "The Cooperative
+# Bug Isolation Project" http://http.cs.berkeley.edu/~liblit/sampler/
+
+use strict;
+#use 5.008;			# for safe pipe opens using list form of open
+
+use Fcntl qw(SEEK_SET);
+use FileHandle;
+
+
+########################################################################
+
+my $exit_value = 0;
+
+die "Usage: $0 <section-name> [<executable> | <object> | <library>] ...\n" unless @ARGV >= 2;
+
+my @argv1;
+my $test_only;                  # just test for the existance of the section
+my $quiet;
+
+foreach my $name (@ARGV) {
+  if ($name eq '-t') {
+    $test_only++;
+  } elsif ($name eq '-q') {
+    $quiet++;
+  } else {
+    push @argv1, $name;
+  }
+}
+
+my $sectionName = shift (@argv1);
+
+foreach my $name (@argv1) {
+    my $objdump = new FileHandle;
+#      open $objdump, '-|', 'objdump', '-h', '-w', $name
+    open($objdump, '-|', "objdump -h -w $name")
+	or die "cannot run objdump: $!\n";
+
+    my $size;
+    my $offset;
+    while (<$objdump>) {
+	my @field = split;
+	next unless @field >= 7;
+	next unless $field[1] eq $sectionName;
+	next unless $field[0] =~ /^\d+$/;
+	$size = hex $field[2];
+	$offset = hex $field[5];
+	last;
+    }
+
+    unless (defined $offset) {
+	warn "\"$sectionName\" section is missing\n" unless $quiet;
+        $exit_value = 1;
+	next;
+    }
+
+    unless ($size) {
+	warn "\"$sectionName\" section is empty\n" unless $quiet;
+        $exit_value = 1;
+	next;
+    }
+
+    if (!$test_only && !$quiet) {
+      my $buffer;
+      my $executable = new FileHandle $name, 'r';
+      $executable->seek($offset, &SEEK_SET);
+      $executable->read($buffer, $size);
+      $buffer =~ s/\0//g;
+      print $buffer;
+    }
+}
+
+exit $exit_value;


Property changes on: vendor/elsa/current/elsa/buildint/extract_section.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/buildint/install
===================================================================
--- vendor/elsa/current/elsa/buildint/install	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/buildint/install	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+runecho() {
+  echo "$@"
+  "$@"
+}
+
+for fn in as c++ cc cc1 cc1plus cpp g++ gcc ld; do
+  if [ ! -L $fn ]; then
+    runecho ln -s interceptor.pl $fn || exit
+  fi
+done
+                                              
+cwd=`pwd`       
+cat <<EOF
+
+To use the interceptor, simply prepend 
+  $cwd 
+to the \$PATH.
+
+The intercepted sources will go to ~/preproc, or wherever you
+put in \$BUILDINT_DIST.
+EOF
+
+# EOF


Property changes on: vendor/elsa/current/elsa/buildint/install
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/buildint/interceptor.pl
===================================================================
--- vendor/elsa/current/elsa/buildint/interceptor.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/buildint/interceptor.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,723 @@
+#!/usr/bin/perl -w
+# intercept a build tool invocation, do some processing, and
+# then run the real program
+
+use strict 'subs';
+
+# 0: quiet
+# 1: write to log file
+# 2: write to terminal
+$verbose = 1;
+
+# under what directory should all my output be placed?
+$outputDir = $ENV{"BUILDINT_DEST"};
+if (!defined($outputDir)) {
+  $outputDir = $ENV{"HOME"} . "/preproc";
+}
+
+$cwd = `pwd`;
+chomp($cwd);
+
+# where is this script?
+($scriptDir, $progName) = ($0 =~ m|^(.*)/([^/]*)$|);    # divide at last '/'
+if (!defined($scriptDir)) {     # no '/' at all
+  $scriptDir = $cwd;
+  $progName = $0;
+}
+
+sub isCompilerDriver {
+  my ($s) = @_;
+  return $s eq "gcc" || $s eq "g++" || $s eq "cc" || $s eq "c++";
+}
+if (isCompilerDriver($progName) && $verbose == 1) {
+  # an extra newline before each invocation of the driver program helps
+  # to mark the groups of related lines
+  writeToLog("\n");
+}
+
+diagnostic("invoked with args: " . join(' ', @ARGV));
+
+# where is the real program?
+$realProgram = "";
+if ($progName eq "cc1" ||
+    $progName eq "cc1plus") {
+  # these are just the original invocation name plus "-real"
+  $realProgram = $0 . "-real";
+}
+else {
+  # search for first occurrence of the program in the path *after* the
+  # one which caused (a symlink to) this script to be found
+  my @path = split(':', $ENV{"PATH"});
+  foreach my $p (@path) {
+    if ($p eq $scriptDir) { next; }
+
+    if (-x "$p/$progName") {
+      # found it
+      $realProgram = "$p/$progName";
+      last;
+    }
+  }
+}
+if (!$realProgram) {
+  die("$0: could not find the real $progName in the path\n");
+}
+
+# copy the arguments; the wrapper code can modify them before execution
+ at av = @ARGV;
+
+# what program am I emulating?
+if (isCompilerDriver($progName)) {
+  gcc_wrapper();
+}
+elsif ($progName eq "cpp") {
+  cpp_wrapper();
+}
+elsif ($progName eq "cc1" ||
+       $progName eq "cc1plus") {
+  cc1_wrapper();
+}
+elsif ($progName eq "ld") {
+  ld_wrapper();
+}
+elsif ($progName eq "as") {
+  # nop; this is a placeholder; the only effect of the wrapper
+  # will have been to log the call if $verbose != 0
+}
+else {
+  die("$0: I do not know how to wrap $progName\n");
+}
+
+# run the real program
+diagnostic("invoking: $realProgram " . join(' ', @av));
+exec($realProgram, @av);
+
+
+sub diagnostic {
+  if ($verbose == 1) {
+    writeToLog("$0: ", @_, "\n");
+  }
+  elsif ($verbose == 2) {
+    print("$0: ", @_, "\n");
+  }
+}
+
+sub writeToLog {
+  # open and close the logfile each time so that I do not hold it
+  # open across the invocation of some other program that might also
+  # want to write to it (in *theory* if everyone uses append mode,
+  # and unix append semantics are implemented correctly, and no one
+  # accidentally buffers something, then it would not matter; but I
+  # play it safe)
+  open(LOG, ">>$outputDir/interceptor.log")
+    or die("cannot write $outputDir/interceptor.log: $!\n");
+  print LOG (@_);
+  close(LOG);
+}
+
+# "a/b/c" -> "a/b/"
+# "/a" -> "/"
+# "a" -> ""
+sub dirname {
+  my ($str) = @_;
+
+  if ($str =~ m|^(.*/)[^/]*$|) {
+    return $1;
+  }
+  else {
+    return "";
+  }
+}
+
+
+# make the given directory plus any needed parent directories
+sub mkdirParents {
+  my ($d) = @_;
+
+  if (0!=system("mkdir -p '$d'")) {
+    die("failed to mkdir -p");
+  }
+}
+
+
+# backtick but no shell interpretation and capture stderr;
+# child's exit status available in $? upon return
+sub betterBacktick {
+  # @_ has the program + args, first element is the program
+
+  # fork a child process
+  my $childPid = open(CHILD, "-|");
+  if (!defined($childPid)) {
+    die("cannot fork: $!\n");
+  }
+
+  # child
+  if (!$childPid) {
+    # send stderr to same place as stdout, namely the pipe to
+    # the parent
+    close(STDERR);
+    open(STDERR, ">&STDOUT");
+
+    # exec the program
+    if (!exec(@_)) {
+      # this error message will go to stdout, but oh well
+      print("exec: $!\n");
+      exit(40);
+    }
+    else {
+      die("not reached");  # this conditional exists only to pacify perl -w
+    }
+  }
+
+  # parent
+  my @ret = <CHILD>;
+  close(CHILD);      # child's exit status goes into $?
+  return @ret;
+}
+
+
+# ----------------------- gcc --------------------------
+sub gcc_wrapper {
+  # find out its version number and where its spec file lives
+  @gccInfo = `"$realProgram" -v 2>&1`;
+  if ($? != 0) {
+    die("$0: $realProgram -v failed\n");
+  }
+  $gccSpecDir = "";
+  $gccVersion = "";
+  foreach $line (@gccInfo) {
+    my ($s) = ($line =~ m|specs from (.*)/specs$|);
+    if (defined($s)) {
+      $gccSpecDir = $s;
+      next;
+    }
+
+    ($s) = ($line =~ m|version (\d+\.\d+\.\d+)|);
+    if (defined($s)) {
+      $gccVersion = $s;
+      next;
+    }
+  }
+  if (!$gccSpecDir || !$gccVersion) {
+    die("$0: failed to parse output of $realProgram -v\n");
+  }
+  if ($gccSpecDir !~ m|^/|) {
+    die("$0: gccSpecDir should be an absolute path\n");
+  }
+
+  # get the gcc version components; we are playing with gcc internals
+  # here, and those change over time
+  my ($major, $minor, $patch) = ($gccVersion =~ m|(\d+)\.(\d+)\.(\d+)|);
+  if (!defined($patch)) {
+    die("wtf?");
+  }
+
+  # make a symlink copy of the gcc spec directory
+  #
+  # I am naming the copy according to how the original spec was named,
+  # so that it will not collide with a spec copy of another installed
+  # compiler.
+  $copyOfSpecDir = $outputDir . "/specdirs" . $gccSpecDir;
+  if (-f "$copyOfSpecDir/cc1") {
+    # the directory and link already exists; assume it is good to go
+  }
+  else {
+    # create it, etc.
+    diagnostic("creating $copyOfSpecDir");
+
+    # link the existing contents
+    my $cmd = <<"EOF";
+rm -rf '$copyOfSpecDir'       &&
+mkdir -p '$copyOfSpecDir'     &&
+cd '$copyOfSpecDir'           &&
+ln -s '$gccSpecDir'/* .
+EOF
+    if (0!=system($cmd)) {
+      die("failed to make $copyOfSpecDir\n");
+    }
+
+    # did we get cc1?
+    if (-f "$copyOfSpecDir/cc1") {
+      $cmd = <<"EOF";
+cd '$copyOfSpecDir'           &&
+mv cc1 cc1-real               &&
+mv cc1plus cc1plus-real
+EOF
+      if (0!=system($cmd)) {
+        die("failed to move cc1\n");
+      }
+    }
+    elsif ($gccSpecDir =~ m|^(.*)/\.\./lib/gcc/(.*)$|) {
+      # in gcc >=3.4, cc1 does not live in the spec directory,
+      # and I do not know the proper way to find it, but this
+      # seems to work
+      #
+      # example spec dir:
+      #   /slack8/home/scott/opt/gcc-3.4.0/bin/../lib/gcc/i686-pc-linux-gnu/3.4.0
+      # example corresponding libexec dir:
+      #   /slack8/home/scott/opt/gcc-3.4.0/bin/../libexec/gcc/i686-pc-linux-gnu/3.4.0/cc1
+      my $gccLibexecDir = "$1/../libexec/gcc/$2";
+      if (-f "$gccLibexecDir/cc1") {
+        $cmd = <<"EOF";
+cd '$copyOfSpecDir'                          &&
+ln -s '$gccLibexecDir/cc1' cc1-real          &&
+ln -s '$gccLibexecDir/cc1plus' cc1plus-real
+EOF
+        if (0!=system($cmd)) {
+          die("failed to symlink cc1[plus] from $gccLibexecDir\n");
+        }
+      }
+      else {
+        die("could not find cc1 in $copyOfSpecDir or $gccLibexecDir\n");
+      }
+    }
+    else {
+      die("could not find cc1 in $copyOfSpecDir\n");
+    }
+
+    # finally, put links to the script directory, pointing
+    # at links to this script
+    $cmd = <<"EOF";
+cd '$copyOfSpecDir'           &&
+ln -s '$scriptDir'/cc1 .      &&
+ln -s '$scriptDir'/cc1plus .
+EOF
+    if (0!=system($cmd)) {
+      die("failed to symlink cc1 from $scriptDir\n");
+    }
+  }
+
+  # point gcc at the new spec directory
+  #
+  # I had been using GCC_EXEC_PREFIX, but for some reason I can't get
+  # it to work with gcc-3.4; gcc just seems to ignore the value when
+  # it is searching for subprocess executables.  So, use -B instead.
+  unshift(@av, "-B${copyOfSpecDir}/");
+
+  # tell gcc to do preprocessing separately
+  if ($major >= 3) {
+    unshift(@av, "--no-integrated-cpp");
+  }
+
+  # decided it was not worth the hassle
+  if (0) {
+    # pass it a special spec file too
+    if ("$major.$minor" >= 3.4) {
+      unshift(@av, "-specs=$scriptDir/interceptor.specs.gcc-3.4");
+    }
+    elsif ($major <= 2) {
+      unshift(@av, "-specs=$scriptDir/interceptor.specs.gcc-2");
+    }
+    else {
+      unshift(@av, "-specs=$scriptDir/interceptor.specs.gcc-3");
+    }
+  }
+}
+
+
+# ----------------------- cpp ------------------------
+sub cpp_wrapper {
+  # Get rid of any -P arguments.
+  #
+  # -P tells the preprocessor not to emit "#" line markers into the
+  # preprocessed output.  We assume that if it is specified, it is
+  # because someone was trying to make the build process faster; but
+  # the premise of build interception is that we want as much info as
+  # possible, whatever the cost, so we remove -P.
+  #
+  # Note that this is *also* done by the gcc specs file above, for
+  # when gcc invokes its own private 'cpp'; the wrapper here is for
+  # the public one usually sitting in /usr/bin.
+  @av = grep {!/^-P$/} @av;
+}
+
+
+# ----------------------- cc1 -----------------------
+sub cc1_wrapper {
+  # gcc-3 invokes cc1 with -E when it wants to only do preprocessing;
+  # just pass that case through
+  if (grep {/^-E$/} @av) {
+    return;
+  }
+
+  # make a unique id; this will be incorporated into the name of the
+  # file that contains the intercepted data; this ensures that no data
+  # is lost, but that also means that intercepted files from old runs
+  # will hang around indefinitely
+  my $unique = sprintf("$$-%d", time());
+
+  # scan the argument list for input filenames
+  my $origFname = "";      # name of .c file preprocessed to get $inputFname
+  my $inputFname = "";     # name of .i file about to be compiled
+  @av = grep {
+    # the actual command-line argument syntax to cc1 is somewhat
+    # complicated; we just assume that if the argument ends with ".i"
+    # or ".ii" then it is the input file we want
+    if ($_ =~ m|\.ii?$|) {
+      $inputFname = $_;
+
+      # discard this element of the list because when we run cc1
+      # we will be passing the name of the *intercepted* file,
+      # not the original input file
+      0;
+    }
+
+    # this argument comes from the special spec file given to gcc
+    elsif ($_ =~ m|^---build_interceptor-orig_filename=(.*)$|) {
+      $origFname = $1;
+      0;         # discard
+    }
+
+    else {
+      1;         # keep
+    }
+  } @av;
+
+  my $dumpBase = "";       # name of .c file supplied with -dumpbase
+  for (my $i=0; $i < @av; $i++) {
+    # in gcc-3, this is the original input filename without its
+    # directory component; gcc-2 does not pass this
+    if ($av[$i] eq "-dumpbase") {
+      $dumpBase = $av[$i+1];
+    }
+  }
+
+  # construct the name of the file where we will save the
+  # intercepted preprocessor input
+  my $interceptFname = "STDIN.i";
+  {
+    if ($origFname) {
+      $interceptFname = $origFname;
+    }
+
+    elsif ($dumpBase) {
+      $interceptFname = $dumpBase;
+    }
+
+    elsif ($inputFname) {
+      $interceptFname = $inputFname;
+    }
+
+    # change the extension to .i or .ii
+    my $ext = ($progName eq "cc1"? ".i" : ".ii");
+    $interceptFname =~ s|\.[^.]*$|$ext|;
+
+    # attach the $unique string
+    $interceptFname =~ s|\.([^.]*)$|-$unique.$1|;
+
+    # make the name absolute
+    if ($interceptFname !~ m|^/|) {
+      $interceptFname = "$cwd/$interceptFname";
+    }
+
+    # put it under $outputDir
+    $interceptFname = $outputDir . $interceptFname;
+  }
+
+  # create the parent directories of $interceptFname
+  mkdirParents(dirname($interceptFname));
+
+  # create the intercepted file
+  if ($inputFname) {
+    if (0!=system("cp '$inputFname' '$interceptFname'")) {
+      die("cp failed");
+    }
+    diagnostic("saved input file to $interceptFname");
+  }
+  else {
+    # read the input from stdin, save it in the intercepted file, and
+    # then we will give that filename explicitly to cc1
+    diagnostic("saving stdin to $interceptFname");
+    open (INTER, ">$interceptFname") or die("cannot write $interceptFname: $!\n");
+    my $line;
+    while (defined($line = <STDIN>)) {
+      print INTER ($line);
+    }
+    close (INTER) or die;
+  }
+
+  # specify it as the input file for cc1
+  unshift @av, $interceptFname;
+
+  # search argument list for output file name and the dumpbase
+  # (whatever that is)
+  my $outputFname = "";
+  my $dumpbase = "";
+  for (my $i=0; $i < @av; ++$i) {
+    if ($av[$i] =~ /^-o/) {
+      if ($av[$i] eq '-o') {
+        $outputFname = $av[$i+1];
+        ++$i;
+      }
+      else {
+        ($outputFname) = ($av[$i] =~ /^-o(.*)$/);
+      }
+    }
+
+    elsif ($av[$i] eq '-dumpbase') {
+      $dumpbase = $av[$i+1];
+    }
+  }
+
+  # input file specified but no output file: output file name is
+  # $inputFname with .s extension
+  if (!$outputFname && $inputFname) {
+    $outputFname = $inputFname;
+    $outputFname =~ s|\.[^.]*$|.s|;
+  }
+
+  # run cc1
+  {
+    # prefix with the name of the program we are calling
+    unshift @av, $realProgram;
+
+    diagnostic("invoking: " . join(' ', @av));
+    system(@av);
+    if ($?) {
+      my $exit_value  = $? >> 8;
+      my $signal_num  = $? & 255;
+      if ($exit_value) {
+        exit($exit_value);
+      }
+      die("$0: $progName died with signal $signal_num\n");
+    }
+  }
+
+  # Compress the intercepted file.  This done because preprocessor
+  # output is usually very big but *highly* (~80%) compressible.  It
+  # is probably faster to uncompress the data than it would be to read
+  # all of the disk blocks containing the uncompressed data.  (It is
+  # slower to compress than to write, especially with write buffering,
+  # but I still think it is worth it.)
+  if (0!=system("gzip", $interceptFname)) {
+    die("gzip failed");
+  }
+
+  # construct extra data to add to the generated assembly
+  my $metadata = <<'END';         # do not interpolate
+.section	.note.cc1_interceptor,"", at progbits
+END
+
+  # sm: I changed the format of this section significantly.  Here is
+  # why:
+  #
+  # I removed the 'raw_args' output because I do not think it would be
+  # very useful.  Furthermore, instead of 'run_args' as a
+  # colon-separated string, I emit those commands as the multi-line
+  # 'command' (the way 'raw_args' used to be emitted).  I envision
+  # using 'command' to reconstruct the .o file from the intercepted .i
+  # file.
+  #
+  # I also removed 'infile' because that often uselessly names a gcc
+  # temporary file.  I renamed 'tmpfile' to 'intercepted' to make it
+  # clear what its role is (in a build process, many things are
+  # "temporary").  Finally, I added 'output' so this section is then
+  # a self-contained transformation description:
+  #
+  #   To make 'output',
+  #   run 'command',
+  #   which reads (only) 'intercepted'.
+  #
+  # Note that 'output' is a .s file which is likely to be a gcc
+  # temporary file too.  Therefore the consumer of this output may
+  # want to search for 'output' in 'command' and replace it with a
+  # different output filename.
+  #
+  # 'output' may also be an empty string, meaning that 'command'
+  # writes to stdout.  Previously this script had used "-" to mean
+  # stdout, but that seems like pointless ambiguity in this context.
+  # (Some programs' command line syntax uses such a convention, but
+  # that is only because it is awkward to pass empty string as a
+  # command line argument.)
+
+  $metadata .= <<"END";
+	.ascii "("
+	.ascii "\\n\\tpwd:${cwd}"
+	.ascii "\\n\\tdollar_zero:$0"
+	.ascii "\\n\\tcommand: ("
+END
+
+  foreach my $a (@av) {
+    $metadata .= <<"END";
+	.ascii "\\n\\t\\t${a}"
+END
+  }
+
+  $metadata .= <<"END";
+	.ascii "\\n\\t)"
+	.ascii "\\n\\tdumpbase:${dumpbase}"
+	.ascii "\\n\\tintercepted:${interceptFname}"
+	.ascii "\\n\\toutput:${outputFname}"
+	.ascii "\\n)\\n"
+END
+
+  # append the constructed data to the output
+  if (!$outputFname) {
+    print STDOUT ($metadata);
+  }
+  else {
+    open(OUT, ">>$outputFname") or die("cannot append to $outputFname: $!\n");
+    print OUT ($metadata);
+    close(OUT) or die;
+  }
+
+  # do not return; the default action of the common part of the script
+  # above would invoke cc1 again
+  exit(0);
+}
+
+
+# --------------------------- ld --------------------------
+# The purpose of this wrapper is to remember the set of files that got
+# used in the construction of an executable, to allow later
+# reconstruction.
+#
+# The primary technique here is to pass the --trace option so that
+# 'ld' will print out the files it uses.  However, this is complicated
+# by the fact that it is not easy to tell which output lines are from
+# --trace and which are other things.  So we use some simple
+# heuristics.
+sub ld_wrapper {
+  # has the trace flag already been passed?
+  my $traceAlready = 0;
+  if (grep {m/^(-t|--trace)$/} @av) {
+    # yes, already present
+    $traceAlready = 1;
+  }
+  else {
+    # add it
+    unshift @av, "--trace";
+  }
+
+  # run the real ld and capture its output
+  diagnostic("invoking: $realProgram " . join(' ', @av));
+  my @output = betterBacktick($realProgram, @av);
+  my $ld_exit_value  = $? >> 8;
+  my $ld_signal_num  = $? & 255;
+
+  # search among the output lines for trace output; remove them
+  # from @output unless $traceAlready
+  my @trace = ();
+  @output = grep {
+    my $line = $_;
+    chomp($line);
+
+    # heuristic #1: if $line is the name of a file, assume it is
+    # tracing output
+    if (-f $line) {
+      push @trace, ($line);
+      $traceAlready;    # keep only if --trace already specified
+    }
+
+    # heuristic #2: if it is of the form "(string1.a)string2" and
+    # "string1.a" is the name of a file, it is tracing output
+    elsif ($line =~ m|^\((.*).a\).*$|) {
+      if (-f "$1.a") {
+        push @trace, ($line);
+        $traceAlready;
+      }
+      else {
+        1;      # keep
+      }
+    }
+
+    elsif ($line =~ m|$progName: mode |) {
+      # this is not tracing output I want, but *is* caused by
+      # the --trace flag; drop it unless the user said --trace
+      $traceAlready;
+    }
+
+    else {
+      1;        # keep
+    }
+  } @output;
+
+  # print the remaining output lines; this should be exactly what
+  # the user would have seen if we didn't mess with the command line,
+  # except it is all going to stdout
+  print STDOUT (@output);
+
+  # did 'ld' fail?
+  if ($ld_exit_value) {
+    exit($ld_exit_value);
+  }
+  if ($ld_signal_num) {
+    die("$0: $progName died with signal $ld_signal_num\n");
+  }
+
+  # were we merely getting the version?
+  if (grep {m/^(-v|-V|--version)$/} @av) {
+    exit(0);
+  }
+
+  # find the output file name
+  my $outfile = "";
+  for (my $i=0; $i < @av; ++$i) {
+    if ($av[$i] =~ m|^-o(.*)$|) {
+      if ($1) {
+        $outfile = $1;
+      }
+      else {
+        $outfile = $av[$i+1];
+        ++$i;
+      }
+    }
+  }
+  if (!$outfile) {
+    $outfile = "a.out";
+  }
+
+  # make it absolute
+  if ($outfile !~ m|^/|) {
+    $outfile = "$cwd/$outfile";
+  }
+
+  # write a temporary file containing the text of the section
+  # to add to the exectuable
+  my $tmpfile = "$outputDir/tmp/ld-interceptor-$$";
+  mkdirParents(dirname($tmpfile));
+  open(TMP, "> $tmpfile") or die("cannot write $tmpfile: $!");
+
+  print TMP (<<"END");
+(
+\tpwd:$cwd
+\tdollar_zero:$0
+\toutfile:$outfile
+\tcommand: (
+\t\t$realProgram
+END
+
+  # this is saved to aid reconstruction of $outfile from binary sources
+  for my $a (@av) {
+    print TMP ("\t\t$a\n");
+  }
+
+  print TMP (<<"END");
+\t)
+\ttrace: (
+END
+
+  # this is saved to aid reconstruction from intercepted source code
+  for my $t (@trace) {
+    print TMP ("\t\t$t\n");
+  }
+
+  print TMP (<<"END");
+\t)
+)
+END
+
+  close(TMP) or die $!;
+
+  # attach the section text to the executable
+  if (0!=system("objcopy", $outfile, '--add-section', ".note.ld_interceptor=$tmpfile")) {
+    die("objcopy failed");
+  }
+  unlink($tmpfile);
+
+  # do not return; the default action of the common part of the script
+  # above would invoke cc1 again
+  exit(0);
+}
+
+
+# EOF


Property changes on: vendor/elsa/current/elsa/buildint/interceptor.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-2
===================================================================
--- vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-2	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-2	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+# -*-sh-*-
+
+# This spec file modifies the build process for build interception.
+# See http://gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/Spec-Files.html#Spec%20Files
+
+# I cannot find an equivalent way to do this in gcc-2
+#  # Remove -P from the gcc command line.  This makes sure that hash-line
+#  # directives are going to show up in the .i files.
+#  %rename cpp_options cpp_options_old0
+
+#  *cpp_options:
+#  %{<P} %(cpp_options_old0)
+
+# It is nice if we can find out the name of the original file to help
+# in creating a name for the temporary file.
+*cc1_options:
++ ---build_interceptor-orig_filename=%i
+
+*cc1plus_options:
++ ---build_interceptor-orig_filename=%i

Added: vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-3
===================================================================
--- vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+# -*-sh-*-
+
+# This spec file modifies the build process for build interception.
+# See http://gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/Spec-Files.html#Spec%20Files
+
+# Remove -P from the gcc command line.  This makes sure that hash-line
+# directives are going to show up in the .i files.
+%rename cpp_options cpp_options_old0
+
+# the following syntax only works in gcc <3.4
+*cpp_options:
+%{<P} %(cpp_options_old0)
+
+# It is nice if we can find out the name of the original file to help
+# in creating a name for the temporary file.
+*cc1_options:
++ ---build_interceptor-orig_filename=%i
+
+*cc1plus_options:
++ ---build_interceptor-orig_filename=%i

Added: vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-3.4
===================================================================
--- vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-3.4	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/buildint/interceptor.specs.gcc-3.4	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+# -*-sh-*-
+
+# This spec file modifies the build process for build interception.
+# See http://gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/Spec-Files.html#Spec%20Files
+
+# Remove -P from the gcc command line.  This makes sure that hash-line
+# directives are going to show up in the .i files.
+%rename cpp_options cpp_options_old0
+
+# the following syntax is specific to gcc >=3.4
+*cpp_options:
+%<P %(cpp_options_old0)
+
+# It is nice if we can find out the name of the original file to help
+# in creating a name for the temporary file.
+*cc1_options:
++ ---build_interceptor-orig_filename=%i
+
+*cc1plus_options:
++ ---build_interceptor-orig_filename=%i

Added: vendor/elsa/current/elsa/buildint/reconstruct-exec.pl
===================================================================
--- vendor/elsa/current/elsa/buildint/reconstruct-exec.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/buildint/reconstruct-exec.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,644 @@
+#!/usr/bin/perl -w
+# reconstruct an executable from the intercepted inputs
+
+use strict 'subs';
+
+
+use FileHandle;                # FileHandle
+use Fcntl qw(SEEK_SET);        # for FileHandle random seeks
+use Fcntl ':mode';             # for S_IFDIR
+
+$verbose = 0;
+
+for (; @ARGV > 0 && $ARGV[0] =~ m/^-/; shift @ARGV) {
+  my $opt = $ARGV[0];
+
+  if ($opt eq "-v") {
+    $verbose = 1;
+  }
+  else {
+    die("unknown option: $opt\n");
+  }
+}
+
+if (@ARGV == 0) {
+  print(<<"EOF");
+usage: $0 [-v] executable-file
+EOF
+  exit(0);
+}
+
+$execFname = $ARGV[0];
+
+$origCwd = `pwd`;
+chomp($origCwd);
+         
+$fqExecFname = $execFname;
+if ($execFname !~ m|^/|) {
+  $fqExecFname = $origCwd . "/" . $execFname;
+}
+
+# ------------------- 1. read the executable -------------------
+# read the ELF sections we care about
+$cc1Notes = "";
+$ldNotes = "";
+{
+  # get extents of all sections
+  my $objdump = new FileHandle;
+  if (!open($objdump, '-|', "objdump -h -w '$execFname'")) {
+    die("cannot run objdump: $!\n");
+  }
+  
+  # for reading the section contents
+  my $executable = new FileHandle $execFname, 'r';
+
+  # search for info about the relevant ones
+  while (<$objdump>) {
+    my @field = split(' ', $_);
+
+    if (!( @field >= 7 &&
+           $field[0] =~ m|^\d+$| )) {
+      # line is a header line, or some other non-section information
+      next;
+    }
+
+    my $size = hex($field[2]);
+    my $offset = hex($field[5]);
+
+    if ($field[1] eq ".note.cc1_interceptor") {
+      $cc1Notes = readFilePart($executable, $offset, $size);
+    }
+
+    elsif ($field[1] eq ".note.ld_interceptor") {
+      $ldNotes = readFilePart($executable, $offset, $size);
+    }
+  }
+  
+  if (!$objdump->close()) {
+    die("objdump failed (code $?)\n");
+  }
+  $executable->close() or die;
+}
+
+
+# ------------------- 2. parse ld section -------------------
+# parse the ld section to figure out how this executable was made
+$ldCwd = "";
+$ldOutfile = "";
+ at ldCommand = ();
+ at ldTrace = ();
+{
+  my @ldNotes = split('\n', $ldNotes);
+  my $state = 1;
+  for (my $i=0; $i < @ldNotes; $i++) {
+    my $line = $ldNotes[$i];
+
+    if ($state == 1) {
+      if ($line =~ m|^\tcommand:|) {
+        $state = 2;
+      }
+      elsif ($line =~ m|\ttrace:|) {
+        $state = 3;
+      }
+      elsif ($line =~ m|\toutfile:(.*)$|) {
+        $ldOutfile = $1;
+      }
+      elsif ($line =~ m|\tpwd:(.*)$|) {
+        $ldCwd = $1;
+      }
+    }
+
+    elsif ($state == 2) {
+      if ($line =~ m|^\t\t(.*)$|) {
+        push @ldCommand, ($1);
+      }
+      elsif ($line =~ m|^\t\)|) {
+        $state = 1;
+      }
+      else {
+        die("malformed line in ld command section: $line\n");
+      }
+    }
+
+    elsif ($state == 3) {
+      if ($line =~ m|^\t\t(.*)$|) {
+        push @ldTrace, ($1);
+      }
+      elsif ($line =~ m|^\t\)|) {
+        $state = 1;
+      }
+      else {
+        die("malformed line in ld trace section: $line\n");
+      }
+    }
+  }
+
+  if (!$ldCwd) {
+    die("missing ld pwd\n");
+  }
+  if (!$ldOutfile) {
+    die("missing ld outfile\n");
+  }
+  if (@ldCommand == 0) {
+    die("missing ld command section\n");
+  }
+  if (@ldTrace == 0) {
+    die("missing ld trace section\n");
+  }
+}
+
+#print("ldCommand: @ldCommand\n");
+#print("ldTrace: @ldTrace\n");
+#print("ldOutfile: $ldOutfile\n");
+
+
+
+# ------------------- 3. analyze trace data -------------------
+# chdir into the link directory so that relative paths might work
+$inLdCwd = chdir($ldCwd);
+
+# process the trace
+ at unintercepted = ();
+foreach my $line (@ldTrace) {
+  # Three cases:
+  #   1. The file $line does not exist anymore.  Then either we
+  #      intercepted its construction and so we will reconstruct it
+  #      and the link will work, or else the final link will have
+  #      undefined symbols.
+  #   2. The file $line exists but does not have interception info.
+  #      Then it is reported as an unintercepted file but linking
+  #      should work.
+  #   3. The file $line exists and has interception info.  We will
+  #      ignore it, since it got intercepted so it will be
+  #      reconstructed.
+  #
+  # For archives, if the archive exists but some member lacks 
+  # interception info, then regard the whole archive as unintercepted.
+  # Consequently, (1) it will be reported as such at the end, and (2)
+  # the reconstruction link will link the archive as a unit, which
+  # should satisfy the needed symbols.
+
+  if (fileExists($line, $inLdCwd)) {
+    if (!objHasInterceptionInfo($line)) {
+      push @unintercepted, ($line);
+    }
+  }
+
+  # (archive.a)obj format?
+  elsif ($line =~ m|^\((.*\.a)\)(.*)$|) {
+    my $archive = $1;
+    my $obj = $2;
+
+    if (fileExists($archive, $inLdCwd)) {
+      # already decided this archive was unintercepted?
+      if (grep {$_ eq $archive} @unintercepted) {
+        # yes, no point in testing
+      }
+      else {
+        # no; check this member
+        if (!archiveMemberHasInterceptionInfo($archive, $obj)) {
+          push @unintercepted, ($archive);
+        }
+      }
+    }
+  }
+}
+
+# how many of the unintercepted files appear to *not* come from
+# some standard system library?
+$nonstandard = 0;
+foreach my $u (@unintercepted) {
+  if ($u !~ m,(^(/usr|/lib))|gcc-lib,) {
+    $nonstandard++;
+  }
+}
+
+if ($verbose) {
+  print("unintercepted ($nonstandard nonstandard):\n");
+  foreach my $u (@unintercepted) {
+    print("  $u\n");
+  }
+}
+
+
+# ------------------- 4. reconstruct object files -------------------
+# process the cc1 interception data, rebuilding one .o file for
+# each section
+ at rebuiltObjs = ();
+eval {
+  my $state = 1;               # state of parsing the notes
+  my $counter = 0;             # number of objs rebuilt so far
+
+  my $rebuiltAsmFname = "";    # .s file to rebuild
+  my $rebuiltObjFname = "";    # .o file to rebuild
+  my $origAsmFname = "";       # .s file built during original build
+  my $interceptedFname = "";   # .i file intercepted
+  my @command = ();            # command used to build .s file
+
+  my @cc1Notes = split('\n', $cc1Notes);
+  for (my $i=0; $i < @cc1Notes; $i++) {
+    my $line = $cc1Notes[$i];
+
+    if ($state == 1) {              # between sections
+      if ($line =~ m|^\(|) {
+        $state++;
+
+        $counter++;
+        $rebuiltAsmFname = getTemporaryFname("rebuilt-obj-$counter", "s");
+        $rebuiltObjFname = getTemporaryFname("rebuilt-obj-$counter", "o");
+        
+        # if either file exists, remove it so that later I can test
+        # for existence to confirm that a program did what I expect
+        if (-f $rebuiltAsmFname) {
+          unlink($rebuiltAsmFname) or die;
+        }
+        if (-f $rebuiltObjFname) {
+          unlink($rebuiltObjFname) or die;
+        }
+
+        # reset per-objfile stats so we don't get accidental contamination
+        $origAsmFname = "";
+        $interceptedFname = "";
+        @command = ();
+      }
+    }
+
+    elsif ($state == 2) {           # in a section
+      if ($line =~ m|^\tintercepted:(.*)$|) {
+        $interceptedFname = $1;
+      }
+      elsif ($line =~ m|^\toutput:(.*)$|) {
+        $origAsmFname = $1;
+      }
+      elsif ($line =~ m|^\tcommand:|) {
+        $state++;
+      }
+      elsif ($line =~ m|^\)|) {
+        $state--;
+
+        # did we see everything we were supposed to?
+        if (!$origAsmFname) {
+          die("cc1 command section missing 'output'\n");
+        }
+        if (!$interceptedFname) {
+          die("cc1 command section missing 'intercepted'\n");
+        }
+        if (@command == 0) {
+          die("cc1 command section missing 'command'\n");
+        }
+
+        # replace the original asm fname with the new one
+        my $found = 0;
+        for (my $i=0; $i < @command; $i++) {
+          if ($command[$i] eq $origAsmFname) {
+            $found++;
+            $command[$i] = $rebuiltAsmFname;
+          }
+        }
+        if ($found != 1) {
+          die("cc1 command section missing original asm fname\n");
+        }
+        
+        # uncompress the intercepted input file
+        if (-f "${interceptedFname}.gz") {
+          if (0!=system("gunzip -c '${interceptedFname}.gz' >'${interceptedFname}'")) {
+            die("gunzip ${interceptedFname}.gz failed\n");
+          }
+        }
+        else {
+          die("intercepted file is missing: ${interceptedFname}.gz\n");
+        }
+        
+        # rebuild the .s file
+        diagnostic("invoking: @command");
+        if (0!=system(@command)) {
+          die("failed: @command\n");
+        }
+        unlink($interceptedFname);
+        if (! -f $rebuiltAsmFname) {
+          die("cc1 did not build $rebuiltAsmFname!\n");
+        }
+        
+        # rebuild the .o file
+        #
+        # NOTE: I am assuming that I do not need the original command line
+        # arguments to the assembler.  If it turns out that I do, then I
+        # will have to intercept the call to 'as' and insert the command
+        # line arguments into the .cc1_interceptor section before passing
+        # the input to the real assembler.  I think that may have a
+        # measurable effect on performance...
+        if (0!=system("as", "-o", $rebuiltObjFname, $rebuiltAsmFname)) {
+          die("as failed to assemble $rebuiltAsmFname\n");
+        }
+        unlink($rebuiltAsmFname);
+        if (! -f $rebuiltObjFname) {
+          die("as did not write $rebuiltObjFname!\n");
+        }
+
+        # remember this file name, as it will be an input to the
+        # linker later, when we try to build the executable
+        push @rebuiltObjs, ($rebuiltObjFname);
+      }
+    }
+
+    elsif ($state == 3) {           # in 'command'
+      if ($line =~ m|^\t\)|) {
+        $state--;
+      }
+      elsif ($line =~ m|^\t\t(.*)$|) {
+        push @command, ($1);
+      }
+      else {
+        die("malformed line in cc1 command section: $line\n");
+      }
+    }
+  }
+}; # eval
+if ($@) {
+  # clean up
+  foreach my $r (@rebuiltObjs) {
+    unlink($r);
+  }
+  die($@);
+}
+
+if ($verbose) {
+  print("rebuiltObjs:\n");
+  foreach my $r (@rebuiltObjs) {
+    print("  $r\n");
+  }
+}
+
+
+# ------------------- 5. clean the ld command -------------------
+# Next, clean the 'ld' command line.
+#
+# I want to remove all of the arguments that specify object files to
+# link against, plus a couple of other arguments.  The tricky part is
+# that I have to be able to tell when an option takes an additional
+# argument, so I know to skip that too.
+#
+# The purpose of retaining *any* arguments is the supposition that the
+# extra flags may be needed for some program to run properly after
+# linking.  Arguably, we don't care about that since the main thing is
+# to ensure we have all the symbols, but I will try anyway; being able
+# to actually run a reconstructed program is that much more assurance
+# that interception was done correctly.
+
+# This info is from
+#
+#   http://www.gnu.org/software/binutils/manual/ld-2.9.1/html_chapter/ld_2.html#SEC3
+#
+# The description there appears to be somewhat inconsistent, sometimes
+# using "--" and sometimes "-" for what appear to be multiletter 
+# options.  There could well be bugs in my interpretation.
+
+# After an initial attempt, I have discovered that parsing ld's
+# arguments is as hard as parsing gcc's arguments.  GNU ld tries to be
+# compatible with a dozen or so different system linkers, with
+# incompatible argument languages.  It's a messy pile of ad-hoc
+# guesses and heuristics, further affected by the -m (linker
+# emulation) option.
+#                   
+# Therefore I am switching strategies: I will only retain a few
+# options that (1) I can reliably parse, and (2) I estimate have a
+# high likelihood of being relevant.
+
+$keepNext = 1;         # retain /usr/bin/ld
+
+for (my $i=0; $i < @ldCommand; $i++) {
+  my $opt = $ldCommand[$i];
+
+  # forced to keep this option?
+  if ($keepNext) {
+    push @newLdCommand, ($opt);
+    $keepNext = 0;
+    next;
+  }
+
+  # drop all non-arguments
+  if ($opt !~ m|^-|) {
+    next;
+  }
+
+  # drop --trace
+  if ($opt eq "-t" || $opt eq "--trace") {
+    next;
+  }
+
+  # drop -l and -L and -o
+  if ($opt =~ m/^(-l|-L|-o|--library|--library-path|--output)/) {
+    # unless we are really unlucky, the argument to these options
+    # (if provided as a separate element of @ldCommand) will be
+    # classified as a non-argument and dropped, without having
+    # to do extra work
+    next;
+  }
+
+  # non-argument forms that might be needed...
+  if ($opt =~ m/^-d[cp]?$/ ||
+      $opt =~ m/^-[EinNr]$/ ||
+      $opt =~ m/^-?-(export-dynamic|shared|Bshareable|Ur)$/ ||
+      $opt =~ m/^--(nmagic|omagic|relocateable|traditional-format)$/) {
+    push @newLdCommand, ($opt);
+    next;
+  }
+
+  # argument-taking single-letter forms that might be needed
+  if ($opt =~ m/^-[efhmu](.*)$/) {
+    push @newLdCommand, ($opt);
+    if (!$1) {
+      $keepNext = 1;
+    }
+    next;
+  }
+
+  # argument-taking double-dash multiletter forms that might be needed
+  if ($opt =~ m/^--(entry|undefined|defsym|wrap)(=.*)?$/) {
+    push @newLdCommand, ($opt);
+    if (!$2) {
+      $keepNext = 1;
+    }
+    next;
+  }
+
+  # argument-taking single- or double-dash multiletter forms
+  if ($opt =~ m/^-?-(soname|dynamic-linker|Tbss|Tdata|Ttext)(=.*)?$/) {
+    push @newLdCommand, ($opt);
+    if (!$2) {
+      $keepNext = 1;
+    }
+    next;
+  }
+
+  # drop everything else
+}
+
+
+# ------------------- 6. rebuild the executable -------------------
+# assemble the previous section's results along with the sets
+# of object files to link
+push @newLdCommand, (@rebuiltObjs, @unintercepted);
+
+# specify an output file
+$reconstructedExec = $fqExecFname . "-recons";
+push @newLdCommand, ("-o", $reconstructedExec);
+    
+# run ld
+diagnostic("invoking: @newLdCommand");
+system(@newLdCommand);
+if ($?) {                                              
+  my $code = $?;
+  printf("leaving %d temporary files in /tmp/%s\n", $#rebuiltObjs+1, $ENV{"USER"});
+  my $exit_value  = $code >> 8;
+  my $signal_num  = $code & 255;
+  if ($exit_value) {
+    exit($exit_value);
+  }
+  die("recons: ld died with signal $signal_num\n");
+}
+
+# clean up
+foreach my $r (@rebuiltObjs) {
+  unlink($r);
+}
+
+# summarize results
+print("Rebuilt $reconstructedExec.\n");
+printf("There were %d unintercepted sources, of which %d are nonstandard.\n",
+       $#unintercepted+1, $nonstandard);
+exit(0);
+
+
+# ------------------- subroutines -------------------
+sub archiveMemberHasInterceptionInfo {
+  my ($archiveFname, $objFname) = @_;
+  
+  # extract the archive member
+  my $tmpfile = getTemporaryFname("reconstruct", ".o");
+  if (0!=system("ar p '$archiveFname' '$objFname' >$tmpfile")) {
+    die("ar p '$archiveFname' '$objFname' failed (code $?)\n");
+  }
+  
+  # test it
+  my $ret = objHasInterceptionInfo($tmpfile);
+                   
+  # clean up
+  unlink($tmpfile);
+  return $ret;
+}
+
+
+sub objHasInterceptionInfo {
+  my ($fname) = @_;
+  
+  if (!open(DUMP, '-|', "objdump -h -w '$fname'")) {
+    die("cannot run objdump: $!\n");
+  }
+                  
+  my $line;
+  my $ret = 0;
+  while (defined($line = <DUMP>)) {
+    my @field = split(' ', $line);
+
+    if (!( @field >= 7 &&
+           $field[0] =~ m|^\d+$| )) {
+      # line is a header line, or some other non-section information
+      next;
+    }
+
+    if ($field[1] eq ".note.cc1_interceptor") {
+      $ret = 1;
+      last;
+    }
+  }
+
+  # it is possible this premature close may trigger a SIGPIPE
+  # in objdump, and hence a "failure" return from 'close';
+  # therefore ignore the return code  
+  close(DUMP);
+
+  return $ret;
+}
+
+
+sub fileExists {
+  my ($fname, $allowRelative) = @_;
+
+  if ($fname =~ m|^/|) {
+    return -f $fname;
+  }
+  elsif (!$allowRelative) {
+    # we are not allowing relative names; regard the file
+    # as nonexistent because it is a relative name
+    return 0;
+  }
+  else {
+    return -f $fname;
+  }
+}
+
+
+sub readFilePart {
+  my ($fh, $offset, $size) = @_;
+
+  my $buffer;
+  $fh->seek($offset, &SEEK_SET);
+  $fh->read($buffer, $size);
+  $buffer =~ s/\0//g;
+  return $buffer;
+}
+
+  
+# get a temporary fname that is not subject to race condition
+# attacks, etc.
+sub getTemporaryFname {
+  my ($str, $ext) = @_;
+
+  my $user = $ENV{"USER"};
+  if (!defined($user) || !$user) {
+    die("no defined USER\n");
+  }
+
+  if (!-d "/tmp/$user") {
+    # create it
+    if (!mkdir("/tmp/$user", 0777)) {
+      die("cannot mkdir /tmp/$user: $!\n");
+    }
+  }
+
+  # ensure it has proper ownership and permissions
+  my @fields = lstat("/tmp/$user");
+  #                   ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+  #                    $atime,$mtime,$ctime,$blksize,$blocks)
+  my $mode = $fields[2];
+  my $uid = $fields[4];
+
+  if (!S_ISDIR($mode)) {
+    die("/tmp/$user must be a directory\n");
+  }
+
+  if ($mode & (S_IWGRP | S_IWOTH)) {
+    die("/tmp/$user must not be group- or world-writable\n");
+  }
+
+  if ($uid != $>) {
+    die("/tmp/$user must be owned by current effective user (id $>)\n");
+  }
+
+  # All of the checks above ensure that the directory is private
+  # to the current user, and therefore immune from mischief.  So,
+  # it is fine to now just return a filename, rather than (say)
+  # an open file handle.
+
+  return "/tmp/${user}/${str}-$$.${ext}";
+}
+
+
+sub diagnostic {
+  if ($verbose) {
+    print("recons: ", @_, "\n");
+  }
+}
+
+# EOF


Property changes on: vendor/elsa/current/elsa/buildint/reconstruct-exec.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/builtin-declarations.h
===================================================================
--- vendor/elsa/current/elsa/builtin-declarations.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/builtin-declarations.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,716 @@
+/*** builtin-declarations.h - generated by builtin-maker */
+#include "builtin-t.h"
+
+/** aio.c */
+
+/** aliases.c */
+
+/** alloca.c */
+void * __builtin_alloca (size_t size);
+
+/** argp.c */
+
+/** argz.c */
+
+/** arpa/inet.c */
+
+/** arpa/nameser.c */
+
+/** assert.c */
+
+/** bits/byteswap.c */
+
+/** bits/dlfcn.c */
+
+/** bits/errno.c */
+
+/** bits/libc-lock.c */
+
+/** bits/sched.c */
+
+/** bits/select.c */
+
+/** bits/shm.c */
+
+/** bits/siginfo.c */
+
+/** bits/sigset.c */
+
+/** bits/sigthread.c */
+
+/** bits/socket.c */
+
+/** bits/string2.c */
+
+/** bits/string.c */
+
+/** bits/stropts.c */
+
+/** bits/sys_errlist.c */
+
+/** bits/time.c */
+
+/** complex.c */
+double complex __builtin_cacos (double complex z);
+double complex __builtin_casin (double complex z);
+double complex __builtin_catan (double complex z);
+double complex __builtin_ccos (double complex z);
+double complex __builtin_csin (double complex z);
+double complex __builtin_ctan (double complex z);
+double complex __builtin_cacosh (double complex z);
+double complex __builtin_casinh (double complex z);
+double complex __builtin_catanh (double complex z);
+double complex __builtin_ccosh (double complex z);
+double complex __builtin_csinh (double complex z);
+double complex __builtin_ctanh (double complex z);
+double complex __builtin_cexp (double complex z);
+double complex __builtin_clog (double complex z);
+double complex __builtin_cpow (double complex __x, double complex __y);
+double complex __builtin_csqrt (double complex z);
+double __builtin_cabs (double complex z);
+double __builtin_carg (double complex z);
+double complex __builtin_conj (double complex z);
+double complex __builtin_cproj (double complex z);
+double __builtin_cimag (double complex z);
+double __builtin_creal (double complex z);
+float complex __builtin_cacosf (float complex z);
+float complex __builtin_casinf (float complex z);
+float complex __builtin_catanf (float complex z);
+float complex __builtin_ccosf (float complex z);
+float complex __builtin_csinf (float complex z);
+float complex __builtin_ctanf (float complex z);
+float complex __builtin_cacoshf (float complex z);
+float complex __builtin_casinhf (float complex z);
+float complex __builtin_catanhf (float complex z);
+float complex __builtin_ccoshf (float complex z);
+float complex __builtin_csinhf (float complex z);
+float complex __builtin_ctanhf (float complex z);
+float complex __builtin_cexpf (float complex z);
+float complex __builtin_clogf (float complex z);
+float complex __builtin_cpowf (float complex __x, float complex __y);
+float complex __builtin_csqrtf (float complex z);
+float __builtin_cabsf (float complex z);
+float __builtin_cargf (float complex z);
+float complex __builtin_conjf (float complex z);
+float complex __builtin_cprojf (float complex z);
+float __builtin_cimagf (float complex z);
+float __builtin_crealf (float complex z);
+long double complex __builtin_cacosl (long double complex z);
+long double complex __builtin_casinl (long double complex z);
+long double complex __builtin_catanl (long double complex z);
+long double complex __builtin_ccosl (long double complex z);
+long double complex __builtin_csinl (long double complex z);
+long double complex __builtin_ctanl (long double complex z);
+long double complex __builtin_cacoshl (long double complex z);
+long double complex __builtin_casinhl (long double complex z);
+long double complex __builtin_catanhl (long double complex z);
+long double complex __builtin_ccoshl (long double complex z);
+long double complex __builtin_csinhl (long double complex z);
+long double complex __builtin_ctanhl (long double complex z);
+long double complex __builtin_cexpl (long double complex z);
+long double complex __builtin_clogl (long double complex z);
+long double complex __builtin_cpowl (long double complex __x, long double complex __y);
+long double complex __builtin_csqrtl (long double complex z);
+long double __builtin_cabsl (long double complex z);
+long double __builtin_cargl (long double complex z);
+long double complex __builtin_conjl (long double complex z);
+long double complex __builtin_cprojl (long double complex z);
+long double __builtin_cimagl (long double complex z);
+long double __builtin_creall (long double complex z);
+
+/** crypt.c */
+
+/** ctype.c */
+
+/** dirent.c */
+
+/** dlfcn.c */
+
+/** envz.c */
+
+/** err.c */
+
+/** error.c */
+
+/** execinfo.c */
+
+/** fcntl.c */
+
+/** fenv.c */
+
+/** fmtmsg.c */
+
+/** fnmatch.c */
+
+/** fstab.c */
+
+/** fts.c */
+
+/** ftw.c */
+
+/** getopt.c */
+
+/** glob.c */
+
+/** gnu/libc-version.c */
+
+/** grp.c */
+
+/** iconv.c */
+
+/** ifaddrs.c */
+
+/** inttypes.c */
+
+/** langinfo.c */
+
+/** libgen.c */
+
+/** libintl.c */
+char * __builtin_gettext (const char *msgid);
+char * __builtin_dgettext (const char *domainname, const char *msgid);
+char * __builtin_dcgettext (const char *domainname, __const char *msgid, int category);
+
+/** link.c */
+
+/** linux/kernel.c */
+
+/** locale.c */
+
+/** _main.c */
+
+/** malloc.c */
+__malloc_ptr_t __builtin_malloc (size_t size);
+__malloc_ptr_t __builtin_calloc (size_t nmemb, size_t size);
+
+/** math.c */
+double __builtin_acos (double x);
+double __builtin_asin (double x);
+double __builtin_atan (double x);
+double __builtin_atan2 (double y, double x);
+double __builtin_cos (double x);
+double __builtin_sin (double x);
+double __builtin_tan (double x);
+double __builtin_cosh (double x);
+double __builtin_sinh (double x);
+double __builtin_tanh (double x);
+void __builtin_sincos (double x, double *sinx, double *cosx);
+double __builtin_acosh (double x);
+double __builtin_asinh (double x);
+double __builtin_atanh (double x);
+double __builtin_exp (double x);
+double __builtin_frexp (double x, int *exponent);
+double __builtin_ldexp (double x, int exponent);
+double __builtin_log (double x);
+double __builtin_log10 (double x);
+double __builtin_modf (double x, double *iptr);
+double __builtin_exp10 (double x);
+double __builtin_pow10 (double x);
+double __builtin_expm1 (double x);
+double __builtin_log1p (double x);
+double __builtin_logb (double x);
+double __builtin_exp2 (double x);
+double __builtin_log2 (double x);
+double __builtin_pow (double x, double y);
+double __builtin_sqrt (double x);
+double __builtin_hypot (double x, double y);
+double __builtin_cbrt (double x);
+double __builtin_ceil (double x);
+double __builtin_fabs (double x);
+double __builtin_floor (double x);
+double __builtin_fmod (double x, double y);
+double __builtin_drem (double x, double y);
+double __builtin_significand (double x);
+double __builtin_copysign (double x, double y);
+double __builtin_nan (const char *tagb);
+double __builtin_j0 (double x);
+double __builtin_j1 (double x);
+double __builtin_jn (int n, double x);
+double __builtin_y0 (double x);
+double __builtin_y1 (double x);
+double __builtin_yn (int n, double x);
+double __builtin_erf (double x);
+double __builtin_erfc (double x);
+double __builtin_lgamma (double x);
+double __builtin_tgamma (double x);
+double __builtin_gamma (double x);
+double __builtin_rint (double x);
+double __builtin_nextafter (double x, double y);
+double __builtin_nexttoward (double x, long double y);
+double __builtin_remainder (double x, double y);
+double __builtin_scalbn (double x, int n);
+int __builtin_ilogb (double x);
+double __builtin_scalbln (double x, long int n);
+double __builtin_nearbyint (double x);
+double __builtin_round (double x);
+double __builtin_trunc (double x);
+double __builtin_remquo (double x, double y, int *quo);
+long int __builtin_lrint (double x);
+long long int __builtin_llrint (double x);
+long int __builtin_lround (double x);
+long long int __builtin_llround (double x);
+double __builtin_fdim (double x, double y);
+double __builtin_fmax (double x, double y);
+double __builtin_fmin (double x, double y);
+double __builtin_fma (double x, double y, double z);
+double __builtin_scalb (double x, double n);
+float __builtin_acosf (float x);
+float __builtin_asinf (float x);
+float __builtin_atanf (float x);
+float __builtin_atan2f (float y, float x);
+float __builtin_cosf (float x);
+float __builtin_sinf (float x);
+float __builtin_tanf (float x);
+float __builtin_coshf (float x);
+float __builtin_sinhf (float x);
+float __builtin_tanhf (float x);
+void __builtin_sincosf (float x, float *sinx, float *cosx);
+float __builtin_acoshf (float x);
+float __builtin_asinhf (float x);
+float __builtin_atanhf (float x);
+float __builtin_expf (float x);
+float __builtin_frexpf (float x, int *exponent);
+float __builtin_ldexpf (float x, int exponent);
+float __builtin_logf (float x);
+float __builtin_log10f (float x);
+float __builtin_modff (float x, float *iptr);
+float __builtin_exp10f (float x);
+float __builtin_pow10f (float x);
+float __builtin_expm1f (float x);
+float __builtin_log1pf (float x);
+float __builtin_logbf (float x);
+float __builtin_exp2f (float x);
+float __builtin_log2f (float x);
+float __builtin_powf (float x, float y);
+float __builtin_sqrtf (float x);
+float __builtin_hypotf (float x, float y);
+float __builtin_cbrtf (float x);
+float __builtin_ceilf (float x);
+float __builtin_fabsf (float x);
+float __builtin_floorf (float x);
+float __builtin_fmodf (float x, float y);
+float __builtin_dremf (float x, float y);
+float __builtin_significandf (float x);
+float __builtin_copysignf (float x, float y);
+float __builtin_nanf (const char *tagb);
+float __builtin_j0f (float x);
+float __builtin_j1f (float x);
+float __builtin_jnf (int n, float x);
+float __builtin_y0f (float x);
+float __builtin_y1f (float x);
+float __builtin_ynf (int n, float x);
+float __builtin_erff (float x);
+float __builtin_erfcf (float x);
+float __builtin_lgammaf (float x);
+float __builtin_tgammaf (float x);
+float __builtin_gammaf (float x);
+float __builtin_rintf (float x);
+float __builtin_nextafterf (float x, float y);
+float __builtin_nexttowardf (float x, long double y);
+float __builtin_remainderf (float x, float y);
+float __builtin_scalbnf (float x, int n);
+int __builtin_ilogbf (float x);
+float __builtin_scalblnf (float x, long int n);
+float __builtin_nearbyintf (float x);
+float __builtin_roundf (float x);
+float __builtin_truncf (float x);
+float __builtin_remquof (float x, float y, int *quo);
+long int __builtin_lrintf (float x);
+long long int __builtin_llrintf (float x);
+long int __builtin_lroundf (float x);
+long long int __builtin_llroundf (float x);
+float __builtin_fdimf (float x, float y);
+float __builtin_fmaxf (float x, float y);
+float __builtin_fminf (float x, float y);
+float __builtin_fmaf (float x, float y, float z);
+float __builtin_scalbf (float x, float n);
+long double __builtin_acosl (long double x);
+long double __builtin_asinl (long double x);
+long double __builtin_atanl (long double x);
+long double __builtin_atan2l (long double y, long double x);
+long double __builtin_cosl (long double x);
+long double __builtin_sinl (long double x);
+long double __builtin_tanl (long double x);
+long double __builtin_coshl (long double x);
+long double __builtin_sinhl (long double x);
+long double __builtin_tanhl (long double x);
+void __builtin_sincosl (long double x, long double *sinx, long double *cosx);
+long double __builtin_acoshl (long double x);
+long double __builtin_asinhl (long double x);
+long double __builtin_atanhl (long double x);
+long double __builtin_expl (long double x);
+long double __builtin_frexpl (long double x, int *exponent);
+long double __builtin_ldexpl (long double x, int exponent);
+long double __builtin_logl (long double x);
+long double __builtin_log10l (long double x);
+long double __builtin_modfl (long double x, long double *iptr);
+long double __builtin_exp10l (long double x);
+long double __builtin_pow10l (long double x);
+long double __builtin_expm1l (long double x);
+long double __builtin_log1pl (long double x);
+long double __builtin_logbl (long double x);
+long double __builtin_exp2l (long double x);
+long double __builtin_log2l (long double x);
+long double __builtin_powl (long double x, long double y);
+long double __builtin_sqrtl (long double x);
+long double __builtin_hypotl (long double x, long double y);
+long double __builtin_cbrtl (long double x);
+long double __builtin_ceill (long double x);
+long double __builtin_fabsl (long double x);
+long double __builtin_floorl (long double x);
+long double __builtin_fmodl (long double x, long double y);
+long double __builtin_dreml (long double x, long double y);
+long double __builtin_significandl (long double x);
+long double __builtin_copysignl (long double x, long double y);
+long double __builtin_nanl (const char *tagb);
+long double __builtin_j0l (long double x);
+long double __builtin_j1l (long double x);
+long double __builtin_jnl (int n, long double x);
+long double __builtin_y0l (long double x);
+long double __builtin_y1l (long double x);
+long double __builtin_ynl (int n, long double x);
+long double __builtin_erfl (long double x);
+long double __builtin_erfcl (long double x);
+long double __builtin_lgammal (long double x);
+long double __builtin_tgammal (long double x);
+long double __builtin_gammal (long double x);
+long double __builtin_rintl (long double x);
+long double __builtin_nextafterl (long double x, long double y);
+long double __builtin_nexttowardl (long double x, long double y);
+long double __builtin_remainderl (long double x, long double y);
+long double __builtin_scalbnl (long double x, int n);
+int __builtin_ilogbl (long double x);
+long double __builtin_scalblnl (long double x, long int n);
+long double __builtin_nearbyintl (long double x);
+long double __builtin_roundl (long double x);
+long double __builtin_truncl (long double x);
+long double __builtin_remquol (long double x, long double y, int *quo);
+long int __builtin_lrintl (long double x);
+long long int __builtin_llrintl (long double x);
+long int __builtin_lroundl (long double x);
+long long int __builtin_llroundl (long double x);
+long double __builtin_fdiml (long double x, long double y);
+long double __builtin_fmaxl (long double x, long double y);
+long double __builtin_fminl (long double x, long double y);
+long double __builtin_fmal (long double x, long double y, long double z);
+long double __builtin_scalbl (long double x, long double n);
+double __builtin_huge_val (void);
+float __builtin_huge_valf (void);
+long double __builtin_huge_vall (void);
+double __builtin_inf (void);
+float __builtin_inff (void);
+long double __builtin_infl (void);
+double __builtin_nans (const char *str);
+float __builtin_nansf (const char *str);
+long double __builtin_nansl (const char *str);
+
+/** mcheck.c */
+
+/** mntent.c */
+
+/** monetary.c */
+ssize_t __builtin_strfmon (char * s, size_t maxsize, const char * format, ...);
+
+/** netdb.c */
+
+/** net/if.c */
+
+/** netinet/ether.c */
+
+/** netinet/in.c */
+
+/** nl_types.c */
+
+/** nss.c */
+
+/** obstack.c */
+
+/** printf.c */
+
+/** pthread.c */
+
+/** pty.c */
+
+/** pwd.c */
+
+/** regex.c */
+
+/** regexp.c */
+
+/** resolv.c */
+
+/** rpc/auth.c */
+
+/** rpc/auth_des.c */
+
+/** rpc/auth_unix.c */
+
+/** rpc/clnt.c */
+
+/** rpc/des_crypt.c */
+
+/** rpc/key_prot.c */
+
+/** rpc/netdb.c */
+
+/** rpc/pmap_clnt.c */
+
+/** rpc/pmap_prot.c */
+
+/** rpc/pmap_rmt.c */
+
+/** rpc/rpc.c */
+
+/** rpc/rpc_msg.c */
+
+/** rpc/svc_auth.c */
+
+/** rpcsvc/bootparam_prot.c */
+
+/** rpc/svc.c */
+
+/** rpcsvc/key_prot.c */
+
+/** rpcsvc/klm_prot.c */
+
+/** rpcsvc/mount.c */
+
+/** rpcsvc/nfs_prot.c */
+
+/** rpcsvc/nis.c */
+
+/** rpcsvc/nis_callback.c */
+
+/** rpcsvc/nislib.c */
+
+/** rpcsvc/nlm_prot.c */
+
+/** rpcsvc/rex.c */
+
+/** rpcsvc/rquota.c */
+
+/** rpcsvc/rstat.c */
+
+/** rpcsvc/rusers.c */
+
+/** rpcsvc/sm_inter.c */
+
+/** rpcsvc/spray.c */
+
+/** rpcsvc/yp.c */
+
+/** rpcsvc/ypclnt.c */
+
+/** rpcsvc/yppasswd.c */
+
+/** rpcsvc/yp_prot.c */
+
+/** rpcsvc/ypupd.c */
+
+/** rpc/xdr.c */
+
+/** sched.c */
+
+/** search.c */
+
+/** semaphore.c */
+
+/** setjmp.c */
+
+/** sgtty.c */
+
+/** shadow.c */
+
+/** signal.c */
+
+/** spawn.c */
+
+/** stdio.c */
+int __builtin_fprintf (FILE * stream, const char * format, ...);
+int __builtin_fprintf_unlocked (FILE * stream, const char * format, ...);
+int __builtin_printf (const char * format, ...);
+int __builtin_printf_unlocked (const char * format, ...);
+int __builtin_sprintf (char * s, const char * format, ...);
+int __builtin_vfprintf (FILE * s, const char * format, va_list arg);
+int __builtin_vprintf (const char * format, va_list arg);
+int __builtin_vsprintf (char * s, const char * format, va_list arg);
+int __builtin_snprintf (char * s, size_t maxlen, const char * format, ...);
+int __builtin_vsnprintf (char * s, size_t maxlen, const char * format, va_list arg);
+int __builtin_fscanf (FILE * stream, const char * format, ...);
+int __builtin_scanf (const char * format, ...);
+int __builtin_sscanf (const char * s, const char * format, ...);
+int __builtin_vfscanf (FILE * s, const char * format, va_list arg);
+int __builtin_vscanf (const char * format, va_list arg);
+int __builtin_vsscanf (const char * s, const char * format, va_list arg);
+int __builtin_fputc (int c, FILE *stream);
+int __builtin_putchar (int c);
+int __builtin_putchar_unlocked (int c);
+int __builtin_fputs (const char * s, FILE * stream);
+int __builtin_puts (const char *__s);
+int __builtin_puts_unlocked (const char *__s);
+size_t __builtin_fwrite (const void * ptr, size_t size, size_t n, FILE * s);
+int __builtin_fputs_unlocked (const char * s, FILE * stream);
+size_t __builtin_fwrite_unlocked (const void * ptr, size_t size, size_t n, FILE * stream);
+
+/** stdio_ext.c */
+
+/** stdlib.c */
+void __builtin_abort (void);
+void __builtin_exit (int status);
+void __builtin__Exit (int status);
+int __builtin_abs (int x);
+long int __builtin_labs (long int x);
+long long int __builtin_llabs (long long int x);
+
+/** string.c */
+void * __builtin_memcpy (void * dest, void const * src, size_t n);
+void * __builtin_memmove (void * dest, const void * src, size_t n);
+void * __builtin_memset (void * s, int c, size_t n);
+int __builtin_memcmp (const void * s1, const void * s2, size_t n);
+char * __builtin_strcpy (char * dest, const char * src);
+char * __builtin_strncpy (char * dest, const char * src, size_t n);
+char * __builtin_strcat (char * dest, const char * src);
+char * __builtin_strncat (char * dest, const char * src, size_t n);
+int __builtin_strcmp (const char * s1, const char * s2);
+int __builtin_strncmp (const char * s1, const char * s2, size_t n);
+char * __builtin_strdup (const char * s1);
+char * __builtin_strchr (const char * s, int c);
+char * __builtin_strrchr (const char * s, int c);
+size_t __builtin_strcspn (const char * s, const char * reject);
+size_t __builtin_strspn (const char * s, const char * accept);
+char * __builtin_strpbrk (const char * s, const char * accept);
+char * __builtin_strstr (const char * haystack, const char * needle);
+void * __builtin_mempcpy (void * dest, const void * src, size_t n);
+size_t __builtin_strlen (const char * s);
+void __builtin_bzero (void * s, size_t n);
+void __builtin_bcopy (const void * src, void * dest, size_t n);
+int __builtin_bcmp (const void * s1, const void * s2, size_t n);
+char * __builtin_index (const char * s, int c);
+char * __builtin_rindex (const char * s, int c);
+int __builtin_ffs (int i);
+int __builtin_ffsl (long int l);
+int __builtin_ffsll (long long int ll);
+char * __builtin_stpcpy (char * dest, const char * src);
+
+/** stropts.c */
+
+/** sys/acct.c */
+
+/** sys/epoll.c */
+
+/** sys/file.c */
+
+/** sys/fsuid.c */
+
+/** sys/gmon.c */
+
+/** sys/io.c */
+
+/** sys/ioctl.c */
+
+/** sys/ipc.c */
+
+/** sys/kdaemon.c */
+
+/** sys/klog.c */
+
+/** sys/mman.c */
+
+/** sys/mount.c */
+
+/** sys/msg.c */
+
+/** sys/perm.c */
+
+/** sys/personality.c */
+
+/** sys/poll.c */
+
+/** sys/prctl.c */
+
+/** sys/profil.c */
+
+/** sys/ptrace.c */
+
+/** sys/quota.c */
+
+/** sys/reboot.c */
+
+/** sys/resource.c */
+
+/** sys/select.c */
+
+/** sys/sem.c */
+
+/** sys/sendfile.c */
+
+/** sys/shm.c */
+
+/** sys/socket.c */
+
+/** sys/stat.c */
+
+/** sys/statfs.c */
+
+/** sys/statvfs.c */
+
+/** sys/swap.c */
+
+/** sys/sysctl.c */
+
+/** sys/sysinfo.c */
+
+/** sys/syslog.c */
+
+/** sys/sysmacros.c */
+
+/** sys/timeb.c */
+
+/** sys/time.c */
+
+/** sys/times.c */
+
+/** sys/timex.c */
+
+/** sys/uio.c */
+
+/** sys/ustat.c */
+
+/** sys/utsname.c */
+
+/** sys/vlimit.c */
+
+/** sys/vm86.c */
+
+/** sys/vtimes.c */
+
+/** sys/wait.c */
+
+/** sys/xattr.c */
+
+/** termios.c */
+
+/** thread_db.c */
+
+/** time.c */
+size_t __builtin_strftime (char * s, size_t maxsize, const char * format, const struct tm * tp);
+
+/** ttyent.c */
+
+/** ucontext.c */
+
+/** ulimit.c */
+
+/** unistd.c */
+
+/** utime.c */
+
+/** utmp.c */
+
+/** utmpx.c */
+
+/** wchar.c */
+
+/** wctype.c */
+
+/** wordexp.c */

Added: vendor/elsa/current/elsa/builtin-t.h
===================================================================
--- vendor/elsa/current/elsa/builtin-t.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/builtin-t.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+
+// $Id: builtin-t.h 2397 2006-07-11 03:51:55Z quarl $
+
+// header file declaring minimal types needed for GCC builtins.
+
+typedef struct _IO_FILE FILE;
+typedef unsigned long size_t;
+typedef int ssize_t;
+typedef __builtin_va_list va_list;
+typedef void *__malloc_ptr_t;
+struct tm;
+#define complex         _Complex

Added: vendor/elsa/current/elsa/builtinops.cc
===================================================================
--- vendor/elsa/current/elsa/builtinops.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/builtinops.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,586 @@
+// builtinops.cc
+// code for builtinops.h
+
+#include "builtinops.h"    // this module
+#include "cc_type.h"       // Type, etc.
+#include "cc_env.h"        // Env
+#include "overload.h"      // getConversionOperators, OverloadResolver
+
+
+// ------------------ CandidateSet -----------------
+CandidateSet::~CandidateSet()
+{}
+
+
+// ------------------ PolymorphicCandidateSet -----------------
+PolymorphicCandidateSet::PolymorphicCandidateSet(Variable *v)
+  : poly(v)
+{}
+
+void PolymorphicCandidateSet::instantiateBinary(Env &env,
+  OverloadResolver &resolver, OverloadableOp op, ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo)
+{
+  // polymorphic candidates are easy
+  resolver.processCandidate(poly);
+}
+
+
+// ------------------ PredicateCandidateSet -----------------
+STATICDEF Type const *PredicateCandidateSet::Inst::getKeyFn(Inst *ic)
+{
+  return ic->type;
+}
+
+STATICDEF unsigned PredicateCandidateSet::Inst::hashFn(Type const *t)
+{
+  return t->hashValue();
+}
+
+STATICDEF bool PredicateCandidateSet::Inst::equalFn(Type const *t1, Type const *t2)
+{
+  return t1->equals(t2);
+}
+
+
+PredicateCandidateSet::PredicateCandidateSet(SimpleTypeId retId, PreFilter r, PostFilter o)
+  : instantiations(&Inst::getKeyFn,
+                   &Inst::hashFn,
+                   &Inst::equalFn),
+    ambigInst(NULL),
+    retAlgorithm(retId),
+    pre(r),
+    post(o),
+    generation(0)
+{}
+
+PredicateCandidateSet::~PredicateCandidateSet()
+{}
+
+
+
+// get the set of types that 'info.type' can be converted to via a
+// user-defined conversion operator, or by the identity conversion
+void getConversionOperatorResults(Env &env, SObjList<Type> &dest, 
+                                  ArgumentInfo &info)
+{
+  if (info.overloadSet.isNotEmpty()) {
+    // 2005-02-25: I am not sure if this will really work, but I am
+    // going to attempt to treat an overloaded function name as if
+    // it could "convert" to all of the types of the overloaded names.
+    SFOREACH_OBJLIST(Variable, info.overloadSet, iter) {
+      dest.prepend(iter.data()->type);
+    }
+    dest.reverse();
+    return;
+  }
+
+  Type *t = info.type;
+  if (!t->asRval()->isCompoundType()) {
+    // this is for when one of the arguments to an operator is not
+    // of class type; we treat it similarly to a class that can only
+    // convert to one type
+    dest.append(t);
+  }
+  else {
+    t = t->asRval();
+
+    // get conops
+    SObjList<Variable> const &convs = t->asCompoundType()->conversionOperators;
+
+    // get return types
+    dest.reverse();
+    SFOREACH_OBJLIST(Variable, convs, iter) {
+      dest.prepend(iter.data()->type->asFunctionTypeC()->retType);
+    }
+    dest.reverse();
+  }
+}
+
+void PredicateCandidateSet::instantiateBinary(Env &env,
+  OverloadResolver &resolver, OverloadableOp op, 
+  ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo)
+{
+  // for this to overflow, I'd have to do 2^31 instantiations in a
+  // single translation unit, which is very unlikely since the AST
+  // that triggers that instantiation would have to be much larger
+  // than 2^31 bytes
+  generation++;
+
+  // pattern candidate with correlated parameter types,
+  // e.g. (13.6 para 14):
+  //
+  //   For every T, where T is a pointer to object type, there exist
+  //   candidate operator functions of the form
+  //     ptrdiff_t operator-(T, T);
+  //
+  // The essential idea here is to compute a set of types with
+  // which to instantiate the above pattern.  Naively, we'd like
+  // to instantiate it with all types, but of course that is not
+  // practical.  Instead, we compute a finite set S of types such
+  // that we get the same answer as we would have if we had
+  // instantiated it with all types.  Note that if we compute S
+  // correctly, it will be the case that any superset of S would
+  // also work; we do not necessarily compute the minimal S.
+  //
+  // The core of the analysis is the least-upper-bound function
+  // on types.  Given a pair of types, the LUB type
+  // instantiation would win against all the other
+  // instantiations the LUB dominates, in the final overload
+  // analysis.  Thus we populate S with the LUBs of all pairs
+  // of types the arguments' con-ops can yield.
+  //
+  // See also: convertibility.txt
+
+  // collect all of the operator functions rettypes from lhs and rhs
+  SObjList<Type> lhsRets, rhsRets;
+  getConversionOperatorResults(env, lhsRets, lhsInfo);
+  getConversionOperatorResults(env, rhsRets, rhsInfo);
+
+  // consider all pairs of conversion results
+  SFOREACH_OBJLIST_NC(Type, lhsRets, lhsIter) {
+    Type *lhsRet = pre(lhsIter.data(), true /*isLeft*/);
+    if (!lhsRet) continue;
+
+    SFOREACH_OBJLIST_NC(Type, rhsRets, rhsIter) {
+      Type *rhsRet = pre(rhsIter.data(), false /*isLeft*/);
+      if (!rhsRet) continue;
+
+      // compute LUB
+      bool wasAmbig;
+      Type *lub = computeLUB(env, lhsRet, rhsRet, wasAmbig);
+      if (wasAmbig) {
+        addAmbigCandidate(env, resolver, op);
+      }
+      else {
+        if (!lub) {
+          // 9/23/04: if either argument is "special" (like 0) I need
+          // to relax the LUB rules
+          if (rhsInfo.special == SE_ZERO && lhsRet->isPointerType()) {
+            lub = lhsRet;
+          }
+          else if (lhsInfo.special == SE_ZERO && rhsRet->isPointerType()) {
+            lub = rhsRet;
+          }
+        }
+
+        if (lub && post(lub)) {
+          // instantiate with this type
+          instantiateCandidate(env, resolver, op, lub);
+        }
+      }
+    }
+  }
+}
+
+
+void PredicateCandidateSet::instantiateCandidate(Env &env,
+  OverloadResolver &resolver, OverloadableOp op, Type *T)
+{
+  // have we already built an instantiated candidate?
+  Inst *ic = instantiations.get(T);
+  if (ic) {
+    // did we already give it to this resolver?
+    if (ic->generation == generation) {
+      // yes, don't do so again
+      OVERLOADTRACE("cset: already given to resolver: " << T->toString());
+      return;
+    }
+
+    OVERLOADTRACE("cset: already instantiated: " << T->toString());
+  }
+
+  else {
+    // need to make a new instantiaton
+    ic = new Inst(T, makeNewCandidate(env, op, T));
+    instantiations.add(T, ic);
+
+    OVERLOADTRACE("cset: made new instantiation: " << T->toString() <<
+                  " (hash=" << T->hashValue() << ")");
+  }
+
+  // give it to the resolver
+  ic->generation = generation;
+  resolver.processCandidate(ic->inst);
+}
+
+
+Variable *PredicateCandidateSet::makeNewCandidate(Env &env,
+  OverloadableOp op, Type *T)
+{
+  Type *retType;
+  if (isConcreteSimpleType(retAlgorithm)) {
+    retType = env.getSimpleType(retAlgorithm);
+  }
+  else {
+    // only non-concrete predicate set is for '?:'
+    xassert(retAlgorithm == ST_PRET_FIRST);
+    retType = T;
+  }
+
+  // parameters are symmetric
+  return env.createBuiltinBinaryOp(retType, op, T, T);
+}
+
+
+// If any LUB is ambiguous, then the final overload analysis over the
+// infinite set of instantiations would also have been ambiguous.
+//
+// But it's not so simple as yielding an error; see in/t0140.cc for an
+// example of why.  What we need to do is yield a candidate that will
+// be ambiguous unless it's beaten by a candidate that is better than
+// any of the built-in instantiations (e.g. a member operator).
+//
+// I defer to the overload module to make such a candidate; here I
+// just say what I want.
+void PredicateCandidateSet::addAmbigCandidate(Env &env, OverloadResolver &resolver,
+  OverloadableOp op)
+{
+  // it doesn't matter if I give this to the resolver more than once,
+  // because it's already ambiguous
+
+  if (!ambigInst) {
+    Type *t_void = env.getSimpleType(ST_VOID);
+    ambigInst = env.createBuiltinBinaryOp(t_void, op, t_void, t_void);
+  }
+  resolver.addAmbiguousBinaryCandidate(ambigInst);
+}
+
+
+
+// ------------------ AssignmentCandidateSet -----------------
+bool isAssignmentOperator(OverloadableOp op)
+{
+  return OP_ASSIGN <= op && op <= OP_BITOREQ;
+}
+
+
+AssignmentCandidateSet::AssignmentCandidateSet(SimpleTypeId retId, PreFilter r, PostFilter o)
+  : PredicateCandidateSet(retId, r, o)
+{}
+
+
+void AssignmentCandidateSet::instantiateBinary(Env &env,
+  OverloadResolver &resolver, OverloadableOp op, 
+  ArgumentInfo &lhsInfo, ArgumentInfo &/*rhsInfo*/)
+{
+  generation++;
+
+  if (isAssignmentOperator(op) && lhsInfo.type->asRval()->isCompoundType()) {
+    // 13.3.1.2p4b2: cannot use user-defined conversions to convert
+    // the LHS of an assignment operator, so that means that if the
+    // LHS is of class type, then a built-in candidate can't be used
+    OVERLOADTRACE("cset: disabling conversion operators of LHS of operator" << toString(op));
+    return;
+  }
+
+  // collect all of the operator functions rettypes
+  SObjList<Type> lhsRets;
+  getConversionOperatorResults(env, lhsRets, lhsInfo);
+
+  // consider conversion results
+  SFOREACH_OBJLIST_NC(Type, lhsRets, lhsIter) {
+    Type *lhsRet = pre(lhsIter.data(), true /*isLeft*/);
+    if (!lhsRet) continue;
+
+    // the way the assignment built-ins work, we only need to
+    // instantiate with the types to which the LHS convert, to
+    // get a complete set (i.e. no additional instantiations
+    // would change the answer)
+    instantiateCandidate(env, resolver, op, lhsRet);
+  }
+}
+
+
+Variable *AssignmentCandidateSet::makeNewCandidate(Env &env,
+  OverloadableOp op, Type *T)
+{
+  // left parameter is a reference, and we need two versions,
+  // one with volatile and one without
+  //
+  // update: now that I directly instantiate the LHS types,
+  // without first stripping their volatile-ness, I don't need to
+  // instantiate volatile versions of types that don't already
+  // have volatile versions present
+
+  xassert(retAlgorithm == ST_PRET_FIRST);
+
+  Type *Tref = env.tfac.makeReferenceType(T);
+  return env.createBuiltinBinaryOp(Tref, op, Tref, T);
+}
+
+
+// ------------------ ArrowStarCandidateSet -----------------
+STATICDEF ArrowStarCandidateSet::TypePair const *
+  ArrowStarCandidateSet::Inst::getKeyFn(Inst *ic)
+{
+  return &(ic->types);
+}
+
+STATICDEF unsigned ArrowStarCandidateSet::Inst::hashFn(TypePair const *p)
+{
+  return p->hashValue();
+}
+
+unsigned ArrowStarCandidateSet::TypePair::hashValue() const
+{
+  return lhsType->hashValue() * 1000 +
+         rhsType->hashValue();
+}
+
+STATICDEF bool ArrowStarCandidateSet::Inst::equalFn
+  (TypePair const *p1, TypePair const *p2)
+{
+  return p1->lhsType->equals(p2->lhsType) &&
+         p1->rhsType->equals(p2->rhsType);
+}
+
+
+ArrowStarCandidateSet::ArrowStarCandidateSet()
+  : instantiations(&Inst::getKeyFn,
+                   &Inst::hashFn,
+                   &Inst::equalFn),
+    generation(0)
+{}
+
+ArrowStarCandidateSet::~ArrowStarCandidateSet()
+{}
+
+
+// goal: instantiate pattern
+//   CV12 T& operator->* (CV1 C1 *, CV2 T C2::*);
+// by finding instantiation pairs (C1,C2)
+void ArrowStarCandidateSet::instantiateBinary(Env &env,
+  OverloadResolver &resolver, OverloadableOp op, ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo)
+{
+  xassert(op == OP_ARROW_STAR);
+  generation++;
+
+  // these arrays record all pairs of types used to instantiate
+  // the pattern, so that we ensure that no pair is instantiated
+  // more than once
+  ArrayStack<Type*> lhsInst, rhsInst;
+
+  // collect all of the operator functions rettypes from lhs and rhs
+  SObjList<Type> lhsRets, rhsRets;
+  getConversionOperatorResults(env, lhsRets, lhsInfo);
+  getConversionOperatorResults(env, rhsRets, rhsInfo);
+
+  // consider all pairs of conversion results
+  SFOREACH_OBJLIST_NC(Type, lhsRets, lhsIter) {
+    Type *lhsRet = lhsIter.data();
+
+    // expect 'lhsRet' to be of form 'class U cv1 *'; extract U
+    if (!lhsRet->isPointer()) continue;
+    Type *lhsUnder = lhsRet->asPointerType()->atType;
+    if (!lhsUnder->isCompoundType()) continue;
+    CompoundType *U = lhsUnder->asCompoundType();
+
+    SFOREACH_OBJLIST_NC(Type, rhsRets, rhsIter) {
+      Type *rhsRet = rhsIter.data();
+
+      // expect 'rhsRet' to be of form 'T cv2 V::*'; extract V
+      if (!rhsRet->isPointerToMemberType()) continue;
+      PointerToMemberType *rhsPtm = rhsRet->asPointerToMemberType();
+      CompoundType *V = rhsPtm->inClass();
+
+      // Now, any possible instantiation C1 and C2 must have an
+      // inheritance relation like
+      //
+      //                   V
+      //                  /
+      //                C2
+      //               /
+      //             C1
+      //            /
+      //           U
+      //
+      // Furthermore, the order on conversions will push C1 towards U
+      // and C2 towards V.  Hence the only instantiation necessary
+      // for the (U,V) pair is (U,V) itself; and that's only if U and
+      // V are related by inheritance.
+
+      if (!U->hasBaseClass(V)) {
+        // necessary relationship between U and V doesn't hold
+        continue;
+      }
+
+      // build operator's parameter types; they're essentially just
+      // lhsRet and rhsRet, except I want to strip toplevel cv flags
+      // before making the instance
+      Type *lhsParam = env.tfac.setQualifiers(SL_UNKNOWN, CV_NONE, lhsRet, NULL /*syntax*/);
+      Type *rhsParam = env.tfac.setQualifiers(SL_UNKNOWN, CV_NONE, rhsRet, NULL /*syntax*/);
+
+      instantiateCandidate(env, resolver, lhsParam, rhsParam);
+    }
+  }
+}
+
+
+string ArrowStarCandidateSet::TypePair::asString() const
+{
+  return stringc << "(" << lhsType->toString()
+                 << ", " << rhsType->toString() << ")";
+}
+
+// based on PredicateCandidateSet::instantiateCandidate
+void ArrowStarCandidateSet::instantiateCandidate(Env &env,
+  OverloadResolver &resolver, Type *lhsType, Type *rhsType)
+{
+  TypePair pair(lhsType, rhsType);
+
+  // have we already built an instantiated candidate?
+  Inst *ic = instantiations.get(&pair);
+  if (ic) {
+    // did we already give it to this resolver?
+    if (ic->generation == generation) {
+      // yes, don't do so again
+      OVERLOADTRACE("->*set: already given to resolver: " << pair.asString());
+      return;
+    }
+
+    OVERLOADTRACE("->*set: already instantiated: " << pair.asString());
+  }
+
+  else {
+    // CV12 T& operator->* (CV1 C1*, CV2 T C2::*);
+    // 
+    // This is the only implementation of ST_PRET_PTM, but we don't need
+    // the code to say what to do; I leave that code in existence, however, 
+    // for uniformity.
+    Type *retType = rhsType->getAtType();                         // CV2 T
+    retType = env.tfac.applyCVToType(SL_UNKNOWN, lhsType->getAtType()->getCVFlags(),
+                                     retType, NULL /*syntax*/);   // CV12 T
+    retType = env.makeReferenceType(retType);                     // CV12 T&
+
+    // need to make a new instantiaton
+    ic = new Inst(pair,
+      env.createBuiltinBinaryOp(retType, OP_ARROW_STAR, lhsType, rhsType));
+
+    instantiations.add(&(ic->types), ic);
+
+    OVERLOADTRACE("->*set: made new instantiation: " << pair.asString() <<
+                  " (hash=" << pair.hashValue() << ")");
+  }
+
+  // give it to the resolver
+  ic->generation = generation;
+  resolver.processCandidate(ic->inst);
+}
+
+
+// ------------------- filters -------------------
+Type *rvalFilter(Type *t, bool)
+{
+  return t->asRval();
+}
+
+Type *rvalIsPointer(Type *t, bool)
+{
+  // 13.3.1.5: functions that return 'T&' are regarded as
+  // yielding 'T' for purposes of this analysis
+  t = t->asRval();
+
+  // only pointer types need consideration
+  if (t->isPointer()) {
+    return t;
+  }
+  else {
+    return NULL;
+  }
+}
+
+// we admit the pattern
+//   T VQ &
+// where T is a pointer to any type (para 19), or
+// is an enumeration or pointer-to-member (para 20)
+//
+// we yield the T for instantiation
+Type *para19_20filter(Type *t, bool)
+{
+  if (!t->isReference()) {
+    return NULL;
+  }
+  t = t->asRval();
+  if (t->isConst()) {
+    return NULL;
+  }
+
+  if (t->isPointer() ||
+      t->isEnumType() ||
+      t->isPointerToMemberType()) {
+    return t;
+  }
+
+  return NULL;
+}
+
+// same as above but with arithmetic types too
+Type *para19_20_andArith_filter(Type *t, bool)
+{
+  if (!t->isReference()) {
+    return NULL;
+  }
+  t = t->asRval();
+  if (t->isConst()) {
+    return NULL;
+  }
+
+  if (t->isPointer() ||
+      t->isEnumType() ||
+      t->isPointerToMemberType()) {
+    return t;
+  }
+
+  // this is the change from above
+  if (t->isSimpleType() &&
+      isArithmeticType(t->asSimpleTypeC()->type)) {
+    return t;
+  }
+
+  return NULL;
+}
+
+
+bool pointerToObject(Type *t)
+{
+  // the pre-filter already guarantees that only pointer types
+  // can result from the LUB, but we need to ensure that
+  // only pointer-to-object types are instantiated
+  Type *at = t->asPointerType()->atType;
+  if (at->isVoid() || at->isFunctionType()) {
+    return false;    // don't instantiate with this one
+  }
+  else {
+    return true;
+  }
+}
+
+bool pointerOrEnum(Type *t)
+{
+  return t->isPointer() || t->isEnumType();
+}
+
+bool pointerOrEnumOrPTM(Type *t)
+{
+  return t->isPointer() || t->isEnumType() || t->isPointerToMemberType();
+}
+
+bool pointerOrPTM(Type *t)
+{
+  return t->isPointer() || t->isPointerToMemberType();
+}
+
+bool pointerToAny(Type *t)
+{
+  // the LUB will ensure this, actually, but it won't
+  // hurt to check again
+  return t->isPointer();
+}
+
+bool anyType(Type *)
+{                  
+  return true;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/builtinops.h
===================================================================
--- vendor/elsa/current/elsa/builtinops.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/builtinops.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,215 @@
+// builtinops.h
+// data structures to represent cppstd 13.6
+
+#ifndef BUILTINOPS_H
+#define BUILTINOPS_H
+
+#include "cc_flags.h"      // BinaryOp
+#include "okhashtbl.h"     // OwnerKHashTable
+
+class Type;                // cc_type.h
+class Variable;            // variable.h
+class Env;                 // cc_env.h
+class OverloadResolver;    // overload.h
+class ArgumentInfo;        // overload.h
+
+
+// a set of candidates, usually one line of 13.6; since many of the
+// sets in 13.6 are infinite, and the finite ones are large, the
+// purpose of this class is to represent those sets in a way that
+// allows overload resolution to act *as if* it used the full sets
+class CandidateSet {
+public:      // funcs
+  virtual ~CandidateSet();
+
+  // instantiate the pattern as many times as necessary, given the
+  // argument types 'lhsType' and 'rhsType'
+  virtual void instantiateBinary(Env &env, OverloadResolver &resolver,
+    OverloadableOp op, ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo)=0;
+};
+   
+
+// describes a set using polymorphism
+class PolymorphicCandidateSet : public CandidateSet {
+public:      // data
+  // the candidate is represented by a single polymorphic function
+  Variable *poly;          // (serf)
+
+public:      // funcs
+  PolymorphicCandidateSet(Variable *v);
+
+  virtual void instantiateBinary(Env &env, OverloadResolver &resolver,
+    OverloadableOp op, ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo);
+};
+
+
+// describes a set with predicates over a pairwise analysis
+class PredicateCandidateSet : public CandidateSet {
+private:     // types
+  // a single instantiated candidate; this structure allows us to
+  // re-use instantiations
+  class Inst {
+  public:      // data
+    Type *type;       // the type with which the pattern was instantiated
+    Variable *inst;   // the instantiation itself
+
+    // clever hack: to ensure that each instantiated candidate is only
+    // given to the overload resolution procedure once, I keep track
+    // of how many times a given candidate set has requested
+    // instantiation, and update the instances with the latest time
+    // they were instantiated
+    unsigned generation;
+
+  public:      // funcs
+    Inst(Type *t, Variable *i)
+      : type(t),
+        inst(i),
+        generation(0)
+    {}
+
+    // hashtable accessor functions
+    static Type const *getKeyFn(Inst *ic);
+    static unsigned hashFn(Type const *t);
+    static bool equalFn(Type const *t1, Type const *t2);
+  };
+
+public:      // types
+  // each potential argument type is passed through this filter before
+  // being evaluated as part of a pair; it can return a different
+  // type, and it can also return NULL to indicate that the type
+  // shouldn't be considered; 'isLeft' says whether this is the left
+  // arg or right arg type (actually, none of the filters use this
+  // information anymore, but I leave it because it makes sense for
+  // the filter to know this)
+  typedef Type* (*PreFilter)(Type *t, bool isLeft);
+
+  // after computing a pairwise LUB, the LUB type is passed
+  // through this filter; if it returns false, then the type
+  // is not used to instantiate the pattern
+  typedef bool (*PostFilter)(Type *t);
+
+protected:   // data
+  // instantiations that already exist, so we can re-use them
+  OwnerKHashTable<Inst, Type> instantiations;
+
+  // instantiation of the ambiguous candidate
+  Variable *ambigInst;
+
+  // return type algorithm
+  SimpleTypeId retAlgorithm;
+
+  // then this pair of functions filters the argument types to a
+  // binary operator in a pairwise analysis to instantiate a pattern
+  PreFilter pre;
+  PostFilter post;
+
+  // count of the number of times instantiation has happened
+  unsigned generation;
+
+protected:   // funcs
+  void instantiateCandidate(Env &env,
+    OverloadResolver &resolver, OverloadableOp op, Type *T);
+  void addAmbigCandidate(Env &env, OverloadResolver &resolver,
+    OverloadableOp op);
+
+  virtual Variable *makeNewCandidate(Env &env, OverloadableOp op, Type *T);
+
+public:      // funcs
+  PredicateCandidateSet(SimpleTypeId retId, PreFilter pre, PostFilter post);
+  ~PredicateCandidateSet();
+
+  virtual void instantiateBinary(Env &env, OverloadResolver &resolver,
+    OverloadableOp op, ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo);
+};
+
+
+// a variant of the predicate set for assignment operators
+class AssignmentCandidateSet : public PredicateCandidateSet {
+protected:   // funcs
+  virtual Variable *makeNewCandidate(Env &env, OverloadableOp op, Type *T);
+
+public:      // funcs
+  AssignmentCandidateSet(SimpleTypeId retId, PreFilter pre, PostFilter post);
+
+  virtual void instantiateBinary(Env &env, OverloadResolver &resolver,
+    OverloadableOp op, ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo);
+};
+
+
+// predicate set for the ->* operator
+class ArrowStarCandidateSet : public CandidateSet {
+private:    // types
+  // pair of types, with hashing and equality
+  class TypePair {
+  public:
+    Type *lhsType, *rhsType;    // types for instantiation
+    
+  public:
+    TypePair(Type *L, Type *R)
+      : lhsType(L),
+        rhsType(R)
+    {}
+    TypePair(TypePair const &obj)
+      : DMEMB(lhsType),
+        DMEMB(rhsType)
+    {}
+    
+    string asString() const;
+    unsigned hashValue() const;
+  };
+
+  // similar to above, for caching candidates
+  class Inst {
+  public:      // data
+    TypePair types;     // types with which the pattern was instantiated
+    Variable *inst;     // the instantiation itself
+
+    unsigned generation;
+
+  public:      // funcs
+    Inst(TypePair const &t, Variable *i)
+      : types(t),
+        inst(i),
+        generation(0)
+    {}
+
+    // hashtable accessor functions
+    static TypePair const *getKeyFn(Inst *ic);
+    static unsigned hashFn(TypePair const *p);
+    static bool equalFn(TypePair const *p1, TypePair const *p2);
+  };
+
+private:    // data
+  OwnerKHashTable<Inst, TypePair> instantiations;
+  
+  unsigned generation;
+
+private:    // funcs
+  void instantiateCandidate(Env &env,
+    OverloadResolver &resolver, Type *lhsType, Type *rhsType);
+
+public:     // funcs
+  ArrowStarCandidateSet();
+  ~ArrowStarCandidateSet();
+
+  virtual void instantiateBinary(Env &env, OverloadResolver &resolver,
+    OverloadableOp op, ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo);
+};
+
+
+// some pre filters
+Type *rvalFilter(Type *t, bool);
+Type *rvalIsPointer(Type *t, bool);
+Type *para19_20filter(Type *t, bool);
+Type *para19_20_andArith_filter(Type *t, bool);
+
+// some post filters
+bool pointerToObject(Type *t);
+bool pointerOrEnum(Type *t);
+bool pointerOrEnumOrPTM(Type *t);
+bool pointerOrPTM(Type *t);
+bool pointerToAny(Type *t);
+bool anyType(Type *t);
+
+
+#endif // BUILTINOPS_H

Added: vendor/elsa/current/elsa/cc.ast
===================================================================
--- vendor/elsa/current/elsa/cc.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,843 @@
+// -*- c++ -*-
+// cc.ast            see license.txt for copyright and terms of use
+// C++ abstract syntax
+
+// The main documentation is in cc.ast.html.
+
+
+// Note that the description in this file is not the whole AST, just
+// the base level of it.  Other files, such as cc_tcheck.ast and
+// gnu.ast, extend the description here by adding additional fields,
+// methods and even AST node types.  The astgen tool (driven by a
+// Makefile rule) combines the various descriptions into one before
+// generating cc.ast.gen.h and cc.ast.gen.cc.  The purpose of this
+// organization is to keep related concepts together, and allow the
+// user to mix+match features by selecting which extensions are used.
+
+
+// note: wherever ASTList or FakeList is used, its elements are listed
+// in the order they appear lexically in the input file, i.e. left to
+// right and then top to bottom
+
+// How do I decide between ASTList and FakeList?  Creating ASTLists
+// can be done with left recursion, which saves stack space, whereas
+// FakeLists require right recursion.  But, ASTLists cannot safely
+// be yielded as semantic values if there's any chance they'll be
+// yielded more than once.
+//
+// So, I use FakeList everywhere I can accept the stack growth.  The
+// only places I cannot accept this growth are places where it is
+// relatively common for the list to have >100 elements.  Those
+// places are:
+//   - toplevel forms (including namespace members)
+//   - statement lists in compound statements
+//   - class/struct members
+//   - compound initializers
+//
+// In these places where I use ASTList, I encapsulate it in another
+// class if necessary to avoid yielding it as a semantic value.
+
+
+// emitted verbatim into generated header (cc.ast.gen.h)
+verbatim {
+  #include "cc_flags.h"         // CVFlags, DeclFlags, etc. (r)
+
+  class CCLang;                 // cc_lang.h
+}
+
+// use a new astgen feature: make a visitor!
+option visitor ASTVisitor;
+option dvisitor DelegatorASTVisitor;
+
+// these turn on the xml serialization and de-serialization code
+option xmlVisitor XmlAstWriter_AstVisitor;
+option xmlParser xml;
+
+option identityManager IdentityManager;
+
+// emit gdb() methods for debugging
+option gdb;
+
+
+// ---------------- file -------------
+// an entire file (with #included stuff) of toplevel forms; I use
+// an ASTList here because I want to use left recursion, and
+// there's never a multiple-yield problem with toplevel forms
+class TranslationUnit (ASTList<TopForm> topForms);
+
+// a toplevel form
+class TopForm (SourceLoc loc) {
+  // represent ambiguous topforms by forming a linked list of
+  // alternatives; the only reason topforms might be ambiguous is
+  // because of implicit int (for old-style C)
+  public TopForm * ambiguity = NULL;
+  public void addAmbiguity(TopForm *alt);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  // includes function prototypes
+  -> TF_decl(Declaration decl);
+
+  // functions with bodies
+  -> TF_func(Function f);
+
+  // template functions or template classes
+  -> TF_template(TemplateDeclaration td);
+
+  // explicit instantiation request; 'instFlags' is for the GNU
+  // "extern template" extension, and is always DF_NONE for ANSI C++
+  -> TF_explicitInst(DeclFlags instFlags, Declaration d);
+
+  // linkage specification enclosing a bunch of forms, e.g.
+  // extern "C" { /*...*/ }
+  -> TF_linkage(StringRef linkageType, TranslationUnit forms);
+
+  // linkage spec with one form and no braces; it turns out this has
+  // different semantics [cppstd 7.5 para 7]
+  -> TF_one_linkage(StringRef linkageType, TopForm form);
+
+  // assembly directive at toplevel
+  -> TF_asm(E_stringLit text);
+
+  // namespace definition [cppstd 7.3.1]
+  -> TF_namespaceDefn(StringRef /*nullable*/ name, ASTList<TopForm> forms);
+
+  // one of three namespace-related declarations that can occur
+  // at toplevel or as a function statement
+  -> TF_namespaceDecl(NamespaceDecl decl);
+}
+
+
+// ----------------------- function -------------------------
+// a function definition (toplevel or class member)
+class Function (
+  DeclFlags dflags,             // static, extern, etc.
+
+  TypeSpecifier retspec,        // type specifier for return value
+
+  Declarator nameAndParams,     // 1. remainder of return value type
+                                // 2. name of function
+                                // 3. names/types of parameters
+
+  FakeList<MemberInit> *inits,  // (for ctors only) member initialization list
+
+  S_compound body,              // body of function
+
+  FakeList<Handler> *handlers   // handlers for ctor "try" block
+) {
+  public SourceLoc getLoc() const;
+}
+
+class MemberInit (
+  PQName name,                    // name of member or base class
+  FakeList<ArgExpression> *args   // arguments to its constructor
+) {
+  // standard way to make it possible to include something
+  // in a FakeList; this line is repeated below in several places
+  public MemberInit *next=NULL;   // FakeList link
+}
+
+
+// --------------- types and declarators ---------------
+// variable declaration or definition, or function declaration
+class Declaration (
+  DeclFlags dflags,                    // typedef, virtual, extern, etc.
+  TypeSpecifier spec,                  // e.g. "int"
+  FakeList<Declarator> *decllist       // e.g. "x=3, y"
+);
+
+
+// just one complete type; appears in parameter decls and in casts; the
+// main difference between an ASTTypeId and a Declaration is that the
+// former can have only one declarator, while the latter can have several
+class ASTTypeId (
+  TypeSpecifier spec,        // "int"
+  Declarator decl            // this will be abstract sometimes (e.g. casts)
+) {
+  // FakeList link; use setNext
+  public ASTTypeId *next = NULL;
+  public void setNext(ASTTypeId *newNext);
+
+  // ambiguity representation
+  public ASTTypeId *ambiguity = NULL;
+  public void addAmbiguity(ASTTypeId *alternative);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+}
+
+// a name with optional class qualifiers (PQ: "possibly qualified");
+// if the first qualifier's 'qualifier' name is NULL, then it means
+// there was a leading "::" symbol; each level of qualification has a
+// 'loc' because each level is a remote reference to some entity, and
+// that lookup might fail
+class PQName(SourceLoc loc) {
+  public bool hasQualifiers() const { return isPQ_qualifier(); };
+
+  public string qualifierString() const;
+  public string toString() const;
+  public string toString_noTemplArgs() const;
+  public friend stringBuilder& operator<< (stringBuilder &sb, PQName const &obj);
+  public friend ostream& operator<< (ostream &os, PQName const &obj) { return os << obj.toString(); };
+
+  // retrieve a StringRef for the underlying name, be it a PQ_name or
+  // a PQ_operator
+  pure_virtual StringRef getName() const;
+
+  // just this component; as if last in chain
+  pure_virtual string toComponentString() const;
+
+  // get the PQName at the bottom of any qualifiers
+  public PQName const *getUnqualifiedNameC() const;
+  public PQName *getUnqualifiedName()
+    { return const_cast<PQName*>(getUnqualifiedNameC()); };
+
+  // true if the 'template' keyword was used in this part of the name
+  public bool templateUsed() const;
+
+  // merge two ambiguous PQNames ('this' and 'obj')
+  public PQName *mergeAmbiguous(PQName *obj);
+
+  // The reason for the "/*fakelist*/TemplateArgument" stuff is that
+  // those fields are treated like lists, but I want to hide their
+  // fake-list-ness from astgen.  Instead, astgen will print and
+  // traverse using the 'next' fields in the TemplateArguments
+  // directly (and if I did not hide the fake-list-ness, these things
+  // would be done twice).
+
+  // outer qualifier applied to some inner PQName, plus an optional
+  // list of template arguments to the qualifier
+  -> PQ_qualifier(StringRef /*nullable*/qualifier,
+                  /*fakelist*/TemplateArgument templArgs,
+                  PQName rest)
+     {
+       // PQNames can be ambiguous; e.g., in/t0455.cc.  However, the
+       // ambiguity always involves a PQ_qualifier, so I will just
+       // attach the ambiguity link to it.
+       public PQName *ambiguity = NULL;
+       custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+       // print ambiguities
+       public void printAmbiguities(ostream &os, int indent) const;
+       custom preemptDebugPrint {
+         if (ambiguity) {
+           printAmbiguities(os, indent);
+           return;     // skip the normal, unambiguous-node print code
+         }
+       }
+     }
+
+  // final name, when it's an ordinary identifier
+  // NOTE: 'name' here is *never* NULL--instead, I use NULL
+  // PQName pointers in abstract declarators
+  -> PQ_name(StringRef name);
+
+  // "operator" names; 'o' has the full info, while 'fakeName' is
+  // for getName(), which is sometimes used for string maps
+  -> PQ_operator(OperatorName o, StringRef fakeName);
+
+  // template instances: a template function or class name, plus
+  // some template arguments
+  -> PQ_template(StringRef name, /*fakelist*/TemplateArgument templArgs);
+}
+
+
+// a name of an "atomic" type--one to which type constructors
+// (e.g. '*') can be applied, but which itself is not syntactically
+// built with type constructors (typedef'd types may have been built
+// with type constructors when the name was defined, but a
+// TypeSpecifier refers only to the name)
+class TypeSpecifier(SourceLoc loc) {
+  public(field,xml) CVFlags cv = CV_NONE;
+  custom clone { ret->cv = cv; }
+
+  public void printExtras(ostream &os, int indent) const;
+  custom debugPrint { printExtras(os, indent); }
+
+  public bool canBeTypeParam() const;
+
+  // a typedef'd name (typedef might be implicit, as for classes);
+  // if 'typenamedUsed' is true, then the user said "typename", so
+  // we don't regard an error as disambiguating
+  -> TS_name(PQName name, bool typenameUsed);
+
+  -> TS_simple(SimpleTypeId id);           // int or char or float or ..
+
+  -> TS_elaborated(                        // "class Foo"
+       TypeIntr keyword,
+       PQName name
+     );
+
+  // class/struct/union definition
+  -> TS_classSpec(                         // "class { ... }"
+       TypeIntr keyword,                     // "class", "struct", "union"
+
+       // 'name' is the user-provided name, if any.
+       // Why is this a PQName instead of just a StringRef?
+       //   - it could be a template specialization, and therefore
+       //     has template arguments
+       //   - it could be a definition or specialization of a class
+       //     declared in another namespace
+       // See cppstd 14.5.4 para 6 for an example of both at once.
+       PQName /*nullable*/ name,
+
+       FakeList<BaseClassSpec> *bases,       // base classes
+       MemberList members                    // field and methods of the class
+     );
+
+  -> TS_enumSpec(                          // "enum { ... }"
+       StringRef /*nullable*/ name,          // name of enum, if any
+       FakeList<Enumerator> *elts            // elements of the enumeration
+     );
+}
+
+// base class specification
+class BaseClassSpec (
+  bool isVirtual,                       // true for virtual base classes
+  AccessKeyword access,                 // public/protected/private
+  PQName name                           // name of base class
+) {
+  public BaseClassSpec *next=NULL;     // FakeList link
+}
+
+// a binding of a name to a constant value
+class Enumerator (
+  SourceLoc loc,                        // location
+  StringRef name,                       // name of this constant
+  Expression /*nullable*/ expr          // constant expr, or NULL for "next"
+) {
+  public Enumerator *next=NULL;     // FakeList link
+}
+
+
+// list of class members; this is encapsulated so I can use
+// ASTList without yielding ASTLists in cc.gr
+class MemberList (ASTList<Member> list);
+
+// member of a class
+class Member (SourceLoc loc) {
+  -> MR_decl(Declaration d);            // data members or functions w/o bodies
+  -> MR_func(Function f);               // function with body
+  -> MR_access(AccessKeyword k);        // section header
+  -> MR_usingDecl(ND_usingDecl decl);   // namespace "using" declaration
+  -> MR_template(TemplateDeclaration d);// member template...
+}
+
+
+// Syntactically, a Declarator introduces a name of a declared thing,
+// and also optionally adds type constructors to the base type of the
+// specifier.  It may have an initializing expression, depending on
+// the context.
+class Declarator (
+  IDeclarator decl,                    // syntax of type designation
+  Initializer init                     // (nullable) optional data initializer
+) {
+  // FakeList link; use 'setNext' to set 'next'
+  public Declarator *next = NULL;
+  public void setNext(Declarator *newNext);
+
+  // ambiguity representation
+  public Declarator *ambiguity = NULL;
+  public void addAmbiguity(Declarator *alternative);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  // dig down and find the name being declared; may return NULL
+  public PQName const *getDeclaratorIdC() const;
+  public PQName *getDeclaratorId()
+    { return const_cast<PQName*>(getDeclaratorIdC()); };
+  public void setDeclaratorId(PQName *n);
+
+  public SourceLoc getLoc() const;
+}
+
+
+// inner declarator; things *recursively* buried inside declarators;
+// cannot have initializers; the internal structure can be ignored
+// once typechecking determines what type is denoted
+class IDeclarator(SourceLoc loc) {
+  // dig down and find the name being declared; may return NULL
+  pure_virtual PQName const *getDeclaratorIdC() const;
+  public PQName *getDeclaratorId()
+    { return const_cast<PQName*>(getDeclaratorIdC()); };
+
+  // dig down one IDeclarator level, yielding the 'base' field,
+  // unless this is a leaf (in which case return NULL)
+  pure_virtual IDeclarator const *getBaseC() const;
+  public IDeclarator *getBase()
+    { return const_cast<IDeclarator*>(getBaseC()); };
+
+  // skip any toplevel grouping operators
+  public IDeclarator *skipGroups();
+
+  // true if this declarator is "obviously" declaring a function type,
+  // i.e. the innermost non-D_name, non-D_grouping constructor is
+  // D_func
+  public bool bottomIsDfunc() const;
+
+  // "x" (NULL means abstract declarator or anonymous parameter);
+  // this is used for ctors and dtors as well as ordinary names
+  // (dtor names start with "~"); it's also used for operator names
+  -> D_name(PQName /*nullable*/ name);
+
+  // "*x" (as in "int *x")
+  -> D_pointer(CVFlags cv,  // optional qualifiers applied to ptr type
+               IDeclarator base);
+
+  // "&x"
+  -> D_reference(IDeclarator base);
+
+  // "f(int)"
+  -> D_func(IDeclarator base,                       // D_name of function, typically
+            FakeList<ASTTypeId> *params,            // params with optional default values
+            CVFlags cv,                             // optional "const" for member functions
+            ExceptionSpec /*nullable*/ exnSpec);    // throwable exceptions
+
+  // "a[5]" or "b[]"
+  -> D_array(IDeclarator base, Expression /*nullable*/ size);
+
+  // "c : 2"
+  //
+  // I use a PQName here instead of a StringRef for uniformity
+  // (so every IDeclarator ends with a PQName); there are never
+  // qualifiers on a bitfield name
+  -> D_bitfield(PQName /*nullable*/ name, Expression bits);
+
+  // "X::*p"
+  -> D_ptrToMember(PQName nestedName, CVFlags cv, IDeclarator base);
+
+  // declarator grouping operator: it's semantically irrelevant
+  // (i.e. equivalent to just 'base' alone), but plays a role in
+  // disambiguation
+  -> D_grouping(IDeclarator base);
+}
+
+// specification of what a function can throw; if an ExceptionSpec
+// pointer is NULL, it means there is no specification, i.e. anything
+// can be thrown
+class ExceptionSpec (
+  FakeList<ASTTypeId> *types       // list of allowable types; might be empty (NULL)
+);
+
+// names for operator and conversion functions
+class OperatorName {
+  // render the operator as a string, for use with string-based maps
+  pure_virtual char const *getOperatorName() const;
+
+  // operator new & delete
+  -> ON_newDel(bool isNew, bool isArray);
+
+  // arithmetic-type operator
+  -> ON_operator(OverloadableOp op);
+
+  // conversion operator to convert to 'type'; type will always have an
+  // abstract declarator, with only pointer-type constructors (if any)
+  -> ON_conversion(ASTTypeId type);
+}
+
+
+// ------------------- statements -----------------
+class Statement (SourceLoc loc) {
+  // represent ambiguous statements by forming a linked list of alternatives
+  public Statement * ambiguity = NULL;
+  public void addAmbiguity(Statement *alt);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  public string lineColString() const;      // e.g. "4:5"
+  public string kindLocString() const;      // e.g. "S_if at 4:5"
+
+  -> S_skip();      // no-op; used whenever optional Statement is not present
+  -> S_label(StringRef name, Statement s);
+  -> S_case(Expression expr, Statement s);
+  -> S_default(Statement s);
+  -> S_expr(FullExpression expr);   // expression evaluated for side effect
+  -> S_compound(ASTList<Statement> stmts);        // using ASTList for performance, I never yield it in cc.gr
+  -> S_if(Condition cond, Statement thenBranch, Statement elseBranch);
+  -> S_switch(Condition cond, Statement branches);
+  -> S_while(Condition cond, Statement body);
+  -> S_doWhile(Statement body, FullExpression expr); // note: 'expr' is not a Condition
+  -> S_for(Statement init, Condition cond,
+           FullExpression after, Statement body);
+  -> S_break();
+  -> S_continue();
+  -> S_return(FullExpression /*nullable*/ expr);
+  -> S_goto(StringRef target);
+  -> S_decl(Declaration decl);
+  -> S_try(Statement body, FakeList<Handler> *handlers);
+  -> S_asm(E_stringLit text);
+  -> S_namespaceDecl(NamespaceDecl decl);
+}
+
+// condition expression in a control-flow statement; it's allowed
+// to declare a variable that will hold the condition's value for
+// the duration of the substatement(s)
+class Condition {
+  // ambiguity representation
+  public Condition *ambiguity = NULL;
+  public void addAmbiguity(Condition *alternative);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  -> CN_expr(FullExpression expr);  // simple expression
+  -> CN_decl(ASTTypeId typeId);     // type, name, & initializer (must all be present)
+}
+
+// exception handler
+class Handler (
+  // type of exception objects this handler catches; note that it
+  // might be ST_ELLIPSIS, which corresponds to the "..." syntax
+  ASTTypeId typeId,
+
+  // code to run when handler catches an exception
+  Statement body
+) {
+  public Handler *next = NULL;      // FakeList link
+
+  // test whether this is the "..." handler; in this case, at the
+  // moment, the type checker will make a type with ST_ELLIPSIS in
+  // it, but ideally an analysis should not rely on this, and instead
+  // check and handle 'isEllipsis' directly without looking further
+  // at 'typeId' (because ST_ELLIPSIS is a hack)
+  public bool isEllipsis() const;
+}
+
+
+// ----------------- expressions -----------------
+// C expressions
+class Expression {
+  // NOTE: we never make lists of Expressions, only of ArgExpressions
+
+  // same as we do for statements
+  public Expression *ambiguity = NULL;
+  public void addAmbiguity(Expression *alternative);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+  custom clone {
+    // don't clone something that is still ambiguous (usually means
+    // hasn't been tchecked)
+    xassert(!ambiguity);
+  }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  // true if this expression is an E_binary with the given operator
+  public bool isBinary(BinaryOp op) const;
+
+  // dig down past any E_grouping nodes; this is sometimes necessary
+  // when a node needs to examine the syntax of subexpressions
+  public Expression *skipGroups();
+  public Expression const *skipGroupsC() const;
+
+  -> E_boolLit(bool b);
+
+  // most of the literals are handled by simply storing the textual
+  // representation the user typed in, including delimiters like
+  // quotes; the tcheck pass could interpret those if desired (and
+  // does in some cases); concatenation of string literals is handled
+  // by making a continuation list
+  -> E_intLit(StringRef text);
+  -> E_floatLit(StringRef text);
+  -> E_stringLit(StringRef text, E_stringLit continuation = NULL, StringRef fullTextNQ = NULL);
+  -> E_charLit(StringRef text);
+
+  // reference to 'this', the address of the receiver object
+  -> E_this();
+
+  // variable reference
+  // 5/19/03: 'loc' field removed because 'name' has a location
+  // 1/30/04: split E_this off so now 'name' is never "this"
+  -> E_variable(PQName name);
+
+  -> E_funCall(Expression func, FakeList<ArgExpression> *args);
+
+  // call to constructor as an expression; the expression's overall
+  // type says which type is being constructed
+  -> E_constructor(TypeSpecifier spec, FakeList<ArgExpression> *args);
+
+  // field within an object; as a special case, fieldName might begin
+  // with "~", meaning we're naming the destructor
+  -> E_fieldAcc(Expression obj, PQName fieldName);
+
+  -> E_sizeof(Expression expr);
+
+  -> E_unary(UnaryOp op, Expression expr);
+  -> E_effect(EffectOp op, Expression expr);
+  -> E_binary(Expression e1, BinaryOp op, Expression e2);
+
+  -> E_addrOf(Expression expr);
+  -> E_deref(Expression ptr);
+
+  -> E_cast(ASTTypeId ctype, Expression expr);
+  -> E_cond(Expression cond, Expression th, Expression el);
+  -> E_sizeofType(ASTTypeId atype);
+
+  // this is a simple assignment if op==BIN_ASSIGN, otherwise it's an
+  // incremental assignment, like a += 3 (e.g. for op==BIN_PLUS)
+  -> E_assign(Expression target, BinaryOp op, Expression src);
+
+  -> E_new(bool colonColon,                        // true if "::" preceeds "new"
+           FakeList<ArgExpression> *placementArgs, // arguments to placement-new (empty/NULL if no placement syntax)
+           ASTTypeId atype,                        // type to allocate
+           ArgExpressionListOpt ctorArgs);         // arguments to type's constructor (NULL if no ctor call syntax)
+
+  -> E_delete(bool colonColon,                     // true if "::" preceeds "delete"
+              bool array,                          // true if "[]" follows "delete"
+              Expression expr);                    // address of obj to deallocate
+
+  -> E_throw(Expression /*nullable*/ expr);
+
+  -> E_keywordCast(CastKeyword key,              // dynamic_cast, static_cast, etc.
+                   ASTTypeId ctype,              // type to cast to
+                   Expression expr);             // expression being cast
+
+  -> E_typeidExpr(Expression expr);
+  -> E_typeidType(ASTTypeId ttype);
+
+  // Both of the following exist only between parsing and
+  // type-checking.  The type checker discards them.
+
+  // an E_grouping is a pair of grouping parentheses; it's present in
+  // the AST for syntactic disambiguation of angle brackets, and an
+  // obscure rule about pointer-to-member
+  -> E_grouping(Expression expr);
+
+  // retained explicitly for possible operator overloading
+  -> E_arrow(Expression obj, PQName fieldName);         // e.g. p->f
+}
+
+
+// maximal expressions: the parent is not an expression
+// (cppstd 1.9 para 12)
+class FullExpression (Expression expr) {
+  // We do not make lists of FullExpressions.
+
+  // nothing is needed here beyond the 'expr'; cc_elaborate.cc adds
+  // a FullExpressionAnnot object, however
+}
+
+
+// In the original version of cc.ast, Expressions had both a FakeList
+// link and an ambiguity link.  All expressions in a given ambiguity
+// list were supposed to have the same FakeList link, and this was
+// a bit of a pain.  Then we added ICExpression (implicit conversion
+// expression), which separated the ambiguity representation and the
+// list representation, which simplified things.  Then we removed
+// ICExpression, because we handled implicit conversions differently,
+// re-introducing the ambiguity/FakeList complications.  I'm now
+// going to add that separation layer back in, just for the purpose
+// of separation, to get back the simplicity we had before.
+class ArgExpression(Expression expr) {   // expression in an argument list
+  // FakeList link
+  public ArgExpression *next = NULL;
+  public void setNext(ArgExpression *newNext);
+
+  // argh.. t0182.cc demonstrates I need ambiguity links at this
+  // level too!  but at least these aren't the matrix-style links
+  // I had before; the 'next' links among ambiguous alternatives
+  // are independent
+  public ArgExpression *ambiguity = NULL;
+  public void addAmbiguity(ArgExpression *alternative);
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+}
+
+
+// this is used for cases where there is a difference between a list
+// with no elements, and no list at all (the latter is represented by
+// a NULL pointer to an ArgExpressionListOpt, while the former is a valid
+// ArgExpressionListOpt with a NULL 'list' field)
+class ArgExpressionListOpt (
+  FakeList<ArgExpression> *list
+);
+
+
+// things that appear after declarations to assign initial values
+class Initializer (SourceLoc loc) {
+  public Initializer *next = NULL;       // FakeList link
+
+  // simple initializer, like "int x = 3"
+  -> IN_expr(Expression e);
+
+  // compound initializer, like "int x[4] = { 1,2,3,4 };
+  // using ASTList for performance; some files have initializers
+  // with thousands of elements
+  -> IN_compound(ASTList<Initializer> inits);
+
+  // constructor initializer, like "int x(3);"
+  -> IN_ctor(FakeList<ArgExpression> *args);
+}
+
+
+// ------------------- templates -------------------
+// wrap some template parameters on a declaration or function
+class TemplateDeclaration (/*fakelist*/TemplateParameter params) {
+  // define a template function
+  -> TD_func(Function f);
+
+  // declare a template function prototype, or declare or define a
+  // template class
+  -> TD_decl(Declaration d);
+
+  // wrap another set of parameters around a template decl;
+  // this is for template members of template classes (14.5.2)
+  -> TD_tmember(TemplateDeclaration d);
+}
+
+// one of the parameters to a template declaration
+class TemplateParameter (SourceLoc loc)(TemplateParameter /*nullable*/ next) {
+  // true if this parameter has a default arg
+  pure_virtual bool hasDefaultArg() const;
+
+  // ambiguity link
+  public TemplateParameter *ambiguity = NULL;
+  public void addAmbiguity(TemplateParameter *alternative);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  // type parameter; when present, 'name' is what the template code
+  // will use to refer to the actual argument type; when present,
+  // 'defaultType' provides a default argument
+  //
+  // 'name' can be NULL after parsing, but the type checker sticks
+  // in a synthesized name, so after tchecking it is never NULL
+  -> TP_type(StringRef /*nullable*/ name,
+             ASTTypeId /*nullable*/ defaultType);
+
+  // non-type paramters
+  -> TP_nontype(ASTTypeId param);
+}
+
+verbatim {
+  // true if any of the parameters have default values
+  bool anyHaveDefaultArgs(TemplateParameter const *list);
+}
+
+
+// one of the arguments to a template instantiation
+class TemplateArgument(/*first*/)(/*last*/ TemplateArgument next) {
+  // NOTE: At one point TemplateArguments were connected with a
+  // FakeList, but it turns out that interacts badly with failing
+  // parses (in/t0179.cc), and the fix is to use ASTLists instead.
+  //
+  // 2005-03-13: Trying again with FakeLists... as an experiment, I
+  // will make 'next' a ctor parameter.  Ok, this is working.  I have
+  // made it a 'last' parameter, meaning it is printed and traversed
+  // *after* everything else.
+
+  // ambiguity link
+  public TemplateArgument *ambiguity = NULL;
+  public void addAmbiguity(TemplateArgument *alternative);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  // return a canonical string for this template argument,
+  // such that different arguments get different strings
+  pure_virtual string argString() const;
+
+  // type argument, corresponds to a TP_type parameter
+  -> TA_type(ASTTypeId type);
+
+  // non-type arguments, corresponds to a TP_nontype parameter
+  -> TA_nontype(Expression expr);
+
+  // This is a special element that, when found in the template
+  // argument list of a PQ_qualifier or PQ_template, signals that
+  // those names were prefixed by the "template" keyword (14.2 para
+  // 4).  Doing it this way, instead of adding a boolean to the PQ_*
+  // classes, saves a little space in the common case, and avoids
+  // cluttering creation sites with "false /*templateUsed*/".
+  -> TA_templateUsed();
+}
+
+
+// -------------------- namespace declarations ----------------------
+// since each of these three forms can appear either at toplevel
+// (or in a namespace) or inside a function, I've collected them
+// together; also, ND_usingDecl can appear as a class member
+class NamespaceDecl {
+  // [cppstd 7.3.2] namespace alias definition: defines 'alias'
+  // to refer to the same namespace as 'original'
+  -> ND_alias(StringRef alias, PQName original);
+
+  // [cppstd 7.3.3] using declaration: the given name's unqualified
+  // form is imported into the current scope as an alias for the named
+  // entity; 'name' must be qualified
+  -> ND_usingDecl(PQName name);
+
+  // [cppstd 7.3.4] using directive: names from the given namespace
+  // are accessible in the current scope without qualification, among
+  // other effects (of the three NamespaceDecls, this is the most
+  // complicated)
+  -> ND_usingDir(PQName name);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc.gr
===================================================================
--- vendor/elsa/current/elsa/cc.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2664 @@
+// cc.gr            see license.txt for copyright and terms of use
+// grammar for C++
+
+// A word of warning: there are three sources of names running
+// around here:
+//   (1) the c++ standard's grammar's names
+//   (2) my modified grammar's names
+//   (3) names of AST nodes
+// (1) and (2) correspond everywhere except in places where I want
+// the grammar to do more parsing work than the standard's (mainly
+// for declarators) and where I've chosen to fold in "opt".  The
+// names in (3) are often different because later phases of analysis
+// want to see different conceptual structure.  Anyway, the point is
+// to be aware of which kind of name a given thing is.
+
+
+// Note about destructive actions: because semantic values can be
+// yielded to more than one reduction action (a phenomenon I call
+// "multi-yield"), actions which modify one of their subtree semantic
+// values are dangerous, because you can have actions from one
+// interpretation interfering with actions from another
+// interpretation.
+//
+// Therefore, to the extent reasonable, I avoid destructive actions.
+//
+// However there are a few places where I want destructive actions
+// anyway, and there are two broad strategies employed for managing
+// them:
+//
+//   (1) Disable multi-yield for the modified subtrees.  If an action
+//       modifies subtree nonterminal 'A', then in the definition of
+//       'A' I say "dup(n) { return NULL; }" to ensure that once the
+//       value is yielded once, it can't be yielded again.  Thus, if
+//       in fact it *is* yielded a second time, I'll get a segfault
+//       which will alert me to the design flaw in my rules.
+//       (DeclSpecifier is a good example of this.)
+//
+//   (2) Design the actions to that multiple modifications are
+//       checked for bad interactions.  In this grammar that is what
+//       I do for FakeLists, where I either (a) prevent putting a
+//       node at the head of two lists, or else (b) make sure that
+//       the two lists are in fact the same list both times.  For
+//       potentially-ambiguous nodes with FakeList links (Expression
+//       and Declarator), additional measures are taken to ensure
+//       the consistency of interaction with the ambiguity links.
+//       (See Expression::addAmbiguity and Expression::setNext in
+//       cc_ast_aux.cc.)
+//
+// Every place there's a destructive modification which isn't handled
+// by FakeLists is marked by the phrase 'destructive action'.
+
+
+// this makes it so that, by default, dup() is the identity function,
+// and del() is a no-op
+option useGCDefaults;
+
+// if I don't specify a merge(), and we want to merge(),
+// then abort
+option defaultMergeAborts;
+
+// expected statistics
+option shift_reduce_conflicts 58;
+option reduce_reduce_conflicts 70;
+option unreachable_nonterminals 0;
+option unreachable_terminals 6;
+
+verbatim {
+
+#include "cc_type.h"      // type identifiers like ST_CHAR (r)
+#include "cc_tokens.h"    // lexer's token ids for classify()
+#include "trace.h"        // trace
+#include "cc_ast.h"       // C++ abstract syntax
+#include "cc_lang.h"      // CCLang
+#include "ccparse.h"      // ParseEnv, the parser context class
+
+#define D(msg) \
+  trace("cc") << msg << endl
+
+inline ostream& operator<< (ostream &os, SourceLoc sl)
+  { return os << toString(sl); }
+
+// implemented in implint.cc
+bool filterOutImplIntFirstParam
+  (SourceLoc loc,
+   IDeclarator *base,
+   FakeList<ASTTypeId> *&params);
+
+// implemented at end of file
+bool isGlobalScopeQualified(PQName const *pq);
+bool endsWithIdentifier(TypeSpecifier const *ts);
+bool keepDeclaration(Declaration const *d);
+
+
+// this is the shareable fragment of CCParse, since the new
+// Elkhound behavior prevents extension modules from inheriting
+// directly from CCParse
+class CCParseShareable : public UserActions, public ParseEnv {
+public:
+  CCParseShareable(StringTable &table, CCLang &lang)
+    : ParseEnv(table, lang) {}
+
+  // when this is the last element in a parameter list, the function
+  // is a vararg function
+  ASTTypeId *ellipsisTypeId(SourceLoc loc)
+  {
+    ASTTypeId *tid =
+      new ASTTypeId(new TS_simple(loc, ST_ELLIPSIS),
+                    new Declarator(new D_name(loc, NULL /*name*/),
+                                   NULL /*init*/));
+    return tid;
+  }
+
+  // make a TS_name, and supply CV flags
+  TS_name *new_TS_name(SourceLoc loc, CVFlags cv, PQName *n,
+                       bool typenameUsed)
+  {
+    TS_name *ret = new TS_name(loc, n, typenameUsed);
+    ret->cv = cv;
+    return ret;
+  }
+
+  // make a TS_simple, and supply CV flags
+  TS_simple *new_TS_simple(SourceLoc loc, CVFlags cv, SimpleTypeId id)
+  {
+    TS_simple *ret = new TS_simple(loc, id);
+    ret->cv = cv;
+    return ret;
+  }
+
+  // make a D_func but not if it attempts to be the return value of
+  // another function (this helps resolve an ambiguity in the presence
+  // of implicit int.. is it needed even without implicit int?)
+  D_func *new_D_func
+    (SourceLoc loc,
+     IDeclarator *base,
+     FakeList<ASTTypeId> *params,
+     CVFlags cv,
+     ExceptionSpec /*nullable*/ *exnSpec)
+  {
+    if (base->isD_func()) {
+      TRACE("cancel", loc << ": function returning a function");
+      return NULL;
+    }
+    if (lang.allowImplicitInt
+        && !filterOutImplIntFirstParam(loc, base, params)) {
+      return NULL;
+    }
+    return new D_func(loc, base, params, cv, exnSpec);
+  }
+
+  D_array *new_D_array
+    (SourceLoc loc, IDeclarator *base, Expression * /*nullable*/ size)
+  {
+    if (base->isD_func()) {
+      TRACE("cancel", loc << ": function returning an array");
+      return NULL;
+    }
+    return new D_array(loc, base, size);
+  }
+
+  TemplateArgument *templateUsed(TemplateArgument *list)
+  {
+    return new TA_templateUsed(list);
+  }
+};
+
+} // verbatim
+
+
+context_class CCParse : public CCParseShareable {
+public:
+  CCParse(StringTable &table, CCLang &lang)
+    : CCParseShareable(table, lang) {}
+};
+
+
+terminals {
+  // grab token list
+  include("cc_tokens.ids")
+
+  // all literals are yielded as their syntax strings
+  token(StringRef) TOK_INT_LITERAL ;
+  token(StringRef) TOK_FLOAT_LITERAL ;
+  token(StringRef) TOK_CHAR_LITERAL ;
+  token(StringRef) TOK_STRING_LITERAL ;
+
+  // similar for identifiers
+  token(StringRef) TOK_NAME ;
+  token(StringRef) TOK_TYPE_NAME;
+  token(StringRef) TOK_VARIABLE_NAME;
+
+  precedence {
+    // high precedence
+    prec  200 TOK_PREFER_REDUCE;
+    right 195 "::";           // 2005-08-14: see doc/coloncolon.txt
+    prec  190 "const" "volatile" "else" "[";
+
+    left  120 ".*" "->*";     // 7/07/03: changed from "right".. why was it that way?
+    left  110 "*" "/" "%";
+    left  100 "+" "-";
+    left   90 "<<" ">>";
+
+    // part of the solution to the angle bracket problem requires
+    // dropping these precedence specs and implementing them in the
+    // grammar instead
+    //left   80 "<" ">" "<=" ">=";
+
+    left   70 "==" "!=";
+    left   60 "&";
+    left   50 "^";
+    left   40 "|";
+    left   30 "&&";
+    left   20 "||";
+
+    prec    1 TOK_PREFER_SHIFT;
+    // low precedence
+  }
+}
+
+
+nonterm(TranslationUnit*) File -> t:TranslationUnit
+  { return t; }
+
+
+// 4/20/04: Removed long-since defunct EnterScope and LeaveScope
+
+
+// ------------- identifiers -------------------
+// simple string of characters
+nonterm(StringRef) Identifier {
+  fun dup(n) { return n; }
+  fun del(n) {}
+  -> n:TOK_NAME          { return n; }
+}
+
+// another name that comes up in a few places; it's supposed
+// to refer to a type, but the typechecker will have to enforce
+// that later
+//
+// update: I've substituted it into the grammar elsewhere, since
+// it's just causing s/r conflicts with no gain
+//  nonterm(StringRef) TypeName {
+//    -> id:Identifier      { return id; }
+//  }
+
+
+// ---------------- higher-level syntax -----------------
+// the section labels that follow (like "A.3") are from the
+// C++ standard document
+
+// ------ A.3 Basic Concepts ------
+nonterm(TranslationUnit*) TranslationUnit {
+  fun dup(n) { return NULL; }    // prevent multi-yield
+
+  -> empty                                { return new TranslationUnit(NULL); }
+
+  // destructive action on 't'
+  -> t:TranslationUnit d:Declaration      { t->topForms.append(d); return t; }
+
+  // arg!  Mozilla is littered with toplevel semicolons..
+  -> t:TranslationUnit ";"                { return t; }
+}
+
+// ------ A.4 Expressions ------
+nonterm(Expression*) PrimaryExpression {
+  -> e:Literal
+       { return e; }
+
+  -> "this"
+       { return new E_this; }
+
+  -> "(" e:Expression ")"
+       { return new E_grouping(e); }
+
+  -> e:IdExpression
+       { return new E_variable(e); }
+}
+
+nonterm(Expression*) Literal {
+  -> i:TOK_INT_LITERAL    { return new E_intLit(i); }
+  -> f:TOK_FLOAT_LITERAL  { return new E_floatLit(f); }
+  -> s:StringLiteral      { return s; }
+  -> c:TOK_CHAR_LITERAL   { return new E_charLit(c); }
+  -> TOK_TRUE             { return new E_boolLit(true); }
+  -> TOK_FALSE            { return new E_boolLit(false); }
+}
+
+// a single quoted sequence of characters; this nonterminal exists
+// so that gnu.gr can extend it
+nonterm(StringRef) PreprocString {
+  -> s:TOK_STRING_LITERAL                   { return s; }
+}
+
+// a string literal, with all concatenated parts
+nonterm(E_stringLit*) StringLiteral {
+  -> s:PreprocString                        { return new E_stringLit(s); }
+  -> s:PreprocString cont:StringLiteral     { return new E_stringLit(s, cont); }
+}
+
+
+// possibly-qualified name
+nonterm(PQName*) IdExpression {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> id:PQualifiedId              { return id; }
+
+  // a bare "::" qualifier can only appear at the start of a qualifier
+  // sequence; I'm enforcing it a little bit differently than the std
+  // does
+  -> "::" id:PQualifiedId
+       { return new PQ_qualifier(loc, NULL /*qualifier*/, NULL /*targs*/, id); }
+}
+
+// names that are not qualified
+nonterm(PQName*) UnqualifiedId {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> id:Identifier                { return new PQ_name(loc, id); }
+  -> on:OperatorFunctionId        { return new PQ_operator(loc, on, str(on->getOperatorName())); }
+  -> on:ConversionFunctionId      { return new PQ_operator(loc, on, str(on->getOperatorName())); }
+
+  // std has `"~" ClassName' here, but I've chosen to separate out the
+  // places that a destructor name can occur, since it avoids an
+  // ambiguity with the "~" unary operator
+
+  -> id:TemplateId                { return id; }
+}
+
+// optional qualifier sequence (with no bare "::"), then an
+// UnqualifiedId; there is no option here that uses "~", since that
+// is handled by PQDtorName
+nonterm(PQName*) PQualifiedId {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> id:UnqualifiedId             precedence("::")
+       { return id; }
+
+  -> n:Identifier "::" id:PQualifiedId
+       { return new PQ_qualifier(loc, n, NULL /*targs*/, id); }
+
+  // quarl 2006-06-14
+  //    changed targs:TemplateArgumentList to targs:TemplateArgumentListOpt;
+  //    see in/k0112.cc
+
+  -> n:Identifier "<" targs:TemplateArgumentListOpt ">" "::" id:PQualifiedId
+       { return new PQ_qualifier(loc, n, targs, id); }
+
+  // versions with "template" in front (it's not clear to me that this
+  // is equivalent to the standard grammar.. I'm hacking it for now);
+  // I just ignore the keyword (is that right?)
+  // NOTE: the pattern here is repeated FIVE times!  argh...
+  // marking all as TEMPLATE_QUALIFIER_HACK
+  //
+  // here, as below, I now realize that the first alternative (using
+  // "template" but not supplying template arguments) is illegal
+  //-> "template" n:Identifier "::" id:PQualifiedId
+  //     { return new PQ_qualifier(loc, n, NULL /*targs*/, id); }
+  -> "template" n:Identifier "<" targs:TemplateArgumentListOpt ">" "::" id:PQualifiedId
+       { return new PQ_qualifier(loc, n, templateUsed(targs), id); }
+}
+
+
+// This is a little subtle.  Most of the function calls in a C++
+// source program appear to be ambiguous between E_funCall and
+// E_constructor.  However both of these constructs contain an
+// argument list, and I want the constructed AST nodes to share that
+// list, instead of duplicating it (and only sharing argument
+// subexpressions), for space efficiency reasons.
+//
+// To do that, I insert this nonterminal, which effectively hides the
+// differences in context from the parsing algorithm, so it will be
+// able to share the expression list one level higher than it
+// otherwise would.  (To see the effect, print the node addresses in
+// the resulting ASTs.)
+nonterm(FakeList<ArgExpression>*) ArgumentList {
+  -> "(" e:ExpressionListOpt ")"      { return e; }
+}
+
+
+nonterm(Expression*) PostfixExpression {
+  // ambiguous:
+  //   x(y)
+  // can either be a function call (x is a function)
+  // or a constructor call (x is a type)
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:PrimaryExpression
+       { return e; }
+
+  // array access
+  -> a:PostfixExpression "[" e:Expression "]"
+       { return new E_binary(a, BIN_BRACKETS, e); }
+
+  // fn call
+  -> f:PostfixExpression a:ArgumentList
+       { return new E_funCall(f, a); }
+
+  // cppstd has two things with "typename", but I can't find anyplace
+  // where their semantics are spelled out.. I have some code from
+  // a gcc header which seems to be using them to mean E_constructor,
+  // so I will assume that is the right interpretation
+  //
+  // Note 1: The two "typename" rules are folded into one, with the
+  // variation (planned to be) captured down inside 'IdExpression'.
+  //
+  // Note 2: cppstd uses the grammar to enforce the restriction that
+  // "typename" can only be used with a qualified name, whereas I
+  // enforce that in the type checker (more informative message).
+  -> "typename" t:IdExpression a:ArgumentList
+       { return new E_constructor(new TS_name(loc, t, true /*typenameUsed*/),
+                                  a); }
+
+  // function-style cast, or (equivalently) call to constructor; will
+  // almost always be ambiguous with function call, so the distinction
+  // will have to be delayed until typechecking
+  -> spec:CtorExpressionType a:ArgumentList
+       { return new E_constructor(spec, a); }
+
+  // field access (includes pseudo-destructor)
+  -> p:PostfixExpression "." n:NameAfterDot
+       { return new E_fieldAcc(p, n); }
+
+  // deref + field access
+  -> p:PostfixExpression "->" n:NameAfterDot
+       { return new E_arrow(p, n); }
+
+  -> p:PostfixExpression "++"
+       { return new E_effect(EFF_POSTINC, p); }
+  -> p:PostfixExpression "--"
+       { return new E_effect(EFF_POSTDEC, p); }
+
+  -> k:CastKeyword "<" t:TypeId ">" "(" e:Expression ")"
+       { return new E_keywordCast(k, t, e); }
+
+  -> "typeid" "(" e:Expression ")"
+       { return new E_typeidExpr(e); }
+  -> "typeid" "(" t:TypeId ")"
+       { return new E_typeidType(t); }
+}
+
+// the std calls this SimpleTypeSpecifier, but then also uses that
+// name in some other roles; this is only for the name of a class or
+// type, used as a constructor name
+nonterm(TypeSpecifier*) CtorExpressionType {
+  //-> ColonColonOpt NestedNameSpecifier "template" TemplateId;
+
+  -> n:PQTypeName        { return new TS_name(loc, n, false /*typename*/); }
+  -> "char"              { return new TS_simple(loc, ST_CHAR); }
+  -> "wchar_t"           { return new TS_simple(loc, ST_WCHAR_T); }
+  -> "bool"              { return new TS_simple(loc, ST_BOOL); }
+  -> "short"             { return new TS_simple(loc, ST_SHORT_INT); }
+  -> "int"               { return new TS_simple(loc, ST_INT); }
+  -> "long"              { return new TS_simple(loc, ST_LONG_INT); }
+  -> "signed"            { return new TS_simple(loc, ST_INT); }
+  -> "unsigned"          { return new TS_simple(loc, ST_UNSIGNED_INT); }
+  -> "float"             { return new TS_simple(loc, ST_FLOAT); }
+  -> "double"            { return new TS_simple(loc, ST_DOUBLE); }
+
+  // std has this, but I don't think it makes sense
+  //
+  // 2005-04-16: but it is used in real code, e.g., in/k0043.cc
+  -> "void"              { return new TS_simple(loc, ST_VOID); }
+}
+
+nonterm(CastKeyword) CastKeyword {
+  -> "dynamic_cast"      { return CK_DYNAMIC; }
+  -> "static_cast"       { return CK_STATIC; }
+  -> "reinterpret_cast"  { return CK_REINTERPRET; }
+  -> "const_cast"        { return CK_CONST; }
+}
+
+// here, and everywhere else that FakeList is used, I use right
+// recursion to construct the list; this does mean the stack size
+// is linear in the size of the list, but the benefit of not
+// having to reverse the list or use ASTList (which is difficult
+// to share) is worth it
+nonterm(FakeList<ArgExpression>*) ExpressionList {
+  // ambiguous; see t0182.cc
+  fun merge(L,R) { L->first()->addAmbiguity(R->first()); return L; }
+
+  -> a:AssignmentExpression
+       { return FakeList<ArgExpression>::makeList(new ArgExpression(a)); }
+  -> a:AssignmentExpression "," e:ExpressionList
+       { ArgExpression *aa = new ArgExpression(a);
+         aa->setNext(e->first());
+         return FakeList<ArgExpression>::makeList(aa); }
+}
+
+nonterm(FakeList<ArgExpression>*) ExpressionListOpt {
+  -> empty               { return FakeList<ArgExpression>::emptyList(); }
+  -> e:ExpressionList    { return e; }
+}
+
+// I am pulling these out since PQVarName can be ~class
+//PseudoDestructorName -> "~" ClassName
+//PseudoDestructorName -> Qualifier PseudoDestructorName
+
+nonterm(Expression*) UnaryExpression {
+  // ambiguous:
+  //   sizeof(x)
+  // could either be size of an expression 'x', or
+  // size of a type called 'x'
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:PostfixExpression         { return e; }
+
+  -> "++" e:CastExpression       { return new E_effect(EFF_PREINC, e); }
+  -> "--" e:CastExpression       { return new E_effect(EFF_PREDEC, e); }
+
+  // size of expression
+  -> "sizeof" e:UnaryExpression  { return new E_sizeof(e); }
+
+  -> e:DeleteExpression          { return e; }
+
+  // dereference, addrof
+  -> "*" e:CastExpression        { return new E_deref(e); }
+  -> "&" e:CastExpression        { return new E_addrOf(e); }
+
+  // other unary operators
+  -> "+" e:CastExpression        { return new E_unary(UNY_PLUS, e); }
+  -> "-" e:CastExpression        { return new E_unary(UNY_MINUS, e); }
+  -> "!" e:CastExpression        { return new E_unary(UNY_NOT, e); }
+  -> "~" e:CastExpression        { return new E_unary(UNY_BITNOT, e); }
+
+  // size of type
+  -> "sizeof" "(" t:TypeId ")"   { return new E_sizeofType(t); }
+
+  -> e:NewExpression             { return e; }
+}
+
+
+// ---------------- "new" and "delete" expressions --------------
+nonterm(bool) ColonColonOpt {
+  -> empty     { return false; }
+  -> "::"      { return true; }
+}
+
+nonterm(E_new*) NewExpression {
+  // ambiguous (see in/t0482.cc)
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> c:ColonColonOpt "new" p:NewPlacementOpt t:NewTypeId i:NewInitializerOpt
+       { return new E_new(c, p, t, i); }
+  -> c:ColonColonOpt "new" p:NewPlacementOpt "(" t:TypeId ")" i:NewInitializerOpt
+       { return new E_new(c, p, t, i); }
+}
+
+nonterm(FakeList<ArgExpression>*) NewPlacementOpt {
+  -> empty                          { return FakeList<ArgExpression>::emptyList(); }
+  -> "(" lst:ExpressionList ")"     { return lst; }
+}
+
+nonterm(ASTTypeId*) NewTypeId {
+  -> spec:TypeSpecifier decl:NewDeclaratorOpt
+       { return new ASTTypeId(spec, new Declarator(decl, NULL)); }
+}
+
+// NewDeclaratorOpt is, as a regular expression:
+//   (PtrOperator)*  ("[" Expression "]"  ("[" ConstExpression "]")* )?
+// where PtrOperator is
+//   "*" CVQualifierSeqOpt, or
+//   "&"
+// however, I cannot find any explanation in the spec of whether "&"
+// is in fact allowed (it doesn't make sense to me) so I do not allow
+// it (so I'll see the counterexample syntax if it exists)
+nonterm(IDeclarator*) NewDeclaratorOpt {
+  -> empty
+       { return new D_name(loc, NULL); }
+
+  // pointers
+  -> "*" cv:CVQualifierSeqOpt d:NewDeclaratorOpt
+       { return new D_pointer(loc, cv, d); }
+  -> n:PtrToMemberName "*" cv:CVQualifierSeqOpt d:NewDeclaratorOpt
+       { return new D_ptrToMember(loc, n, cv, d); }
+
+  // commit to at least one "[" ... "]"
+  -> d:DirectNewDeclarator               { return d; }
+}
+nonterm(IDeclarator*) DirectNewDeclarator {
+  fun keep(x) { return x!=NULL; }
+
+  -> /*abstract declarator*/ "[" sz:Expression "]"
+       { return new_D_array(loc, new D_name(loc, NULL), sz); }
+  -> d:DirectNewDeclarator "[" sz:ConstantExpression "]"
+       { return new_D_array(loc, d, sz); }
+}
+
+nonterm(ArgExpressionListOpt*) NewInitializerOpt {
+  -> empty                            { return NULL; }
+  -> "(" lst:ExpressionListOpt ")"    { return new ArgExpressionListOpt(lst); }
+}
+
+nonterm(Expression*) DeleteExpression {
+  -> c:ColonColonOpt "delete" e:CastExpression
+       { return new E_delete(c, false /*array*/, e); }
+  -> c:ColonColonOpt "delete" "[" "]" e:CastExpression
+       { return new E_delete(c, true /*array*/, e); }
+}
+// ------------ end of "new" and "delete" expressions -------------
+
+
+// -------------- BEGIN: syntax after "." or "->" -------------------
+// The standard calls this part
+//
+//   template_opt id-expression
+//
+// but there are some more restrictions I want to add, and I need to
+// build my AST in a certain way (bottom-up), so I redesigned this
+// part of the grammar.
+
+nonterm(PQName*) NameAfterDot {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> n:NAD1
+       { return n; }
+
+  // cannot say ":: ~", nor ":: template"
+  -> "::" n:NAD2
+       { return new PQ_qualifier(loc, NULL /*qualifier*/, NULL /*targs*/, n); }
+}
+
+// can begin with "~" or "template" or Identifier or "operator"
+nonterm(PQName*) NAD1 {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> n:NAD2
+       { return n; }
+
+  // final names
+  -> "template" n:Identifier "<" list:TemplateArgumentListOpt ">"
+       { return new PQ_template(loc, n, templateUsed(list)); }
+  -> "~" n:Identifier
+       { return new PQ_name(loc, str(stringc << "~" << n)); }
+  -> "~" n:Identifier "<" list:TemplateArgumentListOpt ">"
+       { return new PQ_template(loc, str(stringc << "~" << n), list); }
+  -> on:ConversionFunctionId
+       { return new PQ_operator(loc, on, str(on->getOperatorName())); }
+
+  // qualifier name
+  -> "template" n:Identifier "<" list:TemplateArgumentListOpt ">" "::" rest:NAD1
+       { return new PQ_qualifier(loc, n, templateUsed(list), rest); }
+}
+
+// can only begin with Identifier or "operator"; this is essentially
+// what follows "::" in cppstd's qualified-id
+nonterm(PQName*) NAD2 {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  // final names
+  -> n:Identifier "<" list:TemplateArgumentListOpt ">"
+       { return new PQ_template(loc, n, list); }
+  -> n:Identifier
+       { return new PQ_name(loc, n); }
+  -> on:OperatorFunctionId
+       { return new PQ_operator(loc, on, str(on->getOperatorName())); }
+  -> on:OperatorFunctionId "<" list:TemplateArgumentListOpt ">"
+       { xunimp(stringc << loc << " templatized operator (fc042c37-50e2-4596-8460-c095e7ac892b)"); }
+  -> "template" on:OperatorFunctionId "<" list:TemplateArgumentListOpt ">"
+       { xunimp(stringc << loc << " templatized operator (fc042c37-50e2-4596-8460-c095e7ac892b)"); }
+
+  // qualifier names
+  -> n:Identifier "<" list:TemplateArgumentListOpt ">" "::" rest:NAD1
+       { return new PQ_qualifier(loc, n, list, rest); }
+  -> n:Identifier "::" rest:NAD1
+       { return new PQ_qualifier(loc, n, NULL /*targs*/, rest); }
+}
+// -------------- END: syntax after "." or "->" -------------------
+
+
+nonterm(Expression*) CastExpression {
+  // ambiguous:
+  //   (x)(y)
+  // could either be a call to function 'x' with argument 'y', or
+  // it could be a cast to type 'x' of the expression 'y'
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:UnaryExpression
+       { return e; }
+  -> "(" t:TypeId ")" e:CastExpression
+       { return new E_cast(t, e); }
+}
+
+// ---- binary operator expression ----
+// binary exprs with precedence higher than ">"
+nonterm(Expression*) BinExp_high {
+  // ambiguous:
+  //   (x) - (y)
+  // could either be the difference of expressions x and y, or
+  // it could be negation of expression y, cast to type x
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:CastExpression                          { return e; }
+
+  -> left:BinExp_high ".*"  right:BinExp_high  { return new E_binary(left, BIN_DOT_STAR, right); }
+  -> left:BinExp_high "->*" right:BinExp_high  { return new E_binary(left, BIN_ARROW_STAR, right); }
+
+  -> left:BinExp_high "*"  right:BinExp_high   { return new E_binary(left, BIN_MULT, right); }
+  -> left:BinExp_high "/"  right:BinExp_high   { return new E_binary(left, BIN_DIV, right); }
+  -> left:BinExp_high "%"  right:BinExp_high   { return new E_binary(left, BIN_MOD, right); }
+  -> left:BinExp_high "+"  right:BinExp_high   { return new E_binary(left, BIN_PLUS, right); }
+  -> left:BinExp_high "-"  right:BinExp_high   { return new E_binary(left, BIN_MINUS, right); }
+  -> left:BinExp_high "<<" right:BinExp_high   { return new E_binary(left, BIN_LSHIFT, right); }
+  -> left:BinExp_high ">>" right:BinExp_high   { return new E_binary(left, BIN_RSHIFT, right); }
+}
+
+// binary exprs with same precedence as ">"
+//
+// The binary expressions are split like this because I removed the
+// precedence from ">", etc.  But now (8/21/03) I'm not sure *why* I
+// had to remove them; couldn't I have just forced the other rules
+// that mention ">" to have no precedence (perhaps by adding syntax to
+// Elkhound to say that)?  Hmm... oh well.
+nonterm(Expression*) BinExp_mid {
+  // ambiguous:
+  //   x<y>(z)
+  // could either be two relationals (E_binary), with redundant parens
+  // around 'z', or else it could be the construction of a templatized
+  // object (E_constructor), depending on whether 'x' names a type
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:BinExp_high                             { return e; }
+
+  // must express associativity directly; since these are all
+  // left-associative, we require that there not be any reduced
+  // ">" operators in the right context
+  -> left:BinExp_mid "<"  right:BinExp_high    { return new E_binary(left, BIN_LESS, right); }
+  -> left:BinExp_mid ">"  right:BinExp_high    { return new E_binary(left, BIN_GREATER, right); }
+  -> left:BinExp_mid "<=" right:BinExp_high    { return new E_binary(left, BIN_LESSEQ, right); }
+  -> left:BinExp_mid ">=" right:BinExp_high    { return new E_binary(left, BIN_GREATEREQ, right); }
+}
+
+// binary exprs with lower precedence than ">"
+nonterm(Expression*) BinaryExpression {
+  // ambiguous:
+  //   (x) & (y)
+  // could either be the bitwise AND of expressions x and y, or
+  // it could be the address of expression y, cast to type x
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:BinExp_mid                                        { return e; }
+
+  -> left:BinaryExpression "==" right:BinaryExpression   { return new E_binary(left, BIN_EQUAL, right); }
+  -> left:BinaryExpression "!=" right:BinaryExpression   { return new E_binary(left, BIN_NOTEQUAL, right); }
+  -> left:BinaryExpression "&"  right:BinaryExpression   { return new E_binary(left, BIN_BITAND, right); }
+  -> left:BinaryExpression "^"  right:BinaryExpression   { return new E_binary(left, BIN_BITXOR, right); }
+  -> left:BinaryExpression "|"  right:BinaryExpression   { return new E_binary(left, BIN_BITOR, right); }
+
+  -> left:BinaryExpression "&&" right:BinaryExpression   { return new E_binary(left, BIN_AND, right); }
+  -> left:BinaryExpression "||" right:BinaryExpression   { return new E_binary(left, BIN_OR, right); }
+}
+
+
+nonterm(Expression*) ConditionalExpression {
+  // in/k0012.cc
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:BinaryExpression
+       { return e; }
+
+  -> cond:BinaryExpression "?" th:Expression ":" el:AssignmentExpression
+       { return new E_cond(cond, th, el); }
+}
+
+// why is conditional not allowed on left side of = ?  can I confirm
+// that in another language spec?  clearly both alternatives would have
+// to be like-typed lvalues, but...
+nonterm(Expression*) AssignmentExpression {
+  -> e:ConditionalExpression
+       { return e; }
+
+  -> e1:BinaryExpression op:AssignmentOperator e2:AssignmentExpression
+       { return new E_assign(e1, op, e2); }
+
+  -> e:ThrowExpression
+       { return e; }
+}
+
+nonterm(enum BinaryOp) AssignmentOperator {
+  -> "*="  { return BIN_MULT; }
+  -> "/="  { return BIN_DIV; }
+  -> "%="  { return BIN_MOD; }
+  -> "+="  { return BIN_PLUS; }
+  -> "-="  { return BIN_MINUS; }
+  -> ">>=" { return BIN_RSHIFT; }
+  -> "<<=" { return BIN_LSHIFT; }
+  -> "&="  { return BIN_BITAND; }
+  -> "^="  { return BIN_BITXOR; }
+  -> "|="  { return BIN_BITOR; }
+  -> "="   { return BIN_ASSIGN; }
+}
+
+
+// this is the same definition as ExpressionList, and perhaps it
+// makes sense to collapse them?  the meaning of ',' is quite
+// different in the two cases.. does that matter?
+// update: now that I'm doing translation too, the difference
+// in the meanings is great enough that I think they should be
+// separate, as they are
+nonterm(Expression*) Expression {
+  // ambiguous:
+  //   a < b , c > (d)
+  // could either be a comma-exp with two relationals, or
+  // it could be creating an instance of template a with template
+  // arguments b,c and ctor argument d
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> ae:AssignmentExpression
+       { return ae; }
+
+  -> e:Expression "," ae:AssignmentExpression
+       { return new E_binary(e, BIN_COMMA, ae); }
+}
+
+nonterm(Expression*) ExpressionOpt {
+  // empty expression is a true no-op
+  -> empty         { return new E_boolLit(true); }
+  -> e:Expression  { return e; }
+}
+
+// this is an expression with the additional requirement that
+// it be entirely evaluable to an int at compile time
+// (the name exists simply to help document that fact; the grammar
+// cannot enforce it)
+nonterm(Expression*) ConstantExpression {
+  // cppstd says 'ConditionalExpression', but gcc allows assignments
+  // here too, for its dynamically-sized arrays extension; if that
+  // extension is *not* enabled, we will still reject an assignment
+  // expression here, but because it is not const-eval'able, rather
+  // than due to grammar violation (in/k0042.cc)
+  -> e:AssignmentExpression { return e; }
+}
+
+nonterm(Expression*) ConstantExpressionOpt {
+  -> empty                   { return NULL; }
+  -> e:ConstantExpression    { return e; }
+}
+
+
+// sm: At one point we had a FullExpression nonterminal.  I decided to
+// switch to just inserting FullExpressions into the AST at the
+// appropriate points in the action code, since it's no less clear,
+// leads to less lines of grammar code, and will perform slightly
+// better that way.
+//
+// The same could be argued of ConstantExpression, but I do think it's
+// a little clearer to have a nonterminal instead of sprinkled
+// comments, and much less added code than FullExpression was.  It's a
+// matter of taste, I guess.
+
+
+// ------ A.5 Statements ------
+// pull the label and colon out to make things easier in gnu.gr
+nonterm(StringRef) LabelAndColon {
+  // 10/20/04: The precedence specification here fixes in/c/t0018.c by
+  // telling the parser to shift any __attribute__ that follows the ":".
+  -> n:Identifier ":"    precedence(TOK_PREFER_SHIFT)
+       { return n; }
+}
+
+// labeled-statement
+nonterm(Statement*) Statement {
+  // ambiguous:
+  //   x(y);
+  // can either be an Expression statement (constructor call)
+  // or a BlockDeclaration (declare variable y, of type x)
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> n:LabelAndColon s:Statement
+       { return new S_label(loc, n, s); }
+
+  -> "case" e:ConstantExpression ":" s:Statement
+       { return new S_case(loc, e, s); }
+
+  -> "default" ":" s:Statement
+       { return new S_default(loc, s); }
+
+  // expression-statement
+  -> s:ExpressionStatement
+       { return s; }
+
+  // compound-statement
+  -> s:CompoundStatement
+       { return s; }
+
+  // selection-statement
+  // (prefer to shift "else" over reducing by this rule)
+  -> "if" "(" e:Condition ")" s:Statement     precedence(TOK_PREFER_SHIFT)
+       { return new S_if(loc, e, s, new S_skip(loc)); }
+
+  // if-then-else preferred over if-then when ambiguous
+  -> "if" "(" e:Condition ")" s1:Statement "else" s2:Statement
+       { return new S_if(loc, e, s1, s2); }
+
+  -> "switch" "(" e:Condition ")" s:Statement
+       { return new S_switch(loc, e, s); }
+
+  -> "while" "(" e:Condition ")" s:Statement
+       { return new S_while(loc, e, s); }
+
+  -> "do" s:Statement "while" "(" e:Expression ")" ";"
+       { return new S_doWhile(loc, s, new FullExpression(e)); }
+
+  // I might like to rework this so both semicolons appear here instead
+  // of buried in ForInitStatement; it's this way now because that is how
+  // the standard does it.
+  -> "for" "(" s1:ForInitStatement c:ConditionOpt ";" e:ExpressionOpt ")" s2:Statement
+       { return new S_for(loc, s1, c, new FullExpression(e), s2); }
+
+  -> "break" ";"                        { return new S_break(loc); }
+
+  -> "continue" ";"                     { return new S_continue(loc); }
+
+  -> "return" e:Expression ";"          { return new S_return(loc, new FullExpression(e)); }
+
+  -> "return" ";"                       { return new S_return(loc, NULL); }
+
+  -> "goto" n:Identifier ";"            { return new S_goto(loc, n); }
+
+  // declaration-statement
+  -> d:BlockDeclaration                 { return new S_decl(loc, d); }
+
+  // try-block
+  -> s:TryBlock                         { return s; }
+
+  // assembly statement
+  -> a:AsmDefinition                    { return new S_asm(loc, a); }
+
+  // namespace declaration
+  -> n:NamespaceDecl                    { return new S_namespaceDecl(loc, n); }
+}
+
+nonterm(Statement*) ExpressionStatement {
+  -> ";"                  { return new S_skip(loc); }
+  -> e:Expression ";"     { return new S_expr(loc, new FullExpression(e)); }
+}
+
+nonterm(S_compound*) CompoundStatement {
+  -> seq:CompoundStmtHelper "}"
+       { return seq; }
+}
+
+nonterm(S_compound*) CompoundStmtHelper {
+  // I pushed "{" into this nonterminal so the 'loc' would reflect
+  // its location, instead of the location of the first statement inside
+  // (and in fact since 'empty' has no location, I wouldn't even have
+  // been able to get that..)
+  -> "{" empty
+       { return new S_compound(loc, NULL); }
+  -> c:CompoundStmtHelper s:Statement
+       { c->stmts.append(s); return c; }
+}
+
+
+// the guard of e.g. an 'if' statement
+nonterm(Condition*) Condition {
+  // ambiguous:
+  //   if (A * a = 0) { /*...*/ }
+  // could either be a CN_expr (mult+assign) or CN_decl (of variable 'a')
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:Expression
+       { return new CN_expr(new FullExpression(e)); }
+
+  // variable declaration in the condition clause
+  -> spec:TypeSpecifier decl:Declarator "=" e:AssignmentExpression
+       { return new CN_decl(new ASTTypeId(spec,
+                  new Declarator(decl, new IN_expr(loc, e)))); }
+}
+
+nonterm(Condition*) ConditionOpt {
+  // an empty condition (e.g. in a for loop) is interpreted as true
+  -> empty             { return new CN_expr(new FullExpression(new E_boolLit(true))); }
+  -> c:Condition       { return c; }
+}
+
+nonterm(Statement*) ForInitStatement {
+  // ambiguous:
+  //   x * y = z
+  // could be an expression or a declaration
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> s:ExpressionStatement     { return s; }
+  -> s:SimpleDeclaration       { return new S_decl(loc, s); }
+}
+
+
+// ----- A.6 Declarations ------
+//nonterm(ASTList<Declaration>*) DeclarationSeqOpt {
+//  -> empty
+//       { return new ASTList<Declaration>(); }
+//  -> seq:DeclarationSeqOpt d:Declaration
+//       { seq->append(d); return seq; }
+//}
+
+nonterm(TopForm*) Declaration {
+  -> d:BlockDeclaration        { return new TF_decl(loc, d); }
+  -> f:FunctionDefinition      { return new TF_func(loc, f); }
+  -> t:TemplateDeclaration     { return new TF_template(loc, t); }
+  -> d:ExplicitInstantiation   { return d; }
+  //-> ExplicitSpecialization  // folded into TemplateDeclaration
+  -> s:LinkageSpecification    { return s; }
+
+  // substituted from BlockDeclaration
+  -> a:AsmDefinition           { return new TF_asm(loc, a); }
+  -> n:NamespaceDefinition     { return n; }
+  -> n:NamespaceDecl           { return new TF_namespaceDecl(loc, n); }
+}
+
+nonterm(Declaration*) BlockDeclaration {
+  -> d:SimpleDeclaration     { return d; }
+
+  // all of these have been substituted into the places BlockDeclaration occurs
+  // (namely Declaration and Statement)
+  //-> AsmDefinition;
+  //-> NamespaceAliasDefinition;
+  //-> UsingDeclaration;
+  //-> UsingDirective;
+}
+
+// is the DeclSpecifierSeq optional for implicit-int??
+//   no, it's for constructors, destructors, and conversion operators,
+//   all of which are C++ only, so the DeclSpecifierSeq is now mandatory
+//   (I've moved those guys into more specialized contexts)
+// ok, why is the InitDeclaratorList optional?
+//   for declaring classes and enums
+nonterm(Declaration*) SimpleDeclaration {
+  fun keep(d) {
+    return keepDeclaration(d);     // e.g. in/t0057.cc
+  }
+
+  // destructive action on 'spec'
+  //e.g.: int                x                  ;
+  -> spec:DeclSpecifier list:InitDeclaratorList ";"
+       { spec->decllist = list; return spec; }
+
+  // a bare specifier is a type definition or forward declaration
+  -> spec:DeclSpecifier ";"
+       { return spec; }
+
+
+  // this is now redundant because DeclSpecifier allows "typedef"
+  //-> "typedef" spec:DeclSpecifier list:TypedefDeclaratorList ";"
+  //     {
+  //       spec->dflags = (DeclFlags)(spec->dflags | DF_TYPEDEF);
+  //       spec->decllist = list;
+  //       return spec;
+  //     }
+}
+
+
+// type specifier, i.e. the "int" in "int x;"
+//
+// The legal language of type specifiers is much larger than most
+// people's usage of them; for example, "int signed" is legal, as is
+// "const unsigned volatile long static int".  Reading the standard, I
+// drew up a state diagram from which the following grammar was
+// produced, and will at some point scan my drawing.
+//
+// The basic idea is to have a bitmap (UberModifiers) of all the
+// relevant keywords, to allow collecting them in any order.  Then,
+// since a type specifier can only name one type, once I see something
+// which commits the syntax to one particular kind of type specifier
+// (e.g. TS_name, or TS_simple) then I drop down into collecting a
+// possibly different set of keywords.
+//
+// I explicitly substitute UberModifierSeqOpt into the left sides of
+// the productions below as a performance optimization to avoid
+// shift/reduce conflicts.  That is, I write
+//   ->                    PQTypeName UberModifierSeqOpt
+//   -> UberModifierSeq    PQTypeName UberModifierSeqOpt
+// instead of
+//   -> UberModifierSeqOpt PQTypeName UberModifierSeqOpt
+// because the latter would cause shift/reduce conflicts.
+nonterm(Declaration*) DeclSpecifier {
+  fun dup(d) { return NULL; }    // prevent multi-yield
+
+  // TS_name: triggered by PQTypeName
+  -> n:PQTypeName m2:UberModifierSeqOpt
+       { return new Declaration(uberDeclFlags(m2),
+           new_TS_name(loc, uberCVFlags(m2), n, false /*typename*/), NULL); }
+
+  -> m1:UberModifierSeq n:PQTypeName m2:UberModifierSeqOpt
+       { UberModifiers m = uberCombine(loc, m1, m2);
+         return new Declaration(uberDeclFlags(m),
+           new_TS_name(loc, uberCVFlags(m), n, false /*typename*/), NULL); }
+
+  // TS_simple: triggered by UberTypeKeyword
+  -> k1:UberTypeKeyword m2:UberTypeAndModifierSeqOpt
+       { UberModifiers k = uberCombine(loc, k1, m2);
+         return new Declaration(uberDeclFlags(m2),
+           new_TS_simple(loc, uberCVFlags(m2), uberSimpleType(loc, k)), NULL); }
+
+  -> m1:UberModifierSeq k1:UberTypeKeyword m2:UberTypeAndModifierSeqOpt
+       { UberModifiers m = uberCombine(loc, m1, m2);
+         UberModifiers k = uberCombine(loc, k1, m2);
+         return new Declaration(uberDeclFlags(m),
+           new_TS_simple(loc, uberCVFlags(m), uberSimpleType(loc, k)), NULL); }
+
+  // TS_elaborated, TS_classSpec, TS_enumSpec:
+  // triggered by one of "class", "struct", "union", "enum", "typename",
+  // with the particular instance sorted out by ElaboratedOrSpecifier
+  -> e:ElaboratedOrSpecifier m2:UberModifierSeqOpt
+       { e->cv |= uberCVFlags(m2);     // destructive action
+         return new Declaration(uberDeclFlags(m2), e, NULL); }
+
+  -> m1:UberModifierSeq e:ElaboratedOrSpecifier m2:UberModifierSeqOpt
+       { UberModifiers m = uberCombine(loc, m1, m2);
+         e->cv |= uberCVFlags(m);      // destructive action
+         return new Declaration(uberDeclFlags(m), e, NULL); }
+}
+
+// choose among TS_elaborated, TS_classSpec and TS_enumSpec
+nonterm(TypeSpecifier*) ElaboratedOrSpecifier {
+  fun dup(n) { return NULL; }              // prevent multi-yield
+
+  -> s:ElaboratedTypeSpecifier { return s; }
+  -> s:ClassSpecifier          { return s; }
+  -> s:EnumSpecifier           { return s; }
+}
+
+
+// nonempty sequence of UberModifiers; note that the act of combining
+// UberModifiers sets checks for and complains about duplication
+nonterm(UberModifiers) UberModifierSeq {
+  -> u:UberModifier                    { return u; }
+  -> s:UberModifierSeq u:UberModifier  { return uberCombine(loc, s,u); }
+}
+
+nonterm(UberModifiers) UberModifierSeqOpt {
+  -> empty                    { return UM_NONE; }
+  -> s:UberModifierSeq        { return s; }
+}
+
+
+// possibly empty sequence of modifiers (e.g. "static") or type
+// keywords (e.g. "int")
+nonterm(UberModifiers) UberTypeAndModifierSeqOpt {
+  -> empty                                          { return UM_NONE; }
+  -> s:UberTypeAndModifierSeqOpt u:UberModifier     { return uberCombine(loc, s,u); }
+  -> s:UberTypeAndModifierSeqOpt u:UberTypeKeyword  { return uberCombine(loc, s,u); }
+}
+
+
+// repetition of above rules when the only modifiers allowed
+// are "const" and "volatile"; this is for TypeSpecifier
+nonterm(UberModifiers) UberCVQualifierSeq {
+  -> u:UberCVQualifier                       { return u; }
+  -> s:UberCVQualifierSeq u:UberCVQualifier  { return uberCombine(loc, s,u); }
+}
+
+nonterm(UberModifiers) UberCVQualifierSeqOpt {
+  -> empty                       { return UM_NONE; }
+  -> s:UberCVQualifierSeq        { return s; }
+}
+
+nonterm(UberModifiers) UberTypeAndCVQualifierSeqOpt {
+  -> empty                                             { return UM_NONE; }
+  -> s:UberTypeAndCVQualifierSeqOpt u:UberCVQualifier  { return uberCombine(loc, s,u); }
+  -> s:UberTypeAndCVQualifierSeqOpt u:UberTypeKeyword  { return uberCombine(loc, s,u); }
+}
+
+
+// modifiers
+nonterm(UberModifiers) UberModifier {
+  // storage-class-specifier
+  -> "auto"      { return UM_AUTO; }
+  -> "register"  { return UM_REGISTER; }
+  -> "static"    { return UM_STATIC; }
+  -> "extern"    { return UM_EXTERN; }
+  -> "mutable"   { return UM_MUTABLE; }
+
+  // function-specifier
+  -> "inline"    { return UM_INLINE; }
+  -> "virtual"   { return UM_VIRTUAL; }
+  //-> "explicit"  { return UM_EXPLICIT; }    // can only appear in CDtorModifier
+
+  // decl-specifier terminals
+  -> "friend"    { return UM_FRIEND; }
+  -> "typedef"   { return UM_TYPEDEF; }
+
+  // cv-qualifier
+  -> "const"     { return UM_CONST; }
+  -> "volatile"  { return UM_VOLATILE; }
+}
+
+// just the cv-qualifiers
+nonterm(UberModifiers) UberCVQualifier {
+  -> "const"     { return UM_CONST; }
+  -> "volatile"  { return UM_VOLATILE; }
+}
+
+// keywords that name a type, or part of one
+nonterm(UberModifiers) UberTypeKeyword {
+  -> "char"      { return UM_CHAR; }
+  -> "wchar_t"   { return UM_WCHAR_T; }
+  -> "bool"      { return UM_BOOL; }
+  -> "short"     { return UM_SHORT; }
+  -> "int"       { return UM_INT; }
+  -> "long"      { return UM_LONG; }
+  -> "signed"    { return UM_SIGNED; }
+  -> "unsigned"  { return UM_UNSIGNED; }
+  -> "float"     { return UM_FLOAT; }
+  -> "double"    { return UM_DOUBLE; }
+  -> "void"      { return UM_VOID; }
+}
+
+
+nonterm(TypeSpecifier*) ElaboratedTypeSpecifier {
+  -> k:ClassKey n:PQTypeName    { return new TS_elaborated(loc, k, n); }
+  -> "enum" n:PQTypeName        { return new TS_elaborated(loc, TI_ENUM, n); }
+
+  // cppstd grammar ensures "typename" is only applied to qualified
+  // names, but I find that more natural to enforce during typechecking
+  -> "typename" n:PQTypeName    { return new TS_name(loc, n, true /*typename*/); }
+}
+
+
+// plays role of "TypeSpecifierSeq" in cppstd; this is a
+// version of DeclSpecifier restricted to only allow "const" and
+// "volatile" UberModifiers
+nonterm(TypeSpecifier*) TypeSpecifier {
+  // TS_name
+  -> n:PQTypeName cv2:UberCVQualifierSeqOpt
+       { return new_TS_name(loc, uberCVFlags(cv2), n, false /*typename*/); }
+
+  -> cv1:UberCVQualifierSeq n:PQTypeName cv2:UberCVQualifierSeqOpt
+       { UberModifiers cv = uberCombine(loc, cv1, cv2);
+         return new_TS_name(loc, uberCVFlags(cv), n, false /*typename*/); }
+
+  // TS_simple
+  -> k1:UberTypeKeyword m2:UberTypeAndCVQualifierSeqOpt
+       { UberModifiers k = uberCombine(loc, k1, m2);
+         return new_TS_simple(loc, uberCVFlags(m2), uberSimpleType(loc, k)); }
+
+  -> m1:UberCVQualifierSeq k1:UberTypeKeyword m2:UberTypeAndCVQualifierSeqOpt
+       { UberModifiers m = uberCombine(loc, m1, m2);
+         UberModifiers k = uberCombine(loc, k1, m2);
+         return new_TS_simple(loc, uberCVFlags(m), uberSimpleType(loc, k)); }
+
+  // TS_elaborated, TS_classSpec, TS_enumSpec
+  -> e:ElaboratedOrSpecifier m2:UberCVQualifierSeqOpt
+       { xassert(e != NULL && "388cba6d-895c-4acb-ac25-c28fc1c4c2cb");
+         e->cv |= uberCVFlags(m2);     // destructive action
+         return e; }
+
+  -> m1:UberCVQualifierSeq e:ElaboratedOrSpecifier m2:UberCVQualifierSeqOpt
+       { UberModifiers m = uberCombine(loc, m1, m2);
+         xassert(e != NULL && "ceae1527-94a7-480d-9134-5dbd8cbfb2aa");
+         e->cv |= uberCVFlags(m);      // destructive action
+         return e; }
+}
+
+
+// I had been separating these into typedef/enum/class names, but
+// the parser can never distinguish, so the grammar shouldn't suggest
+// that it can
+nonterm(PQName*) PQTypeName {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> n:PQTypeName_ncc
+       { return n; }
+  -> "::" n:PQTypeName_ncc
+       { return new PQ_qualifier(loc, NULL /*qualifier*/, NULL /*targs*/, n); }
+}
+
+// no-colon-colon
+nonterm(PQName*) PQTypeName_ncc {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> n:Identifier                  precedence("::")
+       { return new PQ_name(loc, n); }
+  -> id:TemplateId                 precedence("::")
+       { return id; }
+
+  -> q:Identifier "::" n:PQTypeName_notfirst
+       { return new PQ_qualifier(loc, q, NULL /*targs*/, n); }
+  -> q:Identifier "<" targs:TemplateArgumentListOpt ">" "::" n:PQTypeName_notfirst
+       { return new PQ_qualifier(loc, q, targs, n); }
+}
+
+// after at least one qualifier other than "::"; 'template' has to be
+// squirreled away down here because otherwise it becomes ambiguous
+// with the 'template' at the start of an ElaboratedTypeSpecifier
+nonterm(PQName*) PQTypeName_notfirst {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> id:PQTypeName_ncc             precedence("::")
+       { return id; }
+
+  // template declaration (in/t0254.cc)
+  -> "template" id:TemplateId      precedence("::")
+       { id->templArgs = templateUsed(id->templArgs);    // destructive action
+         return id; }
+
+  // TEMPLATE_QUALIFIER_HACK
+  //-> "template" q:Identifier "::" n:PQTypeName_notfirst
+  //     { return new PQ_qualifier(loc, q, NULL /*targs*/, n); }
+  -> "template" q:Identifier "<" targs:TemplateArgumentListOpt ">" "::" n:PQTypeName_notfirst
+       { return new PQ_qualifier(loc, q, templateUsed(targs), n); }
+}
+
+
+nonterm(TS_enumSpec*) EnumSpecifier {
+  -> "enum" "{" list:EnumeratorListOpt "}"
+       { return new TS_enumSpec(loc, NULL /*name*/, list); }
+  -> "enum" n:Identifier "{" list:EnumeratorListOpt "}"
+       { return new TS_enumSpec(loc, n, list); }
+}
+
+
+// rewrote this definition so I can always tell with one token of
+// lookahead whether this is the last enumerator definition; this
+// allows an optional comma at the end, on purpose
+nonterm(FakeList<Enumerator>*) EnumeratorListOpt {
+  -> empty
+       { return FakeList<Enumerator>::emptyList(); }
+  -> def:EnumeratorDefinition
+       { return FakeList<Enumerator>::makeList(def); }
+  -> def:EnumeratorDefinition "," list:EnumeratorListOpt
+       { return list->prepend(def); }
+}
+
+
+nonterm(Enumerator*) EnumeratorDefinition {
+  -> name:Identifier
+       { return new Enumerator(loc, name, NULL /*expr*/); }
+  -> name:Identifier "=" expr:ConstantExpression
+       { return new Enumerator(loc, name, expr); }
+}
+
+
+// dsw: this is ambiguous and redundant with a similar thing in
+// gnu.gr; should it be here at all?
+//
+// sm: Yes it should be here.  First, we don't always use the gnu.gr
+// extension module.  Second, gnu.gr's AsmDefinition *extends* this
+// one, which is how it should be.  This is the AsmDefinition for
+// C++.
+nonterm(E_stringLit*) AsmDefinition {
+  -> "asm" "(" s:StringLiteral ")" ";"    { return s; }
+}
+
+
+nonterm(TopForm*) LinkageSpecification {
+  -> "extern" n:TOK_STRING_LITERAL "{" tu:TranslationUnit "}"
+       { return new TF_linkage(loc, n, tu); }
+
+  -> "extern" n:TOK_STRING_LITERAL tf:Declaration
+       { return new TF_one_linkage(loc, n, tf); }
+}
+
+
+// ------ A.7 Declarators ------
+// -- declarator --
+// a declarator is the "x" in a declaration like "int x"
+
+nonterm(FakeList<Declarator>*) InitDeclaratorList {
+  -> d:InitDeclarator
+       { return FakeList<Declarator>::makeList(d); }
+  -> d:InitDeclarator "," list:InitDeclaratorList
+       { d->setNext(list->first());
+         return FakeList<Declarator>::makeList(d); }
+}
+
+// obsolete now that I've substituted it into SimpleDeclaration
+//  nonterm(FakeList<Declarator>*) InitDeclaratorListOpt {
+//    -> empty
+//         { return FakeList<Declarator>::emptyList(); }
+//    -> list:InitDeclaratorList
+//         { return list; }
+//  }
+
+
+nonterm(Declarator*) InitDeclarator {
+  // ambiguous:
+  //   int f(x *y);
+  // could be declaring a variable called "f" with ctor-initializer "(x*y)",
+  // or it could be declaring a function called "f" which accepts a pointer
+  // to an 'x' as a parameter
+  //
+  // another example:
+  //   int m(int (n));
+  // could be declaring a variable called "m" with ctor-initializer "int (n)"
+  // which itself is a call to the constructor for "int", or it could be
+  // declaring a function called "m" with an integer parameter called "n",
+  // the latter surrounded by a redundant set of parens
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> d:Declarator                       // (int)  x
+       { return new Declarator(d, NULL); }
+
+  -> d:Declarator i:Initializer         // (int)  x = 5
+       { return new Declarator(d, i); }
+}
+
+nonterm(Initializer*) Initializer {
+  -> "=" i:SimpleInitializerClause
+       { return i; }
+
+  -> "(" args:ExpressionList ")"
+       { return new IN_ctor(loc, args); }
+
+  // NOTE: there is no alternative for "(" ")"!
+  // see [cppstd. sec. 8.5 para 8]
+}
+
+nonterm(Initializer*) SimpleInitializerClause {
+  -> e:AssignmentExpression              // scalar
+       { return new IN_expr(loc, e); }
+  -> c:CompoundInitializer               // array/structure initializer
+       { return c; }
+}
+
+// this nonterminal exists so that extensions can augment it with
+// possibilities for designated initializers
+nonterm(Initializer*) InitializerClause {
+  -> init:SimpleInitializerClause
+    { return init; }
+}
+
+nonterm(IN_compound*) CompoundInitializer {
+  // array/structure initializer
+  -> "{" list:InitializerList CommaOpt "}"  { return list; }
+
+  // zero whatever it is
+  -> "{" "}"  { return new IN_compound(loc, NULL); }
+}
+
+// useful syntactic quirk
+nonterm CommaOpt {
+  -> empty ;
+  -> "," ;
+}
+
+nonterm(IN_compound*) InitializerList {
+  fun dup(i) { return NULL; }     // prevent multi-yield
+
+  -> init:InitializerClause
+       { IN_compound *list = new IN_compound(loc, NULL);
+         list->inits.append(init);
+         return list; }
+
+  // destructive action on 'list'
+  -> list:InitializerList "," init:InitializerClause
+       { xassert(list != NULL && "8706f04b-0a31-407e-b31b-40607d31edf9");
+         list->inits.append(init); return list; }
+}
+
+
+// perhaps confusing name correspondence:
+//   The AST name "Declarator" corresponds to the grammar name
+//   "InitDeclarator"; the AST name "IDeclarator" (inner declarator)
+//   corresponds to the grammar name "Declarator"
+// this name shift simply reflects the different interests of the
+// parser vs. subsequent phases of analysis
+//
+// regex for this nonterm: (PtrOperator)* DirectDeclarator
+nonterm(IDeclarator*) Declarator {
+  -> "*" cv:CVQualifierSeqOpt d:Declarator
+       { return new D_pointer(loc, cv, d); }
+  // dsw: I could have just allowed 'restrict' here instead of
+  // allowing any CVQualifierSeqOpt after a "&" but it would mean
+  // duplicating the parsing rule three times (there are three
+  // occurances of "&" with this meaning in the grammar) and moving it
+  // to gnu.gr; perhaps Scott will prefer that more specific solution.
+  -> "&" cv:CVQualifierSeqOpt /*dsw: discarded; can be 'restrict' */ d:Declarator
+       { return new D_reference(loc, d); }
+  -> n:PtrToMemberName "*" cv:CVQualifierSeqOpt d:Declarator
+       { return new D_ptrToMember(loc, n, cv, d); }
+  -> d:DirectDeclarator
+       { return d; }
+}
+
+nonterm(IDeclarator*) DirectDeclarator {
+  fun keep(x) { return x!=NULL; }
+
+  // it doesn't matter how this was classified before, because a
+  // declarator binds a new name, so it shadows any prior definitions;
+  // note: this rule handles constructor names!
+  // note: this also handles operator names!
+  -> n:IdExpression//_no_colon_colon
+       { return new D_name(loc, n); }
+
+  // dtor
+  -> n:PQDtorName
+       { return new D_name(loc, n); }
+
+  // function declarator; the return type comes from the type
+  // specifier that precedes this
+  -> d:DirectDeclarator                        // name of function
+     "(" params:ParameterDeclarationClause ")" // parameters
+     cv:CVQualifierSeqOpt                      // optional "const"
+     e:ExceptionSpecificationOpt               // optional "throw" clause
+       { return new_D_func(loc, d, params, cv, e); }
+
+  // array with optional size
+  -> d:DirectDeclarator "[" sz:ConstantExpressionOpt "]"
+       { return new_D_array(loc, d, sz); }
+
+  // precedence grouping; must be recorded in the AST for disambiguation
+  -> "(" d:Declarator ")"
+       { return new D_grouping(loc, d); }
+}
+
+// I choose to encode ctor and dtor names as ordinary PQNames, because
+// the parser can't tell them apart from other PQNames; but the dtor
+// must be handled specially because if I just allowed "~" before any
+// name, then I couldn't tell if the expression "~a" is unary "~" or
+// the name of a destructor.  Destructor names are encoded by prepending
+// a "~" to them, so later phases of analysis will have to look for that.
+// (I notice the standard calls this PseudoDestructorName; I'll stick with
+// my terminology.)
+nonterm(PQName*) PQDtorName {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> "~" n:Identifier
+       { return new PQ_name(loc, str(stringc << "~" << n)); }
+  -> "~" n:Identifier "<" list:TemplateArgumentListOpt ">"
+       { return new PQ_template(loc, str(stringc << "~" << n), list); }
+
+  // as above for PQName_no_colon_colon, I'm temporarily removing an
+  // ambiguity that relates to namespaces (e.g. "::F::~F()")
+  //-> q:Qualifier rhs:PQDtorName  { return new PQ_qualifier(q, rhs); }
+  -> q:Identifier "::" rhs:PQDtorName
+       { return new PQ_qualifier(loc, q, NULL /*targs*/, rhs); }
+
+  -> q:Identifier "<" targs:TemplateArgumentListOpt ">" "::" rhs:PQDtorName
+       { return new PQ_qualifier(loc, q, targs, rhs); }
+
+  // TEMPLATE_QUALIFIER_HACK
+  //-> "template" q:Identifier "::" rhs:PQDtorName
+  //     { return new PQ_qualifier(loc, q, NULL /*targs*/, rhs); }
+  -> "template" q:Identifier "<" targs:TemplateArgumentListOpt ">" "::" rhs:PQDtorName
+       { return new PQ_qualifier(loc, q, templateUsed(targs), rhs); }
+
+  // this rule from cppstd is partially subsumed by the "template" hack
+  //-> ColonColonOpt NestedNameSpecifier "template" TemplateId "::" "~" TypeName;
+}
+
+
+// syntax that precedes "*" in the pointer-to-member declarator syntax
+nonterm(PQName*) PtrToMemberName {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> n:IdExpression "::"    { return n; }
+}
+
+
+// I'll leave this here because it's harmless and the cppstd has it;
+// also, it reminds me that every place I've substituted PtrOperator
+// into the syntaxes elsewhere has an implicit TODO for the
+// pointer-to-member syntax
+//  nonterm PtrOperator {
+//    -> "*" q:CVQualifierSeqOpt ;
+//    -> "&"                     ;
+
+//    // TODO: pointer to member
+//    //-> ColonColonOpt NestedNameSpecifier "*" CvQualifierSeqOpt;
+//  }
+
+
+nonterm(enum CVFlags) CVQualifierSeqOpt {
+  -> empty                       { return CV_NONE; }
+  -> s:CVQualifierSeq            { return s; }
+}
+
+nonterm(enum CVFlags) CVQualifierSeq {
+  -> q:CVQualifier                       { return q; }
+  -> q:CVQualifier s:CVQualifierSeq      { return (CVFlags)(q | s); }
+}
+
+nonterm(enum CVFlags) CVQualifier {
+  -> "const"                 { return CV_CONST; }
+  -> "volatile"              { return CV_VOLATILE; }
+}
+
+
+// -- type-id --
+// a type-id is like a declaration of one thing, but without the variable name;
+// it is, for example, what appears inside the parens of a typecast
+nonterm(ASTTypeId*) TypeId {
+  -> spec:TypeSpecifier decl:AbstractDeclaratorOpt
+       { return new ASTTypeId(spec, new Declarator(decl, NULL)); }
+}
+
+nonterm(IDeclarator*) AbstractDeclaratorOpt {
+  -> empty                 { return new D_name(loc, NULL); }
+  -> d:AbstractDeclarator  { return d; }
+}
+
+// an abstract declarator (not opt) must have *some* ground syntax in it
+nonterm(IDeclarator*) AbstractDeclarator {
+  -> "*" cv:CVQualifierSeqOpt d:AbstractDeclaratorOpt
+       { return new D_pointer(loc, cv, d); }
+  -> "&" cv:CVQualifierSeqOpt /*dsw: discarded; can be 'restrict' */ d:AbstractDeclaratorOpt
+       { return new D_reference(loc, d); }
+  -> n:PtrToMemberName "*" cv:CVQualifierSeqOpt d:AbstractDeclaratorOpt
+       { return new D_ptrToMember(loc, n, cv, d); }
+  -> d:DirectAbstractDeclarator
+       { return d; }
+}
+
+nonterm(IDeclarator*) DirectAbstractDeclaratorOpt {
+  -> empty                       { return new D_name(loc, NULL /*name*/); }
+  -> d:DirectAbstractDeclarator  { return d; }
+}
+
+// this also must have some ground syntax
+nonterm(IDeclarator*) DirectAbstractDeclarator {
+  fun keep(x) { return x!=NULL; }
+
+  // note: the "opt" in the DirectAbstractDeclarator part of the
+  // function type constructor creates an ambiguity:
+  //   typedef int x;
+  //   int foo(int (x));
+  // Is the parameter an int, or a function accepting an 'x'?
+  //
+  // This is addressed by cppstd 8.2 para 7; see D_name_tcheck.
+  //
+  // This ambiguity doesn't show up until ParameterDeclaration, below.
+
+  // function
+  -> d:DirectAbstractDeclaratorOpt
+     "(" args:ParameterDeclarationClause ")"
+     cv:CVQualifierSeqOpt
+     e:ExceptionSpecificationOpt
+       { return new_D_func(loc, d, args, cv, e); }
+
+  // array with optional size
+  -> d:DirectAbstractDeclaratorOpt "[" sz:ConstantExpressionOpt "]"
+       { return new_D_array(loc, d, sz); }
+
+  // precedence grouping; shouldn't need to record this in AST, but
+  // I will for consistency with Declarator
+  -> "(" d:AbstractDeclarator ")"
+       { return new D_grouping(loc, d); }
+}
+
+
+nonterm(FakeList<ASTTypeId>*) ParameterDeclarationClause {
+  -> p:ParameterDeclarationList              // some args
+       { return p; }
+  -> empty                                   // no args
+       { return FakeList<ASTTypeId>::emptyList(); }
+}
+
+// little bending over backwards here to accomodate FakeList
+nonterm(FakeList<ASTTypeId>*) ParameterDeclarationList {
+  // last (and perhaps only) arg is "..."
+  -> "..."
+       { return FakeList<ASTTypeId>::makeList(ellipsisTypeId(loc)); }
+
+  // last arg is "...", and 2nd-to-last is not separated by
+  // a comma from the "..."
+  -> d:ParameterDeclaration "..."
+       { FakeList<ASTTypeId> *list =
+           FakeList<ASTTypeId>::makeList(ellipsisTypeId(loc));
+         d->setNext(list->first());
+         return FakeList<ASTTypeId>::makeList(d); }
+
+  // last arg is not "..."
+  -> d:ParameterDeclaration
+       { return FakeList<ASTTypeId>::makeList(d); }
+
+  // argument then "," then arg or "..." or list
+  -> d:ParameterDeclaration "," list:ParameterDeclarationList
+       { d->setNext(list->first());
+         return FakeList<ASTTypeId>::makeList(d); }
+}
+
+nonterm(ASTTypeId*) ParameterDeclaration {
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  // NOTE: The 'register' keyword is simply ignored.
+
+  -> s:TypeSpecifier pd:ParameterDeclarator
+       { return new ASTTypeId(s, pd); }
+  -> "register" s:TypeSpecifier pd:ParameterDeclarator
+       { return new ASTTypeId(s, pd); }
+  -> s:TypeSpecifier "register" pd:ParameterDeclarator
+       { return new ASTTypeId(s, pd); }
+}
+
+nonterm(Declarator*) ParameterDeclarator {
+  // ambiguity:
+  //   int (x)
+  // is either type "int" with Declarator "(x)", or
+  // it could be type "int f(x q)" such that "(x)" is an
+  // AbstractDeclarator
+  //
+  // see D_name_tcheck in tcheck.cc for resolution
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> d:UnqualifiedDeclarator
+       { return new Declarator(d, NULL /*init*/); }
+  -> d:UnqualifiedDeclarator "=" e:AssignmentExpression
+       { return new Declarator(d, new IN_expr(loc, e)); }
+
+  -> d:AbstractDeclaratorOpt
+       { return new Declarator(d, NULL /*init*/); }
+  -> d:AbstractDeclaratorOpt "=" e:AssignmentExpression
+       { return new Declarator(d, new IN_expr(loc, e)); }
+}
+
+
+// -- function definition --
+nonterm(Function*) FunctionDefinition {
+  // whereas the std merges c/dtors and ordinary functions by making
+  // the DeclSpecifier optional, I split cases; this way in the common
+  // case where I can clearly see a return type, ctor is ruled out;
+  // in fact I wonder if there will ever be an ambiguity, since ordinary
+  // functions always have at least two words before "(" while ctors
+  // always have just one..
+
+  // ambiguous:
+  //   F::G() {}
+  // can either be a definition of F's constructor (then G equals F), or
+  // it can be a definition of a function G in the global scope, with
+  // return type F
+  //
+  // cppstd isn't clear about this, but both gcc and icc eagerly consume
+  // "::" after an identifier, so I cancel a function definition if the
+  // retspec is a typedef and the name begins with "::"
+
+  // in/c/t0015.c contains some code that is not legal C++, though it
+  // is legal K&R C, but which nonetheless triggers a FunctionDefinition
+  // merge in C++ mode:
+  //   x(y) {}
+  // could either have 'x' as return type and 'y' as "function" name,
+  // but missing the D_func, or 'x' as constructor name and 'y' as a
+  // parameter type.  So I will cancel any FunctionDefinition whose
+  // declarator doesn't have a D_func at the bottom.
+  fun keep(f)
+  {
+    if (!f->nameAndParams->decl->bottomIsDfunc()) {
+      xfailure("should not happen anymore due to use of FDDeclarator");
+      TRACE("cancel", "rejecting FunctionDefinition w/o D_func at bottom");
+      return false;
+    }
+    else if (endsWithIdentifier(f->retspec) &&
+             isGlobalScopeQualified(f->nameAndParams->decl->getDeclaratorIdC())) {
+      TRACE("cancel", "rejecting TYPENAME ::NAME");     // e.g. in/t0015.cc
+      return false;
+    }
+    else {
+      return true;
+    }
+  }
+
+  // destructive action on 'r'
+
+  // ordinary function:
+  // return type      name/params   body
+  -> r:DeclSpecifier  d:FDDeclarator  b:FunctionBody
+       {
+         Function *ret = new Function(
+           r->dflags,                // decl flags (static, extern, etc.)
+           r->spec,                  // type specifier for return value
+           new Declarator(d, NULL),  // declarator with fn name, params
+           NULL,                     // ctor member inits
+           b,                        // function body statement
+           NULL                      // exception handlers
+         );
+         r->spec = NULL;    // stole it above (ownership transfer)
+         delete r;          // was just a carrier of dflags/spec
+         return ret;
+       }
+
+  // 2005-03-09: I didn't even realize this was possible for non-ctors
+  // return type      name/params            body            handlers
+  -> r:DeclSpecifier  d:FDDeclarator  "try"  b:FunctionBody  h:HandlerSeq
+       {
+         Function *ret = new Function(
+           r->dflags,                // decl flags (static, extern, etc.)
+           r->spec,                  // type specifier for return value
+           new Declarator(d, NULL),  // declarator with fn name, params
+           NULL,                     // ctor member inits
+           b,                        // function body statement
+           h                         // exception handlers
+         );
+         r->spec = NULL;    // stole it above (ownership transfer)
+         delete r;          // was just a carrier of dflags/spec
+         return ret;
+       }
+
+  // I've now substituted the RHSs of CDtorModifierOpt, to eliminiate
+  // a few s/r conflicts at the toplevel of parsing (where they are
+  // the most harmful to performance)
+
+  // constructor, destructor or conversion operator
+  // "explicit"?         name/params     member inits          body
+  -> m:CDtorModifierSeq  d:FDDeclarator  c:CtorInitializerOpt  b:FunctionBody
+       {
+         return new Function(
+           m,                             // decl flags: explicit, virtual, or none
+           new TS_simple(loc, ST_CDTOR),  // type specifier: ctor or dtor
+           new Declarator(d, NULL),       // declarator with fn name, params
+           c,                             // ctor member inits
+           b,                             // function body statement
+           NULL                           // exception handlers
+         );
+       }
+  -> /*no modifier*/     d:FDDeclarator  c:CtorInitializerOpt  b:FunctionBody
+       {
+         return new Function(
+           DF_NONE,
+           new TS_simple(loc, ST_CDTOR),
+           new Declarator(d, NULL),
+           c,
+           b,
+           NULL
+         );
+       }
+
+  // ctor with a try block
+  // "explicit"?         name/params          member inits         body           handlers
+  -> e:CDtorModifierSeq  d:FDDeclarator "try" c:CtorInitializerOpt b:FunctionBody h:HandlerSeq
+       {
+         return new Function(
+           e,                        // decl flags: explicit is only possibility
+           new TS_simple(loc, ST_CDTOR),
+           new Declarator(d, NULL),
+           c,
+           b,
+           h                         // exception handlers
+         );
+       }
+  -> /*no modifier*/     d:FDDeclarator "try" c:CtorInitializerOpt b:FunctionBody h:HandlerSeq
+       {
+         return new Function(
+           DF_NONE,
+           new TS_simple(loc, ST_CDTOR),
+           new Declarator(d, NULL),
+           c,
+           b,
+           h
+         );
+       }
+}
+
+// function definition declarator; must have D_func at the
+// bottom; moved this down from FunctionDefinition itself
+// to get earlier parse filtering for in/k0041.cc
+nonterm(IDeclarator*) FDDeclarator {
+  fun keep(d)
+  {
+    if (!d->bottomIsDfunc()) {
+      TRACE("cancel", "rejecting FDDeclarator w/o D_func at bottom");
+      return false;
+    }
+    else {
+      return true;
+    }
+  }
+
+  -> d:Declarator    { return d; }
+}
+
+nonterm(S_compound*) FunctionBody -> s:CompoundStatement
+  { return s; }
+
+nonterm(FakeList<MemberInit>*) CtorInitializerOpt {
+  -> empty                        { return FakeList<MemberInit>::emptyList(); }
+  -> ":" list:MemInitializerList  { return list; }
+}
+
+
+// ------ A.8 Classes ------
+nonterm(TS_classSpec*) ClassSpecifier {
+  -> k:ClassKey n:ClassHeadNameOpt b:BaseClauseOpt "{" memb:MemberDeclarationSeqOpt "}"
+       { popClassName(); return new TS_classSpec(loc, k, n, b, memb); }
+}
+
+// this is the name portion of what the standard calls "ClassHead"
+nonterm(PQName*) ClassHeadNameOpt {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> empty               { pushClassName(NULL); return NULL; }
+  -> n:ClassHeadName     { pushClassName(n->getName()); return n; }
+}
+
+// a possibly-qualified Identifier or TemplateId
+nonterm(PQName*) ClassHeadName {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> n:Identifier             precedence("::")
+       { return new PQ_name(loc, n); }
+  -> t:TemplateId             precedence("::")
+       { return t; }
+
+  -> n:Identifier "::" rest:ClassHeadName
+       { return new PQ_qualifier(loc, n, NULL /*targs*/, rest); }
+  -> n:Identifier "<" targs:TemplateArgumentListOpt ">" "::" rest:ClassHeadName
+       { return new PQ_qualifier(loc, n, targs, rest); }
+
+  // TEMPLATE_QUALIFIER_HACK
+  //-> "template" n:Identifier "::" rest:ClassHeadName
+  //     { return new PQ_qualifier(loc, n, NULL /*targs*/, rest); }
+  -> "template" n:Identifier "<" targs:TemplateArgumentListOpt ">" "::" rest:ClassHeadName
+       { return new PQ_qualifier(loc, n, templateUsed(targs), rest); }
+}
+
+nonterm(enum TypeIntr) ClassKey {
+  -> "class"       { return TI_CLASS; }
+  -> "struct"      { return TI_STRUCT; }
+  -> "union"       { return TI_UNION; }
+}
+
+
+// I'm using an encapsulated ASTList to avoid right recursion,
+// since there are often many members of classes
+nonterm(MemberList*) MemberDeclarationSeqOpt {
+  fun dup(m) { return NULL; }       // prevent multi-yield
+
+  -> empty
+       { return new MemberList(NULL); }
+
+  // gcc allows multiple semicolons in a row in a member declaration
+  // list; it would be nontrivial to confine this flexibility to an
+  // extension, and it's not that big a deal, so we just tolerate it
+  // always
+  -> list:MemberDeclarationSeqOpt ";"
+       { return list; }
+
+  // destructive actions on 'list'
+  -> list:MemberDeclarationSeqOpt decl:MemberDeclaration
+       { list->list.append(decl); return list; }
+
+  // explicitly include access specifiers in the AST, instead of
+  // propagating them in the parser, to avoid the complexities of
+  // maintaining the state in the parser context
+  -> list:MemberDeclarationSeqOpt k:AccessSpecifier ":"
+       { list->list.append(new MR_access(loc, k)); return list; }
+}
+
+nonterm(AccessKeyword) AccessSpecifier {
+  -> "public"     { return AK_PUBLIC; }
+  -> "private"    { return AK_PRIVATE; }
+  -> "protected"  { return AK_PROTECTED; }
+}
+
+nonterm(Member*) MemberDeclaration {
+  fun keep(m) { return m!=NULL; }
+
+  // destructive action on 'spec'
+  // member fn decl, or data member
+  -> spec:DeclSpecifier list:MemberDeclaratorList ";"
+       { if (lang.isCplusplus &&        // 10/20/04: e.g. in/c/t0017.c
+             list->firstC()->decl->skipGroups()->isD_name() &&
+             !(spec->dflags & (DF_TYPEDEF | DF_STATIC)) &&
+             spec->spec->isTS_name()) {
+           PQName const *n = spec->spec->asTS_nameC()->name;
+           if (n->isPQ_name() &&
+               n->asPQ_nameC()->name == curClassName()) {
+             // you can't declare an embedded instance of your own class
+             // name, and this might be ambiguous with a constructor
+             // declaration, so cancel it
+             TRACE("cancel", loc << ": declaration of embedded self class instance");
+             return NULL;
+           }
+         }
+         spec->decllist = list;
+         if (!keepDeclaration(spec)) {
+           return NULL;
+         }
+         return new MR_decl(loc, spec);
+       }
+
+  // inner class or enum with no instance defined
+  -> spec:DeclSpecifier ";"
+       { // if the type specifier doesn't start with 'class'
+         // or 'enum' then this is useless, and might be
+         // ambiguous with superclass member publication, so
+         // cancel it [cppstd 9.2 para 7]
+         if (spec->spec->isTS_elaborated() ||
+             spec->spec->isTS_classSpec() ||
+             spec->spec->isTS_enumSpec()) {
+           // ok
+           return new MR_decl(loc, spec);
+         }
+         else {
+           TRACE("cancel", loc << ": bare DeclSpecifier not starting with type keyword");
+           return NULL;
+         }
+       }
+
+  // publishing a superclass member; ambiguous with inner class
+  // declaration (above) and ctor declaration (below), hence the
+  // need for cancellation in both of those two
+  //
+  // equivalent to "using n ;" so parse it as such
+  -> n:PQualifiedId ";"
+       { return new MR_usingDecl(loc, new ND_usingDecl(n)); }
+
+  // the general form
+  -> "using" /*typename?*/ n:IdExpression ";"
+       { return new MR_usingDecl(loc, new ND_usingDecl(n)); }
+
+  // inline function definition; includes c/dtor definitions
+  -> f:FunctionDefinition
+       { return new MR_func(loc, f); }
+
+  // declaration (with no definition) of a c/dtor or conversion
+  // operator function
+  -> d:CDtorProtoDecl
+       {
+         if (lang.allowImplicitInt) {
+           // in/c/k0004.c: ambiguity between constructor and implicit-int
+           TRACE("cancel", loc << ": constructor decl in implicit-int language");
+           return NULL;
+         }
+         return new MR_decl(loc, d);
+       }
+
+  // note above that "explicit" and "virtual" can't be mixed because the former
+  // is for ctors only and the latter can't be used with ctors (so a later stage
+  // of processing will filter it out)
+
+  // member template
+  -> d:TemplateDeclaration
+       { return new MR_template(loc, d); }
+}
+
+// declaration (with no definition) of a c/dtor or conversion
+// operator function
+nonterm(Declaration*) CDtorProtoDecl {
+  fun keep(m) { return m!=NULL; }
+
+  // Q: what about pure virtual?
+  // A: it's part of the MemberDeclarator
+  -> flags:CDtorModifierSeq d:MemberDeclarator ";"
+       { // 'd' is a Declarator
+         return new Declaration(
+           flags,
+           new TS_simple(loc, ST_CDTOR),
+           FakeList<Declarator>::makeList(d)
+         );
+       }
+  -> /*no modifier*/ d:MemberDeclarator ";"
+       {
+         // does the declarator construct a function type?
+         // if not, this might be ambiguous (superclass
+         // member publication), so cancel the entire reduction
+         if (!d->decl->skipGroups()->isD_func()) {
+           TRACE("cancel", loc << ": non-function c/dtor");
+           return NULL;
+         }
+
+         return new Declaration(
+           DF_NONE,
+           new TS_simple(loc, ST_CDTOR),
+           FakeList<Declarator>::makeList(d)
+         );
+       }
+}
+
+nonterm(FakeList<Declarator>*) MemberDeclaratorList {
+  -> d:MemberDeclarator
+       { return FakeList<Declarator>::makeList(d); }
+  -> d:MemberDeclarator "," list:MemberDeclaratorList
+       { d->setNext(list->first());
+         return FakeList<Declarator>::makeList(d); }
+}
+
+// this returns a full Declarator, instead of an IDeclarator, because
+// the grammar doesn't nest MemberDeclarators, and because that way I
+// have a place to return the "=0" of a pure virtual function, and also
+// a place to put member initializers
+nonterm(Declarator*) MemberDeclarator {
+  -> d:Declarator
+       { return new Declarator(d, NULL /*init*/); }
+
+  // here I merge two cases (PureSpecifier and ConstantInitializer) that
+  // the std splits; given that the parser doesn't track at this level
+  // whether 'd' is a function type or not, and it can't tell the
+  // difference between PureSpecifier and ConstantInitializer just by
+  // looking at their syntax, we'd be disambiguating this later anyway
+  -> d:Declarator "=" e:ConstantExpression       // pure, and member inits
+       { return new Declarator(d, new IN_expr(loc, e)); }
+
+  -> n:IdentifierOpt ":" e:ConstantExpression    // bitfield
+       { return new Declarator(new D_bitfield(loc, n? new PQ_name(loc, n) : NULL, e),
+                               NULL /*init*/); }
+}
+
+nonterm(StringRef) IdentifierOpt {
+  -> empty         { return NULL; }
+  -> n:Identifier  { return n; }
+}
+
+
+// modifier flags allowed in front of constructors ("explicit"),
+// destructors ("virtual") and conversion functions (none); plus,
+// "inline" is allowed with any of them..
+//
+// NOTE: to avoid a syntactic ambiguity with the ctor syntax "Foo(x)",
+// the set of flags here must not include "static" or "typedef"; see
+// the action function associated with MemberDeclaration's first production
+nonterm(DeclFlags) CDtorModifier {
+  -> "explicit"    { return DF_EXPLICIT; }
+  -> "virtual"     { return DF_VIRTUAL; }
+  -> "inline"      { return DF_INLINE; }
+
+  // (in/t0527.cc) this is to allow befriending another class's constructor
+  -> "friend"      { return DF_FRIEND; }
+}
+
+nonterm(DeclFlags) CDtorModifierSeq {
+  -> m:CDtorModifier                       { return m; }
+  -> s:CDtorModifierSeq m:CDtorModifier    { return s|m; }
+}
+
+// I substituted this into everywhere it occurred
+//  nonterm(DeclFlags) CDtorModifierSeqOpt {
+//    -> empty                         { return DF_NONE; }
+//    -> m:CDtorModifierSeq            { return m; }
+//  }
+
+
+// ------ A.9 Derived classes ------
+nonterm(FakeList<BaseClassSpec>*) BaseClauseOpt {
+  -> empty                      { return FakeList<BaseClassSpec>::emptyList(); }
+  -> ":" b:BaseSpecifierList    { return b; }
+}
+
+nonterm(FakeList<BaseClassSpec>*) BaseSpecifierList {
+  -> b:BaseSpecifier
+       { return FakeList<BaseClassSpec>::makeList(b); }
+  -> b:BaseSpecifier "," list:BaseSpecifierList
+       { return list->prepend(b); }
+}
+
+
+// TODO: spec allows leading "::" on the PQClassName
+nonterm(BaseClassSpec*) BaseSpecifier {
+  -> n:PQClassName
+       { return new BaseClassSpec(false /*virtual*/, AK_UNSPECIFIED, n); }
+  -> "virtual" a:AccessSpecifierOpt n:PQClassName
+       { return new BaseClassSpec(true /*virtual*/, a, n); }
+  -> a:AccessSpecifier v:VirtualOpt n:PQClassName
+       { return new BaseClassSpec(v, a, n); }
+}
+
+nonterm(bool) VirtualOpt {
+  -> empty      { return false; }
+  -> "virtual"  { return true; }
+}
+
+// if the access specifier is missing, then it defaults to private
+// when inherited by a class, and public when inherited by a struct;
+// typechecking will replace AK_UNSPECIFIED with the right thing later
+nonterm(AccessKeyword) AccessSpecifierOpt {
+  -> empty              { return AK_UNSPECIFIED; }
+  -> k:AccessSpecifier  { return k; }
+}
+
+nonterm(PQName*) PQClassName {
+  fun merge(L,R) { return L->mergeAmbiguous(R); }
+
+  -> n:PQTypeName                 { return n; }
+}
+
+
+// ------ A.10 Special member functions ------
+nonterm(OperatorName*) ConversionFunctionId {
+  -> "operator" t:ConversionTypeId  { return new ON_conversion(t); }
+}
+
+nonterm(ASTTypeId*) ConversionTypeId {
+  -> s:TypeSpecifier d:ConversionDeclaratorOpt
+       { return new ASTTypeId(s, new Declarator(d, NULL /*init*/)); }
+}
+
+// collects the stars that might follow a type specifier in a
+// conversion function (for converting to pointer type)
+nonterm(IDeclarator*) ConversionDeclaratorOpt {
+  // this rule is given low precedence so that if there are
+  // stars (etc.) following, they will be considered to be part
+  // of the conversion operator's name (cppstd 12.3.2 para 4);
+  // there is still an S/R conflict for "::" and I'm not sure how
+  // to resolve that one...
+  -> empty                             precedence(TOK_PREFER_SHIFT)
+       { return new D_name(loc, NULL /*name*/); }
+
+  -> "*" cv:CVQualifierSeqOpt d:ConversionDeclaratorOpt
+       { return new D_pointer(loc, cv, d); }
+  -> "&" cv:CVQualifierSeqOpt /*dsw: discarded; can be 'restrict' */ d:ConversionDeclaratorOpt
+       { return new D_reference(loc, d); }
+  -> n:PtrToMemberName "*" cv:CVQualifierSeqOpt d:ConversionDeclaratorOpt
+       { return new D_ptrToMember(loc, n, cv, d); }
+}
+
+
+nonterm(FakeList<MemberInit>*) MemInitializerList {
+  -> i:MemInitializer
+       { return FakeList<MemberInit>::makeList(i); }
+  -> i:MemInitializer "," list:MemInitializerList
+       { return list->prepend(i); }
+}
+
+nonterm(MemberInit*) MemInitializer {
+  -> n:MemInitializerId "(" e:ExpressionListOpt ")"
+       { return new MemberInit(n, e); }
+}
+
+// the std splits cases on whether we're calling a base class ctor
+// or initializing a field; I'll simply call both a PQName, and
+// then in typechecking make sure that the latter case does not
+// have any qualifiers (because in most cases the parser can't make
+// the distinction so it would fall through to typechecking anyway)
+nonterm(PQName*) MemInitializerId {
+  // PQTypeName includes the 'identifier' case, and is otherwise
+  // exactly right for the 'base class' case, so just use it
+  -> n:PQTypeName { return n; }
+}
+
+
+// ------ A.11 Overloading ------
+nonterm(OperatorName*) OperatorFunctionId {
+  -> "operator" od:Operator  { return od; }
+}
+
+// this nonterm is only used in the OperatorFunctionId context,
+// so go ahead and have it return a full OperatorName
+nonterm(OperatorName*) Operator {
+  // ambiguity:
+  //   void operator delete [] () ;
+  // could be operator "delete[]", or
+  // it could be an array of operator "delete"
+  //
+  // to resolve this I'll specify that the parser should always
+  // prefer to shift when it has seen "new" or "delete" and the
+  // lookahead token is "["
+
+  -> "new"                    precedence(TOK_PREFER_SHIFT)
+       { return new ON_newDel(true /*isNew*/, false /*isArray*/); }
+  -> "delete"                 precedence(TOK_PREFER_SHIFT)
+       { return new ON_newDel(false, false); }
+  -> "new" "[" "]"
+       { return new ON_newDel(true, true); }
+  -> "delete" "[" "]"
+       { return new ON_newDel(false, true); }
+
+  -> "!"     { return new ON_operator(OP_NOT); }
+  -> "~"     { return new ON_operator(OP_BITNOT); }
+
+  -> "++"    { return new ON_operator(OP_PLUSPLUS); }
+  -> "--"    { return new ON_operator(OP_MINUSMINUS); }
+
+  -> "+"     { return new ON_operator(OP_PLUS); }
+  -> "-"     { return new ON_operator(OP_MINUS); }
+  -> "*"     { return new ON_operator(OP_STAR); }
+
+  -> "/"     { return new ON_operator(OP_DIV); }
+  -> "%"     { return new ON_operator(OP_MOD); }
+  -> "<<"    { return new ON_operator(OP_LSHIFT); }
+  -> ">>"    { return new ON_operator(OP_RSHIFT); }
+  -> "&"     { return new ON_operator(OP_AMPERSAND); }
+  -> "^"     { return new ON_operator(OP_BITXOR); }
+  -> "|"     { return new ON_operator(OP_BITOR); }
+
+  -> "="     { return new ON_operator(OP_ASSIGN); }
+  -> "+="    { return new ON_operator(OP_PLUSEQ); }
+  -> "-="    { return new ON_operator(OP_MINUSEQ); }
+  -> "*="    { return new ON_operator(OP_MULTEQ); }
+  -> "/="    { return new ON_operator(OP_DIVEQ); }
+  -> "%="    { return new ON_operator(OP_MODEQ); }
+  -> "<<="   { return new ON_operator(OP_LSHIFTEQ); }
+  -> ">>="   { return new ON_operator(OP_RSHIFTEQ); }
+  -> "&="    { return new ON_operator(OP_BITANDEQ); }
+  -> "^="    { return new ON_operator(OP_BITXOREQ); }
+  -> "|="    { return new ON_operator(OP_BITOREQ); }
+
+  -> "=="    { return new ON_operator(OP_EQUAL); }
+  -> "!="    { return new ON_operator(OP_NOTEQUAL); }
+  -> "<"     { return new ON_operator(OP_LESS); }
+  -> ">"     { return new ON_operator(OP_GREATER); }
+  -> "<="    { return new ON_operator(OP_LESSEQ); }
+  -> ">="    { return new ON_operator(OP_GREATEREQ); }
+
+  -> "&&"    { return new ON_operator(OP_AND); }
+  -> "||"    { return new ON_operator(OP_OR); }
+
+  -> "->"    { return new ON_operator(OP_ARROW); }
+  -> "->*"   { return new ON_operator(OP_ARROW_STAR); }
+
+  -> "[" "]" { return new ON_operator(OP_BRACKETS); }
+  -> "(" ")" { return new ON_operator(OP_PARENS); }
+  -> ","     { return new ON_operator(OP_COMMA); }
+}
+
+
+// ------ A.12 Templates ------
+// I recognize this syntax, but ignore it
+// 8/15/04: it is now folded inline where it occurs
+//nonterm ExportOpt {
+//  -> empty;
+//  -> "export";
+//}
+
+nonterm(TemplateDeclaration*) TemplateDeclaration {
+  fun keep(d) { return d!=NULL; }
+
+  // these are the std's rules for template declarations and specializations:
+  //   -> ExportOpt "template" "<" TemplateParameterList ">" Declaration;
+  //   -> "template" "<" ">" Declaration;
+  // I've unified them by making the parameter list and 'export' optional
+  // in both cases.
+
+  // I have expanded 'Declaration' as appropriate, which cuts down on
+  // the filtering work and also makes the semantic values available
+  // in a more convenient context.  In particular, I dug down several
+  // levels to get 'ClassSpecifier' for template classes, which
+  // dramatically cuts down on the vestigial stuff the std's grammar
+  // would have potentially included.
+
+  // template function definition
+  -> plist:TemplatePreamble def:FunctionDefinition
+       {
+         if (anyHaveDefaultArgs(plist)) {
+           // Function templates and definitions of members of class
+           // templates cannot have default arguments (14.1p9).
+           // Reject here because failure to do so can lead to an
+           // unhandled ambiguity (t0463.cc).
+           TRACE("cancel", loc << ": template function defn with default args");
+           return NULL;
+         }
+         return new TD_func(plist, def);
+       }
+
+  // template function definition, or template class or data member decl/defn
+  -> plist:TemplatePreamble d:SimpleDeclaration
+       { return new TD_decl(plist, d); }
+
+  // definition of a template member
+  -> plist:TemplatePreamble td:TemplateDeclaration
+       { return new TD_tmember(plist, td); }
+
+  // as a toplevel form, this is a specialization of a template class
+  // constructor; as a class member, it is a declaration of a
+  // templatized constructor
+  -> plist:TemplatePreamble d:CDtorProtoDecl
+       { return new TD_decl(plist, d); }
+}
+
+// the "template <...>" stuff
+nonterm(/*fakelist*/TemplateParameter*) TemplatePreamble {
+  // 8/15/04: substituted 'ExportOpt' inline since it gives rise to
+  // easily-removed S/R conflicts (continuing to ignore it though)
+
+  // template declaration
+  -> "template" "<" plist:TemplateParameterList ">"
+       { return plist; }
+  -> "export" "template" "<" plist:TemplateParameterList ">"
+       { return plist; }
+
+  // explicit specialization
+  -> "template" "<" ">"
+       { return NULL; }
+  -> "export" "template" "<" ">"
+       { return NULL; }
+}
+
+nonterm(/*fakelist*/TemplateParameter*) TemplateParameterList {
+  fun keep(x) { return x!=NULL; }
+
+  // unfortunately, while we can record an ambiguous template parameter
+  // list, we do not currently disambiguate it properly; see in/t0465.cc
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> ClassOrTypename i:IdentifierOpt t:DefaultTypeOpt
+     { return new TP_type(loc, i, t, NULL /*next*/); }
+
+  -> ClassOrTypename i:IdentifierOpt t:DefaultTypeOpt "," next:TemplateParameterList
+     { return new TP_type(loc, i, t, next); }
+
+  -> p:ParameterDeclaration
+     {
+       // if the specifier is a TS_elaborated, then it could be a type
+       // parameter; cppstd 14.1 para 3 seems to say that in that case it
+       // always *is* a type parameter
+       if (p->spec->canBeTypeParam()) {
+         TRACE("cancel", loc << ": template parameter can be type param");
+         return NULL;   // don't keep this, it's really a TP_type
+       }
+       else {
+         return new TP_nontype(loc, p, NULL /*next*/);
+       }
+     }
+
+  -> p:ParameterDeclaration "," next:TemplateParameterList
+     {
+       if (p->spec->canBeTypeParam()) {
+         TRACE("cancel", loc << ": template parameter can be type param");
+         return NULL;
+       }
+       else {
+         return new TP_nontype(loc, p, next);
+       }
+     }
+}
+
+nonterm ClassOrTypename {
+  -> "class";
+  -> "typename";
+
+  // quarl 2006-06-06
+  //    Recognize templatized template parameter list; this is not the right
+  //    place to put it, but I just wanted to see a descriptive error message,
+  //    in order to categorize parse errors.
+  -> "template" "<" plist:TemplateParameterList ">" "class"
+     {
+       xunimp(stringc << loc << " templatized template parameter list"
+              " (25eb7000-851c-4028-b762-4e365a5b10bf)");
+     }
+}
+
+nonterm(ASTTypeId*) DefaultTypeOpt {
+  -> empty                    { return NULL; }
+  -> "=" t:TypeId             { return t; }
+}
+
+
+nonterm(/*fakelist*/TemplateArgument*) TemplateArgumentListOpt {
+  -> empty                       { return NULL; }
+  -> list:TemplateArgumentList   { return list; }
+}
+
+nonterm(PQ_template*) TemplateId {
+  -> n:Identifier "<" list:TemplateArgumentListOpt ">"
+       { return new PQ_template(loc, n, list); }
+
+  // 9/21/04: Added this possibility (e.g. d0103.cc).
+  -> on:OperatorFunctionId "<" list:TemplateArgumentListOpt ">"
+       // Note: This leaks 'on', and isn't quite as operator-like
+       // as PQ_operator, so I'm not convinced it behaves perfectly...
+       { return new PQ_template(loc, str(on->getOperatorName()), list); }
+
+  // I suspect this one is needed too, but the problem is that
+  // 'getOperatorName' loses information for conversion operators
+  // (they all map to the same string).  So, I'll leave it commented-out.
+  // One solution would be to make a PQ_operatorTemplate with an
+  // OperatorName first argument...
+  //-> on:ConversionFunctionId "<" list:TemplateArgumentListOpt ">"
+  //     { return new PQ_template(loc, str(on->getOperatorName()), list); }
+
+
+  // version with the word "template" in front
+  //
+  // arg.. this causes some extra ambiguities, see t0255.cc.  since I
+  // don't have a testcase that requires this yet, I'll just remove it
+  //-> "template" n:Identifier "<" list:TemplateArgumentListOpt ">"
+  //     { return new PQ_template(loc, n, templateUsed(list)); }
+}
+
+nonterm(/*fakelist*/TemplateArgument*) TemplateArgumentList {
+  // the list-ness is embedded in TemplateArgument
+  -> a:TemplateArgument
+       { return a; }
+}
+
+nonterm(TemplateArgument*) TemplateArgumentListTailOpt {
+  -> empty                      { return NULL; }
+  -> "," a:TemplateArgument     { return a; }
+}
+
+nonterm(TemplateArgument*) TemplateArgument {
+  // ambiguous due to type/variable name ambiguity, and also
+  // due to angle brackets vs. less-than
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  fun keep(n) { return n!=NULL; }
+
+  -> type:TypeId tail:TemplateArgumentListTailOpt
+     { return new TA_type(type, tail); }
+
+  -> e:AssignmentExpression tail:TemplateArgumentListTailOpt
+     {
+       if (Expression::hasUnparenthesizedGT(e)) {
+         // this is the wrong interpretation because template argument
+         // expressions aren't allowed to have unparenthesized
+         // greater-than operators [cppstd 14.1 para 15]
+         //
+         // this helps eliminate a nasty ambiguity in function
+         // declarators, as otherwise
+         //   template <class T>
+         //   Foo<T> & Foo<T>::get() {}
+         // could be interpreted as a constructor (we don't realize
+         // that 'get' != 'Foo') of a template class with template
+         // argument "T > &Foo < T"
+         TRACE("cancel", loc
+           << ": template argument has unparenthesized greater-than operator");
+         return NULL;
+       }
+       else {
+         return new TA_nontype(e, tail);
+       }
+     }
+
+  // is this for template args that are templates, or what?
+  //-> IdExpression;
+}
+
+nonterm(TopForm*) ExplicitInstantiation {
+  -> "template" d:BlockDeclaration
+       { return new TF_explicitInst(loc, DF_NONE, d); }
+  -> "inline" "template" d:BlockDeclaration
+       { xunimp(stringc << loc << " inline explicit instantiations"
+                " (c24a5f9c-edbd-4945-a56a-ed73a1d6a0fa)"); }
+}
+
+// ------ A.13 Exception handling ------
+nonterm(S_try*) TryBlock {
+  -> "try" s:CompoundStatement h:HandlerSeq  { return new S_try(loc, s, h); }
+}
+
+nonterm(FakeList<Handler>*) HandlerSeq {
+  -> h:Handler                 { return FakeList<Handler>::makeList(h); }
+  -> h:Handler seq:HandlerSeq  { return seq->prepend(h); }
+}
+
+nonterm(Handler*) Handler {
+  -> "catch" "(" d:HandlerParameter ")" s:CompoundStatement
+       { return new Handler(d, s); }
+
+  -> "catch" "(" "..." ")" s:CompoundStatement
+       { return new Handler(
+           new ASTTypeId(new TS_simple(loc, ST_ELLIPSIS),
+                         new Declarator(new D_name(loc, NULL /*name*/),
+                                        NULL /*init*/)),
+           s); }
+}
+
+nonterm(ASTTypeId*) HandlerParameter {
+  -> s:TypeSpecifier d:UnqualifiedDeclarator
+       { return new ASTTypeId(s, new Declarator(d, NULL /*init*/)); }
+  -> s:TypeSpecifier d:AbstractDeclaratorOpt
+       { return new ASTTypeId(s, new Declarator(d, NULL /*init*/)); }
+}
+
+
+// this nonterminal helps with the TYPENAME ::NAME ambiguity, and also
+// partially enforces 8.3.5p8, which says that a parameter name must
+// be an identifier (only), if present
+nonterm(IDeclarator*) UnqualifiedDeclarator {
+  fun keep(d) {
+    PQName const *n = d->getDeclaratorIdC();
+    if (n->hasQualifiers()) {    // 'n' is never NULL
+      TRACE("cancel", d->loc << ": qualified UnqualifiedDeclarator");
+      return false;
+    }
+    return true;
+  }
+
+  -> d:Declarator              { return d; }
+}
+
+// note: There is no such thing as an UnqualifiedAbstractDeclaratorOpt
+// because abstract declarators do not contain an id-expression.
+
+
+nonterm(E_throw*) ThrowExpression {
+  -> "throw"                         { return new E_throw(NULL); }
+  -> "throw" e:AssignmentExpression  { return new E_throw(e); }
+}
+
+
+nonterm(ExceptionSpec*) ExceptionSpecificationOpt {
+  -> empty
+       { return NULL; }
+  -> "throw" "(" ")"
+       { return new ExceptionSpec(FakeList<ASTTypeId>::emptyList()); }
+  -> "throw" "(" list:TypeIdList ")"
+       { return new ExceptionSpec(list); }
+}
+
+nonterm(FakeList<ASTTypeId>*) TypeIdList {
+  -> t:TypeId
+       { return FakeList<ASTTypeId>::makeList(t); }
+  -> t:TypeId "," list:TypeIdList
+       { t->setNext(list->first());
+         return FakeList<ASTTypeId>::makeList(t); }
+}
+
+
+// ------------------------ namespaces -----------------------
+nonterm(TF_namespaceDefn*) NamespaceDefinition {
+  -> "namespace" n:IdentifierOpt "{" unit:TranslationUnit "}"
+       {
+         TF_namespaceDefn *ret = new TF_namespaceDefn(loc, n, NULL /*forms*/);
+         ret->forms.concat(unit->topForms);     // steal list contents
+         delete unit;
+         return ret;
+       }
+}
+
+nonterm(NamespaceDecl*) NamespaceDecl {
+  -> "namespace" alias:Identifier "=" orig:IdExpression ";"
+       { return new ND_alias(alias, orig); }
+
+  // cppstd allows "typename" after "using", but doesn't specify what
+  // it means; I assume they mean to use its semantics as described
+  // elsewhere, but I don't feel like tracking that down now
+  -> "using" /*typename?*/ n:IdExpression ";"
+       { return new ND_usingDecl(n); }
+
+  -> "using" "namespace" n:IdExpression ";"
+       { return new ND_usingDir(n); }
+}
+
+
+
+impl_verbatim {
+  bool isGlobalScopeQualified(PQName const *pq)
+  {
+    return pq->isPQ_qualifier() &&
+           pq->asPQ_qualifierC()->qualifier == NULL;
+  }
+
+  bool endsWithIdentifier(TypeSpecifier const *ts)
+  {
+    return ts->isTS_name() ||
+           ts->isTS_elaborated();
+  }
+
+  // Filter out declarations of the form "TYPENAME ::NAME", since
+  // other front-ends would regard the TYPENAME as a qualifier.
+  //
+  // The performance could be improved by doing static disambiguation,
+  // however that is a little tricky because the productions involved
+  // conflict with several rules, and I need to resolve conflicts with
+  // just certain pairs of rules.  So, until I implement a more
+  // precise form of static disambiguation in Elkhound, I will just
+  // resort to runtime filtering.
+  bool keepDeclaration(Declaration const *d)
+  {
+    if (endsWithIdentifier(d->spec) &&
+        d->decllist->isNotEmpty()) {
+      IDeclarator const *id = d->decllist->firstC()->decl;
+      while (!id->isD_name()) {
+        // skip past type constructors that come *after* the name;
+        // if they come before, then they separate the :: from the
+        // TYPENAME, and hence :: could be the global scope qualifier
+        if (id->isD_func()) {
+          id = id->asD_funcC()->base;
+        }
+        else if (id->isD_array()) {
+          id = id->asD_arrayC()->base;
+        }
+        else {
+          return true;      // something precedes ::, so is ok
+        }
+      }
+      if (isGlobalScopeQualified(id->asD_nameC()->name)) {
+        TRACE("cancel", id->loc << ": TYPENAME ::NAME");
+        return false;
+      }
+    }
+    return true;
+  }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc.lex
===================================================================
--- vendor/elsa/current/elsa/cc.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,489 @@
+/* cc.lex            see license.txt for copyright and terms of use
+ * flex description of scanner for C and C++ souce
+ */
+
+/* ----------------------- C definitions ---------------------- */
+%{
+
+#include "lexer.h"       // Lexer class
+#include "cc_lang.h"     // CCLang (actually gnu.lex needs CCLang, but can't add the #include by itself due to the way lexer extensions work ...)
+
+// this works around a problem with cygwin & fileno
+#define YY_NEVER_INTERACTIVE 1
+
+%}
+
+
+/* -------------------- flex options ------------------ */
+/* no wrapping is needed; setting this means we don't have to link with libfl.a */
+%option noyywrap
+
+/* don't use the default-echo rules */
+%option nodefault
+
+/* I don't call unput */
+%option nounput
+
+/* generate a c++ lexer */
+%option c++
+
+/* use the "fast" algorithm with no table compression */
+%option full
+
+/* utilize character equivalence classes */
+%option ecs
+
+/* the scanner is never interactive */
+%option never-interactive
+
+/* and I will define the class (lexer.h) */
+%option yyclass="Lexer"
+
+/* output file name */
+  /* dsw: Arg!  Don't do this, since it is not overrideable from the
+     command line with -o, which I consider to be a flex bug. */
+  /* sm: fair enough; agreed */
+  /* %option outfile="lexer.yy.cc" */
+
+/* start conditions */
+%x BUGGY_STRING_LIT
+
+/* ------------------- definitions -------------------- */
+/* newline */
+NL            "\n"
+
+/* anything but newline */
+NOTNL         .
+
+/* any of 256 source characters */
+ANY           ({NOTNL}|{NL})
+
+/* backslash */
+BACKSL        "\\"
+
+/* beginnging of line (must be start of a pattern) */
+BOL           ^
+
+/* end of line (would like EOF to qualify also, but flex doesn't allow it */
+EOL           {NL}
+
+/* letter or underscore */
+LETTER        [A-Za-z_]
+
+/* letter or underscore or digit */
+ALNUM         [A-Za-z_0-9]
+
+/* decimal digit */
+DIGIT         [0-9]
+HEXDIGIT      [0-9A-Fa-f]
+
+/* sequence of decimal digits */
+DIGITS        ({DIGIT}+)
+/* sequence of hex digits */
+HEXDIGITS     ({HEXDIGIT}+)
+
+/* sign of a number */
+SIGN          ("+"|"-")
+
+/* integer suffix */
+/* added 'LL' option for gcc/c99 long long compatibility */
+ELL_SUFFIX    [lL]([lL]?)
+INT_SUFFIX    ([uU]{ELL_SUFFIX}?|{ELL_SUFFIX}[uU]?)
+
+/* floating-point suffix letter */
+FLOAT_SUFFIX  [flFL]
+
+/* normal string character: any but quote, newline, or backslash */
+STRCHAR       [^\"\n\\]
+
+/* (start of) an escape sequence */
+ESCAPE        ({BACKSL}{ANY})
+
+/* double quote */
+QUOTE         [\"]
+
+/* normal character literal character: any but single-quote, newline, or backslash */
+CCCHAR        [^\'\n\\]
+
+/* single quote */
+TICK          [\']
+
+/* space or tab */
+SPTAB         [ \t]
+
+/* preprocessor "character" -- any but escaped newline */
+PPCHAR        ([^\\\n]|{BACKSL}{NOTNL})
+
+
+/* ------------- token definition rules --------------- */
+%%
+
+  /* this comment is replaced, by an external script, with whatever
+   * additional rules a language extension author desires */
+  /* EXTENSION RULES GO HERE */
+
+
+  /* operators, punctuators and keywords: tokens with one spelling */
+"asm"              return tok(TOK_ASM);
+"auto"             return tok(TOK_AUTO);
+"break"            return tok(TOK_BREAK);
+"bool"             return tok(TOK_BOOL);
+"case"             return tok(TOK_CASE);
+"catch"            return tok(TOK_CATCH);
+"cdecl"            return tok(TOK_CDECL);
+"char"             return tok(TOK_CHAR);
+"class"            return tok(TOK_CLASS);
+"const"            return tok(TOK_CONST);
+"const_cast"       return tok(TOK_CONST_CAST);
+"continue"         return tok(TOK_CONTINUE);
+"default"          return tok(TOK_DEFAULT);
+"delete"           return tok(TOK_DELETE);
+"do"               return tok(TOK_DO);
+"double"           return tok(TOK_DOUBLE);
+"dynamic_cast"     return tok(TOK_DYNAMIC_CAST);
+"else"             return tok(TOK_ELSE);
+"enum"             return tok(TOK_ENUM);
+"explicit"         return tok(TOK_EXPLICIT);
+"export"           return tok(TOK_EXPORT);
+"extern"           return tok(TOK_EXTERN);
+"false"            return tok(TOK_FALSE);
+"float"            return tok(TOK_FLOAT);
+"for"              return tok(TOK_FOR);
+"friend"           return tok(TOK_FRIEND);
+"goto"             return tok(TOK_GOTO);
+"if"               return tok(TOK_IF);
+"inline"           return tok(TOK_INLINE);
+"int"              return tok(TOK_INT);
+"long"             return tok(TOK_LONG);
+"mutable"          return tok(TOK_MUTABLE);
+"namespace"        return tok(TOK_NAMESPACE);
+"new"              return tok(TOK_NEW);
+"operator"         return tok(TOK_OPERATOR);
+"pascal"           return tok(TOK_PASCAL);
+"private"          return tok(TOK_PRIVATE);
+"protected"        return tok(TOK_PROTECTED);
+"public"           return tok(TOK_PUBLIC);
+"register"         return tok(TOK_REGISTER);
+"reinterpret_cast" return tok(TOK_REINTERPRET_CAST);
+"return"           return tok(TOK_RETURN);
+"short"            return tok(TOK_SHORT);
+"signed"           return tok(TOK_SIGNED);
+"sizeof"           return tok(TOK_SIZEOF);
+"static"           return tok(TOK_STATIC);
+"static_cast"      return tok(TOK_STATIC_CAST);
+"struct"           return tok(TOK_STRUCT);
+"switch"           return tok(TOK_SWITCH);
+"template"         return tok(TOK_TEMPLATE);
+"this"             return tok(TOK_THIS);
+"throw"            return tok(TOK_THROW);
+"true"             return tok(TOK_TRUE);
+"try"              return tok(TOK_TRY);
+"typedef"          return tok(TOK_TYPEDEF);
+"typeid"           return tok(TOK_TYPEID);
+"typename"         return tok(TOK_TYPENAME);
+"union"            return tok(TOK_UNION);
+"unsigned"         return tok(TOK_UNSIGNED);
+"using"            return tok(TOK_USING);
+"virtual"          return tok(TOK_VIRTUAL);
+"void"             return tok(TOK_VOID);
+"volatile"         return tok(TOK_VOLATILE);
+"wchar_t"          return tok(TOK_WCHAR_T);
+"while"            return tok(TOK_WHILE);
+
+"("                return tok(TOK_LPAREN);
+")"                return tok(TOK_RPAREN);
+"["                return tok(TOK_LBRACKET);
+"]"                return tok(TOK_RBRACKET);
+"->"               return tok(TOK_ARROW);
+"::"               return tok(TOK_COLONCOLON);
+"."                return tok(TOK_DOT);
+"!"                return tok(TOK_BANG);
+"~"                return tok(TOK_TILDE);
+"+"                return tok(TOK_PLUS);
+"-"                return tok(TOK_MINUS);
+"++"               return tok(TOK_PLUSPLUS);
+"--"               return tok(TOK_MINUSMINUS);
+"&"                return tok(TOK_AND);
+"*"                return tok(TOK_STAR);
+".*"               return tok(TOK_DOTSTAR);
+"->*"              return tok(TOK_ARROWSTAR);
+"/"                return tok(TOK_SLASH);
+"%"                return tok(TOK_PERCENT);
+"<<"               return tok(TOK_LEFTSHIFT);
+">>"               return tok(TOK_RIGHTSHIFT);
+"<"                return tok(TOK_LESSTHAN);
+"<="               return tok(TOK_LESSEQ);
+">"                return tok(TOK_GREATERTHAN);
+">="               return tok(TOK_GREATEREQ);
+"=="               return tok(TOK_EQUALEQUAL);
+"!="               return tok(TOK_NOTEQUAL);
+"^"                return tok(TOK_XOR);
+"|"                return tok(TOK_OR);
+"&&"               return tok(TOK_ANDAND);
+"||"               return tok(TOK_OROR);
+"?"                return tok(TOK_QUESTION);
+":"                return tok(TOK_COLON);
+"="                return tok(TOK_EQUAL);
+"*="               return tok(TOK_STAREQUAL);
+"/="               return tok(TOK_SLASHEQUAL);
+"%="               return tok(TOK_PERCENTEQUAL);
+"+="               return tok(TOK_PLUSEQUAL);
+"-="               return tok(TOK_MINUSEQUAL);
+"&="               return tok(TOK_ANDEQUAL);
+"^="               return tok(TOK_XOREQUAL);
+"|="               return tok(TOK_OREQUAL);
+"<<="              return tok(TOK_LEFTSHIFTEQUAL);
+">>="              return tok(TOK_RIGHTSHIFTEQUAL);
+","                return tok(TOK_COMMA);
+"..."              return tok(TOK_ELLIPSIS);
+";"                return tok(TOK_SEMICOLON);
+"{"                return tok(TOK_LBRACE);
+"}"                return tok(TOK_RBRACE);
+
+  /* "alternative tokens" of cppstd 2.5p2 */
+"<%"               return alternateKeyword_tok(TOK_LBRACE);
+"%>"               return alternateKeyword_tok(TOK_RBRACE);
+"<:"               return alternateKeyword_tok(TOK_LBRACKET);
+":>"               return alternateKeyword_tok(TOK_RBRACKET);
+  /* "%:" and "%:%:" correspond to "#" and "##", which are only for
+   * the preprocessor, so I will ignore them here */
+"and"              return alternateKeyword_tok(TOK_ANDAND);
+"bitor"            return alternateKeyword_tok(TOK_OR);
+"or"               return alternateKeyword_tok(TOK_OROR);
+"xor"              return alternateKeyword_tok(TOK_XOR);
+"compl"            return alternateKeyword_tok(TOK_TILDE);
+"bitand"           return alternateKeyword_tok(TOK_AND);
+"and_eq"           return alternateKeyword_tok(TOK_ANDEQUAL);
+"or_eq"            return alternateKeyword_tok(TOK_OREQUAL);
+"xor_eq"           return alternateKeyword_tok(TOK_XOREQUAL);
+"not"              return alternateKeyword_tok(TOK_BANG);
+"not_eq"           return alternateKeyword_tok(TOK_NOTEQUAL);
+
+  /* this rule is to avoid backing up in the lexer
+   * when there are two dots but not three */
+".." {
+  yyless(1);     /* put back all but 1; this is inexpensive */
+  return tok(TOK_DOT);
+}
+
+  /* identifier: e.g. foo */
+{LETTER}{ALNUM}* {
+  return svalTok(TOK_NAME);
+}
+
+  /* integer literal; dec, oct, or hex */
+[1-9][0-9]*{INT_SUFFIX}?           |
+[0][0-7]*{INT_SUFFIX}?             |
+[0][xX][0-9A-Fa-f]+{INT_SUFFIX}?   {
+  return svalTok(TOK_INT_LITERAL);
+}
+
+  /* hex literal with nothing after the 'x' */
+[0][xX] {
+  err("hexadecimal literal with nothing after the 'x'");
+  return svalTok(TOK_INT_LITERAL);
+}
+
+  /* floating literal */
+{DIGITS}"."{DIGITS}?([eE]{SIGN}?{DIGITS})?{FLOAT_SUFFIX}?   |
+{DIGITS}"."?([eE]{SIGN}?{DIGITS})?{FLOAT_SUFFIX}?	    |
+"."{DIGITS}([eE]{SIGN}?{DIGITS})?{FLOAT_SUFFIX}?	    {
+  return svalTok(TOK_FLOAT_LITERAL);
+}
+
+  /* floating literal with no digits after the 'e' */
+{DIGITS}"."{DIGITS}?[eE]{SIGN}?   |
+{DIGITS}"."?[eE]{SIGN}?           |
+"."{DIGITS}[eE]{SIGN}?            {
+  err("floating literal with no digits after the 'e'");
+  
+  /* in recovery rules like this it's best to yield the best-guess
+   * token type, instead of some TOK_ERROR, so the parser can still
+   * try to make sense of the input; having reported the error is
+   * sufficient to ensure that later stages won't try to interpret
+   * the lexical text of this token as a floating literal */
+  return svalTok(TOK_FLOAT_LITERAL);
+}
+
+  /* string literal */
+"L"?{QUOTE}({STRCHAR}|{ESCAPE})*{QUOTE} {
+  return svalTok(TOK_STRING_LITERAL);
+}
+
+  /* string literal missing final quote */
+"L"?{QUOTE}({STRCHAR}|{ESCAPE})*{EOL}   {
+  if (lang.allowNewlinesInStringLits) {
+    warning("string literal contains (unescaped) newline character; "
+            "this is allowed for gcc-2 bug compatibility only "
+            "(maybe the final `\"' is missing?)");
+    BEGIN(BUGGY_STRING_LIT);
+    return svalTok(TOK_STRING_LITERAL);
+  }
+  else {
+    err("string literal missing final `\"'");
+    return svalTok(TOK_STRING_LITERAL);     // error recovery
+  }
+}
+
+  /* unterminated string literal; maximal munch causes us to prefer
+   * either of the above two rules when possible; the trailing
+   * optional backslash is needed so the scanner won't back up in that
+   * case; NOTE: this can only happen if the file ends in the string
+   * and there is no newline before the EOF */
+"L"?{QUOTE}({STRCHAR}|{ESCAPE})*{BACKSL}? {
+  err("unterminated string literal");
+  yyterminate();
+}
+
+
+  /* This scanner reads in a string literal that contains unescaped
+   * newlines, to support a gcc-2 bug.  The strategy is to emit a
+   * sequence of TOK_STRING_LITERALs, as if the string had been
+   * properly broken into multiple literals.  However, these literals
+   * aren't consistently surrounded by quotes... */
+<BUGGY_STRING_LIT>{
+  ({STRCHAR}|{ESCAPE})*{QUOTE} {
+    // found the end
+    BEGIN(INITIAL);
+    return svalTok(TOK_STRING_LITERAL);
+  }
+  ({STRCHAR}|{ESCAPE})*{EOL} {
+    // another line
+    return svalTok(TOK_STRING_LITERAL);
+  }
+  <<EOF>> |
+  ({STRCHAR}|{ESCAPE})*{BACKSL}? {
+    // unterminated (this only matches at EOF)
+    err("at EOF, unterminated string literal; support for newlines in string "
+        "literals is presently turned on, maybe the missing quote should have "
+        "been much earlier in the file?");
+    yyterminate();
+  }
+}
+
+
+  /* character literal */
+"L"?{TICK}({CCCHAR}|{ESCAPE})*{TICK}   {
+  return svalTok(TOK_CHAR_LITERAL);
+}
+
+  /* character literal missing final tick */
+"L"?{TICK}({CCCHAR}|{ESCAPE})*{EOL}    {
+  err("character literal missing final \"'\"");
+  return svalTok(TOK_CHAR_LITERAL);       // error recovery
+}
+
+  /* unterminated character literal */
+"L"?{TICK}({CCCHAR}|{ESCAPE})*{BACKSL}?  {
+  err("unterminated character literal");
+  yyterminate();
+}
+
+
+  /* sm: I moved the user-defined qualifier rule into qual_ext.lex
+   * in the oink tree */
+
+
+  /* preprocessor */
+  /* technically, if this isn't at the start of a line (possibly after
+   * some whitespace), it should be an error.. I'm not sure right now how
+   * I want to deal with that (I originally was using '^', but that
+   * interacts badly with the whitespace rule) */
+
+  /* #line directive: the word "line" is optional, then a space, and
+   * then we accept the rest of the line; 'parseHashLine' will finish
+   * parsing the directive */
+"#"("line"?){SPTAB}.*{NL} {
+  parseHashLine(yytext, yyleng);
+  whitespace();       // don't increment line count until after parseHashLine()
+}
+
+  /* other preprocessing: ignore it */
+  /* trailing optional baskslash to avoid backing up */
+"#"{PPCHAR}*({BACKSL}{NL}{PPCHAR}*)*{BACKSL}?   {
+  // treat it like whitespace, ignoring it otherwise
+  whitespace();
+}
+
+  /* whitespace */
+  /* 10/20/02: added '\r' to accomodate files coming from Windows; this
+   * could be seen as part of the mapping from physical source file
+   * characters to the basic character set (cppstd 2.1 para 1 phase 1),
+   * except that it doesn't happen for chars in string/char literals... */
+[ \t\n\f\v\r]+  {
+  whitespace();
+}
+
+  /* C++ comment */
+  /* we don't match the \n because that way this works at EOF */
+"//"{NOTNL}*    {
+  whitespace();
+}
+
+  /* C comment */
+"/""*"([^*]|"*"*[^*/])*"*"+"/"     {
+  // the pattern is a little complicated because the naive one,
+  //   "/""*"([^*]|"*"[^/])*"*/"
+  // fails to match e.g. "/***/" 
+  whitespace();
+}
+
+  /* unterminated C comment */
+"/""*"([^*]|"*"*[^*/])*"*"*        {
+  err("unterminated /""*...*""/ comment");
+  yyterminate();
+}
+
+
+  /* illegal */
+.  {
+  updLoc();
+  err(stringc << "illegal character: `" << yytext[0] << "'");
+}
+
+<<EOF>> {
+  srcFile->doneAdding();
+  yyterminate();
+}
+
+
+%%
+/**************/
+/* extra code */
+/**************/
+
+
+
+// another C comment system using a start state; I chose to (fix and)
+// use the single-line rule instead, so that the entire thing would be
+// matched at once within the FSM instead of dropping out for user
+// actions
+#if 0
+/* exclusive start state for when inside a slash-star style comment */
+%x IN_C_COMMENT
+
+  /* C comment; dsw: one that actually works! */
+"/""*" {
+  yymore();
+  BEGIN IN_C_COMMENT;
+}
+<IN_C_COMMENT>[^*]+ {
+  yymore();
+}
+<IN_C_COMMENT>"*"+"/" {
+  whitespace();
+  BEGIN INITIAL;
+}
+<IN_C_COMMENT>"*"+ {
+  /* NOTE: this rule must come after the above rule */
+  yymore();
+}
+<IN_C_COMMENT><<EOF>> {
+  /* TODO: I don't know why flex doesn't give me an error if I omit this rule, since -f is used */
+  err("unterminated /**/ comment");
+  whitespace();
+  /* dsw: TODO: I think I just have to replicate this here or we could factor it out */
+  srcFile->doneAdding();
+  yyterminate();
+}
+#endif // 0

Added: vendor/elsa/current/elsa/cc_ast.h
===================================================================
--- vendor/elsa/current/elsa/cc_ast.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_ast.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// cc_ast.h            see license.txt for copyright and terms of use
+// a level of indirection for including the generated AST header file
+
+// The idea here is that, since most files are dependent on the AST
+// declarations, and it's sometimes useful to globally change which
+// set of declarations are in use, this file could be replaced by
+// an extension analysis to accomplish that end.  Of course, such a
+// change should not then be committed back into the main Elsa CVS
+// repository.
+
+// The most obvious alternative mechanism for accomplishing this would
+// be to make a preprocessor symbol that expands to "cc.ast.gen.h" by
+// default.  However, I (Scott) don't like to mix #defines and
+// #includes because it can make it quite difficult to understand
+// what happens during preprocessing.
+
+#ifndef CC_AST_H
+#define CC_AST_H
+
+#include "cc.ast.gen.h"     // Elsa's name for the C++ AST declarations file
+
+#endif // CC_AST_H

Added: vendor/elsa/current/elsa/cc_ast_aux.cc
===================================================================
--- vendor/elsa/current/elsa/cc_ast_aux.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_ast_aux.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1615 @@
+// cc_ast_aux.cc            see license.txt for copyright and terms of use
+// auxilliary code (debug printing, etc.) for cc.ast
+
+#include "strutil.h"        // plural
+#include "generic_aux.h"    // C++ AST, and genericPrintAmbiguities, etc.
+#include "cc_ast_aux.h"     // class LoweredASTVisitor
+
+
+// ---------------------- LoweredASTVisitorHelper ----------------------
+void LoweredASTVisitorHelper::oneTempl(Variable *var0) {
+  xassert(var0);
+  xassert(var0->templateInfo());
+
+  // run a sub-traversal of the AST instantiation
+  if (var0->funcDefn) {
+    var0->funcDefn->traverse(loweredVisitor);
+  }
+  if (var0->type->isCompoundType() && var0->type->asCompoundType()->syntax) {
+    var0->type->asCompoundType()->syntax->traverse(loweredVisitor);
+  }
+}
+
+// sm: added this layer to handle new design with specializations
+// as a middle layer between primaries and instantiations
+void LoweredASTVisitorHelper::oneContainer(Variable *container)
+{
+  TemplateInfo *ti = container->templateInfo();
+  xassert(ti);
+
+  if (ti->isCompleteSpec()) {
+    // visit as template and bail
+    oneTempl(container);
+    return;
+  }
+
+  // visit the container itself, if desired
+  if (primariesAndPartials) {
+    // dsw: FIX: Given the avoidance of visiting TemplateDeclaration-s
+    // below in the main visitor, I'm not entirely sure that this
+    // makes sense.  Then again, if you set this flag you get what you
+    // deserve.
+    oneTempl(container);
+  }
+
+  // visit each instantiation
+  SFOREACH_OBJLIST_NC(Variable, ti->instantiations, iter) {
+    oneTempl(iter.data());
+  }
+}
+
+
+void LoweredASTVisitorHelper::oneVariable(Variable *tinfoVar)
+{
+  xassert(tinfoVar);
+
+  TemplateInfo *tinfo = tinfoVar->templateInfo();
+
+  // skip any non-primary TemplateInfo-s
+  if (!tinfo || !tinfo->isPrimary()) {
+    return;
+  }
+
+  // visit a primary only once
+  if (primaryTemplateInfos.contains(tinfo)) {
+    return;
+  }
+  primaryTemplateInfos.add(tinfo);
+
+  // look in the primary (as a container)
+  oneContainer(tinfoVar);
+
+  // look in the specializations (as containers)
+  SFOREACH_OBJLIST_NC(Variable, tinfo->specializations, iter) {
+    oneContainer(iter.data());
+  }
+}
+
+
+void LoweredASTVisitorHelper::visitDeclarator0(Declarator *decltor)
+{
+  // visit all the template instantiations
+  oneVariable(decltor->var);
+}
+
+
+bool LoweredASTVisitorHelper::visitDeclarator(Declarator *decltor)
+{
+  // this kind of check is now done in DelegatorASTVisitor
+//    xassert(!loweredVisitor.visitedAST(decltor));
+
+  // this is silly, but OO-correct
+  if (!ASTVisitor::visitDeclarator(decltor)) return false;
+
+  visitDeclarator0(decltor);
+
+  return true;
+}
+
+
+void LoweredASTVisitorHelper::visitTypeSpecifier0(TypeSpecifier *spec)
+{
+  TS_classSpec *ts = spec->asTS_classSpec();
+  if (ts->ctype) {
+    // visit all the template instantiations
+    oneVariable(ts->ctype->asCompoundType()->getTypedefVar());
+  }
+}
+
+
+bool LoweredASTVisitorHelper::visitTypeSpecifier(TypeSpecifier *spec)
+{
+  if (spec->isTS_classSpec()) {
+    return subvisitTS_classSpec(spec->asTS_classSpec());
+  }
+  return ASTVisitor::visitTypeSpecifier(spec);
+}
+
+
+bool LoweredASTVisitorHelper::subvisitTS_classSpec(TS_classSpec *spec)
+{
+  // ensure idempotency of templatized AST
+  if (loweredVisitor.visitedAST(spec)) {
+    return false;
+  }
+
+  // this is silly, but OO-correct
+  if (!ASTVisitor::visitTypeSpecifier(spec)) return false;
+
+  visitTypeSpecifier0(spec);
+
+  return true;
+}
+
+
+bool LoweredASTVisitorHelper::visitFunction(Function *func)
+{
+  // ensure idempotency of templatized AST
+  if (loweredVisitor.visitedAST(func)) {
+    return false;
+  }
+  return ASTVisitor::visitFunction(func);
+}
+
+// ---------------------- LoweredASTVisitor ----------------------
+
+// **** maintain source location
+
+bool LoweredASTVisitor::visitTopForm(TopForm *obj) {
+  loc = obj->loc;
+  return DelegatorASTVisitor::visitTopForm(obj);
+}
+
+bool LoweredASTVisitor::visitPQName(PQName *obj) {
+  loc = obj->loc;
+  return DelegatorASTVisitor::visitPQName(obj);
+}
+
+// bool LoweredASTVisitor::visitTypeSpecifier(TypeSpecifier *obj) {
+//   loc = obj->loc;
+//   return DelegatorASTVisitor::visitTypeSpecifier(obj);
+// }
+
+bool LoweredASTVisitor::visitEnumerator(Enumerator *obj) {
+  loc = obj->loc;
+  return DelegatorASTVisitor::visitEnumerator(obj);
+}
+
+bool LoweredASTVisitor::visitMember(Member *obj) {
+  loc = obj->loc;
+  return DelegatorASTVisitor::visitMember(obj);
+}
+
+bool LoweredASTVisitor::visitIDeclarator(IDeclarator *obj) {
+  loc = obj->loc;
+  return DelegatorASTVisitor::visitIDeclarator(obj);
+}
+
+// bool LoweredASTVisitor::visitStatement(Statement *obj) {
+//   loc = obj->loc;
+//   return DelegatorASTVisitor::visitStatement(obj);
+// }
+
+// bool LoweredASTVisitor::visitInitializer(Initializer *obj) {
+//   loc = obj->loc;
+//   return DelegatorASTVisitor::visitInitializer(obj);
+// }
+
+bool LoweredASTVisitor::visitTemplateParameter(TemplateParameter *obj) {
+  loc = obj->loc;
+  return DelegatorASTVisitor::visitTemplateParameter(obj);
+}
+
+// ****
+
+bool LoweredASTVisitor::visitFullExpressionAnnot(FullExpressionAnnot *fea)
+{
+  if (!DelegatorASTVisitor::visitFullExpressionAnnot(fea)) return false;
+
+  return true;
+}
+
+// NOTE: I am trying to use visitDeclarator as a way to visit all
+// variables, but it doesn't quite get them all; see
+// visitTypeSpecifier below
+bool LoweredASTVisitor::visitDeclarator(Declarator *decltor)
+{
+  // this kind of check is now done in DelegatorASTVisitor
+//    xassert(!visitedAST(decltor));
+  if (!DelegatorASTVisitor::visitDeclarator(decltor)) return false;
+
+  if (visitElaboratedAST) {
+    if (decltor->ctorStatement) {
+      decltor->ctorStatement->traverse(*this);
+    }
+    if (decltor->dtorStatement) {
+      decltor->dtorStatement->traverse(*this);
+    }
+  }
+
+  helper.visitDeclarator0(decltor);
+
+  return true;
+}
+
+
+// looks like we have to look here as well for typedef variables of
+// class templates
+bool LoweredASTVisitor::visitTypeSpecifier(TypeSpecifier *spec)
+{
+  loc = spec->loc;
+
+  if (spec->isTS_classSpec()) {
+    return subvisitTS_classSpec(spec->asTS_classSpec());
+  }
+
+  return DelegatorASTVisitor::visitTypeSpecifier(spec);
+}
+
+
+bool LoweredASTVisitor::subvisitTS_classSpec(TS_classSpec *spec)
+{
+  // ensure idempotency of templatized AST
+  if (visitedAST(spec)) {
+    return false;
+  }
+  if (!DelegatorASTVisitor::visitTypeSpecifier(spec)) return false;
+  helper.visitTypeSpecifier0(spec);
+  return true;
+}
+
+
+bool LoweredASTVisitor::visitTemplateDeclaration(TemplateDeclaration *templDecl)
+{
+  templDecl->traverse(helper);
+  // PRUNE the walk since we start another one with the helper
+  //
+  // dsw: FIX: I don't know what the semantics should be if the client
+  // has a visitTemplateDeclaration().  It seems to be a contradiction
+  // if they do, as they want the lowered AST and that would not
+  // contain uninstantiated templates.  I could call it anyway, but
+  // what if it returns true?  What if they for some bizare reason
+  // want to not prune at a TemplateDeclaration and are telling me
+  // that by returning true?  Well, this is what we get if they simply
+  // don't have any visitTemplateDeclaration() at all and we get the
+  // default from the superclass.  There is no way to tell those two
+  // situations apart and I want to prune it by default.
+  return false;
+}
+
+
+bool LoweredASTVisitor::visitFunction(Function *func)
+{
+  // ensure idempotency of templatized AST
+  if (visitedAST(func)) {
+    return false;
+  }
+
+  // SPECIAL CASE: due to the way that member functions of template
+  // classes are handled, sometimes Functions exist that have not been
+  // tchecked; avoid them
+  if (func->instButNotTchecked()) {
+    return false;
+  }
+
+  if (!DelegatorASTVisitor::visitFunction(func)) return false;
+
+  if (visitElaboratedAST) {
+    if (func->dtorStatement) {
+      func->dtorStatement->traverse(*this);
+    }
+  }
+
+  return true;
+}
+
+
+bool LoweredASTVisitor::visitMemberInit(MemberInit *mInit)
+{
+  if (!DelegatorASTVisitor::visitMemberInit(mInit)) return false;
+
+  if (visitElaboratedAST) {
+    if (mInit->hasAnnot()) {
+      mInit->getAnnot()->traverse(*this);
+    }
+    if (mInit->ctorStatement) {
+      mInit->ctorStatement->traverse(*this);
+    }
+  }
+
+  return true;
+}
+
+
+bool LoweredASTVisitor::visitStatement(Statement *stmt)
+{
+  loc = stmt->loc;
+
+  if (!DelegatorASTVisitor::visitStatement(stmt)) return false;
+
+  if (visitElaboratedAST) {
+    if (stmt->isS_return()) {
+      if (stmt->asS_return()->ctorStatement) {
+        stmt->asS_return()->ctorStatement->traverse(*this);
+      }
+    }
+  }
+
+  return true;
+}
+
+
+bool LoweredASTVisitor::visitExpression(Expression *expr)
+{
+  if (!DelegatorASTVisitor::visitExpression(expr)) return false;
+
+  if (visitElaboratedAST) {
+    if (expr->isE_new()) {
+      if (expr->asE_new()->ctorStatement) {
+        expr->asE_new()->ctorStatement->traverse(*this);
+      }
+    } else if (expr->isE_delete()) {
+      if (expr->asE_delete()->dtorStatement) {
+        expr->asE_delete()->dtorStatement->traverse(*this);
+      }
+    } else if (expr->isE_throw()) {
+      if (expr->asE_throw()->globalCtorStatement) {
+        expr->asE_throw()->globalCtorStatement->traverse(*this);
+      }
+    } else if (expr->isE_funCall()) {
+      if (expr->asE_funCall()->retObj) {
+        expr->asE_funCall()->retObj->traverse(*this);
+      }
+    } else if (expr->isE_constructor()) {
+      if (expr->asE_constructor()->retObj) {
+        expr->asE_constructor()->retObj->traverse(*this);
+      }
+    }
+  }
+
+  return true;
+}
+
+
+bool LoweredASTVisitor::visitHandler(Handler *handler)
+{
+  if (!DelegatorASTVisitor::visitHandler(handler)) return false;
+
+  if (visitElaboratedAST) {
+    if (handler->hasAnnot()) {
+      handler->getAnnot()->traverse(*this);
+    }
+    if (handler->localArg) {
+      handler->localArg->traverse(*this);
+    }
+    if (handler->globalDtorStatement) {
+      handler->globalDtorStatement->traverse(*this);
+    }
+  }
+
+  return true;
+}
+
+
+bool LoweredASTVisitor::visitFullExpression(FullExpression *fexpr)
+{
+  if (!DelegatorASTVisitor::visitFullExpression(fexpr)) return false;
+
+  if (fexpr->hasAnnot()) {
+    fexpr->getAnnot()->traverse(*this);
+  }
+
+  return true;
+}
+
+
+bool LoweredASTVisitor::visitInitializer(Initializer *initializer)
+{
+  loc = initializer->loc;
+
+  if (!DelegatorASTVisitor::visitInitializer(initializer)) return false;
+
+  if (initializer->hasAnnot()) {
+    initializer->getAnnot()->traverse(*this);
+  }
+
+  return true;
+}
+
+
+// not a visitor method; returns true iff the node has been visited
+// before
+bool LoweredASTVisitor::visitedAST(void *ast)
+{
+  if (visitedTemplatizedASTNodes.contains(ast)) {
+    return true;
+  } else {
+    visitedTemplatizedASTNodes.add(ast);
+    return false;
+  }
+}
+
+
+// ---------------------- refersTo ----------------------
+// Nominally "refers to <loc>", but with additional information
+// about "using declaration" aliasing.  This is an example of how
+// the aliasing complicates what used to be a simple process,
+// in this case getting a unique name for an entity.  We'll see
+// how much more of this I can take before I implement some global
+// de-aliasing measure.
+//
+// Now that I'm using Env::storeVar, the AST shouldn't have any
+// alias pointers in it.  But this method remains so I can do things
+// like grepping through printTypedAST output for stray aliases.
+//
+// 1/15/04: Modified to tolerate NULL 'v' values, and to print types,
+// since Daniel and I wanted to see addtional information while
+// debugging a tricky oink/qual issue.  The result is more verbose but
+// the extra information is probably worth it.
+string refersTo(Variable *v)
+{
+  if (!v) {
+    return "NULL";
+  }
+
+  stringBuilder sb;
+  if (v->isNamespace()) {
+    sb << "namespace " << v->name;
+    return sb;
+  }
+
+  sb << v->toString();
+  sb << ", at " << toString(v->loc);
+  if (v->getUsingAlias()) {
+    sb << ", alias of " << toString(v->skipAlias()->loc);
+  }
+  sb << stringf(" (0x%08X)", (long)v);
+  return sb;
+}
+
+
+// TranslationUnit
+
+// ---------------------- TopForm --------------------
+void TopForm::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "TopForm", os, indent);
+}
+
+
+void TopForm::addAmbiguity(TopForm *alt)
+{
+  // this does not call 'genericAddAmbiguity' because TopForms do not
+  // have 'next' fields
+
+  // prepend 'alt' to my list
+  xassert(alt->ambiguity == NULL);
+  alt->ambiguity = ambiguity;
+  ambiguity = alt;
+}
+
+
+// ---------------------- Function --------------------
+void Function::printExtras(ostream &os, int indent) const
+{
+  if (funcType) {
+    ind(os, indent) << "funcType = " << funcType->toString() << "\n";
+  }
+  ind(os, indent) << "receiver = " << refersTo(receiver) << "\n";
+
+  // template with instantiations to print?
+  if (isTemplate()) {
+    TemplateInfo *ti = nameAndParams->var->templateInfo();
+    int ct=0;
+    SFOREACH_OBJLIST(Variable, ti->instantiations, iter) {
+      Variable const *inst = iter.data();
+
+      string label = stringc << "instantiation[" << ct++ << "]: "
+                             << inst->templateInfo()->templateName();
+
+      if (inst->funcDefn) {
+        label = stringc << label << " (defn)";
+        inst->funcDefn->debugPrint(os, indent+2, label.c_str());
+      }
+      else {
+        ind(os, indent+2) << label << " (decl) = " << inst->toString() << "\n";
+      }
+    }
+  }
+}
+
+
+SourceLoc Function::getLoc() const
+{
+  return nameAndParams->getLoc();
+}
+
+
+Function *Function::shallowClone() const
+{
+  Function *ret = new Function(
+    dflags,
+    retspec? retspec->clone() : NULL,
+    nameAndParams? nameAndParams->clone() : NULL,
+
+    // leave the init/body/handlers empty
+    NULL, NULL, NULL
+  );
+
+  ret->cloneThunkSource = this;
+
+  return ret;
+}
+
+void Function::finishClone()
+{
+  if (cloneThunkSource) {
+    // follow the chain of thunk sources (in/t0258.cc)
+    Function const *src = cloneThunkSource;
+    while (src->cloneThunkSource) {
+      src = src->cloneThunkSource;
+    }
+
+    inits = cloneFakeList(src->inits);
+    body = src->body->clone();
+    handlers = cloneFakeList(src->handlers);
+
+    cloneThunkSource = NULL;
+  }
+}
+
+
+bool Function::isTemplate() const
+{
+  if (nameAndParams->var) {
+    TemplateInfo *ti = nameAndParams->var->templateInfo();
+    if (ti && ti->isPrimary()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// ---------------------- MemberInit ----------------------
+void MemberInit::printExtras(ostream &os, int indent) const
+{
+  if (member) {
+    ind(os, indent) << "member: " << refersTo(member) << "\n";
+  }
+
+  if (base) {
+    ind(os, indent) << "base: " << base->toString() << "\n";
+  }
+
+  if (ctorVar) {
+    ind(os, indent) << "ctorVar: " << refersTo(ctorVar) << "\n";
+  }
+}
+
+
+// Declaration
+
+// ---------------------- ASTTypeId -----------------------
+void ASTTypeId::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "ASTTypeId", os, indent);
+
+  genericCheckNexts(this);
+}
+
+void ASTTypeId::addAmbiguity(ASTTypeId *alt)
+{
+  genericAddAmbiguity(this, alt);
+}
+
+void ASTTypeId::setNext(ASTTypeId *newNext)
+{
+  genericSetNext(this, newNext);
+}
+
+
+// ------------------------ PQName ------------------------
+string targsToString(ObjList<STemplateArgument> const &sargs,
+                     /*fakelist*/TemplateArgument const *targs)
+{
+  // iterate down both lists
+  ObjListIter<STemplateArgument> siter(sargs);
+  TemplateArgument const *titer = targs/*firstC*/;
+
+  if (titer && titer->isTA_templateUsed()) {
+    titer = titer->next;
+  }
+
+  stringBuilder sb;
+  sb << "<";
+  int ct=0;
+
+  while (titer) {
+    if (ct++ > 0) {
+      sb << ", ";
+    }
+
+    if (!siter.isDone()) {
+      // use 'siter'
+      sb << siter.data()->toString();
+      siter.adv();
+    }
+    else {
+      // use 'titer'
+      sb << titer->argString();
+    }
+
+    titer = titer->next;
+  }
+
+  sb << ">";
+  return sb;
+}
+
+
+string PQName::qualifierString() const
+{
+  stringBuilder sb;
+
+  PQName const *p = this;
+  while (p->isPQ_qualifier()) {
+    PQ_qualifier const *q = p->asPQ_qualifierC();
+    sb << q->toComponentString() << "::";
+
+    p = q->rest;
+  }
+  return sb;
+}
+
+stringBuilder& operator<< (stringBuilder &sb, PQName const &obj)
+{
+  sb << obj.toString();
+  return sb;
+}
+
+string PQName::toString() const
+{
+  return stringc << qualifierString()
+                 << getUnqualifiedNameC()->toComponentString();
+}
+
+string PQName::toString_noTemplArgs() const
+{
+  return stringc << qualifierString() << getName();
+}
+
+
+StringRef PQ_qualifier::getName() const
+{
+  return rest->getName();
+}
+
+StringRef PQ_name::getName() const
+{
+  return name;
+}
+
+StringRef PQ_operator::getName() const
+{
+  return fakeName;
+}
+
+StringRef PQ_template::getName() const
+{
+  return name;
+}
+
+
+string PQ_qualifier::toComponentString() const
+{
+  if (templArgs/*isNotEmpty*/) {
+    return stringc << qualifier << targsToString(sargs, templArgs);
+  }
+  else if (qualifier) {
+    return qualifier;
+  }
+  else {
+    // for a NULL qualifier, don't print anything; it means
+    // there was a leading "::" with no explicit qualifier,
+    // and I'll use similar syntax on output
+    return "";
+  }
+}
+
+string PQ_name::toComponentString() const
+{
+  return name;
+}
+
+string PQ_operator::toComponentString() const
+{
+  return fakeName;
+}
+
+string PQ_template::toComponentString() const
+{
+  return stringc << name << targsToString(sargs, templArgs);
+}
+
+
+PQName const *PQName::getUnqualifiedNameC() const
+{
+  PQName const *p = this;
+  while (p->isPQ_qualifier()) {
+    p = p->asPQ_qualifierC()->rest;
+  }
+  return p;
+}
+
+
+bool PQName::templateUsed() const
+{
+  if (isPQ_qualifier() &&
+      asPQ_qualifierC()->templArgs/*->isNotEmpty()*/ &&
+      asPQ_qualifierC()->templArgs/*->firstC()*/->isTA_templateUsed()) {
+    return true;
+  }
+
+  if (isPQ_template() &&
+      asPQ_templateC()->templArgs/*->isNotEmpty()*/ &&
+      asPQ_templateC()->templArgs/*->firstC()*/->isTA_templateUsed()) {
+    return true;
+  }
+
+  return false;
+}
+
+
+// The setup is that 'this' and 'obj' are pointers to chains of
+// ambiguous PQNames.  Each chain consists of an initial sequence
+// of PQ_qualifiers, then (optionally) a final PQ_template.  Each
+// list is of nonzero length (neither is NULL), and there can be
+// at most one PQ_template among both lists.  So the situation
+// looks something like this:
+//
+//            +--------------+   +--------------+   +-------------+
+//     this-->| PQ_qualifier |-->| PQ_qualifier |-->| PQ_template |
+//            +--------------+   +--------------+   +-------------+
+//
+//            +--------------+   +--------------+
+//      obj-->| PQ_qualifier |-->| PQ_qualifier |-->NULL
+//            +--------------+   +--------------+
+//                                     ^
+//                                     |
+//                                    tail (assigned below)
+//
+// The return value is the head of a single unified list.  If there
+// was a PQ_template, it of course goes at the end of the returned
+// list.
+PQName *PQName::mergeAmbiguous(PQName *obj)
+{
+  if (this->isPQ_qualifier()) {
+    PQ_qualifier *thisq = this->asPQ_qualifier();
+
+    if (obj->isPQ_qualifier()) {
+      PQ_qualifier *objq = obj->asPQ_qualifier();
+      PQName *tail = objq->ambiguity;
+
+      // insert 'objq' into 'thisq' ambiguity list
+      objq->ambiguity = thisq->ambiguity;
+      thisq->ambiguity = objq;
+
+      if (tail) {
+        // merge with the tail
+        return thisq->mergeAmbiguous(tail);
+      }
+      else {
+        // done
+        return thisq;
+      }
+    }
+
+    if (thisq->ambiguity) {
+      // push 'obj' further down
+      thisq->ambiguity = thisq->ambiguity->mergeAmbiguous(obj);
+      return thisq;
+    }
+    else {
+      // attach 'obj' here
+      xassert(obj->isPQ_template());
+      thisq->ambiguity = obj;
+      return thisq;
+    }
+  }
+
+  // reverse the roles
+  xassert(obj->isPQ_qualifier());
+  return obj->mergeAmbiguous(this);
+}
+
+
+void PQ_qualifier::printAmbiguities(ostream &os, int indent) const
+{
+  PQName const *n = this;
+  genericPrintAmbiguities(n, "PQName", os, indent);
+}
+
+
+PQName *getAmbiguity(PQName const *n)
+{
+  if (n->isPQ_qualifier()) {
+    return n->asPQ_qualifierC()->ambiguity;
+  }
+  else {
+    return NULL;
+  }
+}
+
+void setAmbiguity(PQName *n, PQName *newAmbig)
+{
+  if (n->isPQ_qualifier()) {
+    n->asPQ_qualifier()->ambiguity = newAmbig;
+  }
+  else {
+    // the 'ambiguity' link is always fixed at NULL
+    xassert(newAmbig == NULL);
+  }
+}
+
+
+//  ------------------- TypeSpecifier ---------------------
+void TypeSpecifier::printExtras(ostream &os, int indent) const
+{
+  // used to do something, now just a placeholder (could be deleted)
+}
+
+
+// disambiguation for cppstd 14.1 para 3
+bool TypeSpecifier::canBeTypeParam() const
+{
+  if (isTS_elaborated() &&
+      asTS_elaboratedC()->keyword == TI_CLASS) {
+    return true;
+  }
+
+  // quarl 2006-06-06
+  //    cppstd 14.1 para 2 "typename followed by a qualified-name denotes the
+  //    type in a non-type parameter-declaration."  If the specifier is
+  //    qualified, then "typename" is not used as a type param.
+  if (isTS_name() &&
+      asTS_nameC()->typenameUsed &&
+      !asTS_nameC()->name->hasQualifiers())
+  {
+    return true;
+  }
+
+  return false;
+}
+
+
+void TS_classSpec::printExtras(ostream &os, int indent) const
+{
+  // template with instantiations to print?
+  if (ctype) {
+    TemplateInfo *ti = ctype->templateInfo();
+    if (ti && (ti->isPrimary() || ti->isPartialSpec())) {
+      ind(os, indent) << "instantiations:\n";
+      int ct=0;
+      SFOREACH_OBJLIST(Variable, ti->instantiations, iter) {
+        string label = stringc << "instantiation[" << ct++ << "] ";
+
+        CompoundType *instCT = iter.data()->type->asCompoundType();
+        if (instCT->syntax) {
+          label = stringc << label << "(defn) " << instCT->instName;
+          instCT->syntax->debugPrint(os, indent+2, label.c_str());
+        }
+        else {
+          ind(os, indent+2) << label << "(decl) = " << instCT->instName << "\n";
+        }
+      }
+    }
+  }
+}
+
+
+// ------------------- BaseClassSpec ---------------------
+void BaseClassSpec::printExtras(ostream &os, int indent) const
+{
+  if (type) {
+    ind(os, indent) << "type: " << type->toString() << "\n";
+  }
+}
+
+
+// MemberList
+// Member
+
+// ---------------------- Enumerator ------------------
+void Enumerator::printExtras(ostream &os, int indent) const
+{
+  if (var) {
+    ind(os, indent) << "var: "
+      << toString(var->flags) << (var->flags? " " : "")
+      << var->toString() << "\n";
+    PRINT_GENERIC(enumValue);
+  }
+}
+
+
+// ---------------------- Declarator ---------------------------
+void Declarator::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "Declarator", os, indent);
+
+  // check 'next' fields
+  for (Declarator *d = ambiguity; d != NULL; d = d->ambiguity) {
+    xassert(this->next == d->next);
+  }
+}
+
+
+void Declarator::addAmbiguity(Declarator *alt)
+{
+  genericAddAmbiguity(this, alt);
+}
+
+void Declarator::setNext(Declarator *newNext)
+{
+  genericSetNext(this, newNext);
+}
+
+
+PQName const *Declarator::getDeclaratorIdC() const
+{
+  return decl->getDeclaratorIdC();
+}
+
+
+void Declarator::setDeclaratorId(PQName *n)
+{
+  IDeclarator *d = decl;
+  for(;;) {
+    IDeclarator *b = d->getBase();
+    if (!b) {
+      break;
+    }
+    d = b;
+  }
+
+  if (d->isD_name()) {
+    d->asD_name()->name = n;
+  }
+  else if (d->isD_bitfield()) {
+    d->asD_bitfield()->name = n;
+  }
+  else {
+    // getBase loop should only have stopped at D_name or D_bitfield
+    xfailure("setting name of unknown base IDeclarator");
+  }
+}
+
+
+SourceLoc Declarator::getLoc() const
+{
+  return decl->loc;
+}
+
+
+void Declarator::printExtras(ostream &os, int indent) const
+{
+  if (var) {
+    ind(os, indent) << "var: "
+      << toString(var->flags) << (var->flags? " " : "")
+      << var->toString();
+
+    if (var->overload) {
+      int n = var->overload->count();
+      os << " (" << n << " " << plural(n, "overloading") << ")";
+    }
+
+    os << "\n";
+  }
+
+  ind(os, indent) << "context = " << toString(context) << "\n";
+}
+
+
+// --------------------- IDeclarator ---------------------------
+PQName const *D_name::getDeclaratorIdC() const
+{
+  return name;
+}
+
+PQName const *D_pointer::getDeclaratorIdC() const
+{
+  return base->getDeclaratorIdC();
+}
+
+PQName const *D_reference::getDeclaratorIdC() const
+{
+  return base->getDeclaratorIdC();
+}
+
+PQName const *D_func::getDeclaratorIdC() const
+{
+  return base->getDeclaratorIdC();
+}
+
+PQName const *D_array::getDeclaratorIdC() const
+{
+  return base->getDeclaratorIdC();
+}
+
+PQName const *D_bitfield::getDeclaratorIdC() const
+{
+  // the ability to simply return 'name' here is why bitfields contain
+  // a PQName instead of just a StringRef
+  return name;
+}
+
+PQName const *D_ptrToMember::getDeclaratorIdC() const
+{
+  return base->getDeclaratorIdC();
+}
+
+PQName const *D_grouping::getDeclaratorIdC() const
+{
+  return base->getDeclaratorIdC();
+}
+
+
+IDeclarator *IDeclarator::skipGroups()
+{
+  if (isD_grouping()) {
+    return asD_grouping()->base->skipGroups();
+  }
+  else {
+    return this;
+  }
+}
+
+
+bool IDeclarator::bottomIsDfunc() const
+{
+  IDeclarator const *d = this;
+  IDeclarator const *prev = d;     // last non-D_name, non-D_grouping declarator seen
+
+  for (;;) {
+    IDeclarator const *next = d->getBaseC();
+    if (!next) {
+      break;
+    }
+
+    if (!d->isD_grouping()) {
+      prev = d;
+    }
+    d = next;
+  }
+
+  return prev->isD_func();
+}
+
+
+IDeclarator const *D_name::getBaseC() const            { return NULL; }
+IDeclarator const *D_pointer::getBaseC() const         { return base; }
+IDeclarator const *D_reference::getBaseC() const       { return base; }
+IDeclarator const *D_func::getBaseC() const            { return base; }
+IDeclarator const *D_array::getBaseC() const           { return base; }
+IDeclarator const *D_bitfield::getBaseC() const        { return NULL; }
+IDeclarator const *D_ptrToMember::getBaseC() const     { return base; }
+IDeclarator const *D_grouping::getBaseC() const        { return base; }
+
+
+// ExceptionSpec
+// OperatorDeclarator
+
+// ---------------------- Statement --------------------
+void Statement::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "Statement", os, indent);
+}
+
+
+void Statement::addAmbiguity(Statement *alt)
+{
+  // this does not call 'genericAddAmbiguity' because Statements
+  // do not have 'next' fields
+
+  // prepend 'alt' to my list
+  xassert(alt->ambiguity == NULL);
+  alt->ambiguity = ambiguity;
+  ambiguity = alt;
+}
+
+
+string Statement::lineColString() const
+{
+  char const *fname;
+  int line, col;
+  sourceLocManager->decodeLineCol(loc, fname, line, col);
+
+  return stringc << line << ":" << col;
+}
+
+string Statement::kindLocString() const
+{
+  return stringc << kindName() << "@" << lineColString();
+}
+
+
+// ----------------------- Condition ----------------------
+void Condition::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "Condition", os, indent);
+}
+
+
+void Condition::addAmbiguity(Condition *alt)
+{
+  // this does not call 'genericAddAmbiguity' because Conditions
+  // do not have 'next' fields
+
+  // prepend 'alt' to my list
+  xassert(alt->ambiguity == NULL);
+  alt->ambiguity = ambiguity;
+  ambiguity = alt;
+}
+
+
+// ----------------------- Handler ----------------------
+bool Handler::isEllipsis() const
+{
+  return typeId->spec->isTS_simple() &&
+         typeId->spec->asTS_simple()->id == ST_ELLIPSIS;
+}
+
+
+// --------------------- Expression ---------------------
+void Expression::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "Expression", os, indent);
+
+  // old
+  //genericCheckNexts(this);
+}
+
+
+void Expression::addAmbiguity(Expression *alt)
+{
+  // it turns out the RHS could have been yielded if the
+  // reduction action is the identity function.. so instead
+  // find the last node in the 'alt' list and we'll splice
+  // that entire list into 'main's ambiguity list
+  Expression *altLast = alt;
+  while (altLast->ambiguity) {
+    altLast = altLast->ambiguity;
+  }
+
+  // finally, prepend 'alt's ambiguity list to 'this's ambiguity list
+  altLast->ambiguity = this->ambiguity;
+  this->ambiguity = alt;
+
+  #if 0     // old; from when I had lists of Expressions
+  genericAddAmbiguity(this, alt);
+  #endif // 0
+}
+
+#if 0     // old; from when I had lists of Expressions
+void Expression::setNext(Expression *newNext)
+{
+  // relaxation: The syntax
+  //   tok = strtok(((void *)0) , delim);
+  // provokes a double-add, where 'next' is the same both
+  // times.  I think this is because we merge a little
+  // later than usual due to unexpected state splitting.
+  // I might try to investigate this more carefully at a
+  // later time, but for now..
+  if (next == newNext) {
+    return;    // bail if it's already what we want..
+  }
+
+  genericSetNext(this, newNext);
+}
+#endif // 0
+
+
+void Expression::printExtras(ostream &os, int indent) const
+{
+  if (type) {
+    ind(os, indent) << "type: " << type->toString() << "\n";
+  }
+
+  // print type-specific extras
+  ASTSWITCHC(Expression, this) {
+    ASTCASEC(E_intLit, i) {
+      ind(os, indent) << "i: " << i->i << "\n";
+    }
+
+    ASTNEXTC(E_floatLit, f) {
+      ind(os, indent) << "f: " << f->d << "\n";
+    }
+
+    ASTNEXTC(E_stringLit, s) {
+      // nothing extra to print since there's no interpretation yet
+      PRETEND_USED(s);
+    }
+
+    ASTNEXTC(E_charLit, c) {
+      ind(os, indent) << "c: " << c->c << "\n";    // prints as an integer
+    }
+
+    ASTNEXTC(E_variable, v)
+      ind(os, indent) << "var: " << refersTo(v->var) << "\n";
+
+    ASTNEXTC(E_constructor, c)
+      ind(os, indent) << "ctorVar: " << refersTo(c->ctorVar) << "\n";
+
+    ASTNEXTC(E_new, n)
+      PRINT_SUBTREE(n->arraySize);
+
+    ASTNEXTC(E_fieldAcc, f)
+      ind(os, indent) << "field: " << refersTo(f->field) << "\n";
+
+    ASTDEFAULTC
+      /* do nothing */
+
+    ASTENDCASEC
+  }
+}
+
+
+bool Expression::isBinary(BinaryOp op) const
+{
+  return isE_binary() &&
+         asE_binaryC()->op == op;
+}
+
+
+// remove layers of parens: keep going down until the expression is
+// not an E_grouping and return that
+Expression *Expression::skipGroups()
+{
+  return const_cast<Expression*>(skipGroupsC());
+}
+
+Expression const *Expression::skipGroupsC() const
+{
+  Expression const *ret = this;
+  while (ret->isE_grouping()) {
+    ret = ret->asE_groupingC()->expr;
+  }
+  return ret;
+}
+
+
+// FullExpression
+
+// ------------------- ArgExpression -------------------------
+void ArgExpression::setNext(ArgExpression *newNext)
+{
+  xassert(next == NULL);
+  next = newNext;
+}
+
+
+void ArgExpression::addAmbiguity(ArgExpression *alt)
+{
+  // find the end of alt's ambiguity list
+  ArgExpression *altLast = alt;
+  while (altLast->ambiguity) {
+    altLast = altLast->ambiguity;
+  }
+
+  // finally, prepend 'alt's ambiguity list to 'this's ambiguity list
+  altLast->ambiguity = this->ambiguity;
+  this->ambiguity = alt;
+}
+
+
+void ArgExpression::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "ArgExpression", os, indent);
+}
+
+
+// ExpressionListOpt
+// Initializer
+// InitLabel
+// TemplateDeclaration
+
+// -------------------- TemplateParameter ---------------------
+bool anyHaveDefaultArgs(TemplateParameter const *list)
+{
+  for (TemplateParameter const *iter = list; iter; iter = iter->next) {
+    if (iter->hasDefaultArg()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+bool TP_type::hasDefaultArg() const
+{
+  return !!defaultType;
+}
+
+bool TP_nontype::hasDefaultArg() const
+{
+  return !!param->decl->init;
+}
+
+
+void TemplateParameter::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "TemplateParameter", os, indent);
+}
+
+
+void TemplateParameter::addAmbiguity(TemplateParameter *alt)
+{
+  xassert(alt->ambiguity == NULL);
+  alt->ambiguity = this->ambiguity;
+  this->ambiguity = alt;
+}
+
+
+// -------------------- TemplateArgument ---------------------
+void TemplateArgument::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "TemplateArgument", os, indent);
+}
+
+
+void TemplateArgument::addAmbiguity(TemplateArgument *alt)
+{
+  xassert(alt->ambiguity == NULL);
+  alt->ambiguity = this->ambiguity;
+  this->ambiguity = alt;
+}
+
+
+string TA_type::argString() const
+{
+  return "(un-tchecked-TA_type)";
+}
+
+string TA_nontype::argString() const
+{
+  return expr->exprToString();
+}
+
+string TA_templateUsed::argString() const
+{
+  // this should not show up in, e.g., error messages, because
+  // it's just a communication device between the parser and
+  // the tchecker
+  return "(templateUsed)";
+}
+
+
+// ----------------- RealVarAndTypeASTVisitor ----------------
+
+void RealVarAndTypeASTVisitor::visitVariable(Variable *var) {
+  if (variableVisitor) variableVisitor->visitVariable(var);
+}
+
+void RealVarAndTypeASTVisitor::visitType(Type *type) {
+  if (typeVisitor) typeVisitor->visitType(type);
+}
+
+
+// **** visit methods
+
+// class BaseClassSpec {
+//   public(xml_TY) CompoundType *type = NULL;
+// }
+
+bool RealVarAndTypeASTVisitor::visitTranslationUnit(TranslationUnit *obj) {
+  typeVisitor->visitScope(obj->globalScope);
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitFunction(Function *obj) {
+  visitVariable(obj->retVar);
+  visitVariable(obj->receiver);
+  visitType(obj->funcType);
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitPQName(PQName *obj) {
+  if (obj->isPQ_variable()) {
+    visitVariable(obj->asPQ_variable()->var);
+  }
+//   else if (obj->isPQ_qualifier()) {
+    // dsw: Ok, it seems that this is supposed to sometimes be a
+    // template even for an instantiated instance (in/t0057.cc).  Is
+    // it possible for this variable to 1) not be a template primary
+    // and 2) also not get visited somehow else?
+//     visitVariable(obj->asPQ_qualifier()->qualifierVar);
+//   }
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitHandler(Handler *obj) {
+  visitVariable(obj->globalVar);
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitExpression(Expression *obj) {
+  if (obj->isE_new()) {
+    E_new *enew = obj->asE_new();
+    visitVariable(enew->heapVar);
+    visitVariable(enew->ctorVar);
+  } else if (obj->isE_throw()) {
+    visitVariable(obj->asE_throw()->globalVar);
+  } else if (obj->isE_this()) {
+    visitVariable(obj->asE_this()->receiver);
+  } else if (obj->isE_variable()) {
+    E_variable *evar = obj->asE_variable();
+    visitVariable(evar->var);
+    visitVariable(evar->nondependentVar);
+  } else if (obj->isE_constructor()) {
+    visitVariable(obj->asE_constructor()->ctorVar);
+  } else if (obj->isE_fieldAcc()) {
+    visitVariable(obj->asE_fieldAcc()->field);
+  }
+  visitType(obj->type);
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitMemberInit(MemberInit *obj) {
+  visitVariable(obj->member);
+  visitVariable(obj->ctorVar);
+//   public(xml_TY) CompoundType *base = NULL;
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitTypeSpecifier(TypeSpecifier *obj) {
+  if (obj->isTS_name()) {
+    TS_name *tsn = obj->asTS_name();
+    visitVariable(tsn->var);
+    visitVariable(tsn->nondependentVar);
+  }
+  if (obj->isTS_type()) {
+    visitType(obj->asTS_type()->type);
+  }
+//   -> TS_elaborated {
+//        public(xml_TY) NamedAtomicType *atype = NULL;
+//      }
+//   -> TS_classSpec {
+//        public(xml_TY) CompoundType *ctype = NULL;
+//      }
+//   -> TS_enumSpec {
+//        public(xml_TY) EnumType *etype = NULL;
+//      }
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitEnumerator(Enumerator *obj) {
+  visitVariable(obj->var);
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitDeclarator(Declarator *obj) {
+  visitVariable(obj->var);
+  visitType(obj->type);
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitInitializer(Initializer *obj) {
+  if (obj->isIN_ctor()) {
+    visitVariable(obj->asIN_ctor()->ctorVar);
+  }
+  return true;
+}
+
+bool RealVarAndTypeASTVisitor::visitTemplateParameter(TemplateParameter *obj) {
+  // this one is a bit outlandish as the whole point is to avoid
+  // templates, so it should probably never be called
+  visitVariable(obj->var);
+  return true;
+}
+
+#ifdef GNU_EXTENSION
+bool RealVarAndTypeASTVisitor::visitASTTypeof(ASTTypeof *obj) {
+  visitType(obj->type);
+  return true;
+}
+#endif // GNU_EXTENSION
+
+// ---------------- ReachableVarsTypeVisitor --------------
+
+bool ReachableVarsTypePred::operator() (Type const *t0) {
+  Type *t = const_cast<Type *>(t0);
+  if (t->isFunctionType()) {
+    // visit the function param variables
+    SFOREACH_OBJLIST_NC(Variable, t->asFunctionType()->params, iter) {
+      variableVisitor.visitVariable(iter.data());
+    }
+  } else if (t->isCompoundType()) {
+    typeVisitor.visitCompoundType(t->asCompoundType());
+  }
+  return false;                 // dummy value; just means keep searching
+}
+
+void ReachableVarsTypeVisitor::visitType(Type *type) {
+  if (!type) return;
+  if (seenTypes.contains(type)) return;
+  seenTypes.add(type);
+  visitTypeIdem(type);
+  ReachableVarsTypePred tPred(*variableVisitor
+                              , *this
+//                               , seenCpdTypes
+                              );
+  bool sat = type->anyCtorSatisfies(tPred);
+  xassert(!sat);                // the point was just to visit anyway
+}
+
+void ReachableVarsTypeVisitor::visitCompoundType(CompoundType *ct) {
+  variableVisitor->visitVariable(ct->typedefVar);
+  visitScope(ct);
+  for(StringRefMap<Variable>::Iter iter(ct->getVariableIter()); !iter.isDone(); iter.adv()) {
+    Variable *v = iter.value();
+    if (v->templateInfo() && !v->templateInfo()->isInstantiation()) continue;
+    variableVisitor->visitVariable(v);
+  }
+  for(StringRefMap<Variable>::Iter iter(ct->getTypeTagIter()); !iter.isDone(); iter.adv()) {
+    Variable *v = iter.value();
+    if (v->templateInfo() && !v->templateInfo()->isInstantiation()) continue;
+    variableVisitor->visitVariable(v);
+  }
+  FOREACH_OBJLIST(BaseClass, ct->bases, iter) {
+    visitCompoundType(iter.data()->ct);
+  }
+  SFOREACH_OBJLIST_NC(Variable, ct->conversionOperators, iter) {
+    Variable *v = iter.data();
+    if (v->templateInfo() && !v->templateInfo()->isInstantiation()) continue;
+    variableVisitor->visitVariable(v);
+  }
+  visitType(ct->selfType);
+}
+
+void ReachableVarsTypeVisitor::visitScope(Scope *scope) {
+  if (!scope) return;
+  // See comment at the declaration of seenScopes.
+  if (seenScopes.contains(scope)) return;
+  seenScopes.add(scope);
+  variableVisitor->visitVariable(scope->namespaceVar);
+  // FIX: If this type is a CompoundType, I think it will get visited
+  // as a Type by the type visitor at some point
+  visitScope(scope->parentScope);
+}
+
+bool ReachableVarsVariableVisitor::shouldVisitVariable(Variable *var) {
+  return true;
+}
+
+void ReachableVarsVariableVisitor::visitVariable(Variable *var) {
+  if (!var) return;
+  if (seenVariables.contains(var)) return;
+  seenVariables.add(var);
+  xassert(!var->isTemplate() && "ee42ebc5-7154-4ace-be35-c2090a2821c5");
+  xassert(!var->isUninstTemplateMember());
+  if (shouldVisitVariable(var)) visitVariableIdem(var);
+  typeVisitor->visitType(var->type);
+  typeVisitor->visitScope(var->scope);
+}
+
+void VisitRealVars::visitVariableIdem(Variable *var) {
+  xassert(var->getReal());     // if this visit is idempotent, this should always be false
+  if (visitVarFunc) visitVarFunc(var);
+}
+
+void MarkRealVars::visitVariableIdem(Variable *var) {
+  xassert(!var->getReal());     // if this visit is idempotent, this should always be false
+  var->setReal(true);
+}
+
+void visitVarsF(ArrayStack<Variable*> &builtinVars, VisitRealVars &visitReal) {
+  FOREACH_ARRAYSTACK_NC(Variable*, builtinVars, iter) {
+    Variable *var = *iter.data();
+    visitReal.visitVariable(var);
+  }
+}
+
+void visitVarsMarkedRealF(ArrayStack<Variable*> &builtinVars, VisitRealVars &visitReal) {
+  FOREACH_ARRAYSTACK_NC(Variable*, builtinVars, iter) {
+    Variable *var = *iter.data();
+    if (!var->getReal()) continue;
+    visitReal.visitVariable(var);
+  }
+}
+
+void visitRealVarsF(TranslationUnit *tunit, VisitRealVars &visitReal) {
+  RealVarAndTypeASTVisitor vis(&visitReal, &visitReal.doNothing_tv);
+  tunit->traverse(vis.loweredVisitor);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/cc_ast_aux.h
===================================================================
--- vendor/elsa/current/elsa/cc_ast_aux.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_ast_aux.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,356 @@
+// cc_ast_aux.h
+// dsw: stuff I would like to put into cc.ast but I can't
+
+#ifndef CC_AST_AUX_H
+#define CC_AST_AUX_H
+
+#include "sobjset.h"            // class SObjSet
+#include "macros.h"             // ENUM_BITWISE_OPS
+#include "cc_ast.h"             // ASTVisitor
+
+// Note that LoweredASTVisitor and LoweredASTVisitorHelper work
+// closely together
+
+// I can't put LoweredASTVisitor and LoweredASTVisitorHelper into
+// cc.ast because the class I inherit from, ASTVisitor, is generated
+// at the end of cc.ast.gen.h
+
+// forward
+class LoweredASTVisitor;
+
+// this class helps LoweredASTVisitor turn off visitation during
+// uninstantiated templated bodies
+class LoweredASTVisitorHelper : public ASTVisitor {
+private:     // data
+  LoweredASTVisitor &loweredVisitor;
+
+  // also visit template definitions of primaries and partials
+  bool primariesAndPartials;
+
+  // set of the (primary) TemplateInfo objects the instantiations of
+  // which we have visited; prevents us from visiting them twice
+  SObjSet<TemplateInfo *> primaryTemplateInfos;
+
+public:      // funcs
+  LoweredASTVisitorHelper(LoweredASTVisitor &loweredVisitor0,
+                          bool primariesAndPartials0)
+    : loweredVisitor(loweredVisitor0)
+    , primariesAndPartials(primariesAndPartials0)
+  {}
+
+  virtual bool visitDeclarator(Declarator *decltor);
+  virtual bool visitTypeSpecifier(TypeSpecifier *spec);
+  virtual bool visitFunction(Function *func);
+
+  virtual bool subvisitTS_classSpec(TS_classSpec *spec);
+
+  void oneTempl(Variable *var0);
+  void oneContainer(Variable *container);
+  void oneVariable(Variable *tinfoVar);
+  void visitDeclarator0(Declarator *decltor);
+  void visitTypeSpecifier0(TypeSpecifier *spec);
+};
+
+
+// there were too many boolean arguments to the LoweredASTVisitor
+// ctor; FIX: make all visitors use these uniformly; FIX: Scott has
+// some scheme to make these work better as flags but I can't find an
+// example just now
+enum VisitorFlags {
+  VF_NONE                    = 0x00,
+  VF_VISIT_ELAB              = 0x01, // visit the elaborated AST field as well
+  VF_VISIT_PRIM_AND_PARTIALS = 0x02, // visit the template primaries and partials as well
+  VF_CHECK_IS_TREE           = 0x04, // check the AST is a tree while we are at it
+
+  VF_ALL                     = 0x07
+};
+ENUM_BITWISE_OPS(VisitorFlags, VF_ALL)
+
+
+// extend the visitor to traverse the lowered AST, which includes
+// additional AST that has bee elaborated into the AST, such as
+// instantiated templates, implicit ctors and dtors, etc.
+class LoweredASTVisitor : public DelegatorASTVisitor {
+private:     // data
+  LoweredASTVisitorHelper helper;
+
+  // track the current source location for the benefit of client
+  // analyses
+  SourceLoc loc;
+
+  // visit elaborated AST fields such as ctorStatement, etc., but
+  // other than instantiated templates
+  bool visitElaboratedAST;
+
+  // FIX: this set for marking visited ast nodes is a rather strange
+  // thing to have here as DelegatorASTVisitor also has one.  This one
+  // is just used to avoid visiting templatized AST twice, which I
+  // think can really legitimately otherwise occur given our template
+  // representation even if the AST is a tree.  The subclasses here
+  // should intercept that duplication and return without calling the
+  // overridden method of superclass which would otherwise fire an
+  // assertion failure.
+  SObjSet<void*> visitedTemplatizedASTNodes;
+
+public:      // funcs
+  LoweredASTVisitor(ASTVisitor *client0,
+                    VisitorFlags flags0 = VF_CHECK_IS_TREE | VF_VISIT_ELAB)
+    : DelegatorASTVisitor(client0, flags0 & VF_CHECK_IS_TREE)
+    , helper(*this, flags0 & VF_VISIT_PRIM_AND_PARTIALS)
+    , loc(SL_UNKNOWN)
+    , visitElaboratedAST(flags0 & VF_VISIT_ELAB)
+  {}
+  virtual ~LoweredASTVisitor() {}
+
+  SourceLoc getLoc() {return loc;}
+
+  // maintain source loc; those commented out occur also below and so
+  // their body is folded in there
+  virtual bool visitTopForm(TopForm *obj);
+  virtual bool visitPQName(PQName *obj);
+  // virtual bool visitTypeSpecifier(TypeSpecifier *obj);
+  virtual bool visitEnumerator(Enumerator *obj);
+  virtual bool visitMember(Member *obj);
+  virtual bool visitIDeclarator(IDeclarator *obj);
+  // virtual bool visitStatement(Statement *obj);
+  // virtual bool visitInitializer(Initializer *obj);
+  virtual bool visitTemplateParameter(TemplateParameter *obj);
+
+  virtual bool visitFullExpressionAnnot(FullExpressionAnnot *fea);
+  virtual bool visitDeclarator(Declarator *decltor);
+  virtual bool visitTypeSpecifier(TypeSpecifier *spec);
+  virtual bool visitTemplateDeclaration(TemplateDeclaration *templDecl);
+  virtual bool visitFunction(Function *func);
+  virtual bool visitMemberInit(MemberInit *mInit);
+  virtual bool visitStatement(Statement *stmt);
+  virtual bool visitExpression(Expression *expr);
+  virtual bool visitHandler(Handler *handler);
+  virtual bool visitFullExpression(FullExpression *fexpr);
+  virtual bool visitInitializer(Initializer *initializer);
+
+  virtual bool subvisitTS_classSpec(TS_classSpec *spec);
+
+  // ensure idempotency of visiting AST
+  bool visitedAST(void *ast);
+};
+
+
+// visitor for checking that the "raw" AST is a tree; note that the
+// ctor arguments given to the parent are the sometime defaults of
+// DelegatorASTVisitor, but we will not rely on that and also make the
+// client code more self documenting by making this separate class
+// here.
+class IsTreeVisitor : public DelegatorASTVisitor {
+public:
+  IsTreeVisitor()
+    : DelegatorASTVisitor(NULL /*client*/, true /*ensureOneVisit*/)
+  {}
+};
+
+
+// visitor for checking that the "raw" AST is a tree *and* the
+// "lowered" AST is a tree; the ensureOneVisit flag of our *parent* is
+// the one that matters for checking that the *lowered* tree is a
+// tree; LoweredASTVisitor inherits from DelegatorASTVisitor which the
+// VF_CHECK_IS_TREE flag below tells to check that the *non*-lowered
+// tree is a tree
+class LoweredIsTreeVisitor : private IsTreeVisitor {
+public:
+  // used at creation site
+  LoweredASTVisitor loweredVisitor;
+
+  LoweredIsTreeVisitor()
+    : loweredVisitor(this /*client*/, VF_VISIT_ELAB | VF_CHECK_IS_TREE)
+  {}
+};
+
+// Visit all the real (not a member of an uninstantiated template)
+// Variables and Types in a TranslationUnit hanging directly off of
+// the AST.
+//
+// The Variables were found by a grep that was not as generous as this
+// one; it found 21 true hits and 4 false hits when I ran this one as
+// a check on the implementation below.
+// grep -n -e '\bVariable[a-zA-Z]*[ ]*\*' *.ast
+//
+// The Types were found by this grep:
+// grep -n -e '\bType[a-zA-Z]*[ ]*\*' *.ast
+class RealVarAndTypeASTVisitor : private ASTVisitor {
+  // types
+  public:
+  class VariableVisitor {
+    public:
+    virtual ~VariableVisitor() {}
+    virtual bool shouldVisitVariable(Variable *var) = 0;
+    virtual void visitVariable(Variable *var) = 0;
+  };
+  class TypeVisitor {
+    public:
+    virtual ~TypeVisitor() {}
+    virtual void visitType(Type *type) = 0;
+    virtual void visitCompoundType(CompoundType *ct) = 0;
+    virtual void visitScope(Scope *scope) = 0;
+  };
+
+  // data
+  public:
+  LoweredASTVisitor loweredVisitor; // use this as the argument for traverse()
+  VariableVisitor *variableVisitor; // callback for vars
+  TypeVisitor *typeVisitor;     // callback for types
+
+  // tor
+  public:
+  explicit RealVarAndTypeASTVisitor(VariableVisitor *variableVisitor0 = NULL)
+    : loweredVisitor(this)
+    , variableVisitor(variableVisitor0)
+    , typeVisitor(NULL)
+  {}
+  explicit RealVarAndTypeASTVisitor(TypeVisitor *typeVisitor0)
+    : loweredVisitor(this)
+    , variableVisitor(NULL)
+    , typeVisitor(typeVisitor0)
+  {}
+  explicit RealVarAndTypeASTVisitor(VariableVisitor *variableVisitor0, TypeVisitor *typeVisitor0)
+    : loweredVisitor(this)
+    , variableVisitor(variableVisitor0)
+    , typeVisitor(typeVisitor0)
+  {}
+  private:
+  RealVarAndTypeASTVisitor(RealVarAndTypeASTVisitor &other); // prohibit
+
+  // methods
+  public:
+  virtual void visitVariable(Variable *var);
+  virtual void visitType(Type *type);
+
+  virtual bool visitTranslationUnit(TranslationUnit *obj);
+  virtual bool visitFunction(Function *obj);
+  virtual bool visitPQName(PQName *obj);
+  virtual bool visitHandler(Handler *obj);
+  virtual bool visitExpression(Expression *obj);
+  virtual bool visitMemberInit(MemberInit *obj);
+  virtual bool visitTypeSpecifier(TypeSpecifier *obj);
+  virtual bool visitEnumerator(Enumerator *obj);
+  virtual bool visitDeclarator(Declarator *obj);
+  virtual bool visitInitializer(Initializer *obj);
+  virtual bool visitTemplateParameter(TemplateParameter *obj);
+#ifdef GNU_EXTENSION
+  virtual bool visitASTTypeof(ASTTypeof *obj);
+#endif // GNU_EXTENSION
+};
+
+class ReachableVarsTypePred : public TypePred {
+  // data
+  RealVarAndTypeASTVisitor::VariableVisitor &variableVisitor;
+  // This is a bit deceptive: it is only for visiting scopes.
+  RealVarAndTypeASTVisitor::TypeVisitor &typeVisitor;
+//   SObjSet<CompoundType*> &seenCpdTypes;
+
+  // tor
+  public:
+  explicit ReachableVarsTypePred
+    (RealVarAndTypeASTVisitor::VariableVisitor &variableVisitor0
+//      , SObjSet<CompoundType*> &seenCpdTypes0
+     , RealVarAndTypeASTVisitor::TypeVisitor &typeVisitor0
+     )
+    : variableVisitor(variableVisitor0)
+    , typeVisitor(typeVisitor0)
+//     , seenCpdTypes(seenCpdTypes0)
+  {}
+  virtual ~ReachableVarsTypePred() {}
+
+  // methods
+  virtual bool operator() (Type const *t);
+};
+
+class ReachableVarsTypeVisitor : public RealVarAndTypeASTVisitor::TypeVisitor {
+  // data
+  public:
+  RealVarAndTypeASTVisitor::VariableVisitor *variableVisitor;
+  SObjSet<Type*> seenTypes;
+  // Careful!  Since CompoundType inherits from Scope, we must use a
+  // different set as the visitation of a CompoundType as a Scope
+  // differs from its visitation as a CompoundType.
+  SObjSet<Scope*> seenScopes;
+//   SObjSet<CompoundType*> seenCpdTypes; // re-used across anyCtorSatisfies visitations
+
+  // tor
+  public:
+  explicit ReachableVarsTypeVisitor(RealVarAndTypeASTVisitor::VariableVisitor *variableVisitor0)
+    : variableVisitor(variableVisitor0)
+  {}
+  virtual ~ReachableVarsTypeVisitor() {}
+
+  // methods
+  virtual void visitType(Type *type);
+  virtual void visitCompoundType(CompoundType *ct);
+  // FIX: should this be in its own visitor?
+  virtual void visitScope(Scope *scope);
+  virtual void visitTypeIdem(Type *type) {}; // only visits each Type once
+};
+
+class ReachableVarsVariableVisitor : public RealVarAndTypeASTVisitor::VariableVisitor {
+  // data
+  public:
+  RealVarAndTypeASTVisitor::TypeVisitor *typeVisitor;
+  SObjSet<Variable*> seenVariables;
+
+  // tor
+  public:
+  explicit ReachableVarsVariableVisitor(RealVarAndTypeASTVisitor::TypeVisitor *typeVisitor0)
+    : typeVisitor(typeVisitor0)
+  {}
+  virtual ~ReachableVarsVariableVisitor() {}
+
+  // methods
+  virtual bool shouldVisitVariable(Variable *var);
+  virtual void visitVariable(Variable *var);
+  virtual void visitVariableIdem(Variable *var) {}; // only visits each Variable once
+};
+
+// visit all the real vars
+class VisitRealVars : public ReachableVarsVariableVisitor {
+  public:
+  // type
+  typedef void visitVarFunc_t(Variable *);
+
+  // data
+  ReachableVarsTypeVisitor doNothing_tv; // a placeholder
+  visitVarFunc_t *visitVarFunc;
+
+  // tor
+  explicit VisitRealVars(visitVarFunc_t *visitVarFunc0)
+    : ReachableVarsVariableVisitor(&doNothing_tv)
+    , doNothing_tv(this)
+    , visitVarFunc(visitVarFunc0)
+  {}
+
+  // methods
+  virtual void visitVariableIdem(Variable *var); // only visits each Variable once
+};
+
+// mark reachable vars as real; NOTE: do NOT make this inherit from
+// VisitRealVars_filter as we want to mark all real vars as real.
+class MarkRealVars : public VisitRealVars {
+  // tor
+  public:
+  explicit MarkRealVars()
+    // instead of supplying a visitVarFunc, we override
+    // visitVariableIdem, hence the NULL here
+    : VisitRealVars(NULL)
+  {}
+  // methods
+  virtual void visitVariableIdem(Variable *var); // only visits each Variable once
+};
+
+// Visit vars (whether real or not)
+void visitVarsF(ArrayStack<Variable*> &builtinVars, VisitRealVars &visitReal);
+
+// Visit vars that have been marked real
+void visitVarsMarkedRealF(ArrayStack<Variable*> &builtinVars, VisitRealVars &visitReal);
+
+// Visit the AST.  This visitation does not depend on real markings and
+// therefore is also used to define real markings.
+void visitRealVarsF(TranslationUnit *tunit, VisitRealVars &visitReal);
+
+#endif // CC_AST_AUX_H

Added: vendor/elsa/current/elsa/cc_elaborate.ast
===================================================================
--- vendor/elsa/current/elsa/cc_elaborate.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_elaborate.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,244 @@
+// cc_elaborate.ast            see license.txt for copyright and terms of use
+// extension to cc.ast defining data for an elaboration pass
+// see also cc_elaborate.h
+
+
+// IMPORTANT: If you add elaboration fields here, then you must also
+// add traverse() calls visiting them in LoweredASTVisitor.
+
+
+verbatim {
+  class ElabVisitor;             // cc_elaborate.h
+  string refersTo(Variable *v);  // cc_ast_aux.cc
+}
+
+
+// Objects with a FullExpressionAnnot have their own scope containing
+// both these declarations and their sub-expressions.  The
+// declarations come semantically before the sub-expression with which
+// this object is associated.
+class FullExpressionAnnot (ASTList<Declaration> declarations) {
+  public bool noTemporaries() const { return declarations.isEmpty(); };
+}
+
+
+class Function {
+  // for EA_ELIM_RETURN_BY_VALUE, this variable is the hidden
+  // parameter bound to the object into which the return value
+  // will be constructed
+  //
+  // NOTE!: If this function is a ctor, then the semantics is as if we
+  // have this line in the code before the MemberInit-s:
+  //   this = &retVar;
+  public(xml_TY,xmlShouldSerialize) Variable *retVar = NULL;
+  custom debugPrint { ind(os,indent) << "retVar: " << refersTo(retVar) << "\n"; }
+
+  // to be called when the function exits; should only be non-NULL for
+  // dtor Functions: it is the superclass and member dtors that are
+  // implicitly called
+  public(field,xml_AST,owner) Statement *dtorStatement = NULL;
+
+  // is this function implicitly defined?  dsw: I need to know so that
+  // the linker imitator doesn't think there is a double-definition
+  // when the same class occurs in two different translation units
+  //
+  // sm: this is now redundant with Variable::isImplicitMemberFunc()
+  public(field,xml) bool implicitlyDefined = false;
+}
+
+
+class PQName {  
+  // denote an existing Variable; avoids having to create syntax
+  -> PQ_variable(Variable *var);
+}
+
+
+class TypeSpecifier {
+  // denote an existing Type
+  -> TS_type(Type *type);
+}
+
+
+class MemberInit {
+  // A single MemberInit seems very much like a single expression to
+  // me, since it is a ctor call and an IN_ctor is also
+  private(xml_AST,owner) FullExpressionAnnot *annot = NULL;
+  public bool hasAnnot();
+  public FullExpressionAnnot *getAnnot();
+
+  // a MemberInit calls a ctor
+  public(field,xml_AST,owner) Statement *ctorStatement = NULL;
+}
+
+
+class Declarator {
+  // each declarator has a construction statement, that does its
+  // initialization, and a destruction statement, that calls any
+  // needed destructors; the latter is to be evaluated when this
+  // declarator goes out of scope
+  public(field,xml_AST,owner) Statement *ctorStatement = NULL;
+  public(field,xml_AST,owner) Statement *dtorStatement = NULL;
+
+  // the 'dflags' are the syntactic declaration flags attached
+  // to the declaration in which this declarator appears
+  public void elaborateCDtors(ElabVisitor &env, DeclFlags dflags = DF_NONE);
+}
+
+
+class IDeclarator {
+  -> D_func {
+//         // elaborate the parameters
+//         public void elaborateParameterCDtors(ElabVisitor &env);
+  }
+}
+
+
+class Statement {
+  -> S_return() {
+    // This is for the copy ctor that is needed when you do a return
+    // by value of a CompoundType.  It always will copy into the
+    // *FunctionType::retVar for the function that it is in.
+    public(field,xml_AST,owner) Statement *ctorStatement = NULL;
+
+    // this function sets 'ctorStatement', and returns a visitor boolean
+    public bool elaborate(ElabVisitor &env);
+  }
+}
+
+
+class Handler {
+    // the global that the throw argument is copy-ctored into, if
+    // thrown by value; this should be linked to the globalVar in
+    // E_throw by a backend
+    public(xml_TY,xmlShouldSerialize) Variable *globalVar = NULL;
+    custom debugPrint { ind(os,indent) << "globalVar: " << refersTo(globalVar) << "\n"; }
+    // we need this so that the temporary that is made when an
+    // exception is caught by value has some place to go; that is, a
+    // Handler has to have all the necessary components of an
+    // E_funCall, as that's how it behaves
+    private(xml_AST,owner) FullExpressionAnnot *annot = NULL;
+    public bool hasAnnot();
+    public FullExpressionAnnot *getAnnot();
+    // local temporary and ctor for it if we catch by value
+    public(field,xml_AST,owner) Expression *localArg=NULL;
+    // dtor for the globalVar if it is a CompoundType or ref to one
+    public(field,xml_AST,owner) Statement *globalDtorStatement = NULL;
+
+    public void elaborate(ElabVisitor &env);
+}
+
+
+class FullExpression {
+  private(xml_AST,owner) FullExpressionAnnot *annot = NULL;
+  public bool hasAnnot();
+  public FullExpressionAnnot *getAnnot();
+}
+
+
+class Expression {
+  // All of the 'elaborate()' functions of Expression return a visitor
+  // boolean: true to elaborate the children automatically, false to
+  // skip the children.  See the SES in cc_elaborate.cc.
+
+  -> E_funCall {
+    // Return by value (for class-valued objects) is elaborated by saying there
+    // is another function parameter, the 'return object'.  At the call site,
+    // we specify an object (reference) that will be bound to that parameter,
+    // and the function implementation is expected to write to that object.
+    public(field,xml_AST,owner) Expression *retObj = NULL;
+  }
+
+  -> E_constructor {
+    // did we manufacture it? needed during elaboration
+    public(field,xml) bool artificial = false;
+
+    // similar to E_funCall; object being constructed
+    public(field,xml_AST,owner) Expression *retObj = NULL;
+  }
+
+  -> E_new {
+    // this statement implements the 'new' operation in terms of more
+    // primitive concepts like allocation and calling the constructor;
+    // after elaboration, and analysis can just ignore the E_new and
+    // look at the 'ctorStatement' instead
+    public(field,xml_AST,owner) Statement *ctorStatement = NULL;
+
+    // I need a place to put the variable being ctored because
+    // E_constructor needs to point at a variable.  Note that this var
+    // is really on the heap.
+    public(xml_TY,xmlShouldSerialize) Variable *heapVar = NULL;
+    custom debugPrint { ind(os,indent) << "heapVar: " << refersTo(heapVar) << "\n"; }
+
+    public bool elaborate(ElabVisitor &env);
+  }
+
+  -> E_delete {
+    // this implements destruction and deallocation; NOTE: E_delete is
+    // already an expression and so will already be inside a
+    // FullExpression; to make it a dtorStatement adds an extra layer
+    // of FullExpression; we do it anyway
+    public(field,xml_AST,owner) Statement *dtorStatement = NULL;
+
+    public bool elaborate(ElabVisitor &env);
+  }
+
+  -> E_throw {
+    // the global that the throw argument is copy-ctored into, if
+    // thrown by value
+    public(xml_TY,xmlShouldSerialize) Variable *globalVar = NULL;
+    custom debugPrint { ind(os,indent) << "globalVar: " << refersTo(globalVar) << "\n"; }
+
+    public(field,xml_AST,owner) Statement *globalCtorStatement=NULL;
+
+    public bool elaborate(ElabVisitor &env);
+  }
+}
+
+
+class Initializer {
+  // [cppstd 1.9 para 12 and 13] "A full-expression is an expression
+  // that is not a subexpression of another expression.  If a language
+  // construct is defined to produce an implicit call of a function, a
+  // use of the language construct is considered to be an expression
+  // for the purposes of this definition.
+
+  // [Note: certain contexts in C++ cause the evaluation of a
+  // full-expression that results from a syntactic construct other
+  // than expression (5.18).  For example, in 8.5, another syntax for
+  // initializer is '( expression-list )' but the resulting construct
+  // is a function call upon a constructor function with
+  // expression-list as an argument list; such a function call is a
+  // full-expression.  For example, in 8.5, another syntax for
+  // initializer is '= initializer-clause' but again the resulting
+  // construct might be a function call upon a constructor function
+  // with one assignment-expression as an argument; again, the
+  // function call is a full-expression. ]
+
+  // Therefore, the arguments to IN_ctor and IN_expr are *not*
+  // FullExpressions because the whole of Initializer is.  I think the
+  // FullExpressionAnnot is redundant in the case of IN_compound, but
+  // I like sharing it in Initializer and an extra layer doesn't hurt.
+
+  // TODO: sm: Currently, we associate a FullExpressionAnnot with
+  // Initializer, which means we get one for every element of a
+  // compound initializer.  This wastes a lot of space, and doesn't
+  // make sense for IN_compound.  I think we should say that (only)
+  // the entire initializer is a single Full Expression, but that
+  // requires adding another layer, like:
+  //
+  //   Initializer                   // has FullExpressionAnnot
+  //     -> IN_cinit(CInitializer)
+  //     -> IN_ctor(..)
+  //   CInitializer                  // "C" for compound
+  //     -> CI_expr
+  //     -> CI_compound(..)
+  //
+  // But I'll leave it for now.
+
+  private(xml_AST,owner) FullExpressionAnnot *annot = NULL;
+  public bool hasAnnot();
+  public FullExpressionAnnot *getAnnot();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc_elaborate.cc
===================================================================
--- vendor/elsa/current/elsa/cc_elaborate.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_elaborate.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2074 @@
+// cc_elaborate.cc            see license.txt for copyright and terms of use
+// code for cc_elaborate.h
+
+
+// Subtree cloning strategy (SCS):
+//
+// Since cloning remains somewhat ad-hoc and untested, when a node has
+// subtrees that are used in its elaboration, we clone the subtrees
+// but put the clone back into the subtree pointer.  Then the original
+// subtree (trusted to be properly tcheck'd) is what's used in the
+// elaboration, since we assume that analyses will look at the
+// elaboration to the exclusion of the subtree pointer.
+//
+// Update: The problem with this is that an analysis has to be
+// explicitly coded to avoid the cloned, defunct subtrees, otherwise
+// it encounters un-elaborated AST.  Therefore the new default is to
+// simply nullify defunct subtrees, despite the fact that it
+// technically results in invalid AST (e.g. E_delete with a NULL
+// 'expr').  The analysis can request the full SCS by setting
+// 'ElabVisitor::cloneDefunct' to true.
+
+
+// Subtree elaboration strategy (SES):
+//
+// Q: An AST node may have subtrees.  When do the subtrees get
+// elaborated, with respect to the elaboration of the parent node?
+//
+// A: The parent node's elaborate() function (goes by various names
+// in the following code) is called first.  The parent then has the
+// responsibility of elaborating its children manually.  For example,
+// if it puts its children into a ctorStatement, 'makeCtorStatement'
+// will elaborate the arguments (children).  Then the visitor returns
+// 'false' so that the children are not elaborated again.  (In fact
+// it would be the children's clones being elaborated "again", and I
+// don't want to elaborate clones.)
+
+
+#include "cc_elaborate.h"      // this module
+#include "cc_ast.h"            // Declaration
+#include "ast_build.h"         // makeExprList1, etc.
+#include "trace.h"             // TRACE
+#include "cc_print.h"          // PrintEnv
+
+// cc_type.h
+Type *makeLvalType(TypeFactory &tfac, Type *underlying);
+
+
+// --------------------- ElabVisitor misc. ----------------------
+ElabVisitor::ElabVisitor(StringTable &s, TypeFactory &tf,
+                         TranslationUnit *tu)
+  : loweredVisitor(this, VF_NONE),
+    str(s),
+    tfac(tf),
+    tunit(tu),
+    env(*this),
+    functionStack(),              // empty
+    fullExpressionAnnotStack(),   // empty
+    enclosingStmtLoc(SL_UNKNOWN),
+    receiverName(s("__receiver")),
+    tempSerialNumber(0),
+    e_newSerialNumber(0),
+
+    // elaboration parameters
+    activities(EA_ALL),
+    cloneDefunctChildren(false)
+{
+  // don't do anything here that depends on the elaboration
+  // parameters, because then the client would be unable to affect
+  // them in time
+}
+
+ElabVisitor::~ElabVisitor()
+{}
+
+
+StringRef ElabVisitor::makeTempName()
+{
+  return str(stringc << "temp-name-" << tempSerialNumber++);
+}
+
+StringRef ElabVisitor::makeE_newVarName()
+{
+  return str(stringc << "e_new-name-" << e_newSerialNumber++);
+}
+
+StringRef ElabVisitor::makeThrowClauseVarName()
+{
+  return str(stringc << "throwClause-name-" << throwClauseSerialNumber++);
+}
+
+StringRef ElabVisitor::makeCatchClauseVarName()
+{
+  return str(stringc << "catchClause-name-" << throwClauseSerialNumber++);
+}
+
+
+Variable *ElabVisitor::makeVariable(SourceLoc loc, StringRef name, Type *type, DeclFlags dflags)
+{
+  return tfac.makeVariable(loc, name, type, dflags);
+}
+
+
+// ----------------------- AST creation ---------------------------
+// This section contains functions that build properly-tcheck'd
+// AST nodes of a variety of kinds.  Part of the strategy for
+// building tcheck'd nodes is for most of the elaboration code
+// to use the functions in this section, which are then individually
+// checked to ensure they set all the fields properly, instead of
+// building AST nodes from scratch.
+
+
+// Variable -> D_name
+D_name *ElabVisitor::makeD_name(SourceLoc loc, Variable *var)
+{
+  D_name *ret = new D_name(loc, new PQ_variable(loc, var));
+  return ret;
+}
+
+
+// given a Variable, make a Declarator that refers to it; assume it's
+// being preceded by a TS_name that fully specifies the variable's
+// type, so we just use a D_name to finish it off
+Declarator *ElabVisitor::makeDeclarator(SourceLoc loc, Variable *var, DeclaratorContext context)
+{
+  IDeclarator *idecl = makeD_name(loc, var);
+
+  Declarator *decl = new Declarator(idecl, NULL /*init*/);
+  decl->var = var;
+  decl->type = var->type;
+  xassert(decl->context == DC_UNKNOWN);
+  decl->context = context;
+
+  return decl;
+}
+
+// and similar for a full (singleton) declaration
+Declaration *ElabVisitor::makeDeclaration(SourceLoc loc, Variable *var, DeclaratorContext context)
+{
+  Declarator *declarator = makeDeclarator(loc, var, context);
+  Declaration *declaration =
+    new Declaration(DF_NONE, new TS_type(loc, var->type),
+      FakeList<Declarator>::makeList(declarator));
+  return declaration;
+}
+
+
+// given a function declaration, make a Declarator containing
+// a D_func that refers to it
+Declarator *ElabVisitor::makeFuncDeclarator(SourceLoc loc, Variable *var, DeclaratorContext context)
+{
+  FunctionType *ft = var->type->asFunctionType();
+
+  // construct parameter list
+  FakeList<ASTTypeId> *params = FakeList<ASTTypeId>::emptyList();
+  {
+    // iterate over parameters other than the receiver object ("this")
+    SObjListIterNC<Variable> iter(ft->params);
+    if (ft->isMethod()) {
+      iter.adv();
+    }
+    for (; !iter.isDone(); iter.adv()) {
+      Variable *param = iter.data();
+
+      ASTTypeId *typeId = new ASTTypeId(new TS_type(loc, param->type),
+                                        makeDeclarator(loc, param, DC_D_FUNC));
+      params = params->prepend(typeId);
+    }
+    params = params->reverse();     // fix prepend()-induced reversal
+  }
+
+  // build D_func
+  IDeclarator *funcIDecl = new D_func(loc,
+                                      makeD_name(loc, var),
+                                      params,
+                                      CV_NONE,
+                                      NULL /*exnSpec*/);
+
+  Declarator *funcDecl = new Declarator(funcIDecl, NULL /*init*/);
+  funcDecl->var = var;
+  funcDecl->type = var->type;
+  xassert(funcDecl->context == DC_UNKNOWN);
+  funcDecl->context = context;
+
+  return funcDecl;
+}
+
+
+// given a function declaration and a body, make a Function AST node
+Function *ElabVisitor::makeFunction(SourceLoc loc, Variable *var,
+                                    FakeList<MemberInit> *inits,
+                                    S_compound *body)
+{
+  FunctionType *ft = var->type->asFunctionType();
+
+  Declarator *funcDecl = makeFuncDeclarator(loc, var, DC_FUNCTION);
+
+  Function *f = new Function(
+    var->flags        // this is too many (I only want syntactic); but won't hurt
+      | DF_INLINE,    // pacify pretty-printing idempotency
+    new TS_type(loc, ft->retType),
+    funcDecl,
+    inits,
+    body,
+    NULL /*handlers*/
+  );
+  f->funcType = var->type->asFunctionType();
+
+  if (ft->isMethod()) {
+    // f's receiver should match that of its funcType
+    f->receiver = f->funcType->getReceiver();
+  }
+
+  f->implicitlyDefined = true;
+
+  // the existence of a definition has implications for the Variable too
+  var->setFlag(DF_DEFINITION);
+  var->funcDefn = f;
+
+  return f;
+}
+
+
+// given a Variable, make an E_variable referring to it
+E_variable *ElabVisitor::makeE_variable(SourceLoc loc, Variable *var)
+{
+  E_variable *evar = new E_variable(new PQ_variable(loc, var));
+  evar->type = makeLvalType(tfac, var->type);
+  evar->var = var;
+  return evar;
+}
+
+E_fieldAcc *ElabVisitor::makeE_fieldAcc
+  (SourceLoc loc, Expression *obj, Variable *field)
+{
+  E_fieldAcc *efieldacc = new E_fieldAcc(obj, new PQ_variable(loc, field));
+  efieldacc->type = makeLvalType(tfac, field->type);
+  efieldacc->field = field;
+  return efieldacc;
+}
+
+
+E_funCall *ElabVisitor::makeMemberCall
+  (SourceLoc loc, Expression *obj, Variable *func, FakeList<ArgExpression> *args)
+{
+  // "a.f"
+  E_fieldAcc *efieldacc = makeE_fieldAcc(loc, obj, func);
+
+  // "a.f(<args>)"
+  E_funCall *funcall = new E_funCall(efieldacc, args);
+  funcall->type = func->type->asFunctionType()->retType;
+
+  return funcall;
+}
+
+FakeList<ArgExpression> *ElabVisitor::emptyArgs()
+{
+  return FakeList<ArgExpression>::emptyList();
+}
+
+
+// reference to the receiver object of the current function
+Expression *ElabVisitor::makeThisRef(SourceLoc loc)
+{
+  Variable *receiver = functionStack.top()->receiver;
+
+  // "this"
+  E_this *ths = new E_this;
+  ths->receiver = receiver;
+  ths->type = tfac.makePointerType(CV_CONST, receiver->type->asRval());
+
+  // "*this"
+  E_deref *deref = new E_deref(ths);
+  deref->type = receiver->type;
+
+  return deref;
+}
+
+
+// wrap up an expression in an S_expr
+S_expr *ElabVisitor::makeS_expr(SourceLoc loc, Expression *e)
+{
+  return new S_expr(loc, new FullExpression(e));
+}
+
+
+// make an empty S_compound
+S_compound *ElabVisitor::makeS_compound(SourceLoc loc)
+{
+  // note that the ASTList object created here is *deleted* by
+  // the act of passing it to the S_compound; the S_compound has
+  // its own ASTList<Statement> inside it
+  return new S_compound(loc, new ASTList<Statement>);
+}
+
+
+// ------------------------ makeCtor ----------------------
+// Make a call to the constructor for 'type', such that the object
+// constructed is in 'target' (a reference to some memory location).
+// 'args' is the list of arguments to the ctor call.
+E_constructor *ElabVisitor::makeCtorExpr(
+  SourceLoc loc,                    // where elaboration is occurring
+  Expression *target,               // reference to object to construct
+  Type *type,                       // type of the constructed object
+  Variable *ctor,                   // ctor function to call
+  FakeList<ArgExpression> *args)    // arguments to ctor (tcheck'd)
+{
+  xassert(target->type->isReference());
+
+  E_constructor *ector0 = new E_constructor(new TS_type(loc, type), args);
+  ector0->type = type;
+  ector0->ctorVar = ctor;
+  ector0->artificial = true;
+  ector0->retObj = target;
+
+  // want to return a node that is both tcheck'd *and* elaborated
+  ector0->traverse(this->loweredVisitor);
+
+  return ector0;
+}
+
+// NOTE: the client should consider cloning the _args_ before passing
+// them in so that the AST remains a tree
+Statement *ElabVisitor::makeCtorStatement(
+  SourceLoc loc,
+  Expression *target,
+  Type *type,
+  Variable *ctor,
+  FakeList<ArgExpression> *args)
+{
+  // see comment below regarding 'getDefaultCtor'; if this assertion
+  // fails it may be due to an input program that is not valid C++,
+  // but the type checker failed to diagnose it
+  //xassert(ctor);
+  //
+  // 2006-04-09: The semantics of E_constructor has been changed to
+  // allow a NULL 'ctorVar', and it means the ctor is trivial.
+
+  E_constructor *ector0 = makeCtorExpr(loc, target, type, ctor, args);
+  Statement *ctorStmt0 = makeS_expr(loc, ector0);
+  return ctorStmt0;
+}
+
+
+// ------------------------ makeDtor ----------------------
+Expression *ElabVisitor::makeDtorExpr(SourceLoc loc, Expression *target,
+                                      Type *type)
+{
+  Variable *dtor = getDtor(type->asCompoundType());
+
+  // question of whether to elaborate returned value is moot, as
+  // elaboration would do nothin anyway
+
+  return makeMemberCall(loc, target, dtor, emptyArgs());
+}
+
+// NOTE: consider cloning the target so that the AST remains a tree
+Statement *ElabVisitor::makeDtorStatement(SourceLoc loc, Expression *target,
+                                          Type *type)
+{
+  Expression *efc0 = makeDtorExpr(loc, target, type);
+  return makeS_expr(loc, efc0);
+}
+
+
+// ------------------- cloning support (SCS) ------------------
+FakeList<ArgExpression> *ElabVisitor::cloneExprList(FakeList<ArgExpression> *args0)
+{
+  FakeList<ArgExpression> *ret = FakeList<ArgExpression>::emptyList();
+
+  if (cloneDefunctChildren) {
+    FAKELIST_FOREACH(ArgExpression, args0, iter) {
+      // clone the AST node
+      ArgExpression *argExpr0 = iter->clone();
+      // use the clone
+      ret = ret->prepend(argExpr0);
+    }
+    return ret->reverse();
+  }
+  else {
+    // empty defunct list
+    return ret;
+  }
+}
+
+
+Expression *ElabVisitor::cloneExpr(Expression *e)
+{
+  if (cloneDefunctChildren) {
+    // clone the AST node
+    Expression *expr0 = e->clone();
+    // use the clone
+    return expr0;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+// ------------------------ elaborateCDtors -----------------------
+void ElabVisitor::elaborateCDtorsDeclaration(Declaration *decl)
+{
+  FAKELIST_FOREACH_NC(Declarator, decl->decllist, decliter) {
+    decliter->elaborateCDtors(env, decl->dflags);
+  }
+
+  // the caller isn't going to automatically traverse into the type
+  // specifier, so we must do it manually (e.g. oink/qual's
+  // test/memberInit_cdtor1.cc.filter-good.cc fails otherwise)
+  decl->spec->traverse(this->loweredVisitor);
+}
+
+
+// for EA_MEMBER_DECL_CDTOR and EA_VARIABLE_DECL_CDTOR
+//
+// Given a Declarator, annotate it with statements that construct and
+// destruct the associated variable.
+void Declarator::elaborateCDtors(ElabVisitor &env, DeclFlags dflags)
+{
+  // don't do anything if this is not data
+  if (var->type->isFunctionType() ||
+      var->hasFlag(DF_TYPEDEF)) {
+    return;
+  }
+
+  // also don't do this for parameters
+  if (var->hasFlag(DF_PARAMETER)) {
+    return;
+  }
+
+  // don't bother unless it is a class-valued object
+  if (!type->isCompoundType()) {
+    // except that we still need to elaborate the initializer, and the
+    // caller is *not* going to let the visitor do so automatically
+    // (since that would violate the SES in the case that the type
+    // *is* compound)
+    if (init) {
+      init->traverse(env.loweredVisitor);
+    }
+
+    return;
+  }
+  CompoundType *ct = type->asCompoundType();
+
+  // this is a property of the variable, not the declaration
+  bool isTemporary =   var->hasFlag(DF_TEMPORARY);
+  // these are properties of the declaration and the variable and
+  // should match
+  //
+  // sm: at least in t0318.cc, they do not; the Variable has the
+  // correct info, whereas the declaration merely has what was
+  // syntactically present and/or obvious
+  bool isMember =      var->hasFlag(DF_MEMBER);
+  bool isStatic =      var->hasFlag(DF_STATIC);
+  // this used to check if the *var* had an extern flag, which is not
+  // correct because if there is a later declaration in the file for
+  // the same variable that is *not* extern then the flag DF_EXTERN
+  // will be removed, which seems reasonable to me.  What we care
+  // about here is if the *declaration* is extern.
+  bool isExtern =      dflags & DF_EXTERN;
+  // note that this assertion is not an equality
+  if (var->hasFlag(DF_EXTERN)) {
+    xassert(isExtern);
+  }
+
+  bool isAbstract = decl->isD_name() && !decl->asD_name()->name;
+  SourceLoc loc = getLoc();
+
+  if (init) {
+    // sm: why this assertion?
+    xassert(!isTemporary);
+
+    // sm: and why this one too?
+    xassert(!isAbstract);
+
+    // get a list of (tcheck'd) arguments to pass to the ctor; we will
+    // clone the existing arguments, and put the clone in where the
+    // original ones were
+    FakeList<ArgExpression> *args0 = NULL;
+
+    // the arguments have not yet been elaborated, that will happen
+    // during 'makeCtorStatement'; but we need a fullexp context
+    // for it
+    FullExpressionAnnot *fullexp = NULL;
+
+    // constructor to call
+    Variable *ctor = NULL;
+
+    ASTSWITCH(Initializer, init) {
+      ASTCASE(IN_ctor, inctor) {
+        args0 = inctor->args;
+        inctor->args = env.cloneExprList(inctor->args);
+
+        fullexp = inctor->getAnnot();
+        ctor = inctor->ctorVar;
+      }
+      ASTNEXT(IN_expr, inexpr) {
+        // just call the copy ctor; FIX: this is questionable; we
+        // haven't decided what should really happen for an IN_expr;
+        // update: dsw: I'm sure that is right
+        args0 = makeExprList1(inexpr->e);
+        inexpr->e = env.cloneExpr(inexpr->e);
+
+        fullexp = inexpr->getAnnot();
+        ctor = env.getCopyCtor(ct);
+      }
+      ASTNEXT(IN_compound, incpd) {
+        // just call the no-arg ctor; FIX: this is questionable; it
+        // is undefined what should happen for an IN_compound since
+        // it is a C99-ism.
+        //
+        // sm: No it isn't.. IN_compound is certainly part of C++.
+        // I still don't know how to handle it, though.
+        args0 = env.emptyArgs();
+
+        fullexp = incpd->getAnnot(); // sm: not sure about this..
+        ctor = env.getDefaultCtor(ct);
+      }
+      ASTENDCASED
+    }
+
+    // According to the semantics of E_constructor, it is legal for
+    // 'ctor' to be NULL here, as it signifies the use of a trivial
+    // constructor.
+
+    env.push(fullexp);
+    ctorStatement = env.makeCtorStatement(loc, env.makeE_variable(loc, var),
+                                          type, ctor, args0);
+    env.pop(fullexp);
+  }
+
+  else /* init is NULL */ {
+    if (!isAbstract &&
+        !isTemporary &&
+        !isMember &&
+        !isExtern
+        ) {
+      // sm: I think this should not be reachable because I modified
+      // the type checker to insert an IN_ctor in this case.  It would be
+      // be bad if it *were* reachable, because there's no fullexp here.
+      xfailure("should not be reachable");
+
+      // call the no-arg ctor; for temporaries do nothing since this is
+      // a temporary, it will be initialized later
+      ctorStatement = env.makeCtorStatement(loc, env.makeE_variable(loc, var),
+                                            type, env.getDefaultCtor(ct),
+                                            env.emptyArgs());
+    }
+  }
+
+  // if isTemporary we don't want to make a ctor since by definition
+  // the temporary will be initialized later
+  //
+  // sm: the logic here could use some more explanation (isTemporary
+  // is discussed but not the others)
+  if (isTemporary ||
+      (isMember && !(isStatic && type->isConst())) ||
+      isExtern
+      ) {
+    // sm: I really have no idea what the rationale here is, and it
+    // is wrong (t0318.cc) anyway, so I'm nerfing this.
+    //xassert(!ctorStatement);
+  } else if (!isAbstract &&
+             (!isMember ||
+              (isStatic && type->isConst() && init)) &&
+             !isExtern     // sm: this is redundant
+             ) {
+    xassert(ctorStatement);
+  }
+
+  // make the dtorStatement
+  if (!isAbstract &&
+      !isExtern
+      ) {
+    // no need to clone the target as makeE_variable makes all new AST
+    dtorStatement = env.makeDtorStatement(loc, env.makeE_variable(loc, var), type);
+  } else {
+    xassert(!dtorStatement);
+  }
+}
+
+
+// -------------------- elaborateCallSite ---------------------
+// If the return type is a CompoundType, then make a temporary and
+// point the retObj at it.  The intended semantics of this is to
+// override the usual way of analyzing the return value just from the
+// return type of the function.
+//
+// Make a Declaration for a temporary; yield the Variable too.
+Declaration *ElabVisitor::makeTempDeclaration
+  (SourceLoc loc, Type *retType, Variable *&var /*OUT*/, DeclaratorContext context)
+{
+  // while a user may attempt this, we should catch it earlier and not
+  // end up down here.
+  xassert(retType->isCompoundType());
+
+  // make up a Variable
+  var = makeVariable(loc, makeTempName(), retType, DF_TEMPORARY);
+
+  // make a decl for it
+  Declaration *decl = makeDeclaration(loc, var, context);
+
+  if (doing(EA_VARIABLE_DECL_CDTOR)) {
+    // elaborate this declaration; because of DF_TEMPORARY this will *not*
+    // add a ctor, but it will add a dtor
+    elaborateCDtorsDeclaration(decl);
+  }
+
+  return decl;
+}
+
+// make the decl, and add it to the innermost FullExpressionAnnot;
+// yield the Variable since neither caller needs the Declaration
+Variable *ElabVisitor::insertTempDeclaration(SourceLoc loc, Type *retType)
+{
+  FullExpressionAnnot *fea0 = env.fullExpressionAnnotStack.top();
+
+  Variable *var;
+  Declaration *declaration0 = makeTempDeclaration(loc, retType, var, DC_FEA);
+
+  // put it into fea0
+  fea0->declarations.append(declaration0);
+
+  return var;
+}
+
+
+// make a comma expression so we can copy the argument before passing it
+//
+// NOTE: the client is expected to clone _argExpr_ before passing it
+// in here *if* needed, since we don't clone it below
+Expression *ElabVisitor::elaborateCallByValue
+  (SourceLoc loc, Type *paramType, Expression *argExpr)
+{
+  CompoundType *paramCt = paramType->asCompoundType();
+
+  // E_variable that points to the temporary
+  Variable *tempVar = insertTempDeclaration(loc, paramType);
+
+  // E_constructor for the temporary that calls the copy ctor for the
+  // temporary taking the real argument as the copy ctor argument.
+  // NOTE: we do NOT clone argExpr here, as the client to this
+  // function is expected to do it
+  E_constructor *ector =
+    env.makeCtorExpr(loc, makeE_variable(loc, tempVar), paramType,
+                     getCopyCtor(paramCt), makeExprList1(argExpr));
+
+  // combine into a comma expression so we do both but return the
+  // value of the second
+  //
+  // sm: I choose to call 'makeE_variable' twice instead of using clone()
+  // since I trust the former more
+  Expression *byValueArg = makeE_variable(loc, tempVar);
+  Expression *ret = new E_binary(ector, BIN_COMMA, byValueArg);
+  ret->type = byValueArg->type;
+  xassert(byValueArg->getType()->isReference()); // the whole point
+  return ret;
+}
+
+
+// this returns the 'retObj', the object that the call is constructing
+Expression *ElabVisitor::elaborateCallSite(
+  SourceLoc loc,
+  FunctionType *ft,
+  FakeList<ArgExpression> *args,
+  bool artificalCtor)          // always false; see call sites
+{
+  Expression *retObj = NULL;
+
+  if (doing(EA_ELIM_RETURN_BY_VALUE)) {
+    // If the return type is a CompoundType, then make a temporary and
+    // point the retObj at it.  NOTE: This can never accidentally create
+    // a temporary for a dtor for a non-temporary object because the
+    // retType for a dtor is void.  However, we do need to guard against
+    // this possibility for ctors.
+    if (artificalCtor) {
+      xassert(ft->isConstructor());
+    }
+    if (ft->retType->isCompoundType() &&
+        (!ft->isConstructor() || !artificalCtor)   // sm: the isConstructor() test is redundant
+        ) {
+      Variable *var0 = insertTempDeclaration(loc, ft->retType);
+      retObj = makeE_variable(loc, var0);
+    }
+  }
+
+  if (doing(EA_ELIM_PASS_BY_VALUE)) {
+    // Elaborate cdtors for CompoundType arguments being passed by
+    // value.
+    //
+    // For each parameter, if it is a CompoundType (pass by value) then 1)
+    // make a temporary variable here for it that has a dtor but not a
+    // ctor 2) for the corresponding argument, replace it with a comma
+    // expression where a) the first part is an E_constructor for the
+    // temporary that has one argument that is what was the arugment in
+    // this slot and the ctor is the copy ctor, and b) E_variable for the
+    // temporary
+
+    SObjListIterNC<Variable> paramsIter(ft->params);
+
+    if (ft->isMethod()) {
+      paramsIter.adv();
+    }
+
+    FAKELIST_FOREACH_NC(ArgExpression, args, arg) {
+      if (paramsIter.isDone()) {
+        // FIX: I suppose we could still have arguments here if there is a
+        // ellipsis at the end of the parameter list.  Can those be passed
+        // by value?
+        break;
+      }
+
+      Variable *param = paramsIter.data();
+      Type *paramType = param->getType();
+      if (paramType->isCompoundType()) {
+        // NOTE: it seems like this is one of those places where I
+        // should NOT clone the "argument" argument to
+        // makeCtorExpr/Statement (which is called by
+        // elaborateCallByValue()) since it is being replaced by
+        // something wrapped around itself: that is the AST tree remains
+        // a tree
+        //
+        // sm: I agree
+        arg->expr = elaborateCallByValue(loc, paramType, arg->expr);
+      }
+
+      paramsIter.adv();
+    }
+
+    if (!paramsIter.isDone()) {
+      // FIX: if (!paramsIter.isDone()) then have to deal with default
+      // arguments that are pass by value if such a thing is even
+      // possible.
+    }
+  }
+
+  return retObj;
+}
+
+
+// ----------------- elaborateFunctionStart -----------------
+// for EA_ELIM_RETURN_BY_VALUE
+void ElabVisitor::elaborateFunctionStart(Function *f)
+{
+  FunctionType *ft = f->funcType;
+  if (ft->retType->isCompoundType()) {
+    // We simulate return-by-value for class-valued objects by
+    // passing a hidden additional parameter of type C& for a
+    // return value of type C.  For static semantics, that means
+    // adding an environment entry for a special name, "<retVar>".
+    // For dynamic semantics, clients looking at the declaration
+    // must simply know (by its name) that this variable is bound
+    // to the reference passed as the 'retObj' at the call site.
+
+    SourceLoc loc = f->nameAndParams->decl->loc;
+    Type *retValType =
+      env.tfac.makeReferenceType(ft->retType);
+    StringRef retValName = env.str("<retVar>");
+    f->retVar = env.makeVariable(loc, retValName, retValType, DF_PARAMETER);
+
+    // sm: This seemed like a good idea, because an analysis would get
+    // to see the declaration and not just the magical appearance of a
+    // new Variable.  But, it was not present in the code that I'm
+    // working from and it messes up pretty printing idempotency; and
+    // I'm now not as convinced that an analysis really wants to see
+    // it.  So I'm commenting it out.
+    #if 0
+    Declaration *declaration = makeDeclaration(loc, f->retVar);
+    f->body->stmts.prepend(new S_decl(loc, declaration));
+    #endif // 0
+  }
+}
+
+
+// ---------------- completeNoArgMemberInits -------------------
+// add no-arg MemberInits to existing ctor body ****************
+
+// Does this Variable want a no-arg MemberInitializer?
+bool ElabVisitor::wantsMemberInit(Variable *var)
+{
+  // function members should be skipped
+  if (var->type->isFunctionType()) return false;
+  // skip arrays for now; FIX: do something correct here
+  if (var->type->isArrayType()) return false;
+  if (var->isStaticMember()) return false;
+  if (var->hasFlag(DF_TYPEDEF)) return false;
+  // FIX: do all this with one test
+  xassert(!var->hasFlag(DF_AUTO));
+  xassert(!var->hasFlag(DF_REGISTER));
+  xassert(!var->hasFlag(DF_EXTERN));
+  xassert(!var->hasFlag(DF_VIRTUAL)); // should be functions only
+  xassert(!var->hasFlag(DF_EXPLICIT)); // should be ctors only
+  xassert(!var->hasFlag(DF_FRIEND));
+  xassert(!var->hasFlag(DF_NAMESPACE));
+  xassert(var->isMember());
+  return true;
+}
+
+// find the MemberInitializer that initializes data member memberVar;
+// return NULL if none
+MemberInit *ElabVisitor::findMemberInitDataMember
+  (FakeList<MemberInit> *inits, // the inits to search
+   Variable *memberVar)         // data member to search for the MemberInit for
+{
+  MemberInit *ret = NULL;
+  FAKELIST_FOREACH_NC(MemberInit, inits, mi) {
+    xassert(!mi->base || !mi->member); // MemberInit should do only one thing
+    if (mi->member == memberVar) {
+      xassert(!ret);            // >1 MemberInit; FIX: this is a user error, not our error
+      ret = mi;
+    }
+  }
+  return ret;
+}
+
+// find the MemberInitializer that initializes data member memberVar;
+// return NULL if none
+MemberInit *ElabVisitor::findMemberInitSuperclass
+  (FakeList<MemberInit> *inits, // the inits to search
+   CompoundType *superclass)    // superclass to search for the MemberInit for
+{
+  MemberInit *ret = NULL;
+  FAKELIST_FOREACH_NC(MemberInit, inits, mi) {
+    xassert(!mi->base || !mi->member); // MemberInit should do only one thing
+    if (mi->base == superclass) {
+      xassert(!ret);            // >1 MemberInit; FIX: this is a user error, not our error
+      ret = mi;
+    }
+  }
+  return ret;
+}
+
+
+// Finish supplying to a ctor the no-arg MemberInits for unmentioned
+// superclasses and members.
+void ElabVisitor::completeNoArgMemberInits(Function *ctor, CompoundType *ct)
+{
+  SourceLoc loc = ctor->getLoc();
+
+  // Iterate through the members in the declaration order (what is in
+  // the CompoundType).  For each one, check to see if we have a
+  // MemberInit for it.  If so, append that (prepend and revese
+  // later); otherwise, make one.  This has the effect of
+  // canonicalizing the MemberInit call order even if none needed to
+  // be added, which I think is in the spec; at least g++ does it (and
+  // gives a warning, which I won't do.)
+  FakeList<MemberInit> *oldInits = ctor->inits;
+  // NOTE: you can't make a new list of inits that is a FakeList
+  // because we are still traversing over the old one.  Linked lists
+  // are a premature optimization!
+  SObjList<MemberInit> newInits;
+  // NOTE: don't do this!
+//    FakeList<MemberInit> *newInits = FakeList<MemberInit>::emptyList();
+
+  FOREACH_OBJLIST(BaseClass, ct->bases, iter) {
+    BaseClass const *base = iter.data();
+    // omit initialization of virtual base classes, whether direct
+    // virtual or indirect virtual.  See cppstd 12.6.2 and the
+    // implementation of Function::tcheck_memberInits()
+    //
+    // FIX: We really should be initializing the direct virtual bases,
+    // but the logic is so complex I'm just going to omit it for now
+    // and err on the side of not calling enough initializers;
+    // UPDATE: the spec says we can do it multiple times for copy
+    // assign operator, so I wonder if that holds for ctors also.
+    if (!ct->hasVirtualBase(base->ct)) {
+      MemberInit *mi = findMemberInitSuperclass(oldInits, base->ct);
+      if (!mi) {
+        PQName *name = new PQ_variable(loc, base->ct->typedefVar);
+        mi = new MemberInit(name, emptyArgs());
+        mi->base = base->ct;
+        mi->ctorVar = getDefaultCtor(base->ct);
+      }
+      newInits.prepend(mi);
+    } else {
+//        cerr << "Omitting a direct base that is also a virtual base" << endl;
+    }
+  }
+  // FIX: virtual bases omitted for now
+  //
+  // sm: note that this code drops (user-supplied!) initializers for
+  // virtual bases on the floor
+
+  SFOREACH_OBJLIST_NC(Variable, ct->dataMembers, iter) {
+    Variable *var = iter.data();
+    if (!wantsMemberInit(var)) continue;
+    MemberInit *mi = findMemberInitDataMember(oldInits, var);
+    // It seems that ints etc. shouldn't have explicit no-arg ctors.
+    // Actually, it seems that even some classes are not default
+    // initialized!  However, if they are of POD type and I default
+    // initialize them anyway, all I'm doing is calling their
+    // implicitly-defined no-arg ctor, which (eventually) will simply do
+    // nothing for the scalar data members, which is equivalent.
+    // 12.6.2 para 4: If a given nonstatic data member or base class is
+    // not named by a mem-initializer-id, then
+    // -- If the entity is a nonstatic data member of ... class type (or
+    // array thereof) or a base class, and the entity class is a non-POD
+    // class, the entity is default-initialized (8.5). ....
+    // -- Otherwise, the entity is not initialized. ....
+    if (!mi && var->type->isCompoundType()) {
+      mi = new MemberInit(new PQ_name(loc, var->name), emptyArgs());
+      mi->member = var;
+      mi->ctorVar = getDefaultCtor(var->type->asCompoundType());
+    }
+    if (mi) newInits.prepend(mi);
+  }
+
+  // *Now* we can destroy the linked list structure and rebuild it
+  // again while also reversing the list.
+  ctor->inits = FakeList<MemberInit>::emptyList();
+  SFOREACH_OBJLIST_NC(MemberInit, newInits, iter) {
+    MemberInit *mi = iter.data();
+    mi->next = NULL;
+    ctor->inits = ctor->inits->prepend(mi);
+  }
+}
+
+
+// ---------------- make compiler-supplied member funcs -------------=
+// make no-arg ctor ****************
+
+// mirrors Env::receiverParameter()
+Variable *ElabVisitor::makeCtorReceiver(SourceLoc loc, CompoundType *ct)
+{
+  Type *recType = tfac.makeTypeOf_receiver(loc, ct, CV_NONE, NULL /*syntax*/);
+  return makeVariable(loc, receiverName, recType, DF_PARAMETER);
+}
+
+// for EA_IMPLICIT_MEMBER_DEFN
+MR_func *ElabVisitor::makeNoArgCtorBody(CompoundType *ct, Variable *ctor)
+{
+  SourceLoc loc = ctor->loc;
+
+  // empty body
+  S_compound *body = makeS_compound(loc);
+
+  // NOTE: The MemberInitializers will be added by
+  // completeNoArgMemberInits() during later elaboration, so we don't
+  // add them now.
+  FakeList<MemberInit> *inits = FakeList<MemberInit>::emptyList();
+
+  Function *f = makeFunction(loc, ctor, inits, body);
+  f->receiver = env.makeCtorReceiver(loc, ct);
+
+  return new MR_func(loc, f);
+}
+
+
+// make copy ctor ****************
+
+MemberInit *ElabVisitor::makeCopyCtorMemberInit(
+  Variable *target,          // member or base class to initialize
+  Variable *srcParam,        // "__other" parameter to the copy ctor
+  SourceLoc loc)
+{
+  // compound, if class-valued (if not, we're initializing a member
+  // that is not class-valued, so it's effectively just an assignment)
+  CompoundType *targetCt = target->type->ifCompoundType();
+
+  // expression referring to "__other"
+  Expression *expr = makeE_variable(loc, srcParam);
+
+  // are we initializing a member?  if not, it's a base class subobject
+  bool isMember = !target->hasFlag(DF_TYPEDEF);
+  if (isMember) {
+    // expression: "__other.<member>"
+    expr = makeE_fieldAcc(loc, expr, target);
+  }
+
+  //           ArgExpression:
+  ArgExpression *argExpr = new ArgExpression(expr);
+  //         args:
+  FakeList<ArgExpression> *args = FakeList<ArgExpression>::makeList(argExpr);
+  //           name = A
+  //           loc = ../oink/ctor1.cc:12:7
+  //         PQ_name:
+
+  //       MemberInit:
+  MemberInit *mi = new MemberInit(new PQ_variable(loc, target), args);
+  push(mi->getAnnot());
+  if (isMember) {
+    mi->member = target;
+  }
+  else {
+    mi->base = targetCt;
+  }
+  mi->ctorVar = targetCt? getCopyCtor(targetCt) : NULL;
+  if (mi->ctorVar) {
+    mi->ctorStatement = makeCtorStatement
+      (loc,
+       env.makeE_variable(loc, target),
+       target->type,
+       mi->ctorVar,
+       mi->args);
+  }
+  pop(mi->getAnnot());
+  return mi;
+}
+
+
+// for EA_IMPLICIT_MEMBER_DEFN
+MR_func *ElabVisitor::makeCopyCtorBody(CompoundType *ct, Variable *ctor)
+{
+  // reversed print AST output; remember to read going up even for the
+  // tree leaves
+
+  SourceLoc loc = ctor->loc;
+
+  // empty body
+  S_compound *body = makeS_compound(loc);
+
+  // the parameter that refers to the source object
+  Variable *srcParam = ctor->type->asFunctionType()->params.first();
+  //StringRef srcNameS = env.str.add("__other");
+
+  // for each member, make a call to its copy ctor; Note that this
+  // works for simple types also; NOTE: We build this in reverse and
+  // then reverse it.
+  FakeList<MemberInit> *inits = FakeList<MemberInit>::emptyList();
+  {
+    FOREACH_OBJLIST(BaseClass, ct->bases, iter) {
+      BaseClass const *base = iter.data();
+      // omit initialization of virtual base classes, whether direct
+      // virtual or indirect virtual.  See cppstd 12.6.2 and the
+      // implementation of Function::tcheck_memberInits()
+      //
+      // FIX: We really should be initializing the direct virtual bases,
+      // but the logic is so complex I'm just going to omit it for now
+      // and err on the side of not calling enough initializers
+      if (!ct->hasVirtualBase(base->ct)) {
+        MemberInit *mi =
+          makeCopyCtorMemberInit(base->ct->typedefVar, srcParam, loc);
+        inits = inits->prepend(mi);
+      }
+      else {
+        //cerr << "Omitting a direct base that is also a virtual base" << endl;
+      }
+    }
+
+    // FIX: What the heck do I do for virtual bases?  This surely isn't
+    // right.
+    //
+    // Also, it seems that the order of interleaving of the virtual and
+    // non-virtual bases has been lost.  Have to be careful of this when
+    // we pretty print.
+    //
+    // FIX: This code is broken anyway.
+  //    FOREACH_OBJLIST_NC(BaseClassSubobj, ct->virtualBases, iter) {
+  //      BaseClass *base = iter->data();
+  // // This must not mean what I think.
+  // //     xassert(base->isVirtual);
+  //      MemberInit *mi = makeCopyCtorMemberInit(base->ct->name, srcNameS, NULL, loc);
+  //      inits = inits->prepend(mi);
+  //    }
+
+    SFOREACH_OBJLIST_NC(Variable, ct->dataMembers, iter) {
+      Variable *var = iter.data();
+      if (!wantsMemberInit(var)) continue;
+      MemberInit *mi = makeCopyCtorMemberInit(var, srcParam, loc);
+      inits = inits->prepend(mi);
+    }
+
+    //     inits:
+    inits = inits->reverse();
+  }
+
+  Function *f = makeFunction(loc, ctor, inits, body);
+  f->receiver = env.makeCtorReceiver(loc, ct);
+
+  return new MR_func(loc, f);
+}
+
+
+// make copy assign op ****************
+
+// "return *this;"
+S_return *ElabVisitor::make_S_return_this(SourceLoc loc)
+{
+  // "return *this;"
+  return new S_return(loc, new FullExpression(makeThisRef(loc)));
+}
+
+// "this->y = __other.y;"
+S_expr *ElabVisitor::make_S_expr_memberCopyAssign
+  (SourceLoc loc, Variable *member, Variable *other)
+{
+  // "__other.y"
+  E_fieldAcc *otherDotY = makeE_fieldAcc(loc, makeE_variable(loc, other), member);
+
+  Expression *action;
+  if (member->type->isCompoundType()) {
+    CompoundType *ct = member->type->asCompoundType();
+
+    // use a call to the assignment operator
+    Variable *assign = getAssignOperator(ct);
+    xassert(assign);
+
+    // "(*this).y.operator=(__other.y)"
+    action = makeMemberCall(loc,
+                            makeE_fieldAcc(loc, makeThisRef(loc), member) /*y*/,
+                            assign,
+                            makeExprList1(otherDotY));
+  }
+  else {
+    // use the E_assign built-in operator
+
+    // "(*this).y = other.y"
+    action = new E_assign(makeE_fieldAcc(loc, makeThisRef(loc), member),
+                          BIN_ASSIGN,
+                          otherDotY);
+    action->type = otherDotY->type;
+  }
+
+  // wrap up as a statement
+  return makeS_expr(loc, action);
+}
+
+// "this->W::operator=(__other);"
+S_expr *ElabVisitor::make_S_expr_superclassCopyAssign
+  (SourceLoc loc, CompoundType *w, Variable *other)
+{
+  // "W::operator="
+  Variable *assign = getAssignOperator(w);
+  xassert(assign);
+
+  // "this->W::operator=(__other)"
+  E_funCall *call = makeMemberCall(loc, makeThisRef(loc), assign,
+                                   makeExprList1(makeE_variable(loc, other)));
+
+  // "this->W::operator=(__other);"
+  return makeS_expr(loc, call);
+}
+
+
+//  12.8 paragraph 10
+//
+//  If the lass definition does not explicitly declare a copy assignment
+//  operator, one is declared implicitly.  The implicitly-declared copy
+//  assignment operator for a class X will have the form
+//
+//          X& X::operator=(X const &)
+//
+//  if [lots of complicated conditions here on whether or not the
+//  parameter should be a reference to const or not; I'm just going to
+//  make it const for now] ...
+//
+//  paragraph 13
+//
+//  The implicitly-defined copy assignment operator for class X performs
+//  memberwise assignment of its subobjects.  ...
+//
+//  sm: I removed some large passages that are not directly relevant
+//  to the operation of this function.  The standard is a copyrighted work
+//  and we should therefore only include brief segments that are highly
+//  relevant.
+//
+// for EA_IMPLICIT_MEMBER_DEFN
+MR_func *ElabVisitor::makeCopyAssignBody
+  (SourceLoc loc, CompoundType *ct, Variable *assign)
+{
+  // get the source parameter, called "__other" (0th param is receiver
+  // object, so 1st is __other)
+  FunctionType *assignFt = assign->type->asFunctionType();
+  xassert(assignFt->params.count() == 2);
+  Variable *other = assignFt->params.nth(1);
+
+  // we make the function now, before filling in 'stmts', because
+  // while we're filling in 'stmts' we want 'f' on the function stack
+  Function *f = makeFunction(loc, assign,
+                             FakeList<MemberInit>::emptyList(),    // inits
+                             makeS_compound(loc));
+  functionStack.push(f);
+
+  // get ahold of the statement list to build
+  ASTList<Statement> *stmts = &(f->body->stmts);
+
+  // NOTE: these are made and appended *in* *order*, not in reverse
+  // and then reversed as with the copy ctor
+  {
+    // For each superclass, make the call to operator =.
+    FOREACH_OBJLIST(BaseClass, ct->bases, iter) {
+      BaseClass const *base = iter.data();
+      // omit initialization of virtual base classes, whether direct
+      // virtual or indirect virtual.  See cppstd 12.6.2 and the
+      // implementation of Function::tcheck_memberInits()
+      //
+      // FIX: We really should be initializing the direct virtual bases,
+      // but the logic is so complex I'm just going to omit it for now
+      // and err on the side of not calling enough initializers
+      if (!ct->hasVirtualBase(base->ct)) {
+        stmts->append(make_S_expr_superclassCopyAssign(loc, base->ct, other));
+      }
+    }
+
+    SFOREACH_OBJLIST_NC(Variable, ct->dataMembers, iter) {
+      Variable *var = iter.data();
+      if (!wantsMemberInit(var)) continue;
+      // skip assigning to const or reference members; NOTE: this is an
+      // asymmetry with copy ctor, which can INITIALIZE const or ref
+      // types, however we cannot ASSIGN to them.
+      //
+      // sm: The existence of consts or refs means that the assignment
+      // operator cannot be called, according to the spec.  But the
+      // behavior of the code here seems fine.
+      Type *type = var->type;
+      if (type->isReference() || type->isConst()) continue;
+      stmts->append(make_S_expr_memberCopyAssign(loc, var, other));
+    }
+
+    stmts->append(make_S_return_this(loc));
+  }
+
+  functionStack.pop();
+  return new MR_func(loc, f);
+}
+
+
+// make implicit dtor ****************
+
+// "a.~A();"
+S_expr *ElabVisitor::make_S_expr_memberDtor
+  (SourceLoc loc, Expression *member, CompoundType *memberType)
+{
+  // "~A"
+  Variable *dtor = getDtor(memberType);
+
+  // "a.~A()"
+  E_funCall *funcall = makeMemberCall(loc, member, dtor, emptyArgs());
+
+  // "a.~A();"
+  return makeS_expr(loc, funcall);
+}
+
+// for EA_MEMBER_DTOR
+void ElabVisitor::completeDtorCalls(
+  Function *func,      // destructor being annotated
+  CompoundType *ct)    // the class of which 'func' is a member
+{
+  SourceLoc loc = func->getLoc();
+
+  // We add to the statements in *forward* order, unlike when adding
+  // to MemberInitializers, but since this is a dtor, not a ctor, we
+  // *do* have to do it in reverse.
+  SObjStack<S_expr> dtorStmtsReverse;
+
+  FOREACH_OBJLIST(BaseClass, ct->bases, iter) {
+    BaseClass const *base = iter.data();
+    // omit initialization of virtual base classes, whether direct
+    // virtual or indirect virtual.  See cppstd 12.6.2 and the
+    // implementation of Function::tcheck_memberInits()
+    //
+    // FIX: We really should be initializing the direct virtual bases,
+    // but the logic is so complex I'm just going to omit it for now
+    // and err on the side of not calling enough destructors
+    if (!ct->hasVirtualBase(base->ct)) {
+      dtorStmtsReverse.push(
+        make_S_expr_memberDtor(loc, makeThisRef(loc), base->ct));
+    }
+  }
+
+  SFOREACH_OBJLIST_NC(Variable, ct->dataMembers, iter) {
+    Variable *var = iter.data();
+    if (!wantsMemberInit(var)) continue;
+    if (!var->type->isCompoundType()) continue;
+    dtorStmtsReverse.push(
+      make_S_expr_memberDtor(loc, makeE_variable(loc, var),
+                             var->type->asCompoundType()));
+  }
+
+  // reverse and append to the statements list
+  ASTList<Statement> *dtorStatements = new ASTList<Statement>();
+  while (!dtorStmtsReverse.isEmpty()) {
+    dtorStatements->append(dtorStmtsReverse.pop());
+  }
+
+  // FIX: I can't figure out the bug right now, but in/t0019.cc fails
+  // with a seg fault if I put this line *before* the while loop
+  // above.  From looking at the data structures, it seems that it
+  // shouldn't matter.
+  //
+  // sm: the reason is that creating an S_compound *deletes* the
+  // ASTList<Statement> that is passed to it
+  func->dtorStatement = new S_compound(loc, dtorStatements);
+}
+
+// for EA_IMPLICIT_MEMBER_DEFN
+MR_func *ElabVisitor::makeDtorBody(CompoundType *ct, Variable *dtor)
+{
+  SourceLoc loc = dtor->loc;
+
+  // function with empty body; the member dtors will be elaborated later
+  Function *f = makeFunction(loc, dtor,
+                             FakeList<MemberInit>::emptyList(),   // inits
+                             makeS_compound(loc));
+
+  return new MR_func(loc, f);
+}
+
+
+// -------------------- special function queries -----------------------
+// a filter on elements of an overload set of members in 'ct'
+typedef bool (*OverloadFilter)(CompoundType *ct, FunctionType *ft);
+
+Variable *overloadSetFilter(CompoundType *ct, Variable *start, OverloadFilter func)
+{
+  if (!start || !start->type->isFunctionType()) {
+    return NULL;               // name maps to no function
+  }
+
+  if (!start->overload) {
+    if (func(ct, start->type->asFunctionType())) {
+      return start;            // name maps to one thing, it passes
+    }
+    else {
+      return NULL;             // name maps to one thing, it fails
+    }
+  }
+
+  // name maps to multiple things, consider each
+  SFOREACH_OBJLIST_NC(Variable, start->overload->set, iter) {
+    if (func(ct, iter.data()->type->asFunctionType())) {
+      return iter.data();      // the first one that passes
+    }
+  }
+
+  return NULL;                 // none pass
+}
+
+
+static bool defaultCtorTest(CompoundType *ct, FunctionType *ft)
+{
+  // every parameter must have a default value
+  return ft->paramsHaveDefaultsPast(0);
+}
+
+Variable *ElabVisitor::getDefaultCtor(CompoundType *ct)
+{
+  return overloadSetFilter(ct, ct->rawLookupVariable(str("constructor-special")),
+                           defaultCtorTest);
+}
+
+
+// true if parameter 'n' is a reference to 'ct'
+static bool nthIsCtReference(CompoundType *ct, FunctionType *ft, int n,
+                             bool mustBeReference = true)
+{
+  if (ft->params.count() <= n) {
+    return false;
+  }
+  Type *t = ft->params.nth(n)->type;
+  if ((!mustBeReference || t->isReference()) &&
+      t->asRval()->ifCompoundType() == ct) {
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+static bool copyCtorTest(CompoundType *ct, FunctionType *ft)
+{
+  return
+    nthIsCtReference(ct, ft, 0) &&   // first param must be a reference to 'ct'
+    ft->paramsHaveDefaultsPast(1);   // subsequent have defaults
+}
+
+Variable *ElabVisitor::getCopyCtor(CompoundType *ct)
+{
+  return overloadSetFilter(ct, ct->rawLookupVariable(str("constructor-special")),
+                           copyCtorTest);
+}
+
+
+static bool assignOperatorTest(CompoundType *ct, FunctionType *ft)
+{
+  return
+    ft->isMethod() &&                // first param is receiver object
+    nthIsCtReference(ct, ft, 1,      // second param must be a reference to 'ct'
+      false /*mustBeReference*/) &&  //   12.8p9 allows non-ref (in/t0560.cc)
+    ft->paramsHaveDefaultsPast(2);   // subsequent have defaults
+}
+
+Variable *ElabVisitor::getAssignOperator(CompoundType *ct)
+{
+  return overloadSetFilter(ct, ct->rawLookupVariable(str("operator=")),
+                           assignOperatorTest);
+}
+
+
+Variable *ElabVisitor::getDtor(CompoundType *ct)
+{
+  // synthesize the dtor name... maybe I should be using
+  // "destructor-special" or something
+  return ct->rawLookupVariable(str(stringc << "~" << ct->name));
+}
+
+
+// --------------------- exception stuff ------------------
+// for EA_GLOBAL_EXCEPTION
+void Handler::elaborate(ElabVisitor &env)
+{
+  SourceLoc loc = body->loc;
+
+  // sm: grumble grumble, this code makes no sense... a separate
+  // global for every handler?  who interacts with all these globals?
+  // certainly not E_throw...
+
+  // NOTE: don't do this if it is just a *ref* to a CompoundType.
+  // Those are dtored later since the reference captures the global
+  // and prevents it from being dtored now.  FIX: we have to deal with
+  // this reference-capture problem just as with "A &a = A();"
+  // UPDATE: Well, I at least need to make the variable if it is a
+  // ref, so I'll make the dtor also.
+  Type *typeIdType = typeId->getType();
+  if (typeIdType->asRval()->isCompoundType()) {
+    if (!globalVar) {
+      globalVar = env.makeVariable(loc, env.makeCatchClauseVarName(),
+                                   typeIdType->asRval(),
+                                   DF_STATIC // I think it is a static global
+                                   | DF_GLOBAL);
+
+      // if we catch by value, we need a copy ctor into a temporary
+      // which is passed into the handler; in other words, we treat
+      // passing the global exception to the handler as if it were a
+      // function call
+      if (typeIdType->isCompoundType()) {
+        localArg = env.elaborateCallByValue
+          (loc, typeIdType,
+           env.makeE_variable(loc, globalVar) // NOTE: elaborateCallByValue() won't clone this
+           );
+      }
+
+      // Scott doesn't like the idea of this being here, but it has to
+      // go somewhere, and, just as we don't have a "global" space in
+      // which to put the globalVar, we don't have a "global" place to
+      // put its dtor, so I put them together.
+      globalDtorStatement =
+        env.makeDtorStatement(loc,
+                              // no need to clone the target as
+                              // makeE_variable() makes all new AST
+                              env.makeE_variable(loc, globalVar),
+                              // can only make a dtor for a CompoundType, not a ref to one
+                              typeIdType->asRval());
+    }
+  }
+}
+
+
+// for EA_GLOBAL_EXCEPTION
+bool E_throw::elaborate(ElabVisitor &env)
+{
+  if (!expr) {
+    return false;     // no children anyway
+  }
+
+  // sm: I think what follows is wrong:
+  //   - 'globalVar' is created, but a declaration is not, so
+  //     an analysis might be confused by its sudden appearance
+  //   - the same object is used for all types, but makeCtorStatement
+  //     is invoked with different types.. it's weird
+  //   - the whole thing with throwClauseSerialNumber is bad.. it
+  //     *should* be a member of Env, and set from the outside after
+  //     construction if a wrapper analysis wants the numbers to not
+  //     be re-used
+
+  // sm: there is no location handy, and it wouldn't make sense anyway
+  // because it makes no sense to associate a new global with every E_throw!
+  // ok, maybe I'm being harsh.. but there's still no loc handy
+  SourceLoc loc = SL_UNKNOWN;
+
+  // If it is a throw by value, it gets copy ctored somewhere, which
+  // in an implementation is some anonymous global.  I can't think of
+  // where the heck to make these globals or how to organize them, so
+  // I just make it in the throw itself.  Some analysis can come
+  // through and figure out how to hook these up to their catch
+  // clauses.
+  Type *exprType = expr->getType()->asRval();
+  if (exprType->isCompoundType()) {
+    if (!globalVar) {
+      globalVar = env.makeVariable(loc, env.makeThrowClauseVarName(),
+                                   exprType,
+                                   DF_STATIC // I think it is a static global
+                                   | DF_GLOBAL);
+
+      // clone the expr, putting the clone back into 'expr', and using
+      // the original (tcheck'd) one in 'makeCtorStatement' (SCS)
+      Expression *origExpr = expr;
+      expr = env.cloneExpr(expr);
+
+      globalCtorStatement =
+        env.makeCtorStatement(loc, env.makeE_variable(loc, globalVar), exprType,
+                              env.getCopyCtor(exprType->asCompoundType()),
+                              makeExprList1(origExpr));
+
+      return false;     // SES
+    }
+  }
+
+  return true;
+}
+
+
+// ------------------------ new/delete ---------------------------
+bool E_new::elaborate(ElabVisitor &env)
+{
+  SourceLoc loc = env.enclosingStmtLoc;
+
+  // TODO: this doesn't work for new[]
+
+  // sm: This is way wrong.  It pretends that 'new' yields a reference
+  // to the same global instance over and over.  The code should
+  // instead do something like:
+  //   C *temp = ::operator new(sizeof(C));
+  //   temp <- C::C();      // 'temp' is 'retObj'
+  //   temp                 // the value of the E_new expression
+
+  // the type of the elements to create
+  Type *t = atype->getType();
+
+  if (t->isCompoundType()) {
+    heapVar = env.makeVariable(loc, env.makeE_newVarName(), t, DF_NONE);
+
+    FakeList<ArgExpression> *args0 = env.emptyArgs();
+    if (ctorArgs) {
+      // original is used in elaboration, clone stays behind (SCS)
+      args0 = ctorArgs->list;
+      ctorArgs->list = env.cloneExprList(ctorArgs->list);
+    }
+
+    ctorStatement = env.makeCtorStatement(loc, env.makeE_variable(loc, heapVar), t,
+                                          ctorVar, args0);
+    return false;    // SES
+  }
+
+  return true;
+}
+
+
+bool E_delete::elaborate(ElabVisitor &env)
+{
+  SourceLoc loc = env.enclosingStmtLoc;
+
+  // TODO: this doesn't work for delete[]
+
+  // the type of the argument to 'delete', typically a pointer to
+  // the type of the elements to destroy
+  Type *t = expr->type->asRval();
+
+  // E_delete::itcheck_x() should have noticed that its not a pointer
+  // and aborted before calling us if it wasn't.
+  PointerType *to = t->asPointerType();
+  if (to->atType->isCompoundType()) {
+    if (!to->atType->asCompoundType()->isComplete()) {
+      // 10/03/04: cppstd 5.3.5 para 5 explains that, while it *is*
+      // legal to delete an incomplete type, the destructor (once the
+      // type is completed) must be trivial (otherwise the program has
+      // undefined behavior); so Elsa will assume that the dtor is in
+      // fact trivial
+      return true;
+    }
+
+    // use orig in elaboration, clone stays behind
+    Expression *origExpr = expr;
+    expr = env.cloneExpr(expr);
+
+    E_deref *deref = new E_deref(origExpr);
+    deref->type = env.tfac.makeReferenceType(to->atType);
+
+    dtorStatement = env.makeDtorStatement
+      (loc,
+       deref,
+       to->atType               // no need to clone this type; it is not stored
+       );
+
+    return false;     // SES
+  }
+
+  return true;
+}
+
+
+// ----------------------- S_return -----------------------
+// for EA_ELIM_RETURN_BY_VALUE
+bool S_return::elaborate(ElabVisitor &env)
+{
+  if (expr) {
+    FunctionType *ft = env.functionStack.top()->funcType;
+    xassert(ft);
+
+    // FIX: check that ft->retType is non-NULL; I'll put an assert for now
+    // sm: FunctionType::retType is never NULL ...
+    xassert(ft->retType);
+
+    if (ft->retType->isCompoundType()) {
+      CompoundType *retTypeCt = ft->retType->asCompoundType();
+
+      // This is an instance of return by value of a compound type.
+      // We accomplish this by calling the copy ctor.
+
+      // get the target of the constructor function
+      E_variable *retVar = env.makeE_variable(loc, env.functionStack.top()->retVar);
+
+      // since the S_return itself will be visited before the subexpr,
+      // we know the expr here has not yet been elaborated, so will not
+      // yet have put any temporaries into the fullexp
+      xassert(expr->getAnnot()->noTemporaries());
+
+      // get the arguments of the constructor function; NOTE: we dig
+      // down below the FullExpression to the raw Expression
+      Expression *subExpr = expr->expr;
+      FakeList<ArgExpression> *args0 =
+      FakeList<ArgExpression>::makeList(new ArgExpression(subExpr));
+      xassert(args0->count() == 1);      // makeList always returns a singleton list
+
+      // make the constructor function
+      env.push(expr->getAnnot());// e.g. in/d0049.cc breaks w/o this
+      ctorStatement = env.makeCtorStatement(loc, retVar, ft->retType,
+                                            env.getCopyCtor(retTypeCt), args0);
+      env.pop(expr->getAnnot());
+
+      // make the original expression a clone
+      expr->expr = env.cloneExpr(expr->expr);
+
+      // traverse only the elaboration
+      //ctorStatement->traverse(env);    // 'makeCtorStatement' does this internally
+      return false;
+    }
+  }
+
+  return true;     // traverse 'expr'
+}
+
+
+// ===================== ElabVisitor =========================
+// ----------------------- TopForm ---------------------------
+bool ElabVisitor::visitTopForm(TopForm *tf)
+{
+  static int elabTopForm = 0;
+  ++elabTopForm;
+  TRACE("elabtopform", elabTopForm);
+  if (doing(EA_VARIABLE_DECL_CDTOR) &&
+      tf->isTF_decl()) {
+    // global variables
+    elaborateCDtorsDeclaration(tf->asTF_decl()->decl);
+    return false;     // SES (e.g. in/d0027.cc breaks if we return true)
+  }
+
+  return true;
+}
+
+
+// ----------------------- Function ---------------------------
+bool ElabVisitor::visitFunction(Function *f)
+{
+  // don't elaborate function bodies that were never typechecked
+  if (f->instButNotTchecked()) {
+    return false;               // prune
+  }
+
+  functionStack.push(f);
+  FunctionType *ft = f->funcType;
+
+  if (doing(EA_ELIM_RETURN_BY_VALUE)) {
+    elaborateFunctionStart(f);
+  }
+
+  if (doing(EA_MEMBER_DTOR) &&
+      ft->isDestructor()) {
+    completeDtorCalls(f, ft->getClassOfMember());
+  }
+
+  if (doing(EA_IMPLICIT_MEMBER_CTORS) &&
+      ft->isConstructor()) {
+    // pull out the compound that this ctor creates
+    CompoundType *ct = f->receiver->type->asReferenceType()->
+                          atType->asCompoundType();
+    completeNoArgMemberInits(f, ct);
+  }
+
+  return true;
+}
+
+
+void ElabVisitor::postvisitFunction(Function *)
+{
+  functionStack.pop();
+}
+
+
+// ---------------------- MemberInit ---------------------------
+bool ElabVisitor::visitMemberInit(MemberInit *mi)
+{
+  push(mi->getAnnot());
+
+  Function *func = functionStack.top();
+  SourceLoc loc = mi->name->loc;
+
+  // should already be tchecked, and either be a member or base class subobject
+  xassert(mi->member || mi->base);
+
+  // TODO: use assignments instead of ctors for non-class-valued objects
+  //        dsw: this comment above is wrong - should be initializations, not
+  //        assignments
+
+  if (doing(EA_MEMBER_CTOR) &&
+      mi->ctorVar) {
+    // clone the arguments, but use the original tcheck'd version as
+    // what will subsequently be elaborated
+    FakeList<ArgExpression> *orig = mi->args;
+    FakeList<ArgExpression> *cloned = env.cloneExprList(mi->args);
+    mi->args = cloned;
+
+    if (mi->member) {
+      // initializing a data member
+      mi->ctorStatement = makeCtorStatement
+        (loc, makeE_variable(loc, mi->member), mi->member->type,
+         mi->ctorVar, orig);
+    }
+
+    else {
+      // initializing a base class subobject
+
+      // need a Type for the eventual E_constructor...
+      Type *type = tfac.makeCVAtomicType(mi->base, CV_NONE);
+
+      mi->ctorStatement = makeCtorStatement
+        (loc, makeE_variable(loc, func->receiver), type,
+         mi->ctorVar, orig);
+    }
+
+    // elaborate the ctorStatement only (not the 'args')
+    //mi->ctorStatement->traverse(this->loweredVisitor); // 'makeCtorStatement' does this internally
+
+    pop(mi->getAnnot());// b/c when I return false, postvisit isn't called
+    return false;       // don't automatically traverse children, esp. 'args' (SES)
+  }
+
+  else {
+    return true;        // automatically traverse, elaborate 'args'
+  }
+}
+
+void ElabVisitor::postvisitMemberInit(MemberInit *mi)
+{
+  pop(mi->getAnnot());
+}
+
+
+// -------------------- TypeSpecifier --------------------------
+bool ElabVisitor::visitTypeSpecifier(TypeSpecifier *ts)
+{
+  if (doing(EA_IMPLICIT_MEMBER_DEFN) &&
+      ts->isTS_classSpec()) {
+    TS_classSpec *spec = ts->asTS_classSpec();
+    SourceLoc loc = spec->loc;
+    CompoundType *ct = spec->ctype;
+
+    if (!ct->name) {
+      return true;      // bail on anonymous classes, since 'addCompilerSuppliedDecls' does
+    }
+
+    // default ctor
+    {
+      // is there an implicit decl?
+      Variable *var = getDefaultCtor(ct);
+      if (var && var->isImplicitMemberFunc()) {
+        spec->members->list.append(makeNoArgCtorBody(ct, var));
+      }
+    }
+
+    // copy ctor
+    {
+      // is there an implicit decl?
+      Variable *var = getCopyCtor(ct);
+      if (var && var->isImplicitMemberFunc()) {
+        spec->members->list.append(makeCopyCtorBody(ct, var));
+      }
+    }
+
+    // assignment operator
+    {
+      // is there an implicit decl?
+      Variable *var = getAssignOperator(ct);
+      if (var && var->isImplicitMemberFunc()) {
+        spec->members->list.append(makeCopyAssignBody(loc, ct, var));
+      }
+    }
+
+    // dtor
+    {
+      // is there an implicit decl?
+      Variable *var = getDtor(ct);
+      if (var && var->isImplicitMemberFunc()) {
+        spec->members->list.append(makeDtorBody(ct, var));
+      }
+    }
+
+    // NOTE: In the code above, we have added to 'members->list', which
+    // means that the added elements *will* be traversed after this
+    // function returns, as part of the usual subtree traversal.
+  }
+
+  return true;     // traverse children (subtrees)
+}
+
+
+// ------------------------ Member -----------------------------
+bool ElabVisitor::visitMember(Member *m)
+{
+  // Calling 'elaborateCDtorsDeclaration' wouldn't make sense because
+  // ctors need to depend on member init arguments, and dtors are more
+  // easily handled by adding them to the containing dtors.
+  #if 0
+  if (doing(EA_MEMBER_DECL_CDTOR) &&
+      m->isMR_decl()) {
+    // members
+    elaborateCDtorsDeclaration(m->asMR_decl()->d);
+    return false;    // SES
+  }
+  #endif // 0
+
+  return true;
+}
+
+
+// ----------------------- Statement ---------------------------
+bool ElabVisitor::visitStatement(Statement *s)
+{
+  enclosingStmtLoc = s->loc;
+
+  if (doing(EA_ELIM_RETURN_BY_VALUE) &&
+      s->isS_return()) {
+    return s->asS_return()->elaborate(*this);
+  }
+
+  if (doing(EA_VARIABLE_DECL_CDTOR) &&
+      s->isS_decl()) {
+    // local variables
+    elaborateCDtorsDeclaration(s->asS_decl()->decl);
+    return false;      // SES
+  }
+
+  return true;
+}
+
+
+// --------------------- Condition ------------------------
+bool ElabVisitor::visitCondition(Condition *c)
+{
+  if (doing(EA_VARIABLE_DECL_CDTOR) &&
+      c->isCN_decl()) {
+    c->asCN_decl()->typeId->decl->elaborateCDtors(*this);
+    return false;      // SES
+  }
+
+  return true;
+}
+
+
+// ---------------------- Handler -------------------------
+bool ElabVisitor::visitHandler(Handler *h)
+{
+  push(h->getAnnot());
+
+  if (doing(EA_GLOBAL_EXCEPTION)) {
+    h->elaborate(*this);
+
+    // the elaboration performed by 'h' doesn't do anything with
+    // the handler body, and default elaboration won't mess with
+    // the handler parameter, so it should be safe to simply allow
+    // default elaboration to take care of subtrees
+    return true;
+  }
+
+  return true;
+}
+
+void ElabVisitor::postvisitHandler(Handler *h)
+{
+  pop(h->getAnnot());
+}
+
+
+// ---------------------- Expression ------------------------
+bool ElabVisitor::visitExpression(Expression *e)
+{
+  // will have to suffice..
+  SourceLoc loc = enclosingStmtLoc;
+
+  if (e->isE_stringLit()) {
+    // There is nothing to elaborate, and I don't want to look at
+    // the 'continuation' since its 'type' field is NULL.  Also,
+    // this avoids dying on the NULL 'type' field of the string
+    // literals in 'asm's.
+    return false;
+  }
+
+  xassert (e->type && "48c58fcf-900a-4b17-bf13-17a2c93d799d");
+
+  // don't elaborate template-dependent expressions
+  //
+  // note that if someone creates an Expression and forgets to set
+  // the 'type' field, it will segfault here, so this test also
+  // serves as something of an AST validator
+  if (e->type->isDependent()) {
+    // FIX: dsw: shouldn't this be an assertion failure now that we
+    // never elaborate template definitions?
+    return false;   // ignore children
+  }
+
+  if (doing(EA_GLOBAL_EXCEPTION) &&
+      e->isE_throw()) {
+    return e->asE_throw()->elaborate(*this);
+  }
+
+  // EA_ELIM_RETURN_BY_VALUE and EA_ELIM_PASS_BY_VALUE; the
+  // individual feature tests are inside 'elaborateCallSite'
+  //
+  // Note that 'elaborateCallSite' produces tcheck'd AST but
+  // does not finish off all elaboration, so afterwards we
+  // let the visitor automatically elaborate subtrees.
+  if (e->isE_funCall()) {
+    E_funCall *call = e->asE_funCall();
+    if (call->func->type->isFunctionType()) {
+      call->retObj = elaborateCallSite(loc, call->func->type->asFunctionType(),
+                                       call->args, false /*artificialCtor*/);
+    }
+    else {
+      // things that end up here:
+      //   - call sites in template functions (e.g. in/t0047.cc);
+      //     maybe don't elaborate template functions at all?
+      //   - calls to function objects (operator()), because our
+      //     operator overload resolution doesn't fix the AST in
+      //     that case
+      // just let these slide for now...
+    }
+  }
+  if (e->isE_constructor()) {
+    E_constructor *call = e->asE_constructor();
+
+    // sm: I'm replicating the logic that was originally in
+    // E_constructor::inner2_itcheck, even though it's clear
+    // that 'artificialCtor' is always false
+    if (call->ctorVar && !call->artificial) {
+      call->retObj = elaborateCallSite(loc, call->ctorVar->type->asFunctionType(),
+                                       call->args, call->artificial /*artificialCtor*/);
+    }
+  }
+
+  if (doing(EA_TRANSLATE_NEW) &&
+      e->isE_new()) {
+    return e->asE_new()->elaborate(*this);
+  }
+  if (doing(EA_TRANSLATE_DELETE) &&
+      e->isE_delete()) {
+    return e->asE_delete()->elaborate(*this);
+  }
+
+  return true;
+}
+
+
+// ----------------------- FullExpression ----------------------
+bool ElabVisitor::visitFullExpression(FullExpression *fe)
+{
+  push(fe->getAnnot());
+  return true;
+}
+
+void ElabVisitor::postvisitFullExpression(FullExpression *fe)
+{
+  pop(fe->getAnnot());
+}
+
+
+// ----------------------- getAnnot() ----------------------
+
+// I construct this lazily because you can't initialize with one
+// because you can't call new on a class that has only been forward
+// declared.
+bool MemberInit::hasAnnot() {
+  return annot;
+}
+
+bool Handler::hasAnnot() {
+  return annot;
+}
+
+bool FullExpression::hasAnnot() {
+  return annot;
+}
+
+bool Initializer::hasAnnot() {
+  return annot;
+}
+
+FullExpressionAnnot *MemberInit::getAnnot() {
+  if (!annot) annot = new FullExpressionAnnot(new ASTList<Declaration>());
+  return annot;
+}
+
+FullExpressionAnnot *Handler::getAnnot() {
+  if (!annot) annot = new FullExpressionAnnot(new ASTList<Declaration>());
+  return annot;
+}
+
+FullExpressionAnnot *FullExpression::getAnnot() {
+  if (!annot) annot = new FullExpressionAnnot(new ASTList<Declaration>());
+  return annot;
+}
+
+FullExpressionAnnot *Initializer::getAnnot() {
+  if (!annot) annot = new FullExpressionAnnot(new ASTList<Declaration>());
+  return annot;
+}
+
+
+// ----------------------- Initializer ----------------------
+bool ElabVisitor::visitInitializer(Initializer *in)
+{
+  // the fullexp annots kick in only for IN_expr and IN_ctor;
+  // its presence in IN_compound is a false orthogonality
+  if (in->isIN_expr() || in->isIN_ctor()) {
+    push(in->getAnnot());
+  }
+
+  return true;
+}
+
+void ElabVisitor::postvisitInitializer(Initializer *in)
+{
+  if (in->isIN_expr() || in->isIN_ctor()) {
+    pop(in->getAnnot());
+  }
+}
+
+
+// =================== extra AST nodes =====================
+// ------------------------ TS_type ------------------------
+Type *TS_type::itcheck(Env &env, DeclFlags dflags)
+{
+  return type;
+}
+
+void TS_type::print(PrintEnv &env)
+{
+  xfailure("I think this is not called because TS_simple::print isn't either");
+}
+
+
+// --------------------- PQ_variable ------------------------
+StringRef PQ_variable::getName() const
+{
+  return var->name;
+}
+
+string PQ_variable::toComponentString() const
+{
+  return var->name;
+}
+
+void PQ_variable::tcheck_pq(Env &env, Scope*, LookupFlags)
+{
+  // nothing to check
+}
+
+void PQ_variable::print(PrintEnv &env)
+{
+  // this is unlikely to tcheck correctly, but that's true of
+  // lots of cc_print functions..
+  *env.out << var->name;
+}
+
+// EOF

Added: vendor/elsa/current/elsa/cc_elaborate.h
===================================================================
--- vendor/elsa/current/elsa/cc_elaborate.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_elaborate.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,308 @@
+// cc_elaborate.h            see license.txt for copyright and terms of use
+// semantic elaboration pass
+// see also cc_elaborate.ast
+
+#ifndef CC_ELABORATE_H
+#define CC_ELABORATE_H
+
+
+// The concept of semantic elaboration is that we provide, for many
+// constructs in the language, equivalent alternative formulations in
+// terms of a smaller set of primitive operations.  Then, an analysis
+// can use the elaboration instead of building into itself the language
+// spec's specified semantics.
+
+
+#include "cc_ast.h"       // AST components, etc.
+#include "macros.h"       // ENUM_BITWISE_OPS
+#include "cc_ast_aux.h"   // class LoweredASTVisitor
+
+// moved FullExpressionAnnot into fullexp.h to reduce dependencies
+// in the #include graph
+//
+// dsw: made it into an AST class to simply serialization and because
+// it has always been a rather odd-man-out and it seems natural as an
+// AST class
+
+
+// counter for generating unique throw clause names; NOTE: FIX: they
+// must not be duplicated across translation units since they are
+// global!  Thus, this must survive even multiple Env objects.
+// (this is for elaboration)
+extern int throwClauseSerialNumber;
+
+
+// This enumeration lists all the activities performed by the elaboration
+// visitor.  Each can be individually turned on or off, though all are
+// on by default.
+enum ElabActivities {
+  // This replaces return-by-value for class-valued objects with
+  // call-by-reference:
+  //   - At every call site that would return by value, a temporary
+  //     is created, and passed to the function as an additional
+  //     argument.  Here, "passed" means the E_funCall or E_constructor
+  //     has a 'retObj' pointer to the expression denoting the temporary.
+  //   - In the callee, a special "<retVar>" variable is created; it is
+  //     implicit that it gets its value from the passed temporary.  All
+  //     S_returns are then rewritten to return nothing, but instead
+  //     construct the <retVar> in their 'ctorStatement'.
+  EA_ELIM_RETURN_BY_VALUE  = 0x0001,
+
+  // At the end of a destructor, create a 'dtorStatement' which is the
+  // sequence of dtors of superclasses and members.
+  EA_MEMBER_DTOR           = 0x0002,
+
+  // At member initializers (MemberInits), create a 'ctorStatement'
+  // which explicates the construction of the superclass subobject or
+  // class member as an E_constructor call.
+  EA_MEMBER_CTOR           = 0x0004,
+
+  // In constructors, for any superclasses or members that are not
+  // explicitly initialized, insert MemberInits that invoke the
+  // default (no-arg) constructor for the superclass or member.
+  EA_IMPLICIT_MEMBER_CTORS = 0x0008,
+
+  // Add inline definitions for the compiler-supplied declarations of
+  // certain member functions: default ctor, copy ctor, assignment op,
+  // and dtor.
+  EA_IMPLICIT_MEMBER_DEFN  = 0x0010,
+
+  // For each class-valued local or global variable, annotate its
+  // declarator with a 'ctorStatement' and 'dtorStatement' that
+  // construct and destruct the member, respectively.
+  EA_VARIABLE_DECL_CDTOR   = 0x0020,
+
+  // At throw and catch sites, add statements to construct, copy, and
+  // destroy the global exception object that communicates thrown
+  // object values from throw to catch.
+  EA_GLOBAL_EXCEPTION      = 0x0040,
+
+  // Eliminate pass-by-value for class-valued objects: at the call site,
+  // create a temporary, and pass that.  Then, the callee can treat all
+  // parameters (for class-valued params) as if they were pass by reference.
+  EA_ELIM_PASS_BY_VALUE    = 0x0080,
+
+  // Translate 'new' into allocation+construction, placing the
+  // translation in the 'ctorStatement' of E_new.
+  EA_TRANSLATE_NEW         = 0x0100,
+
+  // Translate 'delete' into destruction+deallocation, placing the
+  // translation in the 'dtorStatement' of E_delete.
+  EA_TRANSLATE_DELETE      = 0x0200,
+
+  // Elaboration activities for C
+  EA_C_ACTIVITIES          = ( EA_ELIM_RETURN_BY_VALUE |  EA_ELIM_PASS_BY_VALUE ),
+
+  // all flags above
+  EA_ALL                   = 0x03FF,
+
+  // Note that a number of the above activities create temporary
+  // objects.  To support their deletion at the proper time,
+  // cc_elaborate.ast adds FullExpressionAnnot objects to some AST
+  // nodes, and elaboration registers the temporaries with them
+  // accordingly.  An analysis should pay attention to the
+  // FullExpressionAnnot objects so it can properly track temporary
+  // object lifetimes.
+};
+
+ENUM_BITWISE_OPS(ElabActivities, EA_ALL)
+
+
+// this visitor is responsible for conducting all the
+// elaboration activities
+// Intended to be used with LoweredASTVisitor
+class ElabVisitor : private ASTVisitor {
+public:      // data
+  LoweredASTVisitor loweredVisitor; // use this as the argument for traverse()
+
+  // similar fields to Env
+  StringTable &str;
+  TypeFactory &tfac;
+  TranslationUnit *tunit;      // doh! out damned spot!
+
+  // little trick: as code moves about it's convenient if 'env'
+  // always works, even inside ElabVisitor methods
+  ElabVisitor &env;            // refers to *this
+
+  // stack of functions, topmost being the one we're in now
+  ArrayStack<Function*> functionStack;
+
+  // so that we can find the closest nesting S_compound for when we
+  // need to insert temporary variables; its scope should always be
+  // the current scope.
+  ArrayStack<FullExpressionAnnot*> fullExpressionAnnotStack;
+
+  // location of the most recent Statement.. used for approximate
+  // loc info when visiting Expressions
+  SourceLoc enclosingStmtLoc;
+
+  // strings
+  StringRef receiverName;
+
+  // counters for generating unique temporary names; not unique
+  // across translation units
+  int tempSerialNumber;
+  int e_newSerialNumber;
+
+  // ---------- elaboration parameters -----------
+  // These get set to default values by the ctor, but then the client
+  // can change them after construction.  I did it this way to avoid
+  // making tons of ctor parameters.
+
+  // what we're doing; this defaults to EA_ALL
+  ElabActivities activities;
+
+  // When true, we retain cloned versions of subtrees whose semantics
+  // is captured (and therefore the tree obviated) by the elaboration.
+  // When false, we just nullify those subtrees, which results in
+  // sometimes-invalid AST, but makes some analyses happy anway.  This
+  // defaults to false.
+  bool cloneDefunctChildren;
+
+public:      // funcs
+  // true if a particular activity is requested
+  bool doing(ElabActivities a) const { return !!(activities & a); }
+
+  // fresh names
+  StringRef makeTempName();
+  StringRef makeE_newVarName();
+  StringRef makeThrowClauseVarName();
+  StringRef makeCatchClauseVarName();
+
+  // similar to a function in Env
+  Variable *makeVariable(SourceLoc loc, StringRef name,
+                         Type *type, DeclFlags dflags);
+
+  // syntactic convenience
+  void push(FullExpressionAnnot *a)
+    { fullExpressionAnnotStack.push(a); }
+  void pop(FullExpressionAnnot *a)
+    { FullExpressionAnnot *tmp = fullExpressionAnnotStack.pop(); xassert(a == tmp); }
+
+public:      // funcs
+  // This section is organized like the .cc file, but all the comments
+  // are in the .cc file, so look there first.
+
+  // AST creation
+  D_name *makeD_name(SourceLoc loc, Variable *var);
+  Declarator *makeDeclarator(SourceLoc loc, Variable *var, DeclaratorContext context);
+  Declaration *makeDeclaration(SourceLoc loc, Variable *var, DeclaratorContext context);
+  Declarator *makeFuncDeclarator(SourceLoc loc, Variable *var, DeclaratorContext context);
+  Function *makeFunction(SourceLoc loc, Variable *var,
+                         FakeList<MemberInit> *inits,
+                         S_compound *body);
+  E_variable *makeE_variable(SourceLoc loc, Variable *var);
+  E_fieldAcc *makeE_fieldAcc
+    (SourceLoc loc, Expression *obj, Variable *field);
+  E_funCall *makeMemberCall
+    (SourceLoc loc, Expression *obj, Variable *func, FakeList<ArgExpression> *args);
+  FakeList<ArgExpression> *emptyArgs();
+  Expression *makeThisRef(SourceLoc loc);
+  S_expr *makeS_expr(SourceLoc loc, Expression *e);
+  S_compound *makeS_compound(SourceLoc loc);
+
+  // makeCtor
+  E_constructor *makeCtorExpr(
+    SourceLoc loc,
+    Expression *target,
+    Type *type,
+    Variable *ctor,
+    FakeList<ArgExpression> *args);
+  Statement *makeCtorStatement(
+    SourceLoc loc,
+    Expression *target,
+    Type *type,
+    Variable *ctor,
+    FakeList<ArgExpression> *args);
+
+  // makeDtor
+  Expression *makeDtorExpr(SourceLoc loc, Expression *target,
+                           Type *type);
+  Statement *makeDtorStatement(SourceLoc loc, Expression *target,
+                               Type *type);
+
+  // cloning
+  FakeList<ArgExpression> *cloneExprList(FakeList<ArgExpression> *args0);
+  Expression *cloneExpr(Expression *e);
+
+  // elaborateCDtors
+  void elaborateCDtorsDeclaration(Declaration *decl);
+
+  // elaborateCallSite
+  Declaration *makeTempDeclaration
+    (SourceLoc loc, Type *retType, Variable *&var /*OUT*/, DeclaratorContext context);
+  Variable *insertTempDeclaration(SourceLoc loc, Type *retType);
+  Expression *elaborateCallByValue
+    (SourceLoc loc, Type *paramType, Expression *argExpr);
+  Expression *elaborateCallSite(
+    SourceLoc loc,
+    FunctionType *ft,
+    FakeList<ArgExpression> *args,
+    bool artificalCtor);
+
+  // elaborateFunctionStart
+  void elaborateFunctionStart(Function *f);
+
+  // completeNoArgMemberInits
+  bool wantsMemberInit(Variable *var);
+  MemberInit *findMemberInitDataMember
+    (FakeList<MemberInit> *inits,
+     Variable *memberVar);
+  MemberInit *findMemberInitSuperclass
+    (FakeList<MemberInit> *inits,
+     CompoundType *superclass);
+  void completeNoArgMemberInits(Function *ctor, CompoundType *ct);
+
+  // make compiler-supplied member funcs
+  Variable *makeCtorReceiver(SourceLoc loc, CompoundType *ct);
+  MR_func *makeNoArgCtorBody(CompoundType *ct, Variable *ctor);
+  MemberInit *makeCopyCtorMemberInit(
+    Variable *target,
+    Variable *srcParam,
+    SourceLoc loc);
+  MR_func *makeCopyCtorBody(CompoundType *ct, Variable *ctor);
+  S_return *make_S_return_this(SourceLoc loc);
+  S_expr *make_S_expr_memberCopyAssign
+    (SourceLoc loc, Variable *member, Variable *other);
+  S_expr *make_S_expr_superclassCopyAssign
+    (SourceLoc loc, CompoundType *w, Variable *other);
+  MR_func *makeCopyAssignBody
+    (SourceLoc loc, CompoundType *ct, Variable *assign);
+  S_expr *make_S_expr_memberDtor
+    (SourceLoc loc, Expression *member, CompoundType *memberType);
+  void completeDtorCalls(
+    Function *func,
+    CompoundType *ct);
+  MR_func *makeDtorBody(CompoundType *ct, Variable *dtor);
+
+  // some special member functions
+  Variable *getDefaultCtor(CompoundType *ct);    // C(); might be NULL at any time
+  Variable *getCopyCtor(CompoundType *ct);       // C(C const &);
+  Variable *getAssignOperator(CompoundType *ct); // C& operator= (C const &);
+  Variable *getDtor(CompoundType *ct);           // ~C();
+
+public:
+  ElabVisitor(StringTable &str, TypeFactory &tfac, TranslationUnit *tunit);
+  virtual ~ElabVisitor();
+
+  // ASTVisitor funcs
+  bool visitTopForm(TopForm *tf);
+  bool visitFunction(Function *f);
+  void postvisitFunction(Function *f);
+  bool visitMemberInit(MemberInit *mi);
+  void postvisitMemberInit(MemberInit *mi);
+  bool visitTypeSpecifier(TypeSpecifier *ts);
+  bool visitMember(Member *m);
+  bool visitStatement(Statement *s);
+  bool visitCondition(Condition *c);
+  bool visitHandler(Handler *h);
+  void postvisitHandler(Handler *h);
+  bool visitExpression(Expression *e);
+  bool visitFullExpression(FullExpression *fe);
+  void postvisitFullExpression(FullExpression *fe);
+  bool visitInitializer(Initializer *in);
+  void postvisitInitializer(Initializer *in);
+};
+
+
+#endif // CC_ELABORATE_H

Added: vendor/elsa/current/elsa/cc_env.cc
===================================================================
--- vendor/elsa/current/elsa/cc_env.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_env.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5825 @@
+// cc_env.cc            see license.txt for copyright and terms of use
+// code for cc_env.h
+
+#include "cc_env.h"        // this module
+#include "trace.h"         // tracingSys
+#include "ckheap.h"        // heapCheck
+#include "strtable.h"      // StringTable
+#include "cc_lang.h"       // CCLang
+#include "strutil.h"       // suffixEquals, prefixEquals
+#include "overload.h"      // OVERLOADTRACE
+#include "mtype.h"         // MType
+#include "implconv.h"      // ImplicitConversion
+
+
+// forwards in this file
+
+// helper functions for elaboration not during elaboration stage, but during
+// type checking.
+E_addrOf *makeAddr(TypeFactory &tfac, SourceLoc loc, Expression *e);
+
+
+void gdbScopeSeq(ScopeSeq &ss)
+{
+  cout << "scope sequence" << endl;
+  for(int i=0; i<ss.length(); ++i) {
+    Scope *scope = ss[i];
+    xassert(scope);
+    cout << "\t[" << i << "] ";
+    scope->gdb();
+  }
+}
+
+
+inline ostream& operator<< (ostream &os, SourceLoc sl)
+  { return os << toString(sl); }
+
+
+// --------------------
+
+// true if 't' is reference to 'ct', ignoring any c/v
+static bool isRefToCt(Type const *t, CompoundType *ct)
+{
+  if (!t->isReference()) return false;
+
+  ReferenceType const *rt = t->asReferenceTypeC();
+  if (!rt->atType->isCVAtomicType()) return false;
+
+  CVAtomicType const *at = rt->atType->asCVAtomicTypeC();
+  if (at->atomic != ct) return false; // NOTE: atomics are equal iff pointer equal
+
+  return true;
+}
+
+
+// cppstd 12.8 para 2: "A non-template constructor for a class X is a
+// _copy_ constructor if its first parameter is of type X&, const X&,
+// volatile X&, or const volatile X&, and either there are no other
+// parameters or else all other parameters have default arguments
+// (8.3.6)."
+bool isCopyConstructor(Variable const *funcVar, CompoundType *ct)
+{
+  FunctionType *ft = funcVar->type->asFunctionType();
+  if (!ft->isConstructor()) return false; // is a ctor?
+  if (funcVar->isTemplate()) return false; // non-template?
+  if (ft->params.isEmpty()) return false; // has at least one arg?
+
+  // is the first parameter a ref to the class type?
+  if (!isRefToCt(ft->params.firstC()->type, ct)) return false;
+
+  // do all the parameters past the first one have default arguments?
+  bool first_time = true;
+  SFOREACH_OBJLIST(Variable, ft->params, paramiter) {
+    // skip the first variable
+    if (first_time) {
+      first_time = false;
+      continue;
+    }
+    if (!paramiter.data()->value) return false;
+  }
+
+  return true;                  // all test pass
+}
+
+
+// cppstd 12.8 para 9: "A user-declared _copy_ assignment operator
+// X::operator= is a non-static non-template member function of class
+// X with exactly one parameter of type X, X&, const X&, volatile X&
+// or const volatile X&."
+bool isCopyAssignOp(Variable const *funcVar, CompoundType *ct)
+{
+  FunctionType *ft = funcVar->type->asFunctionType();
+  if (!ft->isMethod()) return false; // is a non-static member?
+  if (funcVar->isTemplate()) return false; // non-template?
+  if (ft->params.count() != 2) return false; // has two args, 1) this and 2) other?
+
+  // the second parameter; the first is "this"
+  Type *t0 = ft->params.nthC(1 /*that is, the second element*/)->type;
+
+  // is the parameter of the class type?  NOTE: atomics are equal iff
+  // pointer equal
+  if (t0->isCVAtomicType() && t0->asCVAtomicType()->atomic == ct) return true;
+
+  // or, is the parameter a ref to the class type?
+  return isRefToCt(t0, ct);
+}
+
+
+typedef bool (*MemberFnTest)(Variable const *funcVar, CompoundType *ct);
+
+// test for any match among a variable's overload set
+bool testAmongOverloadSet(MemberFnTest test, Variable *v, CompoundType *ct)
+{
+  if (!v) {
+    // allow this, and say there's no match, because there are
+    // no variables at all
+    return false;
+  }
+
+  if (!v->overload) {
+    // singleton set
+    if (test(v, ct)) {
+      return true;
+    }
+  }
+  else {
+    // more than one element; note that the original 'v' is always
+    // among the elements of this list
+    SFOREACH_OBJLIST_NC(Variable, v->overload->set, iter) {
+      if (test(iter.data(), ct)) {
+        return true;
+      }
+    }
+  }
+
+  return false;        // no match
+}
+
+// this adds:
+//   - a default (no-arg) ctor, if no ctor (of any kind) is already present
+//   - a copy ctor if no copy ctor is present
+//   - an operator= if none is present
+//   - a dtor if none is present
+// 'loc' remains a hack ...
+//
+// FIX: this should be a method on TS_classSpec
+// sm: I don't agree.
+void addCompilerSuppliedDecls(Env &env, SourceLoc loc, CompoundType *ct)
+{
+  // we shouldn't even be here if the language isn't C++.
+  xassert(env.lang.isCplusplus);
+
+  // the caller should already have arranged so that 'ct' is the
+  // innermost scope
+  xassert(env.acceptingScope() == ct);
+
+  // don't bother for anonymous classes (this was originally because
+  // the destructor would then not have a name, but it's been retained
+  // even as more compiler-supplied functions have been added)
+  if (!ct->name) {
+    return;
+  }
+
+  // **** implicit no-arg (aka "default") ctor: cppstd 12.1 para 5:
+  // "If there is no user-declared constructor for class X, a default
+  // constructor is implicitly declared."
+  if (!ct->getNamedField(env.constructorSpecialName, env, LF_INNER_ONLY)) {
+    // add a no-arg ctor declaration: "Class();".  For now we just
+    // add the variable to the scope and don't construct the AST, in
+    // order to be symmetric with what is going on with the dtor
+    // below.
+    FunctionType *ft = env.beginConstructorFunctionType(loc, ct);
+    env.doneParams(ft);
+    Variable *v = env.makeVariable(loc, env.constructorSpecialName, ft,
+                  DF_MEMBER | DF_IMPLICIT);
+    // NOTE: we don't use env.addVariableWithOload() because this is
+    // a special case: we only insert if there are no ctors AT ALL.
+    env.addVariable(v);
+    env.madeUpVariables.push(v);
+  }
+
+  // **** implicit copy ctor: cppstd 12.8 para 4: "If the class
+  // definition does not explicitly declare a copy constructor, one
+  // is declared implicitly."
+  Variable *ctor0 = ct->getNamedField(env.constructorSpecialName, env, LF_INNER_ONLY);
+  xassert(ctor0);             // we just added one if there wasn't one
+
+  // is there a copy constructor?  I'm rolling my own here.
+  if (!testAmongOverloadSet(isCopyConstructor, ctor0, ct)) {
+    // cppstd 12.8 para 5: "The implicitly-declared copy constructor
+    // for a class X will have the form
+    //
+    //   X::X(const X&)
+    //
+    // if [lots of complicated conditions about the superclasses have
+    // const copy ctors, etc.] ... Otherwise, the implicitly-declared
+    // copy constructor will have the form
+    //
+    //   X::X(X&)
+    //
+    // An implicitly-declared copy constructor is an inline public
+    // member of its class."
+
+    // dsw: I'm going to just always make it X::X(X const &) for now.
+    // TODO: do it right.
+
+    // create the effects of a declaration without making any AST or
+    // a body; add a copy ctor declaration: Class(Class const &__other);
+    FunctionType *ft = env.beginConstructorFunctionType(loc, ct);
+    Variable *refToSelfParam =
+      env.makeVariable(loc,
+                       env.otherName,
+                       env.makeReferenceType(
+                         env.makeCVAtomicType(ct, CV_CONST)),
+                       DF_PARAMETER);
+    ft->addParam(refToSelfParam);
+    env.doneParams(ft);
+    Variable *v = env.makeVariable(loc, env.constructorSpecialName, ft,
+                                   DF_MEMBER | DF_IMPLICIT);
+    env.addVariableWithOload(ctor0, v);     // always overloaded; ctor0!=NULL
+    env.madeUpVariables.push(v);
+  }
+
+  // **** implicit copy assignment operator: 12.8 para 10: "If the
+  // class definition does not explicitly declare a copy assignment
+  // operator, one is declared implicitly."
+  Variable *assign_op0 = ct->getNamedField(env.operatorName[OP_ASSIGN],
+                                           env, LF_INNER_ONLY);
+  // is there a copy assign op?  I'm rolling my own here.
+  if (!testAmongOverloadSet(isCopyAssignOp, assign_op0, ct)) {
+    // 12.8 para 10: "The implicitly-declared copy assignment operator
+    // for a class X will have the form
+    //
+    //   X& X::operator=(const X&)
+    //
+    // if [lots of complicated conditions about the superclasses have
+    // const-parmeter copy assignment, etc.] ... Otherwise, the
+    // implicitly-declared copy assignment operator [mistake in spec:
+    // it says "copy constructor"] will have the form
+    //
+    //   X& X::operator=(X&)
+    //
+    // The implicitly-declared copy assignment
+    // operator for class X has the return type X&; it returns the
+    // object for which the assignment operator is invoked, that is,
+    // the object assigned to.  An implicitly-declared copy assignment
+    // operator is an inline public member of its class. ..."
+
+    // dsw: I'm going to just always make the parameter const for now.
+    // TODO: do it right.
+
+    // add a copy assignment op declaration: Class& operator=(Class const &);
+    Type *refToSelfType =
+      env.makeReferenceType(env.makeCVAtomicType(ct, CV_NONE));
+    Type *refToConstSelfType =
+      env.makeReferenceType(env.makeCVAtomicType(ct, CV_CONST));
+
+    FunctionType *ft = env.makeFunctionType(refToSelfType);
+
+    // receiver object
+    ft->addReceiver(env.makeVariable(loc, env.receiverName,
+                                     refToSelfType,
+                                     DF_PARAMETER));
+
+    // source object parameter
+    ft->addParam(env.makeVariable(loc,
+                                  env.otherName,
+                                  refToConstSelfType,
+                                  DF_PARAMETER));
+
+    env.doneParams(ft);
+
+    Variable *v = env.makeVariable(loc, env.operatorName[OP_ASSIGN], ft,
+                                   DF_MEMBER | DF_IMPLICIT);
+    env.addVariableWithOload(assign_op0, v);
+    env.madeUpVariables.push(v);
+  }
+
+  // **** implicit dtor: declare a destructor if one wasn't declared
+  // already; this allows the user to call the dtor explicitly, like
+  // "a->~A();", since I treat that like a field lookup
+  StringRef dtorName = env.str(stringc << "~" << ct->name);
+  if (!ct->lookupVariable(dtorName, env, LF_INNER_ONLY)) {
+    // add a dtor declaration: ~Class();
+    FunctionType *ft = env.makeDestructorFunctionType(loc, ct);
+    Variable *v = env.makeVariable(loc, dtorName, ft,
+                                   DF_MEMBER | DF_IMPLICIT);
+    env.addVariable(v);       // cannot be overloaded
+
+    // put it on the list of made-up variables since there are no
+    // (e.g.) $tainted qualifiers (since the user didn't even type
+    // the dtor's name)
+    env.madeUpVariables.push(v);
+  }
+}
+
+
+// --------------------- Env -----------------
+
+int throwClauseSerialNumber = 0; // don't make this a member of Env
+
+int Env::anonCounter = 1;
+
+Env::Env(StringTable &s, CCLang &L, TypeFactory &tf,
+         ArrayStack<Variable*> &madeUpVariables0,
+         ArrayStack<Variable*> &builtinVars0,
+         TranslationUnit *unit0)
+  : ErrorList(),
+
+    env(*this),
+    unit(unit0),
+    scopes(),
+    disambiguateOnly(false),
+    ctorFinished(false),
+
+    disambiguationNestingLevel(0),
+    checkFunctionBodies(true),
+    secondPassTcheck(false),
+    errors(*this),
+    hiddenErrors(NULL),
+    instantiationLocStack(),
+
+    str(s),
+    lang(L),
+    tfac(tf),
+    madeUpVariables(madeUpVariables0),
+    builtinVars(builtinVars0),
+
+    // some special names; pre-computed (instead of just asking the
+    // string table for it each time) because in certain situations
+    // I compare against them frequently; the main criteria for
+    // choosing the fake names is they have to be untypable by the C++
+    // programmer (i.e. if the programmer types one it won't be
+    // lexed as a single name)
+    conversionOperatorName(str("conversion-operator")),
+    constructorSpecialName(str("constructor-special")),
+    functionOperatorName(str("operator()")),
+    receiverName(str("__receiver")),
+    otherName(str("__other")),
+    quote_C_quote(str("\"C\"")),
+    quote_C_plus_plus_quote(str("\"C++\"")),
+    string__func__(str("__func__")),
+    string__FUNCTION__(str("__FUNCTION__")),
+    string__PRETTY_FUNCTION__(str("__PRETTY_FUNCTION__")),
+    string_main(str("main")),
+
+    // these are done below because they have to be declared as functions too
+    special_checkType(NULL),
+    special_getStandardConversion(NULL),
+    special_getImplicitConversion(NULL),
+    special_testOverload(NULL),
+    special_computeLUB(NULL),
+    special_checkCalleeDefnLine(NULL),
+    special_test_mtype(NULL),
+    special_cause_xfailure(NULL),
+
+    string_realSelector(str("__real__")),
+    string_imagSelector(str("__imag__")),
+    // complexComponentFields init'd below
+
+    dependentScope(new Scope(SK_GLOBAL, 0, SL_INIT)),
+    dependentTypeVar(NULL),
+    dependentVar(NULL),
+    errorTypeVar(NULL),
+    errorVar(NULL),
+    errorCompoundType(NULL),
+
+    globalScopeVar(NULL),
+
+    var__builtin_constant_p(NULL),
+
+    // operatorName[] initialized below
+
+    // builtin{Un,Bin}aryOperator[] start as arrays of empty
+    // arrays, and then have things added to them below
+
+    // (in/t0568.cc) apparently GCC and ICC always delay, so Elsa will
+    // too, even though I think that the only programs for which eager
+    // instantiation fails are invalid C++
+    delayFunctionInstantiation(!tracingSys("eagerFBodyInst")),
+
+    doFunctionTemplateBodyInstantiation(!tracingSys("disableFBodyInst")),
+
+    // this can be turned off with its own flag, or in C mode (since I
+    // have not implemented any of the relaxed C rules)
+    doCompareArgsToParams(!tracingSys("doNotCompareArgsToParams") && L.isCplusplus),
+
+    // 2005-03-09: things are finally ready to turn strict checking
+    // on by default (see doc/permissive.txt)
+    doReportTemplateErrors(!tracingSys("permissive")),
+
+    collectLookupResults("")
+{
+  // create first scope
+  SourceLoc emptyLoc = SL_UNKNOWN;
+  {
+    // among other things, SK_GLOBAL causes Variables inserted into
+    // this scope to acquire DF_GLOBAL
+    Scope *s = new Scope(SK_GLOBAL, 0 /*changeCount*/, emptyLoc);
+
+    // dsw: it is very helpful to be able to get to the global scope
+    // of a translation unit, so if you don't do this here please do
+    // it somewhere; There is a traversal in Elsa that I need this
+    // for, so it doesn't help to have it in Oink
+    unit->globalScope = s;
+
+    scopes.prepend(s);
+    s->openedScope(*this);
+
+    // make a Variable for it
+    globalScopeVar = makeVariable(SL_INIT, str("<globalScope>"),
+                                  NULL /*type*/, DF_NAMESPACE);
+    globalScopeVar->scope = s;
+    s->namespaceVar = globalScopeVar;
+  }
+
+  dependentTypeVar = makeVariable(SL_INIT, str("<dependentTypeVar>"),
+                                  getSimpleType(ST_DEPENDENT), DF_TYPEDEF);
+
+  dependentVar = makeVariable(SL_INIT, str("<dependentVar>"),
+                              getSimpleType(ST_DEPENDENT), DF_NONE);
+
+  errorTypeVar = makeVariable(SL_INIT, str("<errorTypeVar>"),
+                              getSimpleType(ST_ERROR), DF_TYPEDEF);
+
+  // this is *not* a typedef, because I use it in places that I
+  // want something to be treated as a variable, not a type
+  errorVar = makeVariable(SL_INIT, str("<errorVar>"),
+                          getSimpleType(ST_ERROR), DF_NONE);
+
+  errorCompoundType = tfac.makeCompoundType(CompoundType::K_CLASS, str("<errorCompoundType>"));
+  errorCompoundType->typedefVar = errorTypeVar;
+
+  // create declarations for some built-in operators
+  // [cppstd 3.7.3 para 2]
+  Type *t_void = getSimpleType(ST_VOID);
+  Type *t_voidptr = makePtrType(t_void);
+
+  // note: my stddef.h typedef's size_t to be 'int', so I just use
+  // 'int' directly here instead of size_t
+  Type *t_size_t = getSimpleType(ST_INT);
+
+  if (lang.isCplusplus) {
+    // must predefine this to be able to define bad_alloc
+    Scope *std_scope = createNamespace(SL_INIT, str("std"));
+
+    // but I do need a class called 'bad_alloc'..
+    //   class bad_alloc;
+    //
+    // 9/26/04: I had been *defining* bad_alloc here, but gcc defines
+    // the class in new.h so I am following suit.
+    //
+    // 2005-05-23: Define it in std scope, then optionally put an alias
+    // in the global scope too.
+    CompoundType *bad_alloc_ct;
+    Type *t_bad_alloc =
+      makeNewCompound(bad_alloc_ct, std_scope, str("bad_alloc"), SL_INIT,
+                      TI_CLASS, true /*forward*/, true /*builtin*/);
+    if (lang.gcc2StdEqualsGlobalHacks) {
+      // using std::bad_alloc;
+      Variable *using_bad_alloc_ct = makeUsingAliasFor(SL_INIT, bad_alloc_ct->typedefVar);
+      env.builtinVars.push(using_bad_alloc_ct);
+      addTypeTag(bad_alloc_ct->typedefVar);
+    }
+
+    // 2005-08-09 (in/gnu/bugs/gb0008.cc): predeclare std::type_info
+    //
+    // Though this is a bug compatibility feature, there doesn't seem
+    // to be much to gain by making a flag to control it.
+    {
+      CompoundType *dummy;
+      makeNewCompound(dummy, std_scope, str("type_info"), SL_INIT,
+                      TI_CLASS, true /*forward*/, true /*builtin*/);
+    }
+
+    // void* operator new(std::size_t sz) throw(std::bad_alloc);
+    declareFunction1arg(t_voidptr, "operator new",
+                        t_size_t, "sz",
+                        FF_DEFAULT_ALLOC, t_bad_alloc);
+
+    // void* operator new[](std::size_t sz) throw(std::bad_alloc);
+    declareFunction1arg(t_voidptr, "operator new[]",
+                        t_size_t, "sz",
+                        FF_DEFAULT_ALLOC, t_bad_alloc);
+
+    // void operator delete (void *p) throw();
+    declareFunction1arg(t_void, "operator delete",
+                        t_voidptr, "p",
+                        FF_DEFAULT_ALLOC, t_void);
+
+    // void operator delete[] (void *p) throw();
+    declareFunction1arg(t_void, "operator delete[]",
+                        t_voidptr, "p",
+                        FF_DEFAULT_ALLOC, t_void);
+  }
+
+  // 5/04/04: sm: I moved this out of the GNU_EXTENSION section because
+  // the mozilla tests use it, and I won't want to make them only
+  // active in gnu mode ..
+  //
+  // 9/23/04: I made the 'p' argument be '<any type>' instead of 'void *'
+  // since in C++ not all types can be converted to 'void*'.
+  //
+  // for GNU compatibility
+  // void *__builtin_next_arg(void const *p);
+  declareFunction1arg(t_voidptr, "__builtin_next_arg",
+                      getSimpleType(ST_ANY_TYPE), "p");
+
+  if (lang.predefined_Bool) {
+    // sm: I found this; it's a C99 feature: 6.2.5, para 2.  It's
+    // actually a keyword, so should be lexed specially, but I'll
+    // leave it alone for now.
+    //
+    // typedef bool _Bool;
+    Type *t_bool = getSimpleType(ST_BOOL);
+    addVariable(makeVariable(SL_INIT, str("_Bool"),
+                             t_bool, DF_TYPEDEF | DF_BUILTIN | DF_GLOBAL));
+  }
+
+  memset(complexComponentFields, 0, sizeof(complexComponentFields));
+
+  #ifdef GNU_EXTENSION
+    if (lang.declareGNUBuiltins) {
+      addGNUBuiltins();
+    }
+  #endif // GNU_EXTENSION
+
+  // for testing various modules
+  special_checkType = declareSpecialFunction("__elsa_checkType")->name;
+  special_getStandardConversion = declareSpecialFunction("__getStandardConversion")->name;
+  special_getImplicitConversion = declareSpecialFunction("__getImplicitConversion")->name;
+  special_testOverload = declareSpecialFunction("__testOverload")->name;
+  special_computeLUB = declareSpecialFunction("__computeLUB")->name;
+  special_checkCalleeDefnLine = declareSpecialFunction("__checkCalleeDefnLine")->name;
+  special_test_mtype = declareSpecialFunction("__test_mtype")->name;
+  special_cause_xfailure = declareSpecialFunction("__cause_xfailure")->name;
+
+  setupOperatorOverloading();
+
+  ctorFinished = true;
+}
+
+
+// slightly clever: iterate over an array, but look like
+// the contents of the array, not the index
+class OverloadableOpIter {
+  int i;                          // current operator
+  OverloadableOp const *ops;      // array
+  int size;                       // array size
+
+public:
+  OverloadableOpIter(OverloadableOp const *o, int s)
+    : i(0),
+      ops(o),
+      size(s)
+  {}
+
+  // look like the contents
+  operator OverloadableOp ()   { return ops[i]; }
+
+  // iterator interface
+  bool isDone() const          { return i>=size; }
+  void adv()                   { i++; }
+};
+
+#define FOREACH_OPERATOR(iterName, table) \
+  for (OverloadableOpIter iterName(table, TABLESIZE(table)); !iterName.isDone(); iterName.adv())
+
+
+void Env::setupOperatorOverloading()
+{
+  // fill in operatorName[]
+  int i;
+  for (i=0; i < NUM_OVERLOADABLE_OPS; i++) {
+    // debugging hint: if this segfaults, then I forgot to add
+    // something to operatorFunctionNames[]
+    operatorName[i] = str(operatorFunctionNames[i]);
+  }
+
+  // the symbols declared here are prevented from being entered into
+  // the environment by FF_BUILTINOP
+
+  // this has to match the typedef in include/stddef.h
+  SimpleTypeId ptrdiff_t_id = ST_INT;
+  Type *t_ptrdiff_t = getSimpleType(ptrdiff_t_id);
+
+  // some other useful types
+  Type *t_int = getSimpleType(ST_INT);
+  Type *t_bool = getSimpleType(ST_BOOL);
+
+  // Below, whenever the standard calls for 'VQ' (volatile or
+  // nothing), I use two copies of the rule, one with volatile and one
+  // without.  It would be nice to have a way of encoding this choice
+  // directly, but all of the ways I've considered so far would do
+  // more damage to the type system than I'm prepared to do for that
+  // feature.
+
+  // ------------ 13.6 para 3 ------------
+  {
+    Type *T = getSimpleType(ST_ARITHMETIC);
+    Type *Tv = getSimpleType(ST_ARITHMETIC, CV_VOLATILE);
+
+    Type *Tr = tfac.makeReferenceType(T);
+    Type *Tvr = tfac.makeReferenceType(Tv);
+
+    // VQ T& operator++ (VQ T&);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_PLUSPLUS, Tr);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_PLUSPLUS, Tvr);
+
+    // T operator++ (VQ T&, int);
+    addBuiltinBinaryOp(ST_PRET_STRIP_REF, OP_PLUSPLUS, Tr, t_int);
+    addBuiltinBinaryOp(ST_PRET_STRIP_REF, OP_PLUSPLUS, Tvr, t_int);
+  }
+
+  // ------------ 13.6 para 4 ------------
+  {
+    Type *T = getSimpleType(ST_ARITHMETIC_NON_BOOL);
+    Type *Tv = getSimpleType(ST_ARITHMETIC_NON_BOOL, CV_VOLATILE);
+
+    Type *Tr = tfac.makeReferenceType(T);
+    Type *Tvr = tfac.makeReferenceType(Tv);
+
+    // VQ T& operator-- (VQ T&);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_MINUSMINUS, Tr);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_MINUSMINUS, Tvr);
+
+    // T operator-- (VQ T&, int);
+    addBuiltinBinaryOp(ST_PRET_STRIP_REF, OP_MINUSMINUS, Tr, t_int);
+    addBuiltinBinaryOp(ST_PRET_STRIP_REF, OP_MINUSMINUS, Tvr, t_int);
+  }
+
+  // ------------ 13.6 para 5 ------------
+  {
+    Type *T = getSimpleType(ST_ANY_OBJ_TYPE);
+
+    Type *Tp = tfac.makePointerType(CV_NONE, T);
+    Type *Tpv = tfac.makePointerType(CV_VOLATILE, T);
+
+    Type *Tpr = tfac.makeReferenceType(Tp);
+    Type *Tpvr = tfac.makeReferenceType(Tpv);
+
+    // T* VQ & operator++ (T* VQ &);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_PLUSPLUS, Tpr);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_PLUSPLUS, Tpvr);
+
+    // T* VQ & operator-- (T* VQ &);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_MINUSMINUS, Tpr);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_MINUSMINUS, Tpvr);
+
+    // T* operator++ (T* VQ &, int);
+    addBuiltinBinaryOp(ST_PRET_STRIP_REF, OP_PLUSPLUS, Tpr, t_int);
+    addBuiltinBinaryOp(ST_PRET_STRIP_REF, OP_PLUSPLUS, Tpvr, t_int);
+
+    // T* operator-- (T* VQ &, int);
+    addBuiltinBinaryOp(ST_PRET_STRIP_REF, OP_MINUSMINUS, Tpr, t_int);
+    addBuiltinBinaryOp(ST_PRET_STRIP_REF, OP_MINUSMINUS, Tpvr, t_int);
+  }
+
+  // ------------ 13.6 paras 6 and 7 ------------
+  {
+    Type *T = getSimpleType(ST_ANY_NON_VOID);
+    Type *Tp = makePtrType(T);
+
+    // T& operator* (T*);
+    addBuiltinUnaryOp(ST_PRET_FIRST_PTR2REF, OP_STAR, Tp);
+  }
+
+  // ------------ 13.6 para 8 ------------
+  {
+    Type *T = getSimpleType(ST_ANY_TYPE);
+    Type *Tp = makePtrType(T);
+
+    // T* operator+ (T*);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_PLUS, Tp);
+  }
+
+  // ------------ 13.6 para 9 ------------
+  {
+    Type *T = getSimpleType(ST_PROMOTED_ARITHMETIC);
+
+    // T operator+ (T);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_PLUS, T);
+
+    // T operator- (T);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_MINUS, T);
+  }
+
+  // ------------ 13.6 para 10 ------------
+  {
+    Type *T = getSimpleType(ST_PROMOTED_INTEGRAL);
+
+    // T operator~ (T);
+    addBuiltinUnaryOp(ST_PRET_FIRST, OP_BITNOT, T);
+  }
+
+  // ------------ 13.6 para 11 ------------
+  // OP_ARROW_STAR is handled specially
+  addBuiltinBinaryOp(OP_ARROW_STAR, new ArrowStarCandidateSet);
+
+  // ------------ 13.6 para 12 ------------
+  {
+    Type *L = getSimpleType(ST_PROMOTED_ARITHMETIC);
+    Type *R = getSimpleType(ST_PROMOTED_ARITHMETIC);
+
+    static OverloadableOp const ops1[] = {
+      OP_STAR,         // LR operator* (L, R);
+      OP_DIV,          // LR operator/ (L, R);
+      OP_PLUS,         // LR operator+ (L, R);
+      OP_MINUS,        // LR operator- (L, R);
+
+      // these two are a guess
+      OP_MINIMUM,      // LR operator<? (L, R);
+      OP_MAXIMUM,      // LR operator>? (L, R);
+    };
+    FOREACH_OPERATOR(op1, ops1) {
+      addBuiltinBinaryOp(ST_PRET_ARITH_CONV, op1, L, R);
+    }
+
+    static OverloadableOp const ops2[] = {
+      OP_LESS,         // bool operator< (L, R);
+      OP_GREATER,      // bool operator> (L, R);
+      OP_LESSEQ,       // bool operator<= (L, R);
+      OP_GREATEREQ,    // bool operator>= (L, R);
+      OP_EQUAL,        // bool operator== (L, R);
+      OP_NOTEQUAL      // bool operator!= (L, R);
+    };
+    FOREACH_OPERATOR(op2, ops2) {
+      addBuiltinBinaryOp(ST_BOOL, op2, L, R);
+    }
+  }
+
+  // ------------ 13.6 para 13 ------------
+  {
+    Type *T = getSimpleType(ST_ANY_OBJ_TYPE);
+    Type *Tp = makePtrType(T);
+
+    // T* operator+ (T*, ptrdiff_t);
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_PLUS, Tp, t_ptrdiff_t);
+
+    // T& operator[] (T*, ptrdiff_t);
+    addBuiltinBinaryOp(ST_PRET_FIRST_PTR2REF, OP_BRACKETS, Tp, t_ptrdiff_t);
+
+    // T* operator- (T*, ptrdiff_t);
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_MINUS, Tp, t_ptrdiff_t);
+
+    // T* operator+ (ptrdiff_t, T*);
+    addBuiltinBinaryOp(ST_PRET_SECOND, OP_PLUS, t_ptrdiff_t, Tp);
+
+    // T& operator[] (ptrdiff_t, T*);
+    addBuiltinBinaryOp(ST_PRET_SECOND_PTR2REF, OP_BRACKETS, t_ptrdiff_t, Tp);
+  }
+
+  // ------------ 13.6 para 14 ------------
+  // ptrdiff_t operator-(T,T);
+  addBuiltinBinaryOp(ptrdiff_t_id, OP_MINUS, rvalIsPointer, pointerToObject);
+
+  // summary of process:
+  //   - enumerate pairs (U,V) such that left arg can convert
+  //     (directly) to U, and right to V
+  //   - pass U and V through 'rvalIsPointer': strip any reference,
+  //     and insist the result be a pointer (otherwise discard pair);
+  //     call resulting pair(U',V')
+  //   - compute LUB(U',V'), then test with 'pointerToObject': if
+  //     LUB is a pointer to object type, then use that type to
+  //     instantiate the pattern; otherwise, reject the pair
+  // see also: convertibility.txt
+
+  // ------------ 13.6 para 15 ------------
+  // bool operator< (T, T);
+  addBuiltinBinaryOp(ST_BOOL, OP_LESS, rvalFilter, pointerOrEnum);
+
+  // bool operator> (T, T);
+  addBuiltinBinaryOp(ST_BOOL, OP_GREATER, rvalFilter, pointerOrEnum);
+
+  // bool operator<= (T, T);
+  addBuiltinBinaryOp(ST_BOOL, OP_LESSEQ, rvalFilter, pointerOrEnum);
+
+  // bool operator>= (T, T);
+  addBuiltinBinaryOp(ST_BOOL, OP_GREATEREQ, rvalFilter, pointerOrEnum);
+
+  // ------------ 13.6 para 15 & 16 ------------
+  // bool operator== (T, T);
+  addBuiltinBinaryOp(ST_BOOL, OP_EQUAL, rvalFilter, pointerOrEnumOrPTM);
+
+  // bool operator!= (T, T);
+  addBuiltinBinaryOp(ST_BOOL, OP_NOTEQUAL, rvalFilter, pointerOrEnumOrPTM);
+
+  // ------------ 13.6 para 17 ------------
+  {
+    Type *L = getSimpleType(ST_PROMOTED_INTEGRAL);
+    Type *R = getSimpleType(ST_PROMOTED_INTEGRAL);
+
+    static OverloadableOp const ops[] = {
+      OP_MOD,          // LR operator% (L,R);
+      OP_AMPERSAND,    // LR operator& (L,R);
+      OP_BITXOR,       // LR operator^ (L,R);
+      OP_BITOR,        // LR operator| (L,R);
+    };
+    FOREACH_OPERATOR(op, ops) {
+      addBuiltinBinaryOp(ST_PRET_ARITH_CONV, op, L, R);
+    }
+
+    // L operator<< (L,R);
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_LSHIFT, L, R);
+
+    // L operator>> (L,R);
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_RSHIFT, L, R);
+  }
+
+  // ------------ 13.6 para 18 ------------
+  // assignment/arith to arithmetic types
+  {
+    Type *L = getSimpleType(ST_ARITHMETIC);
+    Type *Lv = getSimpleType(ST_ARITHMETIC, CV_VOLATILE);
+
+    Type *Lr = tfac.makeReferenceType(L);
+    Type *Lvr = tfac.makeReferenceType(Lv);
+
+    Type *R = getSimpleType(ST_PROMOTED_ARITHMETIC);
+
+    static OverloadableOp const ops[] = {
+      OP_ASSIGN,       // VQ L& operator= (VQ L&, R);
+      OP_MULTEQ,       // VQ L& operator*= (VQ L&, R);
+      OP_DIVEQ,        // VQ L& operator/= (VQ L&, R);
+      OP_PLUSEQ,       // VQ L& operator+= (VQ L&, R);
+      OP_MINUSEQ       // VQ L& operator-= (VQ L&, R);
+    };
+    FOREACH_OPERATOR(op, ops) {
+      if (lang.nonstandardAssignmentOperator && op==OP_ASSIGN) {
+        // do not add this variant; see below
+        continue;
+      }
+
+      addBuiltinBinaryOp(ST_PRET_FIRST, op, Lr, R);
+      addBuiltinBinaryOp(ST_PRET_FIRST, op, Lvr, R);
+    }
+  }
+
+  // ------------ 13.6 paras 19 and 20 ------------
+  // 19: assignment to pointer type
+  // T: any type
+  // T* VQ & operator= (T* VQ &, T*);
+
+  // 20: assignment to enumeration and ptr-to-member
+  // T: enumeration or pointer-to-member
+  // T VQ & operator= (T VQ &, T);
+
+  // this pattern captures both:
+  // T: pointer, ptr-to-member, or enumeration ('para19_20filter')
+  // T VQ & operator= (T VQ &, T);
+  {
+    Type* (*filter)(Type *t, bool) = para19_20filter;
+    if (lang.nonstandardAssignmentOperator) {
+      // 9/25/04: as best I can tell, what is usually implemented is the
+      //   T* VQ & operator= (T* VQ &, T*);
+      // pattern where T can be pointer (para 19), enumeration (para 20),
+      // pointer to member (para 20), or arithmetic (co-opted para 18)
+      //
+      // in/t0312.cc tests this
+      filter = para19_20_andArith_filter;
+    }
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_ASSIGN, filter,
+                       anyType, true /*isAssignment*/);
+  }
+
+  // ------------ 13.6 para 21 ------------
+  // 21: +=, -= for pointer type
+  {
+    Type *T = getSimpleType(ST_ANY_OBJ_TYPE);
+
+    Type *Tp = tfac.makePointerType(CV_NONE, T);
+    Type *Tpv = tfac.makePointerType(CV_VOLATILE, T);
+
+    Type *Tpr = tfac.makeReferenceType(Tp);
+    Type *Tpvr = tfac.makeReferenceType(Tpv);
+
+    // T* VQ & operator+= (T* VQ &, ptrdiff_t);
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_PLUSEQ, Tpr, t_ptrdiff_t);
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_PLUSEQ, Tpvr, t_ptrdiff_t);
+
+    // T* VQ & operator-= (T* VQ &, ptrdiff_t);
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_MINUSEQ, Tpr, t_ptrdiff_t);
+    addBuiltinBinaryOp(ST_PRET_FIRST, OP_MINUSEQ, Tpvr, t_ptrdiff_t);
+  }
+
+  // ------------ 13.6 para 22 ------------
+  // 22: assignment/arith to integral type
+  {
+    Type *L = getSimpleType(ST_INTEGRAL, CV_NONE);
+    Type *Lv = getSimpleType(ST_INTEGRAL, CV_VOLATILE);
+
+    Type *Lr = tfac.makeReferenceType(L);
+    Type *Lvr = tfac.makeReferenceType(Lv);
+
+    Type *R = getSimpleType(ST_PROMOTED_INTEGRAL);
+
+    static OverloadableOp const ops[] = {
+      OP_MODEQ,        // VQ L& operator%= (VQ L&, R);
+      OP_LSHIFTEQ,     // VQ L& operator<<= (VQ L&, R);
+      OP_RSHIFTEQ,     // VQ L& operator>>= (VQ L&, R);
+      OP_BITANDEQ,     // VQ L& operator&= (VQ L&, R);
+      OP_BITXOREQ,     // VQ L& operator^= (VQ L&, R);
+      OP_BITOREQ       // VQ L& operator|= (VQ L&, R);
+    };
+    FOREACH_OPERATOR(op, ops) {
+      addBuiltinBinaryOp(ST_PRET_FIRST, op, Lr, R);
+      addBuiltinBinaryOp(ST_PRET_FIRST, op, Lvr, R);
+    }
+  }
+
+  // ------------ 13.6 para 23 ------------
+  // bool operator! (bool);
+  addBuiltinUnaryOp(ST_BOOL, OP_NOT, t_bool);
+
+  // bool operator&& (bool, bool);
+  addBuiltinBinaryOp(ST_BOOL, OP_AND, t_bool, t_bool);
+
+  // bool operator|| (bool, bool);
+  addBuiltinBinaryOp(ST_BOOL, OP_OR, t_bool, t_bool);
+
+  // ------------ 13.6 para 24 ------------
+  // 24: ?: on arithmetic types
+  {
+    Type *L = getSimpleType(ST_PROMOTED_ARITHMETIC);
+    Type *R = getSimpleType(ST_PROMOTED_ARITHMETIC);
+
+    // NOTE: For the '?:' operator, I pretend it is binary because the
+    // first argument plays no role in overload resolution, and the
+    // caller will have already ensured it can be converted to 'bool'.
+    // Thus, I only include information for the second and third args.
+
+    // LR operator?(bool, L, R);
+    addBuiltinBinaryOp(ST_PRET_ARITH_CONV, OP_QUESTION, L, R);
+  }
+
+  // ------------ 13.6 para 25 ------------
+  // 25: ?: on pointer and ptr-to-member types
+  // T operator?(bool, T, T);
+  addBuiltinBinaryOp(ST_PRET_FIRST, OP_QUESTION, rvalFilter, pointerOrPTM);
+
+
+  // the default constructor for ArrayStack will have allocated 10
+  // items in each array, which will then have grown as necessary; go
+  // back and resize them to their current length (since that won't
+  // change after this point)
+  for (i=0; i < NUM_OVERLOADABLE_OPS; i++) {
+    builtinUnaryOperator[i].consolidate();
+  }
+  for (i=0; i < NUM_OVERLOADABLE_OPS; i++) {
+    builtinBinaryOperator[i].consolidate();
+  }
+}
+
+
+Env::~Env()
+{
+  // delete the scopes one by one, so we can skip any
+  // which are in fact not owned
+  while (scopes.isNotEmpty()) {
+    Scope *s = scopes.removeFirst();
+    s->closedScope();
+    if (s->curCompound || s->namespaceVar || s->isGlobalScope()) {
+      // this isn't one we own
+      // 8/06/04: don't delete the global scope, just leak it,
+      // because I now let my Variables point at it ....
+    }
+    else {
+      // we do own this one
+      delete s;
+    }
+  }
+
+  delete dependentScope;
+}
+
+
+void Env::tcheckTranslationUnit(TranslationUnit *tunit)
+{
+  tunit->tcheck(env);
+  xassert(env.scope()->isGlobalScope());
+
+  if (delayFunctionInstantiation) {
+    TRACE("template", "------- doing delayed instantiations -------");
+
+    // process any delayed instantiations
+    delayedFuncInsts.reverse();
+    while (delayedFuncInsts.isNotEmpty()) {
+      Owner<DelayedFuncInst> dfi(delayedFuncInsts.removeFirst());
+
+      // set the instantiation loc stack to how it was when
+      // the instantiation was delayed
+      instantiationLocStack = dfi->instLocStack;
+
+      // instantiate
+      instantiateFunctionBodyNow(dfi->instV, dfi->loc);
+    }
+
+    instantiationLocStack.empty();
+    xassert(env.scope()->isGlobalScope());
+  }
+}
+
+
+Variable *Env::makeVariable(SourceLoc L, StringRef n, Type *t, DeclFlags f)
+{
+  if (!ctorFinished) {
+    Variable *v = tfac.makeVariable(L, n, t, f);
+
+    // such variables are entered into a special list, as long as
+    // they're not function parameters (since parameters are reachable
+    // from other made-up variables)
+    if (!(f & DF_PARAMETER)) {
+      madeUpVariables.push(v);
+    }
+
+    return v;
+  }
+
+  else {
+    // usual case
+    return tfac.makeVariable(L, n, t, f);
+  }
+}
+
+
+Variable *Env::declareFunctionNargs(
+  Type *retType, char const *funcName,
+  Type **argTypes, char const **argNames, int numArgs,
+  FunctionFlags flags,
+  Type * /*nullable*/ exnType)
+{
+  FunctionType *ft = makeFunctionType(retType);
+  ft->flags |= flags;
+
+  for (int i=0; i < numArgs; i++) {
+    Variable *p = makeVariable(SL_INIT, str(argNames[i]), argTypes[i], DF_PARAMETER);
+    ft->addParam(p);
+  }
+
+  if (exnType) {
+    ft->exnSpec = new FunctionType::ExnSpec;
+
+    // slightly clever hack: say "throw()" by saying "throw(void)"
+    if (!exnType->isSimple(ST_VOID)) {
+      ft->exnSpec->types.append(exnType);
+    }
+  }
+
+  doneParams(ft);
+
+  Variable *var = makeVariable(SL_INIT, str(funcName), ft, DF_NONE);
+  if (flags & FF_BUILTINOP) {
+    // don't add built-in operator functions to the environment
+  }
+  else {
+    addVariable(var);
+  }
+
+  env.builtinVars.push(var);
+
+  return var;
+}
+
+
+// this declares a function that accepts any # of arguments, and
+// returns 'int'; this is for Elsa's internal testing hook functions
+Variable *Env::declareSpecialFunction(char const *name)
+{
+  return declareFunction0arg(getSimpleType(ST_INT), name, FF_VARARGS);
+}
+
+
+Variable *Env::declareFunction0arg(Type *retType, char const *funcName,
+                                   FunctionFlags flags,
+                                   Type * /*nullable*/ exnType)
+{
+  return declareFunctionNargs(retType, funcName,
+                              NULL /*argTypes*/, NULL /*argNames*/, 0 /*numArgs*/,
+                              flags, exnType);
+}
+
+
+Variable *Env::declareFunction1arg(Type *retType, char const *funcName,
+                                   Type *arg1Type, char const *arg1Name,
+                                   FunctionFlags flags,
+                                   Type * /*nullable*/ exnType)
+{
+  return declareFunctionNargs(retType, funcName,
+                              &arg1Type, &arg1Name, 1 /*numArgs*/,
+                              flags, exnType);
+}
+
+
+Variable *Env::declareFunction2arg(Type *retType, char const *funcName,
+                                   Type *arg1Type, char const *arg1Name,
+                                   Type *arg2Type, char const *arg2Name,
+                                   FunctionFlags flags,
+                                   Type * /*nullable*/ exnType)
+{
+  Type *types[2] = { arg1Type, arg2Type };
+  char const *names[2] = { arg1Name, arg2Name };
+  return declareFunctionNargs(retType, funcName,
+                              types, names, 2 /*numArgs*/,
+                              flags, exnType);
+}
+
+
+Variable *Env::declareFunction4arg(Type *retType, char const *funcName,
+                                   Type *arg1Type, char const *arg1Name,
+                                   Type *arg2Type, char const *arg2Name,
+                                   Type *arg3Type, char const *arg3Name,
+                                   Type *arg4Type, char const *arg4Name,
+                                   FunctionFlags flags,
+                                   Type * /*nullable*/ exnType)
+{
+  Type *types[4] = { arg1Type, arg2Type, arg3Type, arg4Type };
+  char const *names[4] = { arg1Name, arg2Name, arg3Name, arg4Name };
+  return declareFunctionNargs(retType, funcName,
+                              types, names, 4 /*numArgs*/,
+                              flags, exnType);
+}
+
+
+FunctionType *Env::makeImplicitDeclFuncType()
+{
+  // don't need a clone type here as getSimpleType() calls
+  // makeCVAtomicType() which in oink calls new.
+  Type *ftRet = tfac.getSimpleType(ST_INT, CV_NONE);
+  FunctionType *ft = makeFunctionType(ftRet);
+  ft->flags |= FF_NO_PARAM_INFO;
+  doneParams(ft);
+  return ft;
+}
+
+
+Variable *Env::makeImplicitDeclFuncVar(StringRef name)
+{
+  return createDeclaration
+    (loc(), name,
+     makeImplicitDeclFuncType(), DF_FORWARD | DF_EXTERN_C,
+     globalScope(), NULL /*enclosingClass*/,
+     NULL /*prior*/, NULL /*overloadSet*/);
+}
+
+
+FunctionType *Env::beginConstructorFunctionType(SourceLoc loc, CompoundType *ct)
+{
+  FunctionType *ft = makeFunctionType(makeType(ct));
+  ft->flags |= FF_CTOR;
+  // asymmetry with makeDestructorFunctionType(): this must be done by the client
+//    doneParams(ft);
+  return ft;
+}
+
+
+FunctionType *Env::makeDestructorFunctionType(SourceLoc loc, CompoundType *ct)
+{
+  FunctionType *ft = makeFunctionType(getSimpleType(ST_VOID));
+
+  if (!ct) {
+    // there's a weird case in E_fieldAcc::itcheck_x where we're making
+    // a destructor type but there is no class... so just skip making
+    // the receiver
+  }
+  else {
+    ft->addReceiver(receiverParameter(loc, ct, CV_NONE));
+  }
+
+  ft->flags |= FF_DTOR;
+  doneParams(ft);
+  return ft;
+}
+
+
+Scope *Env::createScope(ScopeKind sk)
+{
+  return new Scope(sk, getChangeCount(), loc());
+}
+
+
+Scope *Env::enterScope(ScopeKind sk, char const *forWhat)
+{
+  // propagate the 'curFunction' field
+  Function *f = scopes.first()->curFunction;
+  Scope *newScope = createScope(sk);
+  setParentScope(newScope);
+  scopes.prepend(newScope);
+  newScope->curFunction = f;
+
+  TRACE("scope", locStr() << ": entered " << newScope->desc() << " for " << forWhat);
+
+  newScope->openedScope(*this);
+
+  return newScope;
+}
+
+// set the 'parentScope' field of a scope about to be pushed
+void Env::setParentScope(Scope *s)
+{
+  // 'parentScope' has to do with (qualified) lookup, for which the
+  // template scopes are supposed to be transparent
+  setParentScope(s, nonTemplateScope());
+}
+
+void Env::setParentScope(Scope *s, Scope *parent)
+{
+  if (parent->isPermanentScope()) {
+    s->parentScope = parent;
+  }
+}
+
+void Env::exitScope(Scope *s)
+{
+  s->closedScope();
+
+  TRACE("scope", locStr() << ": exited " << s->desc());
+  Scope *f = scopes.removeFirst();
+  xassert(s == f);
+  delete f;
+}
+
+
+void Env::extendScope(Scope *s)
+{
+  TRACE("scope", locStr() << ": extending " << s->desc());
+
+  Scope *prevScope = scope();
+  scopes.prepend(s);
+  s->curLoc = prevScope->curLoc;
+
+  s->openedScope(*this);
+}
+
+void Env::retractScope(Scope *s)
+{
+  TRACE("scope", locStr() << ": retracting " << s->desc());
+
+  // don't do this here b/c I need to re-enter the scope when
+  // tchecking a Function, but the association only gets established
+  // once, when tchecking the declarator *name*
+  #if 0
+  // if we had been delegating to another scope, disconnect
+  if (s->curCompound &&
+      s->curCompound->parameterizingScope) {
+    Scope *other = s->curCompound->parameterizingScope;
+    xassert(other->parameterizedEntity->type->asCompoundType() == s->curCompound);
+
+    TRACE("templateParams", s->desc() << " removing delegation to " << other->desc());
+
+    other->parameterizedEntity = NULL;
+    s->curCompound->parameterizingScope = NULL;
+  }
+  #endif // 0
+
+  s->closedScope();
+
+  Scope *first = scopes.removeFirst();
+  xassert(first == s);
+  // we don't own 's', so don't delete it
+}
+
+
+void Env::gdbScopes()
+{
+  cout << "Scopes and variables (no __-names), beginning with innermost" << endl;
+  for (int i=0; i<scopes.count(); ++i) {
+    Scope *s = scopes.nth(i);
+    cout << "scope " << i << ", " << s->desc() << endl;
+
+    if (s->isDelegated()) {
+      cout << "  (DELEGATED)" << endl;
+    }
+
+    for (StringRefMap<Variable>::Iter iter = s->getVariableIter();
+         !iter.isDone();
+         iter.adv()) {
+      // suppress __builtins, etc.
+      if (prefixEquals(iter.key(), "__")) continue;
+
+      Variable *value = iter.value();
+      if (value->hasFlag(DF_NAMESPACE)) {
+        cout << "  " << iter.key() << ": " << value->scope->desc() << endl;
+      }
+      else {
+        cout << "  " << iter.key()
+             << ": " << value->toString()
+             << stringf(" (%p)", value);
+  //        cout << "value->serialNumber " << value->serialNumber;
+        cout << endl;
+      }
+    }
+
+    if (s->curCompound &&
+        s->curCompound->parameterizingScope) {
+      cout << "  DELEGATES to " << s->curCompound->parameterizingScope->desc() << endl;
+    }
+  }
+}
+
+
+// this should be a rare event
+void Env::refreshScopeOpeningEffects()
+{
+  TRACE("scope", "refreshScopeOpeningEffects");
+
+  // tell all scopes they should consider themselves closed,
+  // starting with the innermost
+  {
+    FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+      iter.data()->closedScope();
+    }
+  }
+
+  // tell all scopes they should consider themselves opened,
+  // starting with the outermost
+  scopes.reverse();
+  {
+    FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+      iter.data()->openedScope(*this);
+    }
+  }
+
+  // all done
+  scopes.reverse();
+}
+
+
+#if 0   // does this even work?
+CompoundType *Env::getEnclosingCompound()
+{
+  MUTATE_EACH_OBJLIST(Scope, scopes, iter) {
+    if (iter.data()->curCompound) {
+      return iter.data()->curCompound;
+    }
+  }
+  return NULL;
+}
+#endif // 0
+
+
+void Env::setLoc(SourceLoc loc)
+{
+  TRACE("loc", "setLoc: " << toString(loc));
+
+  // only set it if it's a valid location; I get invalid locs
+  // from abstract declarators..
+  if (loc != SL_UNKNOWN) {
+    Scope *s = scope();
+    s->curLoc = loc;
+  }
+}
+
+SourceLoc Env::loc() const
+{
+  return scopeC()->curLoc;
+}
+
+
+string Env::locationStackString() const
+{
+  stringBuilder sb;
+
+  FOREACH_OBJLIST(Scope, scopes, iter) {
+    sb << "  " << toString(iter.data()->curLoc) << "\n";
+  }
+
+  return sb;
+}
+
+
+string Env::instLocStackString() const
+{
+  // build a string that describes the instantiation context
+  if (instantiationLocStack.isEmpty()) {
+    return "";
+  }
+  else {
+    stringBuilder sb;
+    for (int i = instantiationLocStack.length()-1; i >= 0; i--) {
+      sb << " (inst from " << instantiationLocStack[i] << ")";
+    }
+
+    return sb;
+  }
+}
+
+
+// -------- insertion --------
+Scope *Env::acceptingScope(DeclFlags df)
+{
+  if (lang.noInnerClasses &&
+      (df & (DF_TYPEDEF | DF_ENUMERATOR))) {
+    // C mode: typedefs and enumerators go into the outer scope
+    return outerScope();
+  }
+
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    Scope *s = iter.data();
+    if (s->canAcceptNames) {
+      return s;
+    }
+  }
+
+  // 8/07/04: There used to be code here that asserted that an
+  // accepting scope would never be more than two away from the top,
+  // but that is wrong because with member templates (and in fact the
+  // slightly broken way that bindings are inserted for member
+  // functions of template classes) it can be arbitrarily deep.
+
+  xfailure("could not find accepting scope");
+  return NULL;    // silence warning
+}
+
+
+Scope *Env::outerScope()
+{
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    Scope *s = iter.data();
+    if (s->isTemplateScope() ||              // skip template scopes
+        s->isClassScope() ||                 // skip class scopes
+        s->isParameterScope()) {             // skip parameter list scopes
+      continue;
+    }
+
+    return s;
+  }
+
+  xfailure("couldn't find the outer scope!");
+  return NULL;    // silence warning
+}
+
+
+Scope *Env::enclosingScope()
+{
+  // inability to accept names doesn't happen arbitrarily,
+  // and we shouldn't run into it here
+
+  Scope *s = scopes.nth(0);
+  xassert(s->canAcceptNames);
+
+  s = scopes.nth(1);
+  if (!s->canAcceptNames) {
+    error("did you try to make a templatized anonymous union (!), "
+          "or am I confused?");
+    return scopes.nth(2);   // error recovery..
+  }
+
+  return s;
+}
+
+
+Scope *Env::enclosingKindScope(ScopeKind k)
+{
+  return enclosingKindScopeAbove(k, NULL);
+}
+
+
+Scope *Env::enclosingKindScopeAbove(ScopeKind k, Scope *s)
+{
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    if (s) {
+      if (iter.data() == s) {
+        // found the scope we want to look above
+        s = NULL;
+      }
+      else {
+        // still looking for 's'
+      }
+      continue;
+    }
+
+    if (iter.data()->scopeKind == k) {
+      return iter.data();
+    }
+  }
+
+  if (s) {
+    xfailure("did not find scope above which we wanted to look");
+  }
+
+  return NULL;    // not found
+}
+
+
+CompoundType *Env::enclosingClassScope()
+{
+  Scope *s = enclosingKindScope(SK_CLASS);
+  if (s) {
+    return s->curCompound;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+Scope *Env::nonTemplateScope()
+{
+  ObjListIterNC<Scope> iter(scopes);
+  while (iter.data()->scopeKind == SK_TEMPLATE_PARAMS ||
+         iter.data()->scopeKind == SK_TEMPLATE_ARGS) {
+    iter.adv();
+  }
+
+  return iter.data();
+}
+
+bool Env::currentScopeAboveTemplEncloses(Scope const *s)
+{
+  // Skip over template binding and inst-eating scopes for the
+  // purpose of this check.
+  //
+  // We used to use somewhat more precise scope-skipping code, but
+  // when a function instantiates its forward-declared instances it
+  // happens to leave its parameter scope on the stack, which makes
+  // perfectly precise skipping code complicated.
+  return nonTemplateScope()->encloses(s);
+}
+
+
+bool Env::currentScopeEncloses(Scope const *s)
+{
+  return scope()->encloses(s);
+}
+
+
+Scope *Env::findEnclosingScope(Scope *target)
+{
+  // walk up stack of scopes, looking for first one that
+  // encloses 'target'
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    if (iter.data()->encloses(target)) {
+      return iter.data();
+    }
+  }
+
+  xfailure("findEnclosingScope: no scope encloses target!");
+  return NULL;
+}
+
+
+bool Env::addVariable(Variable *v, bool forceReplace)
+{
+  if (disambErrorsSuppressChanges()) {
+    // the environment is not supposed to be modified by an ambiguous
+    // alternative that fails
+    TRACE("env",    "not adding variable `" << v->name
+                 << "' because there are disambiguating errors");
+    return true;    // don't cause further errors; pretend it worked
+  }
+
+  Scope *s = acceptingScope(v->flags);
+  return addVariableToScope(s, v, forceReplace);
+}
+
+bool Env::addVariableToScope(Scope *s, Variable *v, bool forceReplace)
+{
+  s->registerVariable(v);
+  if (s->addVariable(v, forceReplace)) {
+    addedNewVariable(s, v);
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+
+void Env::addVariableWithOload(Variable *prevLookup, Variable *v)
+{
+  if (prevLookup) {
+    prevLookup->getOrCreateOverloadSet()->addMember(v);
+    registerVariable(v);
+
+    TRACE("ovl",    "overloaded `" << prevLookup->name
+                 << "': `" << prevLookup->type->toString()
+                 << "' and `" << v->type->toString() << "'");
+  }
+  else {
+    if (!addVariable(v)) {
+      // since the caller is responsible for passing in the result of
+      // looking up v->name, if it passes NULL, then this addVariable
+      // call must succeed
+      xfailure("collision in addVariableWithOload");
+    }
+  }
+}
+
+
+void Env::registerVariable(Variable *v)
+{
+  Scope *s = acceptingScope(v->flags);
+  s->registerVariable(v);
+}
+
+
+bool Env::addCompound(CompoundType *ct)
+{
+  // like above
+  if (disambErrorsSuppressChanges()) {
+    TRACE("env",    "not adding compound `" << ct->name
+                 << "' because there are disambiguating errors");
+    return true;
+  }
+
+  return typeAcceptingScope()->addCompound(ct);
+}
+
+
+bool Env::addEnum(EnumType *et)
+{
+  // like above
+  if (disambErrorsSuppressChanges()) {
+    TRACE("env",    "not adding enum `" << et->name
+                 << "' because there are disambiguating errors");
+    return true;
+  }
+
+  return typeAcceptingScope()->addEnum(et);
+}
+
+
+bool Env::addTypeTag(Variable *tag)
+{
+  // like above
+  if (disambErrorsSuppressChanges()) {
+    TRACE("env",    "not adding type tag `" << tag->name
+                 << "' because there are disambiguating errors");
+    return true;
+  }
+
+  return typeAcceptingScope()->addTypeTag(tag);
+}
+
+
+Type *Env::declareEnum(SourceLoc loc /*...*/, EnumType *et)
+{
+  Type *ret = makeType(et);
+  if (et->name) {
+    // make the implicit typedef
+    Variable *tv = makeVariable(loc, et->name, ret, DF_TYPEDEF | DF_IMPLICIT);
+    et->typedefVar = tv;
+
+    if (!addEnum(et)) {
+      error(stringc << "multiply defined enum `" << et->name << "'");
+    }
+
+    // TODO: If the enum name is already the name of a typedef,
+    // then that is an error in C++.
+
+    if (lang.tagsAreTypes && !addVariable(tv)) {
+      // this isn't really an error, because in C it would have
+      // been allowed, so C++ does too [ref?]
+      //return env.error(stringc
+      //  << "implicit typedef associated with enum " << et->name
+      //  << " conflicts with an existing typedef or variable",
+      //  true /*disambiguating*/);
+    }
+  }
+
+  return ret;
+}
+
+
+// -------- lookup --------
+
+// select either the primary or one of the specializations, based
+// on the supplied arguments; these arguments will likely contain
+// type variables; e.g., given "T*", select specialization C<T*>;
+// return NULL if no matching definition found
+Variable *Env::getPrimaryOrSpecialization
+  (TemplateInfo *tinfo, ObjList<STemplateArgument> const &sargs)
+{
+  // check that the template scope from which the (otherwise) free
+  // variables of 'sargs' are drawn is all the same scope, and
+  // associate it with 'tinfo' accordingly
+
+
+  // primary?
+  //
+  // I can't just test for 'sargs' equalling 'this->arguments',
+  // because for the primary, the latter is always empty.
+  //
+  // So I'm just going to test that 'sargs' consists entirely
+  // of toplevel type variables, which isn't exactly right ...
+  bool allToplevelVars = true;
+  FOREACH_OBJLIST(STemplateArgument, sargs, argIter) {
+    STemplateArgument const *arg = argIter.data();
+
+    if (arg->isType()) {
+      if (!arg->getType()->isTypeVariable()) {
+        allToplevelVars = false;
+      }
+    }
+    else if (arg->isDepExpr()) {
+      if (!arg->getDepExpr()->isE_variable()) {
+        allToplevelVars = false;
+      }
+    }
+  }
+  if (allToplevelVars) {
+    return tinfo->var;
+  }
+
+  // specialization?
+  SFOREACH_OBJLIST_NC(Variable, tinfo->specializations, iter) {
+    Variable *spec = iter.data();
+    if (spec->templateInfo()->isomorphicArguments(sargs)) {
+      return spec;
+    }
+  }
+
+  // no matching specialization
+  return NULL;
+}
+
+
+// This returns the scope named by the qualifier portion of
+// 'qualifier', or NULL if there is an error.  In the latter
+// case, an error message is also inserted, unless the lookup
+// failed becaue of dependence on a template parameter, in
+// which case 'dependent' is set to true and no error message
+// is inserted.
+Scope *Env::lookupOneQualifier(
+  Scope *startingScope,          // where does search begin?  NULL means current environment
+  PQ_qualifier const *qualifier, // will look up the qualifier on this name
+  bool &dependent,               // set to true if we have to look inside a TypeVariable
+  bool &anyTemplates,            // set to true if we look in uninstantiated templates
+  LookupFlags lflags)
+{
+  // the other call site to lookupOneQualifier_useArgs has a certain
+  // DF_SELFNAME processing that would have to be repeated if this
+  // code is reachable
+  //
+  // I will delete this function when I strip out the last vestiges of
+  // the old lookup mechanism; but I can't do that until
+  // declarator/type-tag lookup is rewritten too
+  xfailure("this function is obsolete");
+
+  // lookup the name
+  Variable *qualVar = lookupOneQualifier_bareName(startingScope, qualifier, lflags);
+  if (!qualVar) {
+    return NULL;     // error already reporeted
+  }
+
+  // refine using the arguments, and yield a Scope
+  return lookupOneQualifier_useArgs(qualVar, qualifier->sargs,
+                                    dependent, anyTemplates, lflags);
+}
+
+
+// lookup just the name part of a qualifier; template arguments
+// (if any) are dealt with later
+Variable *Env::lookupOneQualifier_bareName(
+  Scope *startingScope,          // where does search begin?  NULL means current environment
+  PQ_qualifier const *qualifier, // will look up the qualifier on this name
+  LookupFlags lflags)
+{
+  // get the first qualifier
+  StringRef qual = qualifier->qualifier;
+  if (!qual) {      // i.e. "::" qualifier
+    // should be syntactically impossible to construct bare "::"
+    // with template arguments
+    xassert(qualifier->sargs.isEmpty());
+
+    // this is a reference to the global scope
+    return globalScopeVar;
+  }
+
+  // look for a class called 'qual' in 'startingScope'; look in the
+  // *variables*, not the *compounds*, because it is legal to make
+  // a typedef which names a scope, and use that typedef'd name as
+  // a qualifier
+  //
+  // however, this still is not quite right, see cppstd 3.4.3 para 1
+  //
+  // update: LF_TYPES_NAMESPACES now gets it right, I think
+  lflags |= LF_TYPES_NAMESPACES | LF_SELFNAME;
+  Variable *qualVar = startingScope==NULL?
+    lookupVariable(qual, lflags) :
+    startingScope->lookupVariable(qual, *this, lflags);
+  if (!qualVar) {
+    // 10/02/04: I need to suppress this error for t0329.cc.  It's not
+    // yet clear whether LF_SUPPRESS_ERROR should suppress other errors
+    // as well ...
+    if (!( lflags & LF_SUPPRESS_ERROR )) {
+      // I'd like to include some information about which scope
+      // we were looking in, but I don't want to be computing
+      // intermediate scope names for successful lookups; also,
+      // I am still considering adding some kind of scope->name()
+      // functionality, which would make this trivial.
+      //
+      // alternatively, I could just re-traverse the original name;
+      // I'm lazy for now
+      error(stringc
+        << "cannot find scope name `" << qual << "'",
+        EF_DISAMBIGUATES);
+    }
+    return NULL;
+  }
+
+  // this is what LF_TYPES_NAMESPACES means
+  xassert(qualVar->hasFlag(DF_TYPEDEF) || qualVar->hasFlag(DF_NAMESPACE));
+
+  return qualVar;
+}
+
+
+// Second half of 'lookupOneQualifier': use the template args.
+Scope *Env::lookupOneQualifier_useArgs(
+  Variable *qualVar,                // bare name scope Variable
+  ObjList<STemplateArgument> const &sargs, // template args to apply
+  bool &dependent,                  // set to true if we have to look inside a TypeVariable
+  bool &anyTemplates,               // set to true if we look in uninstantiated templates
+  LookupFlags lflags)
+{
+  if (!qualVar) {
+    // just propagating earlier error
+    return NULL;
+  }
+
+  StringRef qual = qualVar->name;
+
+  // case 1: qualifier refers to a type
+  if (qualVar->hasFlag(DF_TYPEDEF)) {
+    // check for a special case: a qualifier that refers to
+    // a template parameter
+    if (qualVar->type->isTypeVariable() ||
+        qualVar->type->isPseudoInstantiation() ||    // in/t0426.cc
+        qualVar->type->isDependentQType()) {         // in/t0443.cc
+      // we're looking inside an uninstantiated template parameter
+      // type; the lookup fails, but no error is generated here
+      dependent = true;     // tell the caller what happened
+      return NULL;
+    }
+
+    if (!qualVar->type->isCompoundType()) {
+      error(stringc
+        << "typedef'd name `" << qual << "' doesn't refer to a class, "
+        << "so it can't be used as a scope qualifier");
+      return NULL;
+    }
+    CompoundType *ct = qualVar->type->asCompoundType();
+
+    if (ct->isTemplate()) {
+      anyTemplates = true;
+    }
+
+    // TODO: distinguish better between empty template argument list "<>" and
+    // template argument list not existing.
+
+    if (qualVar->hasFlag(DF_SELFNAME) && sargs.isEmpty()) {
+      // it's a reference to the class I'm in (testcase: t0168.cc)
+    } else {
+      // check template argument compatibility
+      if (ct->isTemplate()) {
+        if (sargs.isEmpty()) {
+          // quarl 2006-06-14
+          //    It's permissible for the template argument list to be empty
+          //    (as "<>"), because all template parameters may have default
+          //    values.  It will be checked in
+          //    Env::insertTemplateArgBindings_oneParamList.
+
+          // error(stringc
+          //   << "class `" << qual
+          //   << "' is a template, you have to supply template arguments");
+          // // recovery: use the scope anyway
+        }
+      } else if (!ct->isTemplate()) {
+        if (sargs.isNotEmpty()) {
+          error(stringc
+                << "class `" << qual << "' isn't a template");
+          // recovery: use the scope anyway
+        }
+      }
+
+      if (ct->isTemplate()) {
+        if ((lflags & LF_DECLARATOR) &&
+            containsVariables(sargs)) {    // fix t0185.cc?  seems to...
+          // Since we're in a declarator, the template arguments are
+          // being supplied for the purpose of denoting an existing
+          // template primary or specialization, *not* to cause
+          // instantiation.  For example, we're looking up "C<T>" in
+          //
+          //   template <class T>
+          //   int C<T>::foo() { ... }
+          //
+          // So, as 'ct' is the primary, look in it to find the proper
+          // specialization (or the primary).
+          Variable *primaryOrSpec =
+            getPrimaryOrSpecialization(ct->templateInfo(), sargs);
+          if (!primaryOrSpec) {
+            // I'm calling this disambiguating because I do so above,
+            // when looking up just 'qual'; it's not clear that this
+            // is the right thing to do.
+            //
+            // update: t0185.cc triggers this error.. so as a hack I'm
+            // going to make it non-disambiguating, so that in
+            // template code it will be ignored.  The right solution
+            // is to treat member functions of template classes as
+            // being independent template entities.
+            //
+            // Unfortunately, since this is *only* used in template
+            // code, it's always masked.  Therefore, use the 'error'
+            // tracing flag to see it when desired.  Hopefully a
+            // proper fix for t0185.cc will land soon and we can make
+            // this visible.
+            //
+            // 8/07/04: I think the test above, 'containsVariables',
+            // has resolved this issue.
+            error(stringc << "cannot find template primary or specialization `"
+                          << qual << sargsToString(sargs) << "'",
+                  EF_DISAMBIGUATES);
+            return ct;     // recovery: use the primary
+          }
+
+          return primaryOrSpec->type->asCompoundType();
+        }
+
+        // if the template arguments are not concrete, then this is
+        // a dependent name, e.g. "C<T>::foo"
+        if (containsVariables(sargs)) {
+          // 2005-03-07: I think this little mechanism might obviate
+          // a number of DF_SELFNAME hacks running around... but I am
+          // not going to try removing them just yet.
+          CompoundType *t = getMatchingTemplateInScope(ct, sargs);
+          if (t) {
+            // this C<T> is referring to a known C<T>
+            return t;
+          }
+
+          // some unknown dependent type
+          dependent = true;
+          return NULL;
+        }
+
+        Variable *inst = instantiateClassTemplate(loc(), qualVar, sargs);
+        if (!inst) {
+          return NULL;     // error already reported
+        }
+
+        // instantiate the body too, since we want to look inside it
+        ensureCompleteType("use as qualifier", inst->type);
+
+        ct = inst->type->asCompoundType();
+      }
+    }
+
+    // TODO: actually check that there are the right number
+    // of arguments, of the right types, etc.
+
+    // now that we've found it, that's our active scope
+    return ct;
+  }
+
+  // case 2: qualifier refers to a namespace
+  else /*DF_NAMESPACE*/ {
+    if (sargs.isNotEmpty()) {
+      error(stringc << "namespace `" << qual << "' can't accept template args");
+    }
+
+    // the namespace becomes the active scope
+    xassert(qualVar->scope);
+    return qualVar->scope;
+  }
+}
+
+
+// We want to get all the parent scopes of 'scopeVar' up to
+// (and not including) the first scope already on the global
+// scope stack.
+//
+// As noted at comments next to 'pushDeclarationScopes', there
+// is some overlap with that function's behavior.
+void Env::getParentScopes(ScopeSeq &scopes, Variable *scopeVar)
+{
+  getParentScopes(scopes, scopeVar->getDenotedScope());
+}
+
+void Env::getParentScopes(ScopeSeq &scopes, Scope *scope)
+{
+  // check for the common case: we can walk up the scope tree
+  // and find the current innermost scope
+  //
+  //          global
+  //           /
+  //          A
+  //         /
+  //        B (innerScope)
+  //       /
+  //      X
+  //     /
+  //    Y (scope)
+  //
+  // this search takes linear time
+  Scope *innerScope = this->scopes.first();
+  for (Scope *s = scope; s; s = s->parentScope) {
+    if (s == innerScope) {
+      // good; just collect everything from 'scope' up to but
+      // not including 's'
+      getParentScopesLimit(scopes, scope, s);
+      return;
+    }
+  }
+
+  // we must have a situation like this:    .
+  //                                        .
+  //              global                    .
+  //              /    \                    .
+  //             X      A                   .
+  //            /        \                  .
+  //   (scope) Y          B (innerScope)    .
+  //
+  // so, collect scopes up to the join point (here the global
+  // scope); the search for the join is quadratic, which is why
+  // we only do it if the quick one fails
+  getParentScopesLimit(scopes, scope, findEnclosingScope(scope));
+}
+
+void Env::getParentScopesLimit(ScopeSeq &scopes, Scope *scope, Scope *limit)
+{
+  if (scope == limit) {
+    // do not include the limit
+    return;
+  }
+  xassert(scope->parentScope);     // must hit the limit before end of chain
+
+  // we will want to push them in order from outermost to innermost,
+  // so put the outermost on the list first
+  getParentScopesLimit(scopes, scope->parentScope, limit);
+
+  // finally, this scope
+  scopes.push(scope);
+}
+
+
+void Env::extendScopeSeq(ScopeSeq const &scopes)
+{
+  for (int i=0; i < scopes.length(); i++) {
+    extendScope(scopes[i]);
+  }
+}
+
+void Env::retractScopeSeq(ScopeSeq const &scopes)
+{
+  // do this one backwards, to reverse the effects
+  // of 'extendScopeSeq'
+  for (int i = scopes.length()-1; i>=0; i--) {
+    retractScope(scopes[i]);
+  }
+}
+
+
+bool hadTcheckErrors(ObjList<STemplateArgument> const &args)
+{
+  FOREACH_OBJLIST(STemplateArgument, args, iter) {
+    if (iter.data()->kind == STemplateArgument::STA_NONE) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// given something like "C<T>", where "C" has been looked up to yield
+// 'var' and "<T>" is still attached to 'final', combine them
+Variable *Env::applyPQNameTemplateArguments
+  (Variable *var,         // (nullable) may or may not name a template primary
+   PQName const *final,   // final part of name, may or may not have template arguments
+   LookupFlags flags)
+{
+  if (!var) {
+    // caller already had an error and reported it; just propagate
+    return NULL;
+  }
+
+  // reference to a class in whose scope I am?
+  if (var->hasFlag(DF_SELFNAME)) {
+    xassert(!final->isPQ_template());    // otherwise how'd LF_SELFNAME get set?
+
+    // cppstd 14.6.1 para 1: if the name refers to a template
+    // in whose scope we are, then it need not have arguments
+    TRACE("template", "found bare reference to enclosing template: " << var->name);
+    return var;
+  }
+
+  // 2005-02-18: Do this regardless of whether 'var->isTemplate()',
+  // since it could be overloaded, making that test meaningless.
+  // See, e.g., in/t0372.cc.
+  if (flags & LF_TEMPL_PRIMARY) {
+    return var;
+  }
+
+  // compare the name's template status to whether template
+  // arguments were supplied; note that you're only *required*
+  // to pass arguments for template classes, since template
+  // functions can infer their arguments
+  if (var->isTemplate(false /*considerInherited*/)) {
+    if (!final->isPQ_template()
+        && var->isTemplateClass() // can be inferred for template functions, so we duck
+        ) {
+      // this disambiguates
+      //   new Foo< 3 > +4 > +5;
+      // which could absorb the '3' as a template argument or not,
+      // depending on whether Foo is a template
+      error(stringc
+        << "`" << var->name << "' is a class template, but template "
+        << "arguments were not supplied",
+        EF_DISAMBIGUATES);
+      return lookupErrorObject(flags);
+    }
+
+    if (var->isTemplateClass()) {
+      // apply the template arguments to yield a new type based
+      // on the template
+      PQ_template const *tqual = final->asPQ_templateC();
+      if (hadTcheckErrors(tqual->sargs)) {
+        return var;           // recovery (in/t0546.cc)
+      }
+      return instantiateClassTemplate_or_PI(var->type->asCompoundType(),
+                                            tqual->sargs);
+    }
+    else {                    // template function
+      xassert(var->isTemplateFunction());
+
+      // it's quite likely that this code is not right...
+
+      if (!final->isPQ_template()) {
+        // no template arguments supplied... just return the primary
+        return var;
+      }
+      else {
+        // hope that all of the arguments have been supplied
+        xassert(var->templateInfo()->isPrimary());
+
+        PQ_template const *pqt = final->asPQ_templateC();
+        if (hadTcheckErrors(pqt->sargs)) {
+          // do not try to instantiate if there were errors; return the
+          // primary as recovery action (in/k0038.cc)
+          return var;
+        }
+
+        if (containsVariables(pqt->sargs)) {
+          return dependentVar;    // in/t0545.cc
+        }
+
+        return instantiateFunctionTemplate(loc(), var, pqt->sargs);
+      }
+    }
+  }
+  else if (!var->isTemplate() &&
+           final->isPQ_template()) {
+    // disambiguates the same example as above, but selects
+    // the opposite interpretation
+    error(stringc
+      << "`" << var->name << "' is not a template, but template arguments were supplied",
+      EF_DISAMBIGUATES);
+    return NULL;
+  }
+
+  return var;
+}
+
+
+Variable *Env::instantiateClassTemplate_or_PI
+  (CompoundType *ct, ObjList<STemplateArgument> const &args)
+{
+  // if the template arguments are not concrete, then create
+  // a PseudoInstantiation
+  if (containsVariables(args)) {
+    PseudoInstantiation *pi = createPseudoInstantiation(ct, args);
+    xassert(pi->typedefVar);
+    return pi->typedefVar;
+  }
+  else {
+    return instantiateClassTemplate(loc(), ct->typedefVar, args);
+  }
+}
+
+
+
+Variable *Env::lookupVariable(StringRef name, LookupFlags flags)
+{
+  Scope *dummy;
+  return lookupVariable(name, flags, dummy);
+}
+
+Variable *Env::lookupVariable(StringRef name, LookupFlags flags,
+                              Scope *&foundScope)
+{
+  LookupSet candidates;
+  return lookupVariable_set(candidates, name, flags, foundScope);
+}
+
+Variable *Env::lookupVariable_set(LookupSet &candidates,
+                                  StringRef name, LookupFlags flags,
+                                  Scope *&foundScope)
+{
+  if (flags & LF_INNER_ONLY) {
+    // here as in every other place 'innerOnly' is true, I have
+    // to skip non-accepting scopes since that's not where the
+    // client is planning to put the name
+    foundScope = acceptingScope();
+    return foundScope->lookupVariable_set(candidates, name, *this, flags);
+  }
+
+  // look in all the scopes
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    Scope *s = iter.data();
+    if ((flags & LF_SKIP_CLASSES) && s->isClassScope()) {
+      continue;
+    }
+
+    if (s->isDelegated()) {
+      // though 's' appears physically here, it is searched in a different order
+      continue;
+    }
+
+    // look in 's'
+    Variable *v = s->lookupVariable_set(candidates, name, *this, flags);
+    if (v) {
+      foundScope = s;
+      return v;
+    }
+
+    // is 's' connected to a delegated scope?
+    Scope *delegated = s->getDelegationPointer();
+    if (delegated) {
+      v = delegated->lookupVariable_set(candidates, name, *this, flags);
+      if (v) {
+        foundScope = s;     // not 'delegated'
+        return v;
+      }
+    }
+  }
+  return NULL;    // not found
+}
+
+CompoundType *Env::lookupCompound(StringRef name, LookupFlags flags)
+{
+  if (flags & LF_INNER_ONLY) {
+    // 10/17/04: dsw/sm: Pass DF_TYPEDEF here so that in C mode we
+    // will be looking at 'outerScope'.
+    return acceptingScope(DF_TYPEDEF)->lookupCompound(name, env, flags);
+  }
+
+  // look in all the scopes
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    CompoundType *ct = iter.data()->lookupCompound(name, env, flags);
+    if (ct) {
+      return ct;
+    }
+  }
+  return NULL;    // not found
+}
+
+EnumType *Env::lookupEnum(StringRef name, LookupFlags flags)
+{
+  if (flags & LF_INNER_ONLY) {
+    return acceptingScope()->lookupEnum(name, *this, flags);
+  }
+
+  xfailure("lookupEnum: expected LF_INNER_ONLY");
+  return NULL;   // silence warning
+
+  #if 0   // defunct
+  // look in all the scopes
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    EnumType *et = iter.data()->lookupEnum(name, *this, flags);
+    if (et) {
+      return et;
+    }
+  }
+  return NULL;    // not found
+  #endif // 0
+}
+
+
+StringRef Env::getAnonName(TypeIntr keyword, char const *relName)
+{
+  return getAnonName(toString(keyword), relName);
+}
+
+
+StringRef Env::getAnonName(char const *why, char const *relName)
+{
+  // construct a name
+  stringBuilder sb;
+  sb << "__anon_" << why << "_";
+
+  if (relName) {
+    // quarl 2006-07-14
+    //    allow semi-anonymous structs so that we can mangle them consistently
+    //    across translation units
+    sb << relName;
+  } else {
+    sb << anonCounter;
+  }
+  anonCounter++;
+
+  // map to a stringref
+  return str(sb);
+}
+
+
+TemplateInfo * /*owner*/ Env::takeFTemplateInfo(bool allowInherited)
+{
+  // for now, difference is that function TemplateInfos have
+  // NULL baseNames
+  //
+  // and in fact that difference is now gone too...
+  return takeCTemplateInfo(allowInherited);
+}
+
+TemplateInfo * /*owner*/ Env::takeCTemplateInfo(bool allowInherited)
+{
+  // delay building a TemplateInfo until it is sure to be needed
+  TemplateInfo *ret = NULL;
+
+  // could this be a member of complete specialization class?
+  // if I do nothing it will get a degenerate TemplateInfo, so
+  // I need to detect that situation and throw the tinfo away
+  bool couldBeCompleteSpecMember = true;
+
+  // do the enclosing scopes other than the closest have params?
+  // if so, find and attach all inherited parameter lists
+  ObjListIter<Scope> iter(scopes);
+  for (; !iter.isDone(); iter.adv()) {
+    Scope const *s = iter.data();
+
+    // template parameters are only inherited across some kinds of
+    // scopes (this is a little bit of a hack as I try to guess the
+    // right rules)
+    if (!( s->scopeKind == SK_CLASS ||
+           s->scopeKind == SK_NAMESPACE ||
+           s->scopeKind == SK_TEMPLATE_PARAMS )) {
+      break;
+    }
+
+    if (s->isTemplateParamScope()) {
+      // found some parameters that we need to record in a TemplateInfo
+      if (!ret) {
+        ret = new TemplateInfo(loc());
+      }
+
+      // are these as-yet unassociated params?
+      if (!s->parameterizedEntity) {
+        if (ret->params.isNotEmpty()) {
+          // there was already one unassociated, and now we see another
+          error("too many template <...> declarations");
+        }
+        else {
+          ret->params.appendAll(s->templateParams);
+          couldBeCompleteSpecMember = false;
+
+          TRACE("templateParams", "main params: " << ret->paramsToCString());
+        }
+      }
+
+      else if (!allowInherited) {
+        // ignore these inherited parameters
+      }
+
+      else {
+        // record info about these params and where they come from
+        InheritedTemplateParams *itp
+          = new InheritedTemplateParams(s->parameterizedEntity->type->asCompoundType());
+        itp->params.appendAll(s->templateParams);
+
+        if (s->templateParams.isNotEmpty()) {
+          couldBeCompleteSpecMember = false;
+        }
+
+        // stash them in 'ret', prepending so as we work from innermost
+        // to outermost, so the last one prepended will be the outermost,
+        // and hence first in the list when we're done
+        ret->inheritedParams.prepend(itp);
+
+        TRACE("templateParams", "inherited " << itp->paramsToCString() <<
+                                " from " << s->parameterizedEntity->name);
+      }
+    }
+  }
+
+  if (ret && couldBeCompleteSpecMember) {
+    // throw away this tinfo; the thing is fully concrete and
+    // not a specialization of any template
+    //
+    // TODO: I need a testcase for this in Elsa.. right now there
+    // is only an Oink testcase.
+    TRACE("templateParams", "discarding TemplateInfo for member of complete specialization");
+    delete ret;
+    ret = NULL;
+  }
+
+  return ret;
+}
+
+
+Type *Env::makeNewCompound(CompoundType *&ct, Scope * /*nullable*/ scope,
+                           StringRef name, SourceLoc loc,
+                           TypeIntr keyword, bool forward, bool builtin)
+{
+  // make the type itself
+  ct = tfac.makeCompoundType((CompoundType::Keyword)keyword, name);
+  if (scope) {
+    setParentScope(ct, scope);
+  }
+
+  // make the implicit typedef
+  Type *ret = makeType(ct);
+  Variable *tv = makeVariable(loc, name, ret, DF_TYPEDEF | DF_IMPLICIT);
+  if (builtin) env.builtinVars.push(tv);
+  ct->typedefVar = tv;
+
+  // add the tag to the scope
+  ct->forward = forward;
+  if (name && scope) {
+    bool ok = scope->addCompound(ct);
+    xassert(ok);     // already checked that it was ok
+  }
+
+  // cppstd section 9, para 2: add to class' scope itself, too
+  #if 0
+  // It turns out this causes infinite loops elsewhere, and is in
+  // fact unnecessary, because any lookup that would find 'ct' in
+  // 'ct' itself would *also* find it in 'scope', since in the
+  // space of compound types we can't get the kind of hiding that
+  // can occur in the variable namespace.
+  if (name) {
+    bool ok = ct->addCompound(ct);
+    xassert(ok);
+  }
+  #endif // 0
+
+  // transfer template parameters
+  {
+    TemplateInfo *ti = takeCTemplateInfo();
+    if (ti) {
+      ct->setTemplateInfo(ti);
+
+      // it turns out any time I pass in a non-NULL scope, I'm in
+      // the process of making a primary
+      if (scope) {
+        if (this->scope()->isTemplateParamScope()) {
+          this->scope()->setParameterizedEntity(ct->typedefVar);
+        }
+
+        // set its defnScope, which is used during instantiation
+        ti->defnScope = scope;
+      }
+    }
+  }
+
+  if (name && scope) {
+    scope->registerVariable(tv);
+    if (lang.tagsAreTypes) {
+      if (!scope->addVariable(tv)) {
+        // this isn't really an error, because in C it would have
+        // been allowed, so C++ does too [ref?]
+        //return env.error(stringc
+        //  << "implicit typedef associated with " << ct->keywordAndName()
+        //  << " conflicts with an existing typedef or variable",
+        //  true /*disambiguating*/);
+      }
+      else {
+        addedNewVariable(scope, tv);
+      }
+    }
+    else {
+      // dsw: I found that it interfered to put the implicit typedef
+      // into the space in C, and as far as I understand, it doesn't
+      // exist in C anyway.  See in/c/dC0012.c
+      //
+      // sm: yes, that is right
+    }
+  }
+
+  // also add the typedef to the class' scope
+  if (name && lang.compoundSelfName) {
+    if (tv->templateInfo() && tv->templateInfo()->hasParameters()) {
+      // the self type should be a PseudoInstantiation, not the raw template
+      //
+      // 2005-03-05: This always fills in arguments corresponding to
+      // the template primary.  If this is a specialization, the caller
+      // will modify the selfname later.
+      ct->selfType = pseudoSelfInstantiation(ct, CV_NONE);
+    }
+    else {
+      // just the class' type
+      ct->selfType = ret;
+    }
+    Variable *selfVar = makeVariable(loc, name, ct->selfType,
+                                     DF_TYPEDEF | DF_SELFNAME);
+    ct->addUniqueVariable(selfVar);
+    addedNewVariable(ct, selfVar);
+    if (builtin) env.builtinVars.push(selfVar);
+  }
+
+  return ret;
+}
+
+
+bool Env::setDisambiguateOnly(bool newVal)
+{
+  bool ret = disambiguateOnly;
+  disambiguateOnly = newVal;
+  return ret;
+}
+
+
+Type *Env::implicitReceiverType()
+{
+  Variable *receiver = lookupVariable(receiverName);
+  if (!receiver) {
+    return NULL;
+  }
+  else {
+    return receiver->type;
+  }
+}
+
+
+Variable *Env::receiverParameter(SourceLoc loc, NamedAtomicType *nat, CVFlags cv,
+                                 D_func *syntax)
+{
+  // For templatized classes, do something a little different.  It's
+  // unfortunate that whether we call into tfac depends on whether 'nat'
+  // is a template class.  I think 'makeTypeOf_receiver' should simply
+  // be removed from the tfac.
+  Type *recType;
+  if (nat->isCompoundType() &&
+      nat->typedefVar->isTemplate()) {
+    // get the basic selfType; we re-use the one from the CompoundType
+    // instead of calling Env::pseudoSelfInstantiation because we want
+    // all the receiver parameters of methods in the uninstantiated
+    // class to be the same (in/t0410.cc)
+    Type *selfType = nat->asCompoundType()->selfType;
+    xassert(selfType);
+
+    // apply 'cv'
+    selfType = tfac.applyCVToType(SL_UNKNOWN, cv, selfType, NULL /*syntax*/);
+
+    // build a reference
+    recType = makeReferenceType(selfType);
+  }
+  else {
+    // this doesn't use 'implicitReceiverType' because of the warnings above
+    recType = tfac.makeTypeOf_receiver(loc, nat, cv, syntax);
+  }
+
+  return makeVariable(loc, receiverName, recType, DF_PARAMETER);
+}
+
+
+// cppstd 5 para 8
+Type *Env::operandRval(Type *t)
+{
+  // 4.1: lval to rval
+  if (t->isReferenceType()) {
+    t = t->asRval();
+
+    // non-compounds have their constness stripped at this point too,
+    // but I think that would not be observable in my implementation
+  }
+
+  // 4.2: array to pointer
+  if (t->isArrayType()) {
+    t = makePointerType(CV_NONE, t->getAtType());
+  }
+
+  // 4.2: function to pointer
+  if (t->isFunctionType()) {
+    t = makePointerType(CV_NONE, t);
+  }
+
+  return t;
+}
+
+
+// Get the typeid type (5.2.8, 18.5.1).  The program is required to
+// #include <typeinfo> before using it, so we don't need to define
+// this class (since that header does).
+Type *Env::type_info_const_ref()
+{
+  // does the 'std' namespace exist?
+  Scope *scope = globalScope();
+  Variable *stdNS = scope->lookupVariable(str("std"), *this);
+  if (stdNS && stdNS->isNamespace()) {
+    // use that instead of the global scope
+    scope = stdNS->scope;
+  }
+
+  // look for 'type_info'
+  Variable *ti = scope->lookupVariable(str("type_info"), *this, LF_ONLY_TYPES);
+  if (ti && ti->hasFlag(DF_TYPEDEF)) {
+    // make a const reference
+    return makeReferenceType(
+             tfac.applyCVToType(loc(), CV_CONST, ti->type, NULL /*syntax*/));
+  }
+  else {
+    return error("must #include <typeinfo> before using typeid");
+  }
+}
+
+
+void Env::addBuiltinUnaryOp(SimpleTypeId retId, OverloadableOp op, Type *x)
+{
+  Type *retType = getSimpleType(retId);
+  builtinUnaryOperator[op].push(createBuiltinUnaryOp(retType, op, x));
+}
+
+Variable *Env::createBuiltinUnaryOp(Type *retType, OverloadableOp op, Type *x)
+{
+  Variable *v = declareFunction1arg(
+    retType, operatorName[op],
+    x, "x",
+    FF_BUILTINOP);
+  v->setFlag(DF_BUILTIN);
+
+  return v;
+}
+
+
+void Env::addBuiltinBinaryOp(SimpleTypeId retId, OverloadableOp op,
+                             Type *x, Type *y)
+{
+  Type *retType = getSimpleType(retId);
+  addBuiltinBinaryOp(op, new PolymorphicCandidateSet(
+    createBuiltinBinaryOp(retType, op, x, y)));
+}
+
+void Env::addBuiltinBinaryOp(SimpleTypeId retId, OverloadableOp op,
+                             PredicateCandidateSet::PreFilter pre,
+                             PredicateCandidateSet::PostFilter post,
+                             bool isAssignment)
+{
+  if (isAssignment) {
+    addBuiltinBinaryOp(op, new AssignmentCandidateSet(retId, pre, post));
+  }
+  else {
+    addBuiltinBinaryOp(op, new PredicateCandidateSet(retId, pre, post));
+  }
+}
+
+void Env::addBuiltinBinaryOp(OverloadableOp op, CandidateSet * /*owner*/ cset)
+{
+  builtinBinaryOperator[op].push(cset);
+}
+
+
+Variable *Env::createBuiltinBinaryOp(Type *retType, OverloadableOp op,
+                                     Type *x, Type *y)
+{
+  // PLAN:  Right now, I just leak a bunch of things.  To fix
+  // this, I want to have the Env maintain a pool of Variables
+  // that represent built-in operators during overload
+  // resolution.  I ask the Env for operator-(T,T) with a
+  // specific T, and it rewrites an existing one from the pool
+  // for me.  Later I give all the pool elements back.
+
+  Variable *v = declareFunction2arg(
+    retType, operatorName[op],
+    x, "x", y, "y",
+    FF_BUILTINOP);
+  v->setFlag(DF_BUILTIN);
+
+  return v;
+}
+
+
+// comparing types for equality, *except* we allow array types
+// to match even when one of them is missing a bound and the
+// other is not; I cannot find where in the C++ standard this
+// exception is specified, so I'm just guessing about where to
+// apply it and exactly what the rule should be
+//
+// note that this is *not* the same rule that allows array types in
+// function parameters to vary similarly, see
+// 'normalizeParameterType()'
+bool Env::almostEqualTypes(Type const *t1, Type const *t2,
+                           MatchFlags mflags)
+{
+  if (t1->isArrayType() &&
+      t2->isArrayType()) {
+    ArrayType const *at1 = t1->asArrayTypeC();
+    ArrayType const *at2 = t2->asArrayTypeC();
+
+    if ((at1->hasSize() && !at2->hasSize()) ||
+        (at2->hasSize() && !at1->hasSize())) {
+      // the exception kicks in
+      return at1->eltType->equals(at2->eltType /*BUG?*/);
+
+      // TODO: I think the above call is a bug because it should be
+      // passing the 'mflags', but for now I leave it as-is because
+      // that's how the code has worked in the past, and for the
+      // moment I can't easily translate MatchFlags into EqFlags.
+    }
+  }
+
+  // strict equality
+  return equivalentTypes(t1, t2, mflags);
+}
+
+
+// check if multiple definitions of a global symbol are ok; also
+// updates some data structures so that future checks can be made
+bool multipleDefinitionsOK(Env &env, Variable *prior, DeclFlags dflags)
+{
+  // dsw: this seems like it might be the natural place to deal with
+  // gnu extern inline functions that are being handled as weak static
+  // inline functions: we allow them to be redefined (this is the
+  // point of considering them to be 'weak').
+  if (prior->hasFlag(DF_GNU_EXTERN_INLINE)) {
+    // we should not get here if handleExternInline_asPrototype() as
+    // there is no definition to override
+    xassert(handleExternInline_asWeakStaticInline());
+    xassert(prior->type->isFunctionType());
+    return true;
+  }
+
+  if (!env.lang.uninitializedGlobalDataIsCommon) {
+    return false;
+  }
+
+  // dsw: I think the "common symbol exception" only applies to
+  // globals.
+  if (!prior->hasFlag(DF_GLOBAL)) {
+    return false;
+  }
+
+  // can't be initialized more than once
+  if (dflags & DF_INITIALIZED) {
+    if (prior->hasFlag(DF_INITIALIZED)) {
+      return false; // can't both be initialized
+    }
+    else {
+      prior->setFlag(DF_INITIALIZED); // update for future reference
+    }
+  }
+
+  // don't allow this for functions!
+  if (prior->type->isFunctionType()) {
+    return false;
+  }
+
+  return true;
+}
+
+
+// little hack: Variables don't store pointers to the global scope,
+// they store NULL instead, so canonize the pointers by changing
+// global scope pointers to NULL before comparison
+//
+// dsw: 8/10/04: the above is no longer true, so this function is
+// now trivial
+bool sameScopes(Scope *s1, Scope *s2)
+{
+  return s1 == s2;
+}
+
+// If a new variable was created, return it, else NULL.
+Variable *Env::makeUsingAliasFor(SourceLoc loc, Variable *origVar)
+{
+  Type *type = origVar->type;
+  StringRef name = origVar->name;
+  Scope *scope = this->scope();
+  CompoundType *enclosingClass = scope->curCompound;
+
+  // TODO: check that 'origVar' is accessible (w.r.t. access control)
+  // in the current context
+
+  // 7.3.3 paras 4 and 6: the original and alias must either both
+  // be class members or neither is class member
+  if (scope->isClassScope() !=
+      (origVar->scope? origVar->scope->isClassScope() : false)) {
+    error(stringc << "bad alias `" << name
+                  << "': alias and original must both be class members or both not members");
+    return NULL;
+  }
+
+  if (scope->isClassScope()) {
+    // 7.3.3 para 13: overload resolution for imported class members
+    // needs to treat them as accepting a derived-class receiver argument,
+    // so we'll make the alias have a type consistent with its new home
+    if (type->isMethod()) {
+      FunctionType *oldFt = type->asFunctionType();
+
+      // everything the same but empty parameter list
+      FunctionType *newFt =
+        tfac.makeSimilarFunctionType(SL_UNKNOWN, oldFt->retType, oldFt);
+
+      // add the receiver parameter
+      CompoundType *ct = scope->curCompound;
+      newFt->addReceiver(receiverParameter(SL_UNKNOWN, ct, oldFt->getReceiverCV()));
+
+      // copy the other parameters
+      SObjListIterNC<Variable> iter(oldFt->params);
+      iter.adv();     // skip oldFt's receiver
+      for (; !iter.isDone(); iter.adv()) {
+        newFt->addParam(iter.data());    // share parameter objects
+      }
+      doneParams(newFt);
+
+      // treat this new type as the one to declare from here out
+      type = newFt;
+    }
+
+    // 7.3.3 para 4: the original member must be in a base class of
+    // the class where the alias is put
+    if (!enclosingClass->hasBaseClass(origVar->scope->curCompound)) {
+      error(stringc << "bad alias `" << name
+                    << "': original must be in a base class of alias' scope");
+      return NULL;
+    }
+  }
+
+  // check for existing declarations
+  Variable *prior = lookupVariableForDeclaration(scope, name, type,
+    type->isFunctionType()? type->asFunctionType()->getReceiverCV() : CV_NONE);
+
+  // 10/20/04: 7.3.3 para 8 says duplicate aliases are allowed wherever
+  // duplicate declarations are normally allowed.  I don't quite understand
+  // where they are normally allowed; the example suggests they are ok
+  // at global/namespace scope, so that is what I will allow...
+  // (in/d0109.cc) (in/t0289.cc) (in/t0161.cc) (in/std/7.3.3f.cc)
+  // (in/t0547.cc); this is probably not right..
+  if (prior &&
+      prior->skipAliasC() == origVar->skipAliasC() &&
+      (scope->isGlobalScope() || scope->isNamespace())) {
+    return NULL;
+  }
+
+  // check for overloading
+  OverloadSet *overloadSet = getOverloadForDeclaration(prior, type);
+
+  // are we heading for a conflict with an alias?
+  if (prior &&
+      prior->getUsingAlias() &&
+      !prior->hasFlag(DF_TYPEDEF) &&
+      !sameScopes(prior->skipAlias()->scope, scope)) {
+    // 7.3.3 para 11 says it's ok for two aliases to conflict when
+    // not in class scope; I assume they have to be functions for
+    // this to be allowed
+    if (!enclosingClass &&
+        prior->type->isFunctionType()) {
+      // turn it into an overloading situation
+      overloadSet = prior->getOrCreateOverloadSet();
+      prior = NULL;
+    }
+
+    // if we are in class scope, call it an error now; that way I know
+    // down in 'createDeclaration' that if 'prior' is an alias, then
+    // we are *not* trying to create another alias
+    else if (enclosingClass) {
+      // this error message could be more informative...
+      error(stringc << "alias `" << name << "' conflicts with another alias");
+      return NULL;
+    }
+  }
+
+  // make new declaration, taking to account various restrictions
+  Variable *newVar = createDeclaration(loc, name, type, origVar->flags | DF_USING_ALIAS,
+                                       scope, enclosingClass, prior, overloadSet);
+  #if 0     // 2005-02-23: share the referent's templateInfo
+  if (origVar->templateInfo()) {
+    newVar->setTemplateInfo(new TemplateInfo(*origVar->templateInfo()));
+  }
+  #endif // 0
+
+  if (newVar == prior) {
+    // found that the name/type named an equivalent entity
+    return NULL;
+  }
+
+  // hook 'newVar' up as an alias for 'origVar'
+  newVar->setUsingAlias(origVar->skipAlias());    // don't make long chains
+
+  TRACE("env", "made alias `" << name <<
+               "' for origVar at " << toString(origVar->loc));
+
+  return newVar;
+}
+
+
+// lookup in inner, plus signature matching in overload set; the
+// const/volatile flags on the receiver parameter are given by this_cv
+// since in D_name_tcheck they aren't yet attached to the type (and it
+// isn't easy to do so because of ordering issues)
+Variable *Env::lookupVariableForDeclaration
+  (Scope *scope, StringRef name, Type *type, CVFlags this_cv)
+{
+  // does this name already have a declaration in this scope?
+  //
+  // 8/13/04: It seems like I need LF_SELFNAME (d0087.cc).  I think
+  // the callers generally have names w/o template arguments..
+  Variable *prior = scope->lookupVariable(name, *this, LF_INNER_ONLY | LF_SELFNAME);
+  if (prior &&
+      prior->overload &&
+      type->isFunctionType()) {
+    // set 'prior' to the previously-declared member that has
+    // the same signature, if one exists
+    FunctionType *ft = type->asFunctionType();
+    Variable *match = findInOverloadSet(prior->overload, ft, this_cv);
+    if (match) {
+      prior = match;
+    }
+  }
+
+  return prior;
+}
+
+
+// Search in an overload set for a specific element, given its type.
+// This is like the obsolete OverloadSet::findByType, except it works
+// when elements of the set are templatized.
+Variable *Env::findInOverloadSet(OverloadSet *oset,
+                                 FunctionType *ft, CVFlags receiverCV)
+{
+  SFOREACH_OBJLIST_NC(Variable, oset->set, iter) {
+    FunctionType *iterft = iter.data()->type->asFunctionType();
+
+    // check the parameters other than '__receiver'
+    //
+    // We also ignore the cv-flags on the function type, even though
+    // we probably should not, because they are represented by
+    // attaching to the __receiver, which has not been created in 'ft'
+    // yet (for the same reasons we're ignoring them in this
+    // comparison; we don't have enough info to build them
+    // completely).
+    //
+    MatchFlags mflags = MF_STAT_EQ_NONSTAT | MF_IGNORE_IMPLICIT |
+                        MF_IGNORE_FUNC_CV;
+
+    if (inUninstTemplate()) {
+      // do not check the return types; we can diagnose a mismatch
+      // when the template is instantiated, and it is sometimes
+      // hard to tell when they match (in/t0290.cc)
+      mflags |= MF_IGNORE_RETURN;
+    }
+
+    if (!equivalentTypes(iterft, ft, mflags)) {
+      continue;    // not the one we want
+    }
+
+    // if 'this' exists, it must match 'receiverCV'
+    if (iterft->getReceiverCV() != receiverCV) continue;
+
+    // ok, this is the right one
+    return iter.data();
+  }
+  return NULL;    // not found
+}
+
+Variable *Env::findInOverloadSet(OverloadSet *oset, FunctionType *ft)
+{
+  return findInOverloadSet(oset, ft, ft->getReceiverCV());
+}
+
+
+// true if two function types have equivalent signatures, meaning
+// if their names are the same then they refer to the same function,
+// not two overloaded instances
+bool Env::equivalentSignatures(FunctionType *ft1, FunctionType *ft2)
+{
+  return equivalentTypes(ft1, ft2, MF_SIGNATURE);
+}
+
+
+#if 0     // not needed right now
+class ContainsUTP : public TypeVisitor {
+public:
+  bool anyUTP;
+
+public:
+  ContainsUTP() : anyUTP(false) {}
+  virtual bool visitAtomicType(AtomicType *obj);
+};
+
+bool ContainsUTP::visitAtomicType(AtomicType *obj)
+{
+  if (obj->isTypeVariable() &&
+      !obj->asTypeVariableC()->isAssociated()) {
+    anyUTP = true;
+    return false;     // no need to check children
+  }
+  return true;
+}
+
+bool containsUnassociatedTemplateParams(Type *t)
+{
+  ContainsUTP cutp;
+  t->traverse(cutp);
+  return cutp.anyUTP;
+}
+#endif // 0
+
+// 2005-03-03: This function is taking over some of the duties of
+// 'equalOrIsomorphic', in particular those that involve checking
+// function signature equivalence for the purpose of matching
+// declarations and definitions.  It distinguishes template parameters
+// by whether they have been associated with a template: those that
+// have been associated are essentially regarded as concrete, while
+// those that have not are regarded as arbitrary type variables, and
+// therefore subject to unification by MType.
+bool Env::equivalentTypes(Type const *a, Type const *b, MatchFlags mflags)
+{
+  // the 'a' type refers to the already-existing function template
+  // declaration, wherein the parameters *have* been associated, and
+  // the 'b' type refers to the new declaration we are trying to
+  // match up, so its parameters have *not* been associated
+  MType match;
+  if (!match.matchType(a, b, mflags | MF_MATCH | MF_ISOMORPHIC | MF_UNASSOC_TPARAMS)) {
+    return false;
+  }
+
+  // 2005-05-28: The following is a bit of a hack...
+  // (in/t0494.cc) check the symmetric condition too
+  // (in/t0184.cc) letting all tparams unify
+  MType match2;
+  return match2.matchType(b, a, mflags | MF_MATCH | MF_ISOMORPHIC);
+}
+
+
+bool equalOrIsomorphic(Type const *a, Type const *b)
+{
+  MType match;
+  return match.matchType(a, b, MF_ISOMORPHIC|MF_MATCH);
+}
+
+
+// if 'prior' refers to an overloaded set, and 'type' could be the type
+// of a new (not existing) member of that set, then return that set
+// and nullify 'prior'; otherwise return NULL
+OverloadSet *Env::getOverloadForDeclaration(Variable *&prior, Type *type)
+{
+  OverloadSet *overloadSet = NULL;    // null until valid overload seen
+  if (lang.allowOverloading &&
+      prior &&
+      !(prior->name == string_main && prior->isGlobal()) &&   // cannot overload main()
+      prior->type->isFunctionType() &&
+      type->isFunctionType()) {
+    // potential overloading situation
+
+    // get the two function types
+    FunctionType *priorFt = prior->type->asFunctionType();
+    FunctionType *specFt = type->asFunctionType();
+    bool sameType =
+      (prior->name == conversionOperatorName?
+        equivalentTypes(priorFt, specFt) :       // conversion: equality check
+        equivalentSignatures(priorFt, specFt));  // non-conversion: signature check
+
+    // figure out if either is (or will be) a template
+    bool priorIsTemplate = prior->templateInfo() &&
+                           prior->templateInfo()->hasParameters();
+    bool thisIsTemplate = scope()->isTemplateParamScope();
+    bool sameTemplateNess = (priorIsTemplate == thisIsTemplate);
+
+    // can only be an overloading if their signatures differ
+    if (!sameType || !sameTemplateNess) {
+      // ok, allow the overload
+      TRACE("ovl",    "overloaded `" << prior->name
+                   << "': `" << prior->type->toString()
+                   << "' and `" << type->toString() << "'");
+      overloadSet = prior->getOrCreateOverloadSet();
+      prior = NULL;    // so we don't consider this to be the same
+    }
+  }
+
+  return overloadSet;
+}
+
+
+// dsw: is this function of the type that would be created as an implicit
+// type in K and R C at the call site to a function that has not been
+// declared; this seems too weird to make a method on FunctionType, but
+// feel free to move it
+static bool isImplicitKandRFuncType(FunctionType *ft)
+{
+  // is the return type an int?
+  Type *retType = ft->retType;
+  if (!retType->isCVAtomicType()) return false;
+  if (!retType->asCVAtomicType()->isSimpleType()) return false;
+  if (retType->asCVAtomicType()->asSimpleTypeC()->type != ST_INT) return false;
+
+  // does it accept lack parameter information?
+  if (ft->params.count() != 0) return false;
+  if (!(ft->flags & FF_NO_PARAM_INFO)) return false;
+
+  return true;
+}
+
+
+static bool compatibleParamCounts(FunctionType *ft1, FunctionType *ft2)
+{
+  return ft1->hasFlag(FF_NO_PARAM_INFO) ||
+         ft2->hasFlag(FF_NO_PARAM_INFO) ||
+         ft1->params.count() == ft2->params.count();
+}
+
+
+// The ANSI C99 standard, 6.7.2p4, explains that each enumerated type
+// is "compatible with" some implementation-defined integral type.  A
+// little experimentation with GCC 3.4.3 suggests that its rule is to
+// use 'unsigned int' if there are no negative enumerators, and
+// 'signed int' otherwise.  Emulating this behavior is necessary to
+// parse examples like in/c/k0013.c.
+static SimpleTypeId normalizeEnumToInteger(Type *t)
+{
+  if (t->isCVAtomicType()) {
+    AtomicType *at = t->asCVAtomicType()->atomic;
+    if (at->isSimpleType()) {
+      return at->asSimpleType()->type;
+    }
+    else if (at->isEnumType()) {
+      EnumType *et = at->asEnumType();
+      if (et->hasNegativeValues) {
+        return ST_INT;
+      }
+      else {
+        return ST_UNSIGNED_INT;
+      }
+    }
+  }
+
+  // not an enum or integral type
+  return ST_ERROR;
+}
+
+static bool compatibleEnumAndIntegerTypes(Type *t1, Type *t2)
+{
+  SimpleTypeId nt1 = normalizeEnumToInteger(t1);
+  if (nt1 == ST_ERROR) {
+    return false;
+  }
+
+  SimpleTypeId nt2 = normalizeEnumToInteger(t2);
+
+  return nt1 == nt2;
+}
+
+
+// possible outcomes:
+//   - error, make up a dummy variable
+//   - create new declaration
+//   - re-use existing declaration 'prior'
+// caller shouldn't have to distinguish first two
+Variable *Env::createDeclaration(
+  SourceLoc loc,            // location of new declaration
+  StringRef name,           // name of new declared variable
+  Type *type,               // type of that variable
+  DeclFlags dflags,         // declaration flags for new variable
+  Scope *scope,             // scope into which to insert it
+  CompoundType *enclosingClass,   // scope->curCompound, or NULL for a hack that is actually wrong anyway (!)
+  Variable *prior,          // pre-existing variable with same name and type, if any
+  OverloadSet *overloadSet  // set into which to insert it, if that's what to do
+) {
+  // if this gets set, we'll replace a conflicting variable
+  // when we go to do the insertion
+  bool forceReplace = false;
+
+  bool staticBecauseInline = false;
+  // quarl 2006-07-11
+  //    "inline" implies static linkage under certain conditions.  We can't
+  //    set DF_STATIC in all of those conditions because the flag is
+  //    overloaded; but we must set it under some of those conditions
+  //    because env won't be available in Variable::linkerVisibleName().
+  if ((dflags & DF_INLINE) && !(dflags & DF_GNU_EXTERN_INLINE) /*&& !(dflags & DF_EXTERN)*/) {
+    if (dflags & DF_MEMBER) {
+      // quarl 2006-07-11
+      //    Can't set DF_STATIC since DF_MEMBER|DF_STATIC implies static
+      //    member.  However, when DF_INLINE|DF_MEMBER can only occur in C++
+      //    where inlineImpliesStaticLinkage, so we check for that combination
+      //    in isStaticLinkage().  It would be nice to factor DF_STATIC into
+      //    DF_STATIC_LINKAGE and DF_STATIC_MEMBER.
+      xassert(env.lang.inlineImpliesStaticLinkage);
+    } else {
+      if (env.lang.inlineImpliesStaticLinkage) {
+        if (!(dflags & DF_STATIC)) {
+          dflags |= DF_STATIC;
+          staticBecauseInline = true;
+        }
+      }
+    }
+  }
+
+  // is there a prior declaration?
+  if (prior) {
+    // check for exception given by [cppstd 7.1.3 para 2]:
+    //   "In a given scope, a typedef specifier can be used to redefine
+    //    the name of any type declared in that scope to refer to the
+    //    type to which it already refers."
+    if (prior->hasFlag(DF_TYPEDEF) &&
+        (dflags & DF_TYPEDEF)) {
+      // let it go; the check below will ensure the types match
+    }
+
+    else {
+      // check for violation of the One Definition Rule
+      if (prior->hasFlag(DF_DEFINITION) &&
+          (dflags & DF_DEFINITION) &&
+          !multipleDefinitionsOK(*this, prior, dflags)) {
+        if (scope->isParameterScope()) {
+          env.diagnose3(env.lang.allowDuplicateParameterNames, loc, stringc
+            << "parameter `" << type->toCString(name)
+            << "' conflicts with previous parameter `"
+            << prior->toCStringAsParameter() << "' (gcc bug allows it [gcc PR 13717])");
+
+          // I will recover by removing the name
+          return makeVariable(loc, NULL /*name*/, type, dflags);
+        }
+
+        // HACK: if the type refers to type variables, then let it slide
+        // because it might be Foo<int> vs. Foo<float> but my simple-
+        // minded template implementation doesn't know they're different
+        //
+        // actually, I just added TypeVariables to 'Type::containsErrors',
+        // so the error message will be suppressed automatically
+        //
+        // 8/15/04: removing 'prior->type' so I can detect duplicate
+        // definitions of template functions (t0258.cc errors 1 and
+        // 2); I think the right soln is to remove the
+        // type-vars-suppress-errors thing altogether, but I want to
+        // minimize churn for the moment
+        error(/*prior->type,*/ stringc
+          << "duplicate definition for `" << name
+          << "' of type `" << prior->type->toString()
+          << "'; previous at " << toString(prior->loc),
+          maybeEF_STRONG());
+
+      makeDummyVar:
+        // the purpose of this is to allow the caller to have a workable
+        // object, so we can continue making progress diagnosing errors
+        // in the program; this won't be entered in the environment, even
+        // though the 'name' is not NULL
+        Variable *ret = makeVariable(loc, name, type, dflags);
+
+        // set up the variable's 'scope' field as if it were properly
+        // entered into the scope; this is for error recovery, in particular
+        // for going on to check the bodies of methods
+        scope->registerVariable(ret);
+
+        return ret;
+      }
+
+      // (t0468.cc) if the previous version has dependent type, then
+      // just ignore this decl, as we effectively already have a
+      // dependent-typed overload set
+      if (prior->type->isSimple(ST_DEPENDENT)) {
+        goto makeDummyVar;
+      }
+
+      // check for violation of rule disallowing multiple
+      // declarations of the same class member; cppstd sec. 9.2:
+      //   "A member shall not be declared twice in the
+      //   member-specification, except that a nested class or member
+      //   class template can be declared and then later defined."
+      //
+      // I have a specific exception for this when I do the second pass
+      // of typechecking for inline members (the user's code doesn't
+      // violate the rule, it only appears to because of the second
+      // pass); this exception is indicated by DF_INLINE_DEFN.
+      //
+      // 8/15/04: Now using 'secondPassTcheck' instead of DF_INLINE_DEFN.
+      if (enclosingClass &&
+          !secondPassTcheck &&
+          !prior->isImplicitTypedef()) {    // allow implicit typedef to be hidden
+        if (prior->getUsingAlias()) {
+          // The declaration we're trying to make conflicts with an alias
+          // imported from a base class.  7.3.3 para 12 says that's ok,
+          // that the new declaration effectively replaces the old.
+          TRACE("env", "hiding imported alias " << prior->name);
+
+          // Go in and change the variable to update what it means.
+          // This isn't the cleanest thing in the world, but the
+          // alternative involves pulling the old Variable ('prior')
+          // out of the scope (easy) and the overload sets (hard), and
+          // then substituting the new one for it.
+          prior->loc = loc;
+          // name remains unchanged
+          prior->type = type;
+          prior->setFlagsTo(dflags);
+          prior->funcDefn = NULL;
+          // overload can stay the same
+          prior->setUsingAlias(NULL);
+          scope->registerVariable(prior);
+          return prior;
+        }
+        else if (lang.allowMemberWithClassName &&
+                 prior->hasAllFlags(DF_SELFNAME | DF_TYPEDEF)) {
+          // 9/22/04: Special case for 'struct ip_opts': allow the member
+          // to replace the class name, despite 9.2 para 13.
+          TRACE("env", "allowing member `" << prior->name <<
+                       "' with same name as class");
+          forceReplace = true;
+          goto noPriorDeclaration;
+        }
+        else {
+          error(stringc
+            << "duplicate member declaration of `" << name
+            << "' in " << enclosingClass->keywordAndName()
+            << "; previous at " << toString(prior->loc),
+            maybeEF_STRONG());    // weakened for t0266.cc
+          goto makeDummyVar;
+        }
+      }
+    }
+
+    // are we redeclaring a 3.7.3p2 default?
+    if (prior->type->isFunctionType() &&
+        prior->type->asFunctionType()->hasFlag(FF_DEFAULT_ALLOC)) {
+      // replace it
+      TRACE("env", "replacing default declaration `" << prior->toString()
+                << "' with `" << type->toString() << "'");
+      forceReplace = true;
+      goto noPriorDeclaration;
+    }
+
+    // check that the types match, and either both are typedefs
+    // or neither is a typedef
+    if ((prior->flags & DF_TYPEDEF) != (dflags & DF_TYPEDEF)) {
+      if (prior->isImplicitTypedef()) {
+        // if the previous guy was an implicit typedef, then as a
+        // special case allow it, and arrange for the environment
+        // to replace the implicit typedef with the variable being
+        // declared here
+        //
+        // 2005-03-01: this is only legal if the new declaration
+        // is for a non-type (7.1.3p3)
+        xassert(!(dflags & DF_TYPEDEF));   // implied by preceding conditionals
+
+        TRACE("env",    "replacing implicit typedef of " << prior->name
+                     << " at " << prior->loc << " with new decl at "
+                     << loc);
+        forceReplace = true;
+
+        goto noPriorDeclaration;
+      }
+
+      error(loc, stringc
+        << "prior declaration of " << prior->name << ", at " << prior->loc
+        << ", was " << (prior->flags&DF_TYPEDEF? "a" : "not a")
+        << " type, but this one " << (dflags&DF_TYPEDEF? "is" : "is not")
+        << " a type");
+      goto makeDummyVar;
+    }
+    else if (almostEqualTypes(prior->type, type, MF_COMPARE_EXN_SPEC)) {
+      // same types, same typedef disposition, so they refer
+      // to the same thing
+    }
+    else if (lang.allowExternCThrowMismatch &&
+             prior->hasFlag(DF_EXTERN_C) &&
+             (prior->flags & DF_TYPEDEF) == (dflags & DF_TYPEDEF) &&
+             prior->type->isFunctionType() &&
+             almostEqualTypes(prior->type, type, MF_NONE /*not checking exn spec*/)) {
+      // 10/01/04: allow the nonstandard variation in exception specs
+      // for extern-C decls (since they usually don't throw exceptions
+      // at all)
+      //
+      // Note that by regarding these decls as compatible, the second
+      // exn spec will be ignored in favor of the first, which will be
+      // unsound if the second allows more exceptions and the function
+      // really can throw an exception.
+      warning(stringc << "allowing nonstandard variation in exception specs "
+                      << "(conflicting decl at " << prior->loc
+                      << ") due to extern-C");
+    }
+    else if (lang.allowImplicitFunctionDecls &&
+             prior->hasFlag(DF_FORWARD) &&
+             prior->type->isFunctionType() &&
+             isImplicitKandRFuncType(prior->type->asFunctionType())) {
+      // dsw: in K&R C sometimes what happens is that a function is
+      // called and then later declared; at the function call site a
+      // declaration is invented with type 'int (...)' but the real
+      // declaration is likely to collide with that here.  We don't
+      // try to back-patch and do anything clever or sound, we just
+      // turn the error into a warning so that the file can go
+      // through; this is an unsoundness
+      warning(stringc
+              << "prior declaration of function `" << name
+              << "' at " << prior->loc
+              << " had type `" << prior->type->toString()
+              << "', but this one uses `" << type->toString() << "'."
+              << " This is most likely due to the prior declaration being implied "
+              << "by a call to a function before it was declared.  "
+              << "Keeping the implied, weaker declaration; THIS IS UNSOUND.");
+    }
+    else if (name == string_main &&
+             scope->isGlobalScope()) {
+      // let the discrepancy go for now; we will get another chance to
+      // deal with this later, when 'handleTypeOfMain' is called
+    }
+    else {
+      // this message reports two declarations which declare the same
+      // name, but their types are different; we only jump here *after*
+      // ruling out the possibility of function overloading
+
+      string msg = stringc
+        << "prior declaration of `" << name
+        << "' at " << prior->loc
+        << " had type `" << prior->type->toString()
+        << "', but this one uses `" << type->toString() << "'";
+
+      if (!lang.isCplusplus &&
+          prior->type->isFunctionType() &&
+          type->isFunctionType() &&
+          compatibleParamCounts(prior->type->asFunctionType(),
+                                type->asFunctionType())) {
+        // dsw: not sure where to do this so I'm doing it here; if the
+        // two types are function types and one has FF_VARARGS and the
+        // other does not it causes me problems in Oink
+        if (prior->type->asFunctionType()->flags | FF_VARARGS) {
+          type->asFunctionType()->flags |= FF_VARARGS;
+        }
+        if (type->asFunctionType()->flags | FF_VARARGS) {
+          prior->type->asFunctionType()->flags |= FF_VARARGS;
+        }
+
+        // 10/08/04: In C, the rules for function type declaration
+        // compatibility are more complicated, relying on "default
+        // argument promotions", a determination of whether the
+        // previous declaration came from a prototype (and whether it
+        // had param info), and a notion of type "compatibility" that
+        // I don't see defined.  (C99 6.7.5.3 para 15)  So, I'm just
+        // going to make this a warning and go on.  I think more needs
+        // to be done for an analysis, though, since an argument
+        // passed as an 'int' but treated as a 'char' by the function
+        // definition (as in in/c/t0016.c) is being implicitly
+        // truncated, and this might be relevant to the analysis.
+        //
+        // Actually, compatibility is introduced in 6.2.7, though
+        // pieces of its actual definition appear in 6.7.2 (6.7.2.3
+        // only?), 6.7.3 and 6.7.5.  I still need to track down what
+        // argument promotions are.
+        //
+        // TODO: tighten all this down; I don't like leaving such big
+        // holes in what is being checked....
+        msg = stringc << msg << " (allowed due to C func param compatibility)";
+        warning(msg);
+      }
+      else if (!lang.isCplusplus &&
+               compatibleEnumAndIntegerTypes(prior->type, type)) {
+        msg = stringc << msg << " (allowed due to C enum/int compatibility)";
+        warning(msg);
+      }
+      else {
+        // usual error message
+        error(type, msg);
+        goto makeDummyVar;
+      }
+    }
+
+    // if the prior declaration refers to a different entity than the
+    // one we're trying to declare here, we have a conflict (I'm trying
+    // to implement 7.3.3 para 11); I try to determine whether they
+    // are the same or different based on the scopes in which they appear
+    if (!prior->skipAlias()->scope &&
+        !scope->isPermanentScope()) {
+      // The previous decl is not in a named scope.. I *think* that
+      // means that we could only have found it by looking in the same
+      // scope that 'scope' refers to, which is also non-permanent, so
+      // just allow this.  I don't know if it's really right.  In any
+      // case, d0097.cc is a testcase.
+    }
+    else if (!sameScopes(prior->skipAlias()->scope, scope)) {
+      error(type, stringc
+            << "prior declaration of `" << name
+            << "' at " << prior->loc
+            << " refers to a different entity, so it conflicts with "
+            << "the one being declared here");
+      goto makeDummyVar;
+    }
+
+    // ok, use the prior declaration, but update the 'loc'
+    // if this is the definition
+    if (dflags & DF_DEFINITION) {
+      TRACE("odr",    "def'n of " << name
+                   << " at " << toString(loc)
+                   << " overrides decl at " << toString(prior->loc));
+      prior->loc = loc;
+      prior->setFlag(DF_DEFINITION);
+      prior->clearFlag(DF_EXTERN);
+      prior->clearFlag(DF_FORWARD); // dsw: I added this
+
+      // dsw: if the prior declaration was DF_INLINE then it stays
+      // that way; if it was not and the definition is DF_INLINE, then
+      // we propagate DF_INLINE to the prior
+      if (dflags & DF_INLINE) {
+        prior->setFlag(DF_INLINE);
+      }
+
+      // kc: If we are now defining a previously prototyped function,
+      // propagate the 'extern inline'
+      if (dflags & DF_GNU_EXTERN_INLINE) {
+        prior->setFlag(DF_GNU_EXTERN_INLINE);
+        // kc: The linker needs to know that this extern inline function has
+        // static linkage
+        if (dflags & DF_STATIC) {
+          prior->setFlag(DF_STATIC);
+        }
+        // We need to propagate the anti-externness from the extern inline
+        // definition, but it's already being deleted above
+      } else if (prior->scope && prior->scope->isGlobalScope()) {
+        // kc: Illegal to declare or define a function or data variable
+        // previously declared as static (?)  gcc-3.4 warns; gcc-4.0 errors.
+        if ((dflags & DF_STATIC) && !prior->hasFlag(DF_STATIC)) {
+          if (staticBecauseInline) {
+            // quarl 2006-07-11
+            //    It's apparently okay to propagate staticness if it's
+            //    implicit from an inline definition.
+            prior->setFlag(DF_STATIC);
+          } else {
+            env.diagnose3(lang.allowStaticAfterNonStatic, loc, stringc
+                          << "prior declaration of `" << name
+                          << "' at " << prior->loc
+                          << " declared non-static, cannot re-declare as static");
+          }
+        }
+      }
+    }
+
+    // dsw: if one has a size and the other doesn't, use the size of
+    // the one that is defined
+    if (prior->type->isArrayType()
+        && prior->type->asArrayType()->size == ArrayType::NO_SIZE) {
+      prior->type->asArrayType()->size = type->asArrayType()->size;
+    }
+
+    // prior is a ptr to the previous decl/def var; type is the
+    // type of the alias the user wanted to introduce, but which
+    // was found to be equivalent to the previous declaration
+
+    // 10/03/04: merge default arguments
+    // UPDATE: dsw: currently the way the builtins are declared, they
+    // can have the FF_NO_PARAM_INFO flag even if we are in C++;
+    // therefore we have to check for that and avoid it or we can get
+    // a mismatch on the number of parameters
+    if (lang.isCplusplus && type->isFunctionType()
+        && !(prior->type->asFunctionType()->flags & FF_NO_PARAM_INFO)
+        && !(type->asFunctionType()->flags & FF_NO_PARAM_INFO)
+        ) {
+      mergeDefaultArguments(loc, prior, type->asFunctionType());
+    }
+
+    // TODO: enforce restrictions on successive declarations'
+    // DeclFlags; see cppstd 7.1.1, around para 7
+
+    // it's an allowed, repeated declaration
+    return prior;
+  }
+
+noPriorDeclaration:
+  // no prior declaration, make a new variable and put it
+  // into the environment (see comments in Declarator::tcheck
+  // regarding point of declaration)
+  Variable *newVar = makeVariable(loc, name, type, dflags);
+
+  // set up the variable's 'scope' field
+  scope->registerVariable(newVar);
+
+  if (overloadSet) {
+    // don't add it to the environment (another overloaded version
+    // is already in the environment), instead add it to the overload set
+    overloadSet->addMember(newVar);
+    newVar->overload = overloadSet;
+    TRACE("ovl", "overload set for " << name << " now has " <<
+                 overloadSet->count() << " elements");
+  }
+  else if (!type->isError()) {
+    // 8/09/04: add error-typed vars anyway?
+    //
+    // No, they get ignored by Scope::addVariable anyway, because
+    // it's part of ensuring that erroneous interpretations don't
+    // modify the environment, during disambiguation.
+
+    if (disambErrorsSuppressChanges()) {
+      TRACE("env", "not adding D_name `" << name <<
+            "' because there are disambiguating errors");
+    }
+    else {
+      scope->addVariable(newVar, forceReplace);
+      addedNewVariable(scope, newVar);
+    }
+  }
+
+  return newVar;
+}
+
+
+// if 'type' refers to a function type, and it has some default
+// arguments supplied, then:
+//   - it should only be adding new defaults, not overriding
+//     any from a previous declaration
+//   - the new defaults should be merged into the type retained
+//     in 'prior->type', so that further uses in this translation
+//     unit will have the benefit of the default arguments
+//   - the resulting type should have all the default arguments
+//     contiguous, and at the end of the parameter list
+// reference: cppstd, 8.3.6
+void Env::mergeDefaultArguments(SourceLoc loc, Variable *prior, FunctionType *type)
+{
+  if (prior->name == string_main && prior->isGlobal()) {
+    // main() should not have default args anyway, and the scheme
+    // for allowing varying declarations messes up the logic here
+    return;
+  }
+
+  SObjListIterNC<Variable> priorParam(prior->type->asFunctionType()->params);
+  SObjListIterNC<Variable> newParam(type->params);
+
+  bool seenSomeDefaults = false;
+
+  int paramCt = 1;
+  for(; !priorParam.isDone() && !newParam.isDone();
+      priorParam.adv(), newParam.adv(), paramCt++) {
+    Variable *p = priorParam.data();
+    Variable *n = newParam.data();
+
+    if (n->value) {
+      seenSomeDefaults = true;
+
+      if (p->value) {
+        error(loc, stringc
+          << "declaration of `" << prior->name
+          << "' supplies a redundant default argument for parameter "
+          << paramCt);
+      }
+      else {
+        // augment 'p' with 'n->value'
+        //
+        // TODO: what are the scoping issues w.r.t. evaluating
+        // default arguments?
+        p->setValue(n->value);
+      }
+    }
+    else if (!p->value && seenSomeDefaults) {
+      error(loc, stringc
+        << "declaration of `" << prior->name
+        << "' supplies some default arguments, but no default for later parameter "
+        << paramCt << " has been supplied");
+    }
+  }
+
+  // both parameter lists should end simultaneously, otherwise why
+  // did I conclude they are declaring the same entity?
+  xassert(priorParam.isDone() && newParam.isDone() &&
+          "2068fccd-bce0-4634-888c-06063852a47c");
+}
+
+
+// a global symbol 'main' was just declared, and it was determined
+// that the name refers to an entity (possibly previously
+// declared) of type 'prior', while the current declaration
+// denoted 'type'
+void Env::handleTypeOfMain(SourceLoc loc, Variable *prior, Type *&type)
+{
+  // relevent sections: C++ 3.6.1, C99 5.1.2.2.1
+
+  // We will allow declarations of main() to differ so that it is
+  // possible for a prototype in a header file to attach type
+  // qualifiers to (all) the parameters, while still allowing the
+  // implementation of main() to omit some of the parameters.
+  //
+  // To try to avoid analyses having to special-case this, I will
+  // make it so the second declaration looks like it had the same
+  // number of parameters as the first, if possible.
+
+  if (!type->isFunctionType()) {
+    env.error(loc, stringc
+      << "global name `main' must be a function, not `"
+      << type->toString() << "'");
+    return;
+  }
+
+  if (!prior->type->isFunctionType()) {
+    return;    // presumably already reported
+  }
+
+  // dsw: during Declarator::mid_tcheck() I made sure that if this is
+  // a global main function that it ends up with a DF_EXTERN_C flag
+  xassert(prior->hasFlag(DF_EXTERN_C) &&
+          "c524f127-19cb-44eb-a829-f49faf2185a4"); // in/k0063.cc
+
+  FunctionType *priorFt = prior->type->asFunctionType();
+  if (priorFt->hasFlag(FF_NO_PARAM_INFO)) {
+    // (in/c/dC0025.c) punt: just let the prior defn be, and hope
+    // that the existing handling of no-param-info-prototypes
+    // is adequate
+    return;
+  }
+
+  // check that the types of the declared parameters agree
+  FunctionType *typeFt = type->asFunctionType();
+  SObjListIterNC<Variable> priorIter(priorFt->params);
+  SObjListIterNC<Variable> typeIter(typeFt->params);
+  while (!priorIter.isDone() && !typeIter.isDone()) {
+    MatchFlags mflags = MF_IGNORE_TOP_CV;
+    if (!priorIter.data()->type->equals(typeIter.data()->type, mflags)) {
+      env.error(loc, stringc
+        << "prior declaration of main() at " << prior->loc
+        << " had type `" << prior->type->toString()
+        << "', but this one uses `" << type->toString() << "'");
+      return;
+    }
+    priorIter.adv();
+    typeIter.adv();
+  }
+
+  // I am not checking correspondence of return types.. I seem
+  // to remember that in C mode we're lax about that anyway?
+
+  if (typeIter.isDone() && priorIter.isDone()) {
+    return;     // no variance, nothing needs to be done
+  }
+
+  // must be 'type' that ends early
+  if (!typeIter.isDone()) {
+    error(type, loc, stringc
+      << "prior declaration of main() at " << prior->loc
+      << " had " << pluraln(priorFt->params.count(), "parameter")
+      << ", but this one has " << pluraln(typeFt->params.count(), "parameter")
+      << "; we do allow the parameter lists of main() to vary, "
+      << "but only when the earliest declaration has the largest "
+      << "number of parameters");
+    return;
+  }
+
+  // build a new FunctionType that is like 'dt.type' but has the
+  // trailing parameters from 'var->type' (we cannot simply modify
+  // 'typeFt' itself because it has already had doneParams()
+  // called)
+  FunctionType *newFt =
+    tfac.makeSimilarFunctionType(loc, typeFt->retType, typeFt);
+  SFOREACH_OBJLIST_NC(Variable, typeFt->params, iter) {
+    newFt->addParam(iter.data());    // should be ok to re-use the Variables
+  }
+  while (!priorIter.isDone()) {
+    newFt->addParam(priorIter.data());
+    priorIter.adv();
+  }
+  tfac.doneParams(newFt);
+
+  // from here on, use 'newFt' in place of 'type'
+  type = newFt;
+}
+
+
+Variable *Env::storeVar(Variable *var)
+{
+  // this is my point of global de-aliasing; it's the obvious place to
+  // potentially implement a more flexible scheme where the analysis
+  // could request that dealiasing not be done
+
+  // this works even when 'var' is NULL because 'skipAlias' is not a
+  // virtual function, and it internally checks for a NULL 'this'
+
+  return var->skipAlias();
+}
+
+Variable *Env::storeVarIfNotOvl(Variable *var)
+{
+  // NULL and non-aliases go through fine
+  if (!var ||
+      !var->getUsingAlias()) {
+    return var;
+  }
+
+  if (!var->overload && !var->getUsingAlias()->overload) {
+    // neither the alias nor the aliased entity are overloaded, can
+    // safely skip aliases now
+    return storeVar(var);
+  }
+
+  // since 'var' or its alias is overloaded, we'll need to wait for
+  // overload resolution, which must act on the aliases; when it is
+  // finished it will skip remaining aliases
+  return var;
+}
+
+
+void Env::checkFuncAnnotations(FunctionType *, D_func *)
+{}
+
+void Env::addedNewCompound(CompoundType *)
+{}
+
+int Env::countInitializers(SourceLoc loc, Type *type, IN_compound const *cpd)
+{
+  return cpd->inits.count();
+}
+
+void Env::addedNewVariable(Scope *, Variable *)
+{}
+
+
+E_intLit *Env::build_E_intLit(int i)
+{
+  StringRef text = str(stringc << i);
+  E_intLit *ret = new E_intLit(text);
+  ret->i = i;
+  ret->type = tfac.getSimpleType(ST_INT);
+  return ret;
+}
+
+
+// implemented in cc_tcheck.cc
+Type *makeLvalType(TypeFactory &tfac, Type *underlying);
+
+E_variable *Env::build_E_variable(Variable *var)
+{
+  E_variable *ret = new E_variable(new PQ_variable(SL_UNKNOWN, var));
+  ret->var = var;
+
+  // Wrap with ReferenceType?  (similar to E_variable::itcheck)
+  if (var->isTemplateParam() || var->hasFlag(DF_ENUMERATOR)) {
+    ret->type = var->type;                       // do not wrap it
+  }
+  else {
+    ret->type = makeLvalType(tfac, var->type);   // possibly wrap it
+  }
+
+  return ret;
+}
+
+
+E_addrOf *Env::build_E_addrOf(Expression *underlying)
+{
+  E_addrOf *ret = new E_addrOf(underlying);
+
+  // are we building an address-of nonstatic member?
+  if (underlying->isE_variable()) {
+    Variable *underVar = underlying->asE_variable()->var;
+    if (underVar->hasFlag(DF_MEMBER) &&
+        !underVar->hasFlag(DF_STATIC)) {
+      CompoundType *inClassNAT = underVar->scope->curCompound;
+      xassert(inClassNAT);
+      ret->type = tfac.makePointerToMemberType(inClassNAT, CV_NONE,
+                                               underVar->type);
+      return ret;
+    }
+  }
+
+  // ordinary pointer
+  ret->type = tfac.makePointerType(CV_NONE, underlying->type->asRval());
+  return ret;
+}
+
+
+// create a PseudoInstantiation, bind its arguments, and create
+// the associated typedef variable
+PseudoInstantiation *Env::createPseudoInstantiation
+  (CompoundType *ct, ObjList<STemplateArgument> const &args)
+{
+  TRACE("pseudo", "creating " << ct->name << sargsToString(args));
+
+  // make the object itself
+  PseudoInstantiation *pi = new PseudoInstantiation(ct);
+
+  // attach the template arguments, using default args if needed
+  if (!supplyDefaultTemplateArguments(ct->templateInfo(), pi->args,
+                                      objToSObjListC(args))) {
+    // some error.. it will be reported, but we may as well continue
+    // anyway with the argument list we have
+  }
+
+  // make the typedef var; do *not* add it to the environment
+  pi->typedefVar = makeVariable(loc(), ct->name, makeType(pi),
+                                DF_TYPEDEF | DF_IMPLICIT);
+
+  return pi;
+}
+
+
+// Push onto the scope stack the scopes that contain the declaration
+// of 'v', stopping (as we progress to outer scopes) at 'stop' (do
+// not push 'stop').
+//
+// This is doing something quite similar to 'getParentScopes', but
+// the differences are not trivial to collapse and these functions
+// are pretty small so I'm leaving the duplication.
+void Env::pushDeclarationScopes(Variable *v, Scope *stop)
+{
+  ObjListMutator<Scope> mut(scopes);
+  Scope *s = v->scope;
+
+  while (s != stop) {
+    // put in a piece of 'extendScope'; I can't call that directly
+    // because it would put things in the wrong order
+    s->openedScope(*this);
+    TRACE("scope", locStr() << ": extending " << s->desc());
+
+    mut.insertBefore(s);     // insert 's' before where 'mut' points
+    mut.adv();               // advance 'mut' past 's', so it points at orig obj
+    s = s->parentScope;
+    if (!s) {
+      // 'v->scope' must not have been inside 'stop'
+      xfailure("pushDeclarationScopes: missed 'stop' scope");
+    }
+  }
+}
+
+// undo the effects of 'pushDeclarationScopes'
+void Env::popDeclarationScopes(Variable *v, Scope *stop)
+{
+  Scope *s = v->scope;
+  while (s != stop) {
+    retractScope(s);
+    s = s->parentScope;
+    xassert(s);
+  }
+}
+
+
+Variable *getParameterizedPrimary(Scope *s)
+{
+  Variable *entity = s->parameterizedEntity;
+  TemplateInfo *tinfo = entity->templateInfo();
+  xassert(tinfo);
+  Variable *ret = tinfo->getPrimary()->var;
+  xassert(ret);
+  return ret;
+}
+
+// We are in a declarator, processing a qualifier that has template
+// arguments supplied.  The question is, which template arg/param
+// scope is the one that goes with this qualifier?
+Scope *Env::findParameterizingScope(Variable *bareQualifierVar,
+                                    bool argsHaveVariables)
+{
+  // keep track of the last unassociated template scope seen
+  Scope *lastUnassoc = NULL;
+
+  // search from inside out
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    Scope *s = iter.data();
+
+    if (s->isTemplateScope()) {
+      if (!s->parameterizedEntity) {
+        lastUnassoc = s;
+      }
+      else if (getParameterizedPrimary(s) == bareQualifierVar) {
+        // found it!  this scope is already marked as being associated
+        // with this variable
+        return s;
+      }
+    }
+    else if (s->isClassScope()) {
+      // keep searching..
+    }
+    else {
+      // some kind of scope other than a template or class scope; I don't
+      // think I should look any higher
+      break;
+    }
+  }
+
+  // didn't find a scope already associated with the qualifier, so I
+  // think the outermost unassociated is the right one (this is
+  // something of a guess.. the spec isn't terribly clear on corner
+  // conditions regarding template params..)
+
+  if (!lastUnassoc) {
+    if (argsHaveVariables) {
+      error(stringc << "no template parameter list supplied for `"
+                    << bareQualifierVar->name << "'");
+    }
+    else {
+      diagnose3(lang.allowExplicitSpecWithoutParams, loc(), stringc
+        << "explicit specialization missing \"template <>\" (gcc bug allows it)");
+    }
+  }
+
+  return lastUnassoc;
+}
+
+
+// Remove all scopes that are inside 'bound' from 'scopes' and put them
+// into 'dest' instead, in reverse order (to make it easy to undo).
+void Env::removeScopesInside(ObjList<Scope> &dest, Scope *bound)
+{
+  xassert(bound);
+  while (scopes.first() != bound) {
+    Scope *s = scopes.removeFirst();
+    TRACE("scope", "temporarily removing " << s->desc());
+    dest.prepend(s);
+  }
+}
+
+// Undo the effects of 'removeScopesInside'.
+void Env::restoreScopesInside(ObjList<Scope> &src, Scope *bound)
+{
+  xassert(scopes.first() == bound);
+  while (src.isNotEmpty()) {
+    Scope *s = src.removeFirst();
+    TRACE("scope", "restoring " << s->desc());
+    scopes.prepend(s);
+  }
+}
+
+
+bool Env::ensureCompleteType(char const *action, Type *type)
+{
+  if (type->isCompoundType()) {
+    CompoundType *ct = type->asCompoundType();
+    return ensureCompleteCompound(action, ct);
+  }
+
+  if (type->isArrayType() &&
+      type->asArrayType()->size == ArrayType::NO_SIZE) {
+    if (lang.assumeNoSizeArrayHasSizeOne) {
+      warning(stringc << "array of no size assumed to be a complete type");
+      return true;
+    } else {
+      // 8.3.4 para 1: this is an incomplete type
+      error(stringc << "attempt to " << action <<
+            " incomplete type `" << type->toString() << "'");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+bool Env::ensureCompleteCompound(char const *action, CompoundType *ct)
+{
+  // maybe it's a template we can instantiate?
+  if (!ct->isComplete() && ct->isInstantiation()) {
+    instantiateClassBody(ct->typedefVar);
+  }
+
+  if (!ct->isComplete()) {
+    error(stringc << "attempt to " << action <<
+                     " incomplete class `" << ct->name << "'");
+    return false;
+  }
+
+  return true;
+}
+
+
+// if 'e' is the name of a function, or an address of one, which is
+// overloaded, get the Variable denoting the overload set; otherwise,
+// return NULL
+Variable *Env::getOverloadedFunctionVar(Expression *e)
+{
+  if (e->isE_addrOf()) {
+    e = e->asE_addrOf()->expr;
+  }
+
+  if (e->isE_variable()) {
+    Variable *ret = e->asE_variable()->var;
+    if (ret && ret->isOverloaded()) {
+      return ret;
+    }
+  }
+
+  return NULL;
+}
+
+
+// having selected 'selVar' from the set of overloaded names denoted
+// by 'e', modify 'e' to reflect that selection, by modifying the
+// 'type' and 'var' annotations; this function mirrors
+// 'getOverloadedFunctionVar' in structure, as we assume that 'e'
+// already went through that one and returned non-NULL
+void Env::setOverloadedFunctionVar(Expression *e, Variable *selVar)
+{
+  if (e->isE_grouping()) {
+    E_grouping *g = e->asE_grouping();
+    setOverloadedFunctionVar(g->expr, selVar);
+    g->type = g->expr->type;
+    return;
+  }
+
+  if (e->isE_addrOf()) {
+    E_addrOf *a = e->asE_addrOf();
+    setOverloadedFunctionVar(a->expr, selVar);
+
+    if (selVar->type->isFunctionType()) {
+      FunctionType *ft = selVar->type->asFunctionType();
+      if (ft->isMethod()) {
+        // form pointer-to-member to this function type
+        a->type = env.tfac.makePointerToMemberType(ft->getNATOfMember(),
+                                                   CV_NONE, ft);
+        return;
+      }
+    }
+
+    a->type = makePointerType(CV_NONE, a->expr->type);
+    return;
+  }
+
+  if (e->isE_variable()) {
+    E_variable *ev = e->asE_variable();
+
+    ev->type = selVar->type;
+    ev->var = selVar;
+  }
+
+  else if (e->isE_fieldAcc()) {
+    E_fieldAcc *eacc = e->asE_fieldAcc();
+
+    eacc->type = selVar->type;
+    eacc->field = selVar;
+  }
+
+  else {
+    xfailure("setOverloadedFunctionVar: bad expression kind");
+  }
+}
+
+
+// given an overload set, and the type to which the overloaded name is
+// being converted, select the element that matches that type, if any
+// [cppstd 13.4 para 1]
+Variable *Env::pickMatchingOverloadedFunctionVar(LookupSet &set, Type *type)
+{
+  // normalize 'type' to just be a FunctionType
+  type = type->asRval();
+  if (type->isPointerType() || type->isPointerToMemberType()) {
+    type = type->getAtType();
+  }
+  if (!type->isFunctionType()) {
+    return NULL;     // no matching element if not converting to function
+  }
+
+  // as there are no standard conversions for function types or
+  // pointer to function types [cppstd 13.4 para 7], simply find an
+  // element with an equal type
+  SFOREACH_OBJLIST_NC(Variable, set, iter) {
+    Variable *v = iter.data();
+
+    if (v->isTemplate()) {
+      // TODO: cppstd 13.4 paras 2,3,4
+      unimp("address of overloaded name, with a templatized element");
+    }
+
+    if (v->type->equals(type)) {
+      OVERLOADTRACE("13.4: selected `" << v->toString() << "'");
+      return v;     // found it
+    }
+  }
+
+  OVERLOADTRACE("13.4: no match for type `" << type->toString() << "'");
+  return NULL;      // no matching element
+}
+
+
+// given an expression that more or less begins with a name,
+// find the name
+PQName const *getExprName(Expression const *e)
+{
+  ASTSWITCHC(Expression, e) {
+    ASTCASEC(E_variable, v)
+      return v->name;
+
+    ASTNEXTC(E_fieldAcc, f)
+      return f->fieldName;
+
+    ASTNEXTC(E_addrOf, a)
+      return getExprName(a->expr);
+
+    ASTNEXTC(E_grouping, g)
+      return getExprName(g->expr);
+
+    ASTDEFAULTC
+      xfailure("getExprName: does not begin with a name");
+      return NULL;      // silence warning
+
+    ASTENDCASEC
+  }
+}
+
+// given an expression that more or less begins with a name,
+// find its location
+SourceLoc getExprNameLoc(Expression const *e)
+{
+  return getExprName(e)->loc;
+}
+
+
+// 'expr/info' is being passed to 'paramType'; if 'expr' is the
+// name of an overloaded function, resolve it
+//
+// part of the implementation of cppstd 13.4
+void Env::possiblySetOverloadedFunctionVar(Expression *expr, Type *paramType,
+                                           LookupSet &set)
+{
+  if (set.count() >= 2) {
+    // pick the one that matches the target type
+    Variable *ovlVar =
+      env.pickMatchingOverloadedFunctionVar(set, paramType);
+    if (ovlVar) {
+      // modify 'arg' accordingly
+      env.setOverloadedFunctionVar(expr, ovlVar);
+    }
+    else {
+      env.error(getExprNameLoc(expr), stringc
+        << "failed to resolve address-of of overloaded function `"
+        << *(getExprName(expr)) << "' assigned to type `"
+        << paramType->toString() << "'; candidates:\n"
+        << chomp(set.asString()));
+    }
+  }
+}
+
+
+// get scopes associated with 'type'; cppstd 3.4.2 para 2
+//
+// this could perhaps be made faster by using a hash table set
+void Env::getAssociatedScopes(SObjList<Scope> &associated, Type *type)
+{
+  switch (type->getTag()) {
+    default:
+      xfailure("bad type tag");
+
+    case Type::T_ATOMIC: {
+      AtomicType *atomic = type->asCVAtomicType()->atomic;
+      switch (atomic->getTag()) {
+        default:
+          // other cases: nothing
+          return;
+
+        case AtomicType::T_SIMPLE:
+          // bullet 1: nothing
+          return;
+
+        case AtomicType::T_COMPOUND: {
+          CompoundType *ct = atomic->asCompoundType();
+          if (!ct->isInstantiation()) {
+            // bullet 2: the class, all base classes, and definition scopes
+
+            // class + bases
+            SObjList<BaseClassSubobj const> bases;
+            getSubobjects(bases, ct);
+
+            // put them into 'associated'
+            SFOREACH_OBJLIST(BaseClassSubobj const, bases, iter) {
+              CompoundType *base = iter.data()->ct;
+              associated.prependUnique(base);
+
+              // get definition namespace too
+              if (base->parentScope) {
+                associated.prependUnique(base->parentScope);
+              }
+              else {
+                // parent is not named.. I'm pretty sure in this case
+                // any names that should be found will be found by
+                // ordinary lookup, so it will not matter whether the
+                // parent scope of 'base' gets added to 'associated'
+              }
+            }
+
+            // also, class of which it is a member (in/t0569.cc)
+            if (ct->parentScope && ct->parentScope->curCompound) {
+              CompoundType *container = ct->parentScope->curCompound;
+              associated.prependUnique(container);
+
+              // and its definition scope
+              if (container->parentScope) {
+                associated.prependUnique(container->parentScope);
+              }
+            }
+          }
+          else {
+            // bullet 7: template instantiation: definition scope plus
+            // associated scopes of template type arguments
+
+            // definition scope
+            if (ct->parentScope) {
+              associated.prependUnique(ct->parentScope);
+            }
+
+            // I am disabling this because:
+            //   - it fixes in/k0009.cc
+            //   - it is hard (though not impossible) to conjure a
+            //     situation where a name found in an argument's
+            //     associated scope could be used
+            //   - gcc and edg seem not to do it, at least as evidenced
+            //     by their acceptance of in/k0009.cc
+            // In general, arg-dep lookup is poorly tested right now.
+            // What I should do at some point is write a few dozen
+            // tests that hit all the corners, and determine the extent
+            // to which my interpretation of the standard agrees with
+            // gcc and edg.
+            //
+            // 2005-08-09 (in/t0532.cc): my current hypothesis is that
+            // template args are used, but that when searching classes,
+            // only friend declarations are considered
+            //
+            // look at template arguments
+            TemplateInfo *ti = ct->templateInfo();
+            xassert(ti);
+            FOREACH_OBJLIST(STemplateArgument, ti->arguments, iter) {
+              STemplateArgument const *arg = iter.data();
+              if (arg->isType()) {
+                getAssociatedScopes(associated, arg->getType());
+              }
+              else if (arg->isTemplate()) {
+                // TODO: implement this (template template parameters)
+              }
+            }
+          }
+          break;
+        }
+
+        case AtomicType::T_ENUM: {
+          // bullet 3 (enum): definition scope
+          EnumType *et = atomic->asEnumType();
+          if (et->typedefVar &&        // ignore anonymous enumerations...
+              et->typedefVar->scope) {
+            associated.prependUnique(et->typedefVar->scope);
+          }
+          break;
+        }
+      }
+      break;
+    }
+
+    case Type::T_REFERENCE:
+      // implicitly skipped as being an lvalue
+    case Type::T_POINTER:
+    case Type::T_ARRAY:
+      // bullet 4: skip to atType
+      getAssociatedScopes(associated, type->getAtType());
+      break;
+
+    case Type::T_FUNCTION: {
+      // bullet 5: recursively look at param/return types
+      FunctionType *ft = type->asFunctionType();
+      getAssociatedScopes(associated, ft->retType);
+      SFOREACH_OBJLIST(Variable, ft->params, iter) {
+        getAssociatedScopes(associated, iter.data()->type);
+      }
+      break;
+    }
+
+    case Type::T_POINTERTOMEMBER: {
+      // bullet 6/7: the 'inClassNAT', plus 'atType'
+      PointerToMemberType *ptm = type->asPointerToMemberType();
+      if (ptm->inClassNAT->isCompoundType()) {
+        associated.prependUnique(ptm->inClassNAT->asCompoundType());
+      }
+      getAssociatedScopes(associated, ptm->atType);
+      break;
+    }
+  }
+}
+
+
+// cppstd 3.4.2; returns entries for 'name' in scopes
+// that are associated with the types in 'args'
+void Env::associatedScopeLookup(LookupSet &candidates, StringRef name,
+                                ArrayStack<Type*> const &argTypes, LookupFlags flags)
+{
+  // let me disable this entire mechanism, to measure its performance
+  //
+  // 2005-02-11: On in/big/nsHTMLEditRules, I see no measurable difference
+  static bool enabled = !tracingSys("disableArgDepLookup");
+  if (!enabled) {
+    return;
+  }
+
+  // union over all arguments of "associated" namespaces and classes
+  SObjList<Scope> associated;
+  for (int i=0; i < argTypes.length(); i++) {
+    getAssociatedScopes(associated, argTypes[i]);
+  }
+
+  // 3.4.2 para 3: ignore 'using' directives for these lookups
+  flags |= LF_IGNORE_USING;
+
+  // 2005-08-09: ignore class members too (i.e., when searching in
+  // class scopes, only friend declarations are used); testcases
+  // include in/t0532.cc, in/t0471.cc and in/t0569.cc
+  flags |= LF_ARG_DEP;
+
+  // get candidates from the lookups in the "associated" scopes
+  SFOREACH_OBJLIST_NC(Scope, associated, scopeIter) {
+    Scope *s = scopeIter.data();
+    if ((flags & LF_SKIP_CLASSES) && s->isClassScope()) {
+      continue;
+    }
+
+    // lookup
+    Variable *v = s->lookupVariable(name, env, flags);
+
+    // toss them into the set
+    if (v) {
+      if (!v->type->isFunctionType()) {
+        // The standard doesn't say anything about this.  GCC rejects
+        // if non-function found, while ICC seems to just ignore
+        // non-functions.  Oy.
+        env.error(loc(), stringc
+          << "during argument-dependent lookup of `" << name
+          << "', found non-function of type `" << v->type->toString()
+          << "' in " << s->scopeName());
+      }
+      else {
+        addCandidates(candidates, v);
+      }
+    }
+  }
+}
+
+
+// some lookup yielded 'var'; add its candidates to 'candidates'
+void Env::addCandidates(LookupSet &candidates, Variable *var)
+{
+  candidates.adds(var);
+}
+
+
+// This could be parameterized on the kind of AtomicType
+// transformation being done, though we do not process the parameters
+// of a FunctionType.
+//
+// If 't' includes any function or array types, and 't' contains DQTs
+// that need to be resolved, they must be in the partially-built state
+// that arises during declarator parsing.
+//
+// Returns NULL if no change is needed.
+Type *Env::resolveDQTs(SourceLoc loc, Type *t)
+{
+  switch (t->getTag()) {
+    default: xfailure("bad tag");
+
+    case Type::T_ATOMIC: {
+      CVAtomicType *at = t->asCVAtomicType();
+      if (at->atomic->isNamedAtomicType()) {
+        Type *resolved = resolveDQTs_atomic(loc, at->atomic);
+        if (resolved) {
+          // must combine the 'resolved' type with 'at->cv'
+          return tfac.applyCVToType(loc, at->cv, resolved, NULL /*syntax*/);
+        }
+      }
+      return NULL;
+    }
+
+    case Type::T_POINTER: {
+      PointerType *pt = t->asPointerType();
+      Type *resolved = resolveDQTs(loc, pt->atType);
+      if (resolved) {
+        return tfac.makePointerType(pt->cv, resolved);
+      }
+      return NULL;
+    }
+
+    case Type::T_REFERENCE: {
+      ReferenceType *rt = t->asReferenceType();
+      Type *resolved = resolveDQTs(loc, rt->atType);
+      if (resolved) {
+        return tfac.makeReferenceType(resolved);
+      }
+      return NULL;
+    }
+
+    case Type::T_FUNCTION: {
+      FunctionType *ft = t->asFunctionType();
+      Type *resolved = resolveDQTs(loc, ft->retType);
+      if (resolved) {
+        // 'finish' ft, since we are about to discard it
+        xassert(ft->params.isEmpty());    // partially built
+        tfac.doneParams(ft);
+
+        // return a new unfinished function type
+        return tfac.makeFunctionType(resolved);
+      }
+      return NULL;
+    }
+
+    case Type::T_ARRAY: {
+      ArrayType *at = t->asArrayType();
+      Type *resolved = resolveDQTs(loc, at->eltType);
+      if (resolved) {
+        return tfac.makeArrayType(resolved, at->size);
+      }
+      return NULL;
+    }
+
+    case Type::T_POINTERTOMEMBER: {
+      PointerToMemberType *ptm = t->asPointerToMemberType();
+      Type *resolvedAtType = resolveDQTs(loc, ptm->atType);
+      Type *resolvedNAT = resolveDQTs_atomic(loc, ptm->inClassNAT);
+      if (resolvedAtType || resolvedNAT) {
+        if (!resolvedAtType) {
+          resolvedAtType = ptm->atType;
+        }
+
+        // map 'resolvedNAT' down to a true NamedAtomicType
+        NamedAtomicType *nat;
+        if (!resolvedNAT) {
+          nat = ptm->inClassNAT;
+        }
+        else {
+          breaker();      // need to test
+          if (!resolvedNAT->isCVAtomicType() ||
+              !resolvedNAT->asCVAtomicType()->atomic->isNamedAtomicType()) {
+            error(loc, stringc << "`" << t->toString() << "' is `"
+                               << resolvedNAT->toString() << "', but that "
+                               << "is not allowed as a ptm-qualifier");
+            return NULL;
+          }
+          nat = resolvedNAT->asCVAtomicType()->atomic->asNamedAtomicType();
+
+          // TODO: there are still more conditions; essentially, 'nat'
+          // should be a class, or some dependent type that might be a
+          // class in the right circumstances
+        }
+
+        return tfac.makePointerToMemberType(nat, ptm->cv, resolvedAtType);
+      }
+      return NULL;
+    }
+  }
+}
+
+
+Type *Env::resolveDQTs_atomic(SourceLoc loc, AtomicType *t)
+{
+  // (in/t0503.cc) might need to resolve DQTs inside template args
+  if (t->isPseudoInstantiation()) {
+    AtomicType *at = resolveDQTs_pi(loc, t->asPseudoInstantiation());
+    if (at) {
+      // build a new CVAtomicType on top of 'at'
+      return makeType(at);
+    }
+    else {
+      return NULL;
+    }
+  }
+
+  if (!t->isDependentQType()) {
+    return NULL;
+  }
+  DependentQType *dqt = t->asDependentQType();
+
+  if (!dqt->first->isPseudoInstantiation()) {
+    return NULL;
+  }
+  PseudoInstantiation *firstPI = dqt->first->asPseudoInstantiation();
+
+  // Is there a template definition whose primary is
+  // 'firstPI->primary' somewhere on the scope stack?
+  CompoundType *scopeCt =
+    getMatchingTemplateInScope(firstPI->primary, firstPI->args);
+  if (scopeCt) {
+    // re-start lookup from 'scopeCt'
+    LookupSet set;
+    lookupPQ_withScope(set, dqt->rest, LF_QUALIFIED, scopeCt);
+    Variable *v = set.isEmpty()? NULL : set.first();
+
+    if (!v || !v->isType()) {
+      error(loc, stringc << "no such type `" << t->toCString()
+                         << "' (while resolving DQTs)");
+      return NULL;     // just keep using what we already have
+    }
+
+    return v->type;
+  }
+
+  // negative, just keep using what we have
+  return NULL;
+}
+
+
+// given 'C' and '<T>', check if it 'C<T>' is already in scope
+CompoundType *Env::getMatchingTemplateInScope
+  (CompoundType *primary, ObjList<STemplateArgument> const &sargs)
+{
+  FOREACH_OBJLIST(Scope, scopes, iter) {
+    // filter for scopes that are template definitions
+    if (!iter.data()->curCompound) continue;
+    CompoundType *scopeCt = iter.data()->curCompound;
+    TemplateInfo *scopeTI = scopeCt->templateInfo();
+    if (!scopeTI) continue;
+
+    // same template+arguments?
+    if (!scopeTI->matchesPI(primary, sargs)) {
+      continue;
+    }
+
+    // found it!
+    return scopeCt;
+  }
+
+  // not found
+  return NULL;
+}
+
+
+AtomicType *Env::resolveDQTs_pi(SourceLoc loc, PseudoInstantiation *pi)
+{
+  // work through the template arguments, attempting to resolve them
+  bool resolvedAny = false;
+  ObjList<STemplateArgument> resolvedArgs;
+  FOREACH_OBJLIST(STemplateArgument, pi->args, iter) {
+    STemplateArgument const *orig = iter.data();
+    if (orig->isType()) {
+      Type *t = resolveDQTs(loc, orig->getType());
+      if (t) {
+        // refined this type; add the refined type to 'resolvedArgs'
+        resolvedAny = true;
+        resolvedArgs.prepend(new STemplateArgument(t));
+        continue;
+      }
+    }
+
+    // not a type, or could not resolve it; keep original
+    resolvedArgs.prepend(orig->shallowClone());
+  }
+
+  if (!resolvedAny) {
+    // no progress
+    return NULL;
+  }
+
+  // complete the prepend+reverse idiom
+  resolvedArgs.reverse();
+
+  // combine pi->primary with resolvedArgs
+  if (containsVariables(resolvedArgs)) {
+    // new PI, but with more precise arguments
+    return createPseudoInstantiation(pi->primary, resolvedArgs);
+  }
+  else {
+    // concrete type!
+    Variable *inst = instantiateClassTemplate(loc, pi->primary->typedefVar, resolvedArgs);
+    return inst->type->asCompoundType();
+  }
+}
+
+
+// This function produces a string describing the set of dependent
+// base classes that were not searched during unqualified lookup.
+string Env::unsearchedDependentBases()
+{
+  stringBuilder sb;
+  int ct=0;
+
+  FOREACH_OBJLIST(Scope, scopes, iter) {
+    // filter for scopes that are template definitions
+    if (!iter.data()->curCompound) continue;
+    CompoundType *scopeCt = iter.data()->curCompound;
+    TemplateInfo *scopeTI = scopeCt->templateInfo();
+    if (!scopeTI) continue;
+
+    // list unsearched bases
+    SFOREACH_OBJLIST(Type, scopeTI->dependentBases, baseIter) {
+      if (ct++ == 0) {
+        sb << " (due to nondependent lookup, did not search bases: ";
+      }
+      else {
+        sb << ", ";
+      }
+      sb << baseIter.data()->toString();
+    }
+  }
+
+  if (ct) {
+    sb << ")";
+  }
+
+  return sb;
+}
+
+
+// ---------------- new lookup mechanism --------------------
+bool sameArguments(ObjList<STemplateArgument> const &args1,
+                   ObjList<STemplateArgument> const &args2)
+{
+  ObjListIter<STemplateArgument> iter1(args1);
+  ObjListIter<STemplateArgument> iter2(args2);
+
+  for (; !iter1.isDone() && !iter2.isDone(); iter1.adv(), iter2.adv()) {
+    STemplateArgument const &sarg1 = *(iter1.data());
+    STemplateArgument const &sarg2 = *(iter2.data());
+
+    if (!sarg1.equals(sarg2)) {
+      return false;
+    }
+  }
+
+  return iter1.isDone() && iter2.isDone();
+}
+
+
+void Env::lookupPQ(LookupSet &set, PQName *name, LookupFlags flags)
+{
+  // this keeps track of where the next lookup will occur; NULL means
+  // "in the current scope stack", and non-NULL means "in the named
+  // scope"
+  Scope *scope = NULL;
+
+  // ---- BEGIN: second entry point ---
+  // I need to jump in to the algorithm right here for 3.4.5p4, so
+  // break the function and expose an entry.  When reading
+  // Env::lookupPQ, one can effectively ignore the entire 'second
+  // entry point' section.
+  lookupPQ_withScope(set, name, flags, scope);
+}
+void Env::lookupPQ_withScope(LookupSet &set, PQName *name, LookupFlags flags,
+                             Scope *scope)    // 'scope' is as stated above
+{
+  // ---- END: second entry point ---
+
+  // keep track of the scope we found just before 'scope'
+  Scope *prevScope = NULL;
+
+  // lookup along the chain of qualifiers
+  while (name->isPQ_qualifier()) {
+    PQ_qualifier *qual = name->asPQ_qualifier();
+    prevScope = scope;
+
+    if (!qual->qualifier) {
+      scope = globalScope();
+      qual->qualifierVar = globalScopeVar;
+    }
+
+    else {
+      // lookup this qualifier in 'scope'
+      Variable *svar = lookupScopeVar(scope, qual->qualifier, flags);
+      qual->qualifierVar = svar;
+
+      if (svar && svar->hasFlag(DF_SELFNAME)) {
+        if (qual->sargs.isNotEmpty()) {
+          // 2005-03-04: referring to the self-name but passing args:
+          // regard the arguments as being applied to the primary
+          // (in/t0425.cc) (in/0428.cc)
+          if (svar->type->isCompoundType()) {
+            // have to go via the CompoundType because the DF_SELFNAME
+            // may not have templateInfo
+            CompoundType *ct = svar->type->asCompoundType();
+            if (ct->templateInfo()) {
+              svar = ct->templateInfo()->getPrimary()->var;
+            }
+          }
+          else if (svar->type->isPseudoInstantiation()) {
+            PseudoInstantiation *pi = svar->type->asPseudoInstantiation();
+
+            // (in/t0433.cc) if the template arguments match those of
+            // 'pi', then the qualifier is referring to a known
+            // template, not a generic dependent type; this is important
+            // because we may need to get a more precise type for
+            // decl-defn matching
+            if (sameArguments(qual->sargs, pi->args)) {
+              scope = svar->scope;    // selfname -> container
+              goto bottom_of_loop;    // ...
+            }
+
+            svar = svar->type->asCVAtomicType()->atomic->
+                     asPseudoInstantiation()->primary->typedefVar;
+          }
+        }
+
+        else {
+          // 2005-05-24: (in/t0476.cc) self-name and not passing args:
+          // just like we were passing args that matched the primary
+          scope = svar->scope;        // selfname -> container
+          goto bottom_of_loop;        // like above
+        }
+      }
+
+      // interpret 'var', apply template args, etc. (legacy call)
+      bool dependent=false, anyTemplates=false;
+      scope = lookupOneQualifier_useArgs(svar, qual->sargs, dependent,
+                                         anyTemplates, flags);
+
+      // dependent qualified name: if a variable, just yield
+      // 'dependentVar', but if a type, we need to construct a more
+      // detailed record so we can match declarations with definitions
+      if (dependent) {
+        DependentQType *dqt;
+
+        if (!( flags & (LF_TYPENAME | LF_ONLY_TYPES) )) {
+          set.add(dependentVar);    // user makes no claim, so it's a variable
+          dqt = NULL;               // don't need a DQT
+        }
+
+        else if (svar->type->isCompoundType()) {
+          xassert(containsVariables(qual->sargs));  // otherwise why dependent?
+
+          // build DependentQType PseudoInstantiation(svar, qual->targs)::...
+          CompoundType *ct = svar->type->asCompoundType();
+          dqt = new DependentQType(createPseudoInstantiation(ct, qual->sargs));
+        }
+
+        else if (svar->type->isNamedAtomicType()) {
+          if (qual->sargs.isNotEmpty()) {
+            error(name->loc, stringc     // t0265.cc error 1
+              << "cannot apply template arguments to `" << qual->qualifier << "'",
+              EF_STRONG);
+            return;
+          }
+
+          // build DependentQType on top of 'svar->type'; could be
+          // a TypeVariable, a PseudoInstantiation (in/t0430.cc), or
+          // another DependentQType (in/t0433.cc)
+          dqt = new DependentQType(svar->type->asNamedAtomicType());
+        }
+
+        else {
+          xfailure("unhandled case of dependent qualified type in lookupPQ");
+        }
+
+        // examine the names further down
+        finishDependentQType(set, dqt, qual->rest);
+        return;
+      }
+
+      if (!scope) {
+        return;      // error already reported
+      }
+
+      // a scope used as a qualifier must be a complete type; I cannot
+      // find anyplace in the standard that explicitly requires this,
+      // though it seems to be clearly true (t0245.cc)
+      if (scope->curCompound) {
+        env.ensureCompleteCompound("use as qualifier", scope->curCompound);
+      }
+    }
+
+  bottom_of_loop:
+    flags |= LF_QUALIFIED;            // subsequent lookups are qualified
+    name = qual->rest;
+  }
+
+  if (flags & LF_GET_SCOPE_ONLY) {
+    // caller just wants 'scope', not the whole name
+    if (scope) {
+      set.add(scope->getScopeVariable());
+    }
+    return;
+  }
+
+  // 3.4.3p5: qualified dtor name?
+  if (scope && name->getName()[0]=='~') {
+    // get a pointer to the StringRef in 'name'
+    StringRef *nameStringRef;
+    if (name->isPQ_name()) {
+      nameStringRef = &(name->asPQ_name()->name);
+    }
+    else /*PQ_template*/ {
+      nameStringRef = &(name->asPQ_template()->name);
+    }
+
+    // we want to lookup the type; temporarily remove the '~'
+    StringRef origStringRef = *nameStringRef;
+    *nameStringRef = str(origStringRef+1);
+
+    // original name is of form
+    //   prevScope :: scope :: ~ class-name
+    Scope *lookupScope;
+    if (scope->isNamespace()) {
+      lookupScope = scope;              // lookup class-name in 'scope'
+    }
+    else {
+      xassert(scope->isClassScope());
+      lookupScope = prevScope;          // lookup class-name in 'prevScope'
+    }
+    Variable *className =
+      unqualifiedFinalNameLookup_one(lookupScope, name, flags);
+
+    // repair 'name'
+    *nameStringRef = origStringRef;
+
+    // get the destructor
+    if (!className || !className->isClass()) {
+      string scopeName;
+      if (lookupScope) {
+        scopeName = stringc << "in scope `" << lookupScope->fullyQualifiedCName() << "'";
+      }
+      env.error(name->loc, stringc
+        << "no such class `" << *name << "'" << scopeName);
+    }
+    else {
+      lookupClassDestructor(set, className->type->asCompoundType(), flags);
+    }
+
+    return;
+  }
+
+  // unqualified lookup in 'scope'
+  unqualifiedFinalNameLookup(set, scope, name, flags);
+}
+
+void Env::unqualifiedFinalNameLookup(LookupSet &set, Scope *scope,
+                                     PQName *name, LookupFlags flags)
+{
+  unqualifiedLookup(set, scope, name->getName(), flags);
+  if (set.isEmpty()) {
+    return;
+  }
+
+  // TODO: BUG: If 'name' is ON_conversion, then we need to further
+  // filter the resulting set for those that convert to the right
+  // type.  Also, we need to check that looking up the type name in
+  // 'scope' yields the same results as its current setting, which
+  // came from tchecking in the current scope.
+
+  // regardless of LF_TEMPL_PRIMARY, if there are template arguments,
+  // then we want to filter non-templates out of the set
+  if (name->isPQ_template()) {
+    set.removeNonTemplates();
+
+    if (set.isEmpty()) {           // t0460.cc
+      env.error(name->loc, stringc
+        << "cannot apply template args to non-template `"
+        << name->getName() << "'", EF_DISAMBIGUATES);
+      return;
+    }
+  }
+
+  // consider template arguments?
+  if (flags & LF_TEMPL_PRIMARY) {
+    return;    // no
+  }
+
+  if ((flags & LF_EXPECTING_TYPE) &&
+      !set.first()->isType()) {
+    // we are expecting a type, and intend only to apply template
+    // args to a type, not to a function (cppstdex/14.5.2p4.cc)
+    return;    // yield the primary, caller will report the problem
+  }
+
+  if (set.first()->isType()) {
+    // apply template arguments, if any (legacy call)
+    Variable *var = set.removeFirst();
+    var = applyPQNameTemplateArguments(var, name, flags);
+    if (var) {
+      set.add(var);
+    }
+    return;
+  }
+
+  // we have a set of overloaded functions; apply what template
+  // arguments we have to each one, retaining those that are
+  // compatible with the arguments
+  SObjListMutator<Variable> mut(set);
+  while (!mut.isDone()) {
+    Variable *var = mut.data();
+
+    var = applyPQNameTemplateArguments(var, name, flags);
+    if (var) {
+      mut.dataRef() = var;     // replace
+      mut.adv();
+    }
+    else {
+      mut.remove();            // remove
+    }
+  }
+
+  #if 0    // old; not sure what I was thinking
+  // if we are even considering applying template arguments, the
+  // name must be unambiguous
+  if (set.count() > 1) {
+    env.error(name->loc, stringc << "ambiguous use of `" << *name
+                                 << "' in non-overloadable context");
+    set.removeAllButOne();    // error recovery
+    return;
+  }
+
+  // apply template arguments, if any (legacy call)
+  Variable *var = set.removeFirst();
+  var = applyPQNameTemplateArguments(var, name, flags);
+  if (var) {
+    set.add(var);
+  }
+  #endif // 0
+}
+
+
+// starting from 'scope', lookup scope name 'name' to get
+// the corresponding Variable (NULL if (reported) error);
+// in the case of a template class, this returns the primary,
+// so template args may still have to be applied
+Variable *Env::lookupScopeVar(Scope * /*nullable*/ scope, StringRef name,
+                              LookupFlags flags)
+{
+  // lookup 'name' in 'scope'
+  flags |= LF_QUALIFIER_LOOKUP;
+  flags &= ~LF_ONLY_TYPES;      // only-types is only for the final component, not the qualifiers
+  LookupSet set;
+  unqualifiedLookup(set, scope, name, flags);
+  if (set.isEmpty()) {
+    return NULL;                // error already reported
+  }
+  xassert(set.count() == 1);    // 'flags' should ensure this
+  return set.first();
+}
+
+
+void Env::unqualifiedLookup(LookupSet &set, Scope * /*nullable*/ scope,
+                            StringRef name, LookupFlags flags)
+{
+  if (scope) {
+    // lookup in a specific scope
+    scope->lookup(set, name, env, flags);
+    return;
+  }
+
+  if (flags & LF_INNER_ONLY) {
+    // look in innermost accepting scope
+    scope = acceptingScope();
+    scope->lookup(set, name, env, flags);
+    return;
+  }
+
+  // look in current scope stack
+  FOREACH_OBJLIST_NC(Scope, scopes, iter) {
+    scope = iter.data();
+    if ((flags & LF_SKIP_CLASSES) && scope->isClassScope()) {
+      continue;
+    }
+
+    if (scope->isDelegated()) {
+      // though 'scope' appears physically here, it is searched in a different order
+      continue;
+    }
+
+    // look in 'scope'
+    scope->lookup(set, name, env, flags);
+    if (set.isNotEmpty()) {
+      return;
+    }
+
+    // is 'scope' connected to a delegated scope?
+    Scope *delegated = scope->getDelegationPointer();
+    if (delegated) {
+      delegated->lookup(set, name, env, flags);
+      if (set.isNotEmpty()) {
+        return;
+      }
+    }
+  }
+}
+
+
+void Env::lookupClassDestructor(LookupSet &set, CompoundType *ct,
+                                LookupFlags flags)
+{
+  // make the destructor name (perhaps this should be saved somewhere?)
+  StringRef dtorName = env.str(stringc << "~" << ct->name);
+
+  // look it up
+  ct->lookup(set, dtorName, env, flags);
+}
+
+
+// caller promises that it will reject function names anyway
+Variable *Env::lookupPQ_one(PQName *name, LookupFlags flags)
+{
+  LookupSet set;
+  lookupPQ(set, name, flags);
+  return set.isEmpty()? NULL : set.first();
+}
+
+Variable *Env::unqualifiedLookup_one(StringRef name, LookupFlags flags)
+{
+  LookupSet set;
+  unqualifiedLookup(set, NULL /*scope*/, name, flags);
+  return set.isEmpty()? NULL : set.first();
+}
+
+Variable *Env::unqualifiedFinalNameLookup_one(Scope *scope, PQName *name,
+                                              LookupFlags flags)
+{
+  LookupSet set;
+  unqualifiedFinalNameLookup(set, scope, name, flags);
+  return set.isEmpty()? NULL : set.first();
+}
+
+
+// given a partially-constructed DQT, with trailing name components
+// 'name', finish building it, and then put its typedef Variable
+// into 'set'
+void Env::finishDependentQType(LookupSet &set, DependentQType * /*nullable*/ dqt,
+                               PQName *name)
+{
+  PQName *origName = name;
+
+  // finish checking for proper use of 'template' keyword
+  while (name->isPQ_qualifier()) {
+    PQ_qualifier *qual = name->asPQ_qualifier();
+    checkTemplateKeyword(qual);
+    name = qual->rest;
+  }
+  checkTemplateKeyword(name);
+
+  // finish building the DQT
+  if (dqt) {
+    // attach the remainder of the name to the DQT
+    dqt->rest = origName;
+
+    // slap a typedefVar on 'dqt' so we can put it into 'set'
+    dqt->name = name->getName();
+    dqt->typedefVar = makeVariable(name->loc, dqt->name,
+                                   makeType(dqt),
+                                   DF_TYPEDEF | DF_IMPLICIT);
+    set.add(dqt->typedefVar);
+  }
+}
+
+// given 'name' that appears below a dependent-type qualifier,
+// check that the 'template' keyword is used properly
+void Env::checkTemplateKeyword(PQName *name)
+{
+  bool templateUsed = name->templateUsed();
+  bool hasTemplArgs = name->isPQ_template() ||
+                      (name->isPQ_qualifier() && name->asPQ_qualifier()->sargs.isNotEmpty());
+
+  // we only need to check for one kind of mismatch, because the
+  // other kind is rejected by the parser
+  if (!templateUsed && hasTemplArgs) {
+    // specific gcc-2 bug? (in/d0112.cc)
+    if (lang.allowGcc2HeaderSyntax &&
+        name->isPQ_qualifier() &&
+        name->asPQ_qualifier()->qualifier == env.str("rebind") &&
+        name->getName() == env.str("other")) {
+      env.diagnose3(lang.allowGcc2HeaderSyntax, name->loc,
+                    "dependent template scope name requires 'template' keyword (gcc-2 bug allows it)");
+    }
+    else {
+      // without the "template" keyword, the dependent context may give
+      // rise to ambiguity, so reject it
+      env.error("dependent template scope name requires 'template' keyword",
+                EF_DISAMBIGUATES | EF_STRONG);
+    }
+  }
+}
+
+
+// A lookup has caused an error, and we want to return an error object
+// to distinguish this from a lookup that simply fails to find a name.
+//
+// Currently, lookup functions always return NULL when something is not
+// found, but have an ad-hoc and inconsistent mix of behaviors when a
+// lookup is erroneous, including:
+//   - returning NULL
+//   - returning a related object, like a template primary
+//   - returning error[Type]Var
+// I would like to transition to a scheme that consistently uses error
+// objects for erroneous lookups, but my plan for the moment is to do
+// so incrementally.
+Variable *Env::lookupErrorObject(LookupFlags flags)
+{
+  if (flags & (LF_ONLY_TYPES | LF_TYPENAME | LF_QUERY_TAGS)) {
+    return errorTypeVar;
+  }
+  else {
+    return errorVar;
+  }
+}
+
+
+// 'decl' is a declarator in a class member declaration (and not a
+// friend).  Handle the case where it declares a qualified name.
+void Env::checkForQualifiedMemberDeclarator(Declarator *decl)
+{
+  // dig down to the D_name
+  IDeclarator *idecl = decl->decl;
+  while (idecl->getBase()) {
+    idecl = idecl->getBase();
+  }
+
+  // look at the name
+  PQName *name = idecl->getDeclaratorId();
+  if (!name || !name->hasQualifiers()) {
+    return;    // nothing to do
+  }
+
+  // 8.3 para 1 says (in part):
+  //   "A declarator-id shall not be qualified except for the
+  //    definition of a member function [etc.] ... *outside* of
+  //    its class, ..." (emphasis mine)
+
+  // complain
+  diagnose3(lang.allowQualifiedMemberDeclarations, name->loc,
+            "qualified name is not allowed in member declaration "
+            "(gcc bug accepts it)");
+
+  // skip the qualifiers
+  do {
+    name = name->asPQ_qualifier()->rest;
+  } while (name->hasQualifiers());
+
+  // put the unqualified name back into 'idecl' to pacify the tcheck
+  // code that comes after this check, as it expects member
+  // declarators to never be qualified
+  if (idecl->isD_name()) {
+    idecl->asD_name()->name = name;
+  }
+  else if (idecl->isD_bitfield()) {
+    idecl->asD_bitfield()->name = name;
+  }
+  else {
+    xfailure("unknown leaf IDeclarator");
+  }
+}
+
+
+Scope *Env::createNamespace(SourceLoc loc, StringRef name)
+{
+  // make an entry in the surrounding scope to refer to the new namespace
+  Variable *v = makeVariable(loc, name, NULL /*type*/, DF_NAMESPACE);
+  if (name) {
+    addVariable(v);
+  }
+
+  // make new scope
+  Scope *s = new Scope(SK_NAMESPACE, 0 /*changeCount; irrelevant*/, loc);
+  s->namespaceVar = v;
+
+  // point the variable at it so we can find it later
+  v->scope = s;
+
+  // hook it into the scope tree; this must be done before the
+  // using edge is added, for anonymous scopes
+  setParentScope(s);
+
+  // if name is NULL, we need to add an "active using" edge from the
+  // surrounding scope to 's'
+  if (!name) {
+    Scope *parent = scope();
+    parent->addUsingEdge(s);
+    parent->addUsingEdgeTransitively(env, s);
+  }
+
+  return s;
+}
+
+
+// This is used in contexts where we need the set of subobjects,
+// and therefore might need to instantiate the class to get them,
+// but the language spec does not appear to actually *require*
+// that the type be complete, just that if it is, then we should
+// use its base-class info.
+void Env::getSubobjects(SObjList<BaseClassSubobj const> &dest,
+                        CompoundType *ct)
+{
+  ensureClassBodyInstantiated(ct);
+  ct->getSubobjects(dest);
+}
+
+
+Type *Env::sizeofType(Type *t, int &size, Expression * /*nullable*/ expr)
+{
+  // 5.3.3p2: want type underneath any reference
+  t = t->asRval();
+
+  // 5.3.3p1: must be complete
+  env.ensureCompleteType("compute size of", t);
+
+  try {
+    size = t->reprSize();
+    TRACE("sizeof", "sizeof(" << (expr? expr->exprToString() : t->toString()) <<
+                    ") is " << size);
+  }
+  catch (XReprSize &e) {
+    HANDLER();
+    if (e.isDynamic) {
+      // There are at least two reasonable approaches to handling
+      // dynamically-sized arrays.  One is to just make sure that
+      // an analysis can recognize them and handle them specially
+      // if necessary.  That is what Elsa is doing.  (An analysis
+      // can recognize ArrayType::DYN_SIZE.)
+      //
+      // The other approach would be to translate them away, using
+      // lower-level concepts.  However, this would (IMO) make more
+      // of a mess than is beneficial (using alloca, or perhaps even
+      // malloc), so we don't.
+      //
+      // A third approach, mentioned near declaration of
+      // XReprSize::isDynamic, is for reprSize to possibly return a
+      // symbolic expression...
+      size = 0;
+
+      env.warning("sizeof dynamically-sized array not fully implemented, size assumed to be 0");
+      TRACE("sizeof", "sizeof(" << (expr? expr->exprToString() : t->toString()) <<
+                      ") is dynamic..");
+    }
+    else if (t->isArrayType()) {
+      ArrayType *at = t->asArrayType();
+      if (at->size == ArrayType::NO_SIZE &&
+          env.lang.assumeNoSizeArrayHasSizeOne) {
+        // just hacking this for now
+        return env.sizeofType(at->eltType, size, expr);
+      }
+      else {
+        return env.error(e.why());
+      }
+    }
+    else {
+      return env.error(e.why());
+    }
+  }
+
+  // 5.3.3p6: result is of type 'size_t'; most systems (including my
+  // elsa/include/stddef.h header) make that the same as 'unsigned';
+  // in any case, it must be an unsigned integer type (c99, 7.17p2)
+  return t->isError()? t : env.getSimpleType(ST_UNSIGNED_INT);
+}
+
+
+void Env::instantiateTemplatesInConversion(ImplicitConversion &ic)
+{
+  if (ic.kind == ImplicitConversion::IC_USER_DEFINED) {
+    ensureFuncBodyTChecked(ic.user);
+  }
+}
+
+
+// ----------------------- makeQualifiedName -----------------------
+// prepend to 'name' all possible qualifiers, starting with 's'
+PQName *Env::makeFullyQualifiedName(Scope *s, PQName *name)
+{
+  if (!s || s->scopeKind == SK_GLOBAL) {
+    // cons the global-scope qualifier on front
+    return new PQ_qualifier(SL_UNKNOWN, NULL /*qualifier*/,
+                            NULL /*targs*/, name);
+  }
+
+  // add 's'
+  name = makeQualifiedName(s, name);
+
+  // now find additional qualifiers needed to name 's'
+  return makeFullyQualifiedName(s->parentScope, name);
+}
+
+
+// prepend to 'name' information about 's', the scope that contains it
+PQName *Env::makeQualifiedName(Scope *s, PQName *name)
+{
+  // should only be called for named scopes
+  Variable *typedefVar = s->getTypedefName();
+  xassert(typedefVar);
+
+  // is this scope an instantiated template class?
+  TemplateInfo *ti = typedefVar->templateInfo();
+  if (ti) {
+    // construct the list of template arguments; we must rebuild them
+    // instead of using templateInfo->arguments directly, because the
+    // TS_names that are used in the latter might not be in scope here
+    /*fakelist*/TemplateArgument *targs = makeTemplateArgs(ti);
+
+    // cons a template-id qualifier on to the front
+    return new PQ_qualifier(loc(), typedefVar->name, targs, name);
+  }
+  else {
+    // cons an ordinary qualifier in from
+    return new PQ_qualifier(loc(), typedefVar->name, NULL /*targs*/, name);
+  }
+}
+
+
+// construct the list of template arguments
+/*fakelist*/TemplateArgument *Env::makeTemplateArgs(TemplateInfo *ti)
+{
+  // will build the reversed list first
+  TemplateArgument *targs = NULL;
+
+  FOREACH_OBJLIST(STemplateArgument, ti->arguments, iter) {
+    STemplateArgument const *sarg = iter.data();
+    if (sarg->kind == STemplateArgument::STA_TYPE) {
+      // pull out the Type, then build a new ASTTypeId for it
+      targs = new TA_type(buildASTTypeId(sarg->getType()), targs);
+    }
+    else {
+      // will make an Expr node; put it here
+      Expression *e = NULL;
+      switch (sarg->kind) {
+        default: xfailure("bad kind");
+
+        case STemplateArgument::STA_ENUMERATOR:
+        case STemplateArgument::STA_REFERENCE:
+        case STemplateArgument::STA_POINTER:
+        case STemplateArgument::STA_MEMBER:
+        case STemplateArgument::STA_TEMPLATE:
+          // I want to find a place where someone is mapping a Variable
+          // into a PQName, so I can re-use/abstract that mechanism.. but
+          // I can't even find a place where the present code is even
+          // called!  So for now....
+          xunimp("can't handle this kind of template argument");
+
+        case STemplateArgument::STA_INT:
+          // synthesize an AST node for the integer
+          e = build_E_intLit(sarg->getInt());
+          break;
+      }
+
+      // put the expr in a TA_nontype
+      targs = new TA_nontype(e, targs);
+    }
+  }
+
+  // get the un-reversed version
+  FakeList<TemplateArgument> *ret = FakeList<TemplateArgument>::makeList(targs);
+  ret = ret->reverse();
+
+  return ret->first();
+}
+
+
+ASTTypeId *Env::buildASTTypeId(Type *type)
+{
+  // there used to be a big function here that built the full syntax
+  // of a type, but I am going to try to use TS_type instead
+  return new ASTTypeId(new TS_type(loc(), type),
+                       new Declarator(new D_name(loc(), NULL /*name*/),
+                                      NULL /*init*/));
+}
+
+// This function is called *after* the arguments have been type
+// checked and overload resolution performed (if necessary).  It must
+// compare the actual arguments to the parameters.  It also must
+// finish the job started above of resolving address-of overloaded
+// function names, by comparing to the parameter.
+//
+// One bad aspect of the current design is the need to pass both 'args'
+// and 'argInfo'.  Only by having both pieces of information can I do
+// resolution of overloaded address-of.  I'd like to consolidate that
+// at some point...
+//
+// Note that 'args' *never* includes the receiver object, whereas
+// 'argInfo' *always* includes the type of the receiver object (or
+// NULL) as its first element.
+//
+// It returns the # of default args used.
+
+// Elaboration: if 'ic' involves a user-defined conversion, then modify the
+// AST to make that explicit.
+Expression *Env::makeConvertedArg(Expression * const arg,
+                                  ImplicitConversion const &ic)
+{
+  Expression *newarg = arg;
+
+  switch (ic.kind) {
+  case ImplicitConversion::IC_NONE:
+    // an error message is already printed above.
+    break;
+  case ImplicitConversion::IC_STANDARD:
+    if (ic.scs & SC_GROUP_1_MASK) {
+      switch (ic.scs & SC_GROUP_1_MASK) {
+      case SC_LVAL_TO_RVAL:
+        // TODO
+        break;
+      case SC_ARRAY_TO_PTR:
+        // TODO
+        break;
+      case SC_FUNC_TO_PTR:
+        newarg = makeAddr(env.tfac, env.loc(), arg);
+        break;
+      default:
+        // only 3 kinds in SC_GROUP_1_MASK
+        xfailure("shouldn't reach here");
+        break;
+      }
+    } else {
+      // TODO
+    }
+    break;
+  case ImplicitConversion::IC_USER_DEFINED:
+    // TODO
+    break;
+  case ImplicitConversion::IC_ELLIPSIS:
+    // TODO
+    break;
+  case ImplicitConversion::IC_AMBIGUOUS:
+    xfailure("IC_AMBIGUOUS -- what does this mean here? (25f0c1af-5aea-4528-b994-ccaac0b3a8f1)");
+    break;
+  default:
+    xfailure("shouldn't reach here");
+    break;
+  }
+  return newarg;
+}
+
+// quarl 2006-07-26
+//    used in function call parameter type checking and also initializer
+bool Env::elaborateImplicitConversionArgToParam(Type *paramType, Expression *&arg)
+{
+  // try to convert the argument to the parameter
+  Type *src = arg->getType();
+  ImplicitConversion ic =
+    getImplicitConversion(env,
+                          arg->getSpecial(env.lang),
+                          src,
+                          paramType,
+                          false /*destIsReceiver*/);
+
+  if (!ic) {
+    if (paramType->isArrayType()) {
+      // quarl 2006-07-26
+      //    This seems to be a case that's not handled in
+      //    getImplicitConversion and it seems to persist because this case
+      //    can't occur in a function call, but now shows up in an
+      //    initializer.
+      return true;
+    }
+
+    return false;        // error
+  }
+
+  // Elaboration: if 'ic' involves a user-defined conversion, then
+  // modify the AST to make that explicit
+  arg = env.makeConvertedArg(arg, ic);
+
+  // at least note that we plan to use this conversion, so
+  // if it involves template functions, instantiate them
+  env.instantiateTemplatesInConversion(ic);
+
+  return true;           // success
+}
+
+
+// ------------------------ SavedScopePair -------------------------
+SavedScopePair::SavedScopePair(Scope *s)
+  : scope(s),
+    parameterizingScope(NULL)
+{}
+
+SavedScopePair::~SavedScopePair()
+{
+  if (scope) {
+    delete scope;
+  }
+}
+
+
+// ------------------- DefaultArgumentChecker -----------------
+bool DefaultArgumentChecker::visitIDeclarator(IDeclarator *obj)
+{
+  // I do this from D_func to be sure I am only getting Declarators
+  // that represent parameters, as opposed to random other uses
+  // of Declarators.
+  if (obj->isD_func()) {
+    FAKELIST_FOREACH(ASTTypeId, obj->asD_func()->params, iter) {
+      Declarator *d = iter->decl;
+      if (d->init) {
+        if (!isInstantiation) {
+          // usual thing
+          d->tcheck_init(env);
+        }
+        else {
+          // if this is an instantiation, then we want to postpone
+          // instantiating the default arguments until the method
+          // is called (cppstd 14.7.1 para 11); we remove the default
+          // arg from the AST and attach it to the Variable
+          xassert(d->init->isIN_expr());    // should be parse failure otherwise, I think
+          IN_expr *ie = d->init->asIN_expr();
+          d->var->setValue(ie->e);
+          ie->e = NULL;
+        }
+      }
+    }
+  }
+
+  return true;    // traverse into children
+}
+
+
+bool DefaultArgumentChecker::visitTypeSpecifier(TypeSpecifier *obj)
+{
+  if (obj->isTS_classSpec()) {
+    // (in/t0498.cc) We do not want to dig down into a nested class
+    // definition, because if it is a template class then its template
+    // parameters will no longer be in scope.  The nested class will
+    // have already taken care of tchecking its default args.
+    return false;     // do not visit children
+  }
+
+  return true;
+}
+
+
+// ----------------- DisambiguationErrorTrapper ---------------------
+DisambiguationErrorTrapper::DisambiguationErrorTrapper(Env &e)
+  : env(e),
+    existingErrors()
+{
+  // grab the existing list of error messages
+  existingErrors.takeMessages(env.errors);
+
+  // tell the environment about this hidden list of errors, so that
+  // if an error needs to be added that has nothing to do with this
+  // disambiguation, it can be
+  if (env.hiddenErrors == NULL) {     // no hidden yet, I'm the first
+    env.hiddenErrors = &existingErrors;
+  }
+
+  // having stolen the existing errors, we now tell the environment
+  // we're in a disambiguation pass so it knows that any disambiguating
+  // errors are participating in an active disambiguation
+  env.disambiguationNestingLevel++;
+}
+
+DisambiguationErrorTrapper::~DisambiguationErrorTrapper()
+{
+  // we're about to put the pre-existing errors back into env.errors
+  env.disambiguationNestingLevel--;
+
+  if (env.hiddenErrors == &existingErrors) {     // I'm the first
+    env.hiddenErrors = NULL;          // no more now
+  }
+
+  // put all the original errors in
+  //
+  // 2005-08-08: Since 'existingErrors' are the older ones, I want
+  // them to (semantically) precede the errors in 'env.errors'.
+  // Therefore I am calling 'prependMessages'; previously I had been
+  // calling 'takeMessages', and do not know why.  A test of this
+  // behavior is in/t0521.cc.
+  env.errors.prependMessages(existingErrors);
+}
+
+
+// ------------------------------------------------------------
+//
+// helper functions for elaboration not during elaboration stage, but during
+// type checking.
+
+// make a address-of operator.  This is not a method because it's used in
+// cc_tcheck to elaborate implicit conversions
+E_addrOf *makeAddr(TypeFactory &tfac, SourceLoc loc, Expression *e)
+{
+  // "&e"
+  E_addrOf *amprE = new E_addrOf(e);
+  amprE->type = tfac.makePointerType(CV_CONST, e->type);
+
+  return amprE;
+}
+
+// -------- diagnostics --------
+Type *Env::errorType()
+{
+  return getSimpleType(ST_ERROR);
+}
+
+Type *Env::dependentType()
+{
+  return getSimpleType(ST_DEPENDENT);
+}
+
+Type *Env::error(rostring msg, ErrorFlags eflags)
+{
+  return error(loc(), msg, eflags);
+}
+
+
+Type *Env::warning(rostring msg)
+{
+  return warning(loc(), msg);
+}
+
+Type *Env::warning(SourceLoc loc, rostring msg)
+{
+  string instLoc = instLocStackString();
+  TRACE("error", "warning: " << msg << instLoc);
+  errors.addError(new ErrorMsg(loc, msg, EF_WARNING, instLoc));
+  return getSimpleType(ST_ERROR);
+}
+
+
+Type *Env::unimp(rostring msg)
+{
+  string instLoc = instLocStackString();
+
+  // always print this immediately, because in some cases I will
+  // segfault (typically deref'ing NULL) right after printing this
+  cout << toString(loc()) << ": unimplemented: " << msg << instLoc << endl;
+
+  breaker();
+  errors.addError(new ErrorMsg(
+    loc(), stringc << "unimplemented: " << msg, EF_NONE, instLoc));
+  return getSimpleType(ST_ERROR);
+}
+
+
+Type *Env::error(Type *t, SourceLoc loc, rostring msg)
+{
+  if (t->isSimple(ST_DEPENDENT)) {
+    // no report, propagate dependentness
+    return t;
+  }
+
+  if (t->containsErrors()) {
+    // no report
+    return getSimpleType(ST_ERROR);
+  }
+
+  // report
+  return error(loc, msg, EF_NONE);
+}
+
+Type *Env::error(Type *t, rostring msg)
+{
+  return error(t, loc(), msg);
+}
+
+
+ErrorFlags Env::maybeEF_STRONG() const
+{
+  return EF_STRONG;
+
+  #if 0   // still needed?
+  if (disambiguateOnly && !doReportTemplateErrors) {
+    return EF_STRONG | EF_WARNING;
+  }
+  else {
+    return EF_STRONG;
+  }
+  #endif // 0
+}
+
+
+// 2005-03-11: removed Env::doOverload
+
+
+bool Env::doOperatorOverload() const
+{
+  static bool disabled = tracingSys("doNotOperatorOverload");
+  if (disabled) { return false; }
+
+  if (!lang.allowOverloading) { return false; }
+
+  // 10/09/04: *Do* overload resolution even in template bodies, as
+  // long as the arguments are not dependent (checked elsewhere).
+  //if (disambiguateOnly) { return false; }
+
+  return true;
+}
+
+
+void Env::diagnose3(Bool3 b, SourceLoc L, rostring msg, ErrorFlags eflags)
+{
+  if (b == B3_WARN) {
+    warning(L, msg);
+  }
+  else if (b == B3_FALSE) {
+    error(L, msg, eflags);
+  }
+}
+
+
+void Env::weakError(SourceLoc L, rostring msg)
+{
+  warning(L, stringc << msg <<
+    " (this will be an error when the implementation matures)");
+}
+
+
+string errorFlagBlock(ErrorFlags eflags)
+{
+  if (eflags == EF_NONE) {
+    return "";
+  }
+  else {
+    stringBuilder sb;
+    sb << "[";
+    if (eflags & EF_WARNING) {
+      sb << "w";
+    }
+    if (eflags & EF_STRONG) {
+      sb << "s";
+    }
+    if (eflags & EF_DISAMBIGUATES) {
+      sb << "d";
+    }
+    if (eflags & EF_FROM_DISAMB) {
+      sb << "f";
+    }
+    if (eflags & EF_FROM_TEMPLATE) {
+      sb << "t";
+    }
+    if (eflags & EF_STRICT_ERROR) {
+      sb << "p";     // suppressed b/c of 'p'assive mode
+    }
+    sb << "] ";
+    return sb;
+  }
+}
+
+Type *Env::error(SourceLoc L, rostring msg, ErrorFlags eflags)
+{
+  addError(new ErrorMsg(L, msg, eflags));
+
+  return errorType();
+}
+
+
+// I want this function to always be last in this file, so I can easily
+// find it to put a breakpoint in it.
+void Env::addError(ErrorMsg * /*owner*/ e)
+{
+  string instLoc = instLocStackString();
+  if (instLoc.length()) {
+    e->instLoc = instLoc;
+  }
+
+  if (disambiguateOnly) {
+    e->flags |= EF_FROM_TEMPLATE;
+
+    if (!(e->flags & EF_WARNING) &&
+        !(e->flags & EF_DISAMBIGUATES) &&
+        !(e->flags & EF_STRONG) &&
+        !env.doReportTemplateErrors) {
+      // reduce severity to warning, but strong so it doesn't get
+      // tossed once we come out of template checking, and also
+      // mark with EF_STRICT_ERROR so I can tell this happened
+      e->flags |= EF_WARNING | EF_STRONG | EF_STRICT_ERROR;
+    }
+  }
+
+  TRACE("error", errorFlagBlock(e->flags)
+              << toString(e->loc) << ": " << e->msg << instLoc);
+
+  // breakpoint typically goes on the next line
+  ErrorList::addError(e);
+}
+
+
+// Don't add any more functions below 'Env::error'.  Instead, put them
+// above the divider line that says "diagnostics".
+
+// EOF

Added: vendor/elsa/current/elsa/cc_env.h
===================================================================
--- vendor/elsa/current/elsa/cc_env.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_env.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1116 @@
+// cc_env.h            see license.txt for copyright and terms of use
+// Env class, which is the compile-time C++ environment
+
+#ifndef CC_ENV_H
+#define CC_ENV_H
+
+#include "cc_type.h"      // Type, AtomicType, etc. (r)
+#include "strobjdict.h"   // StrObjDict
+#include "owner.h"        // Owner
+#include "exc.h"          // xBase
+#include "sobjlist.h"     // SObjList
+#include "objstack.h"     // ObjStack
+#include "sobjstack.h"    // SObjStack
+#include "cc_ast.h"       // C++ ast components
+#include "variable.h"     // Variable (r)
+#include "cc_scope.h"     // Scope
+#include "cc_err.h"       // ErrorList
+#include "array.h"        // ArrayStack, ArrayStackEmbed
+#include "builtinops.h"   // CandidateSet
+#include "cc_lang.h"      // Bool3
+#include "ptrmap.h"       // PtrMap
+#include "mflags.h"       // MatchFlags
+
+class StringTable;        // strtable.h
+class CCLang;             // cc_lang.h
+class TypeListIter;       // typelistiter.h
+class SavedScopePair;     // fwd in this file
+class MType;              // mtype.h
+class ImplicitConversion; // implconv.h
+class DelayedFuncInst;    // template.h
+
+
+// type of collection to hold a sequence of scopes
+// for nested qualifiers; it can hold up to 2 scopes
+// before resorting to heap allocation
+typedef ArrayStackEmbed<Scope*, 2> ScopeSeq;
+
+// need to be able to print these out
+void gdbScopeSeq(ScopeSeq &ss);
+
+// flags for the template argument inference functions
+enum InferArgFlags {
+  IA_NONE            = 0,
+  IA_NO_ERRORS       = 0,      // do not report errors
+  IA_REPORT_ERRORS   = 0x01,   // report inference errors in Env
+  IA_RECEIVER        = 0x02,   // passed arguments include potential receiver obj
+
+  IA_ALL             = 0x03
+};
+ENUM_BITWISE_OPS(InferArgFlags, IA_ALL)
+
+
+// the entire semantic analysis state
+class Env : protected ErrorList {
+protected:   // data
+  // bound to '*this'; facilitates moving code into and out of Env
+  Env &env;
+
+  // The TranslationUnit we are typechecking; see note in the ctor
+  TranslationUnit *unit;
+
+  // stack of lexical scopes; first is innermost
+  //
+  // NOTE: If a scope has a non-NULL curCompound or namespaceVar,
+  // then this list does *not* own it.  Otherwise it does own it.
+  ObjList<Scope> scopes;
+
+  // when true, all errors are ignored (dropped on floor) except:
+  //   - errors with the 'disambiguates' flag set
+  //   - unimplemented functionality
+  // this is used when processing bodies of template classes and
+  // functions, where we don't know anything about the type
+  // parameters
+  bool disambiguateOnly;
+
+  // counter for constructing names
+  //
+  // dsw: 2005-04-18: made it static so multiple Envs won't collide
+  static int anonCounter;
+
+  // initially false, this becomes true once Env::Env has finished;
+  // this is used to distinguish entities introduced automatically
+  // at the start from those that appeared in the input file
+  bool ctorFinished;
+
+  // set of function templates whose instantiation has been delayed
+  ObjList<DelayedFuncInst> delayedFuncInsts;
+
+public:      // data
+  // nesting level of disambiguation passes; 0 means not disambiguating;
+  // this is used for certain kinds of error reporting and suppression
+  int disambiguationNestingLevel;
+
+  // when true, function bodies are tchecked; when false, they are
+  // treated like prototypes; this lets class definitions delay
+  // body tchecking until all the members have been entered into
+  // the class scope
+  bool checkFunctionBodies;
+
+  // when true, we are re-typechecking part of a class definition,
+  // hence the names encountered should already be declared, etc.
+  bool secondPassTcheck;
+
+  // list of error messages; during disambiguation, the existing
+  // list is set aside, so 'errors' only has errors from the
+  // disambiguation we're doing now (if any)
+  ErrorList &errors;                 // reference to '*this'
+
+  // if the disambiguator has temporarily hidden the "real" list of
+  // errors, it can still be found here
+  ErrorList *hiddenErrors;           // (nullable serf stackptr)
+
+  // stack of locations at which template instantiation has been
+  // initiated but not finished; this information can be used to
+  // make error messages more informative, and also to detect
+  // infinite looping in template instantiation
+  ArrayStack<SourceLoc> instantiationLocStack;
+
+  // string table for making new strings
+  StringTable &str;
+
+  // language options in effect
+  CCLang &lang;
+
+  // interface for making types
+  TypeFactory &tfac;
+
+  // client analyses may need to get ahold of all the Variables that I made
+  // up, so this is a list of them; these don't include Variables built for
+  // parameters of function types, but the functions themselves appear here so
+  // the parameters are reachable (NOTE: at the moment, I don't think anyone
+  // is using this information)
+  //
+  // dsw: this is not what we wanted at all!  madeUpVariables has all kinds of
+  // weird crap in it; I vote that you get rid of it.  Things like elaborate
+  // member declarations for implicit members get found by LoweredASTVisitor
+  // anyway.
+  ArrayStack<Variable*> &madeUpVariables;
+
+  // Just the built-in variables.
+  ArrayStack<Variable*> &builtinVars;
+
+  // ---- BEGIN: special names ----
+  // name under which conversion operators are looked up
+  StringRef conversionOperatorName;
+
+  // name under which constructors are looked up
+  StringRef constructorSpecialName;
+
+  // name of the operator()() functions
+  StringRef functionOperatorName;
+
+  // "__receiver", a reference to the receiver object; it's a
+  // parameter of methods
+  StringRef receiverName;
+
+  // "__other", the name of the parameter in implicit methods
+  // that accept a reference to another object of the same type
+  // (e.g. copy ctor)
+  StringRef otherName;
+
+  // linkage specification strings
+  StringRef quote_C_quote;
+  StringRef quote_C_plus_plus_quote;
+
+  // a few more just to save string table lookups
+  StringRef string__func__;
+  StringRef string__FUNCTION__;
+  StringRef string__PRETTY_FUNCTION__;
+  StringRef string_main;
+
+  StringRef special_checkType;
+  StringRef special_getStandardConversion;
+  StringRef special_getImplicitConversion;
+  StringRef special_testOverload;
+  StringRef special_computeLUB;
+  StringRef special_checkCalleeDefnLine;
+  StringRef special_test_mtype;
+  StringRef special_cause_xfailure;
+  // ---- END: special names ----
+
+  // gcc __complex__ support
+  StringRef string_realSelector;
+  StringRef string_imagSelector;
+  Variable *complexComponentFields[2 /*real=0, imag=1*/]
+                                  [3 /*float=0, double=1, longdouble=2*/];
+
+  // special variables associated with particular types
+  Scope *dependentScope;                // (owner)
+  Variable *dependentTypeVar;           // (serf)
+  Variable *dependentVar;               // (serf)
+  Variable *errorTypeVar;               // (serf)
+  Variable *errorVar;                   // (serf)
+  CompoundType *errorCompoundType;      // (serf)
+
+  // Variable that acts like the name of the global scope; used in a
+  // place where I want to return the global scope, but the function
+  // is returning a Variable.. has DF_NAMESPACE
+  Variable *globalScopeVar;             // (serf)
+
+  // dsw: Can't think of a better way to do this, sorry.
+  // sm: Do what?  Who uses this?  I don't see any uses in Elsa.
+  Variable *var__builtin_constant_p;
+
+  // operator function names, indexed by the operators they overload
+  StringRef operatorName[NUM_OVERLOADABLE_OPS];
+
+  // built-in operator function sets, indexed by operator
+  ArrayStack<Variable*> builtinUnaryOperator[NUM_OVERLOADABLE_OPS];
+  ObjArrayStack<CandidateSet> builtinBinaryOperator[NUM_OVERLOADABLE_OPS];
+
+  // TODO: eliminate this!
+  TranslationUnit *tunit;
+
+  // when this is true, all template function instantiations are
+  // delayed until the end of the translation unit
+  bool delayFunctionInstantiation;
+
+  // the following flags are used to disable certain parts of the
+  // type checker due to maturity issues; they don't change during
+  // the execution of the checker
+  bool doFunctionTemplateBodyInstantiation;
+  bool doCompareArgsToParams;
+  bool doReportTemplateErrors;     // see doc/permissive.txt
+
+  // when non-empty, the variable lookup results are collected and
+  // compared to the text stored in this pointer; it is supplied via
+  // an an 'asm' directive (see TF_asm::itcheck)
+  string collectLookupResults;
+
+private:     // funcs
+  // old
+  //CompoundType *instantiateClass(
+  //  CompoundType *tclass, FakeList<TemplateArgument> *args);
+
+  // these are intended to help build the initialization-time stuff,
+  // not build functions that result from the user's input syntax
+  Variable *declareFunctionNargs(
+    Type *retType, char const *funcName,
+    Type **argTypes, char const **argNames, int numArgs,
+    FunctionFlags flags,
+    Type * /*nullable*/ exnType);
+
+  Variable *declareFunction0arg(Type *retType, char const *funcName,
+                                FunctionFlags flags = FF_NONE,
+                                Type * /*nullable*/ exnType = NULL);
+
+  Variable *declareFunction1arg(Type *retType, char const *funcName,
+                                Type *arg1Type, char const *arg1Name,
+                                FunctionFlags flags = FF_NONE,
+                                Type * /*nullable*/ exnType = NULL);
+
+  Variable *declareFunction2arg(Type *retType, char const *funcName,
+                                Type *arg1Type, char const *arg1Name,
+                                Type *arg2Type, char const *arg2Name,
+                                FunctionFlags flags = FF_NONE,
+                                Type * /*nullable*/ exnType = NULL);
+
+  // NOTE: 3 arg missing; goes here.
+
+  Variable *declareFunction4arg(Type *retType, char const *funcName,
+                                Type *arg1Type, char const *arg1Name,
+                                Type *arg2Type, char const *arg2Name,
+                                Type *arg3Type, char const *arg3Name,
+                                Type *arg4Type, char const *arg4Name,
+                                FunctionFlags flags,
+                                Type * /*nullable*/ exnType);
+
+  void addGNUBuiltins();
+
+  void setupOperatorOverloading();
+
+  void addBuiltinUnaryOp(SimpleTypeId retId, OverloadableOp op, Type *x);
+
+  void addBuiltinBinaryOp(SimpleTypeId retId, OverloadableOp op, Type *x, Type *y);
+  void addBuiltinBinaryOp(SimpleTypeId retId, OverloadableOp op,
+                          PredicateCandidateSet::PreFilter pre,
+                          PredicateCandidateSet::PostFilter post,
+                          bool isAssignment = false);
+  void addBuiltinBinaryOp(OverloadableOp op, CandidateSet * /*owner*/ cset);
+
+  PseudoInstantiation *createPseudoInstantiation
+    (CompoundType *ct, ObjList<STemplateArgument> const &args);
+
+  bool equivalentSignatures(FunctionType *ft1, FunctionType *ft2);
+  bool equivalentTypes(Type const *t1, Type const *t2,
+                       MatchFlags mflags = MF_NONE);
+
+  Variable *getPrimaryOrSpecialization
+    (TemplateInfo *tinfo, ObjList<STemplateArgument> const &sargs);
+
+  bool addVariableToScope(Scope *s, Variable *v, bool forceReplace=false);
+
+  Scope *createScope(ScopeKind sk);
+
+  void mergeDefaultArguments(SourceLoc loc, Variable *prior, FunctionType *type);
+
+public:      // funcs
+  Env(StringTable &str, CCLang &lang, TypeFactory &tfac,
+      ArrayStack<Variable*> &madeUpVariables0, ArrayStack<Variable*> &builtinVars0,
+      TranslationUnit *unit0);
+
+  // 'virtual' only to silence stupid warning; destruction is not part of polymorphic contract
+  virtual ~Env();
+
+  // this function kicks off type checking for a translation unit;
+  // it is not recursive (it should *not* call itself for namespaces)
+  virtual void tcheckTranslationUnit(TranslationUnit *tunit);
+
+  int getChangeCount() const { return scopeC()->getChangeCount(); }
+
+  // scopes
+  Scope *enterScope(ScopeKind sk, char const *forWhat);   // returns new Scope
+  void exitScope(Scope *s);       // paired with enterScope()
+  void extendScope(Scope *s);     // push onto stack, but don't own
+  void retractScope(Scope *s);    // paired with extendScope()
+
+  // the current, innermost scope
+  Scope *scope() { return scopes.first(); }
+  Scope const *scopeC() const { return scopes.firstC(); }
+
+  // print out the variables in every scope with serialNumber-s
+  void gdbScopes();
+
+  // innermost scope that can accept names; the decl flags might
+  // be used to choose exactly which scope to use
+  Scope *acceptingScope(DeclFlags df = DF_NONE);
+  Scope *typeAcceptingScope() { return acceptingScope(DF_TYPEDEF); }
+
+  // innermost non-class, non-template, non-function-prototype scope
+  Scope *outerScope();
+
+  // innermost scope that can accept names, *other* than
+  // the one we're in now
+  Scope *enclosingScope();
+
+  // return the nearest enclosing scope of kind 'k', or NULL if there
+  // is none with that kind
+  Scope *enclosingKindScope(ScopeKind k);
+  Scope *globalScope() { return enclosingKindScope(SK_GLOBAL); }
+
+  // essentially: enclosingKindScope(SK_CLASS)->curCompound;
+  CompoundType *enclosingClassScope();
+
+  // more flexible: don't begin looking for a scope with kind 'k'
+  // until we pass 's' going up on the scope stack
+  Scope *enclosingKindScopeAbove(ScopeKind k, Scope *s);
+
+  bool inTemplate()
+    { return !!enclosingKindScope(SK_TEMPLATE_PARAMS); }
+
+  // do we need both this and 'inTemplate()'?
+  bool inUninstTemplate() const
+    { return disambiguateOnly; }
+
+  // innermost scope that is neither SK_TEMPLATE_PARAMS nor SK_TEMPLATE_ARGS
+  Scope *nonTemplateScope();
+
+  // if we are in a template scope, go up one and then call
+  // currentScopeEncloses(); FIX: I suspect this is not general enough
+  // for what I really want
+  bool currentScopeAboveTemplEncloses(Scope const *s);
+
+  // true if the current scope contains 's' as a nested scope
+  bool currentScopeEncloses(Scope const *s);
+
+  // return the innermost scope that contains both the current
+  // scope and 'target'
+  Scope *findEnclosingScope(Scope *target);
+
+  // set 'parentScope' for new scope 's', depending on whether
+  // 'parent' is a scope that should be pointed at
+  void setParentScope(Scope *s, Scope *parent);
+  void setParentScope(Scope *s);     // compute 'parent' using current scope
+
+  // bit of a hack: recompute what happens when all the active
+  // scopes are opened; this is for using-directives
+  void refreshScopeOpeningEffects();
+
+
+  // source location tracking
+  void setLoc(SourceLoc loc);                // sets scope()->curLoc
+  SourceLoc loc() const;                     // gets scope()->curLoc
+  string locStr() const { return toString(loc()); }
+  string locationStackString() const;        // all scope locations
+  string instLocStackString() const;         // inst locs only
+
+  // insertion into the current scope; return false if the
+  // name collides with one that is already there (but if
+  // 'forceReplace' true, silently replace instead); if you
+  // want to insert into a specific scope, use Scope::addVariable
+  bool addVariable(Variable *v, bool forceReplace=false);
+  bool addCompound(CompoundType *ct);
+  bool addEnum(EnumType *et);
+  bool addTypeTag(Variable *tag);
+
+  // like 'addVariable' in that the 'scope' field gets set, but
+  // nothing is added to the maps
+  void registerVariable(Variable *v);
+
+  // like 'addVariable', but if 'prevLookup' is not NULL then 'v' gets
+  // added to prevLookup's overload set instead of the current scope;
+  // it is *not* the case that all overloaded variables are added
+  // using this interface
+  void addVariableWithOload(Variable *prevLookup, Variable *v);
+
+  // 'addEnum', plus typedef variable creation and checking for duplicates
+  Type *declareEnum(SourceLoc loc /*...*/, EnumType *et);
+
+
+  // lookup in the environment (all scopes); if the name is not found,
+  // return NULL, and emit an error if the name is qualified
+  // (otherwise do not emit an error)
+  Variable *lookupVariable  (StringRef name,     LookupFlags f=LF_NONE);
+
+  // this variant returns the Scope in which the name was found
+  Variable *lookupVariable(StringRef name, LookupFlags f, Scope *&scope);
+
+  CompoundType *lookupCompound  (StringRef name,     LookupFlags f=LF_NONE);
+
+  EnumType *lookupEnum  (StringRef name,     LookupFlags f=LF_NONE);
+
+  // name + template args = inst
+  Variable *applyPQNameTemplateArguments
+    (Variable *var, PQName const *name, LookupFlags flags);
+
+  // lookup a single qualifier; see comments at definition cc_env.cc
+  Scope *lookupOneQualifier(
+    Scope *startingScope,
+    PQ_qualifier const *qualifier,
+    bool &dependent,
+    bool &anyTemplates,
+    LookupFlags lflags = LF_NONE);
+
+  // 'lookupOneQualifier', broken into two pieces; see implementation
+  Variable *lookupOneQualifier_bareName(
+    Scope *startingScope,
+    PQ_qualifier const *qualifier,
+    LookupFlags lflags);
+  Scope *lookupOneQualifier_useArgs(
+    Variable *qualVar,
+    ObjList<STemplateArgument> const &sargs,
+    bool &dependent,
+    bool &anyTemplates,
+    LookupFlags lflags);
+
+  // extended interface capable of returning a set
+  Variable *lookupVariable_set(LookupSet &candidates,
+                               StringRef name, LookupFlags flags,
+                               Scope *&foundScope);
+
+  // push 'scope' and all its parents onto 'scopes'
+  void getParentScopes(ScopeSeq &scopes, Variable *scopeVar);
+  void getParentScopes(ScopeSeq &scopes, Scope *scope);
+  void getParentScopesLimit(ScopeSeq &scopes, Scope *scope, Scope *limit);
+
+  // extend/retract entire scope sequences
+  void extendScopeSeq(ScopeSeq const &scopes);
+  void retractScopeSeq(ScopeSeq const &scopes);
+
+  // push/pop scopes that contain v's declaration (see implementation)
+  void pushDeclarationScopes(Variable *v, Scope *stop);
+  void popDeclarationScopes(Variable *v, Scope *stop);
+
+  // if the innermost scope has some template parameters, take
+  // them out and return them; otherwise return NULL; this is for
+  // use by template *functions*
+  TemplateInfo * /*owner*/ takeFTemplateInfo(bool allowInherited = true);
+
+  // like the above, but for template *classes*
+  TemplateInfo * /*owner*/ takeCTemplateInfo(bool allowInherited = true);
+
+  // return a new name for an anonymous type; 'keyword' says which kind of
+  // type we're naming; 'relName' (if !NULL) gives it a deterministic name
+  // instead of an index
+  StringRef getAnonName(TypeIntr keyword, char const *relName);
+
+  // more general
+  StringRef getAnonName(char const *why, char const *relName);
+
+  // introduce a new compound type name; return the constructed
+  // CompoundType's pointer in 'ct', after inserting it into 'scope'
+  // (if that is not NULL)
+  Type *makeNewCompound(CompoundType *&ct, Scope * /*nullable*/ scope,
+                        StringRef name, SourceLoc loc,
+                        TypeIntr keyword, bool forward, bool builtin);
+
+
+  // this is for ErrorList clients
+  virtual void addError(ErrorMsg * /*owner*/ obj);
+
+  // diagnostic reports; all return ST_ERROR type
+  Type *error(SourceLoc L, rostring msg, ErrorFlags eflags = EF_NONE);
+  Type *error(rostring msg, ErrorFlags eflags = EF_NONE);
+  Type *warning(SourceLoc L, rostring msg);
+  Type *warning(rostring msg);
+  Type *unimp(rostring msg);
+  void diagnose3(Bool3 b, SourceLoc L, rostring msg, ErrorFlags eflags = EF_NONE);
+
+  // this is used when something is nominally an error, but I think
+  // or know that the code that detects the error is itself not yet
+  // trustworthy, so I want to just accept the input with a warning
+  void weakError(SourceLoc L, rostring msg);
+
+  // diagnostics involving type clashes; will be suppressed
+  // if the type is ST_ERROR
+  Type *error(Type *t, rostring msg);
+  Type *error(Type *t, SourceLoc loc, rostring msg);
+
+  // just return ST_ERROR
+  Type *errorType();
+
+  // similarly for ST_DEPENDENT
+  Type *dependentType();
+
+  // set 'disambiguateOnly' to 'val', returning prior value
+  bool setDisambiguateOnly(bool val);
+  bool onlyDisambiguating() const { return disambiguateOnly; }
+
+  // return true if the given list of errors contain any which
+  // are disambiguating errors
+  bool hasDisambErrors() const { return errors.hasDisambErrors(); }
+
+  // return true if environment modifications should be suppressed
+  // because of disambiguating errors
+  bool disambErrorsSuppressChanges() const
+    { return disambiguationNestingLevel>0 && hasDisambErrors(); }
+
+  // number of errors; intended to be called after type checking,
+  // to see how many errors (if any) resulted
+  int numErrors() const { return errors.numErrors(); }
+
+  // This is the error mode used for errors that I want to be
+  // EF_STRONG (reported even in templates) while implementing new
+  // features, but EF_NONE (not reported in templates) when trying to
+  // get big testcases through.
+  ErrorFlags maybeEF_STRONG() const;
+
+  // report on unsearched base classes; "" if none
+  string unsearchedDependentBases();
+
+  // return value for (some...) erroneous lookups
+  Variable *lookupErrorObject(LookupFlags flags);
+
+  // when true, operator expressions are checked to see if they
+  // are to be treated as calls to overloaded operator functions
+  bool doOperatorOverload() const;
+
+  // makes a function type that returns ST_CDTOR and accepts no params
+  // (other than the receiver object of type 'ct')
+  FunctionType *makeDestructorFunctionType(SourceLoc loc, CompoundType *ct);
+
+  // similar to above, except its flagged with FF_CTOR, and the caller
+  // must call 'doneParams' when it has finished adding parameters
+  FunctionType *beginConstructorFunctionType(SourceLoc loc, CompoundType *ct);
+
+  // TypeFactory funcs; all of these simply delegate to 'tfac'
+  CVAtomicType *makeCVAtomicType(AtomicType *atomic, CVFlags cv)
+    { return tfac.makeCVAtomicType(atomic, cv); }
+  PointerType *makePointerType(CVFlags cv, Type *atType)
+    { return tfac.makePointerType(cv, atType); }
+  Type *makeReferenceType(Type *atType)
+    { return tfac.makeReferenceType(atType); }
+  FunctionType *makeFunctionType(Type *retType)
+    { return tfac.makeFunctionType(retType); }
+  void doneParams(FunctionType *ft)
+    { tfac.doneParams(ft); }
+  ArrayType *makeArrayType(Type *eltType, int size = ArrayType::NO_SIZE)
+    { return tfac.makeArrayType(eltType, size); }
+
+  // (this does the work of the old 'makeMadeUpVariable')
+  Variable *makeVariable(SourceLoc L, StringRef n, Type *t, DeclFlags f);
+
+  CVAtomicType *getSimpleType(SimpleTypeId st, CVFlags cv = CV_NONE)
+    { return tfac.getSimpleType(st, cv); }
+  CVAtomicType *makeType(AtomicType *atomic)
+    { return tfac.makeType(atomic); }
+  Type *makePtrType(Type *type)
+    { return tfac.makePtrType(type); }
+
+  // others are more obscure, so I'll just call into 'tfac' directly
+  // in the places I call them
+
+  // if in a context where an implicit receiver object is available,
+  // return its type; otherwise return NULL
+  Type *implicitReceiverType();
+
+  // create the receiver object parameter for use in a FunctionType
+  Variable *receiverParameter(SourceLoc loc, NamedAtomicType *nat, CVFlags cv,
+                              D_func *syntax = NULL);
+
+  // standard conversion 4.1, 4.2, and 4.3
+  Type *operandRval(Type *t);
+
+  // get 'std::type_info const &'
+  Type *type_info_const_ref();
+
+  // create a built-in candidate for operator overload resolution
+  Variable *createBuiltinUnaryOp(Type *retType, OverloadableOp op, Type *x);
+  Variable *createBuiltinBinaryOp(Type *retType, OverloadableOp op, Type *x, Type *y);
+
+  // several steps of the declaration creation process, broken apart
+  // to aid sharing among D_name_tcheck and makeUsingAliasFor; best
+  // to look at their implementations and the comments therein
+  Variable *lookupVariableForDeclaration
+    (Scope *scope, StringRef name, Type *type, CVFlags this_cv);
+  OverloadSet *getOverloadForDeclaration(Variable *&prior, Type *type);
+  Variable *createDeclaration(
+    SourceLoc loc,
+    StringRef name,
+    Type *type,
+    DeclFlags dflags,
+    Scope *scope,
+    CompoundType *enclosingClass,
+    Variable *prior,
+    OverloadSet *overloadSet
+  );
+
+  // compare types for equality; see extensive comment at
+  // implementation
+  bool almostEqualTypes(Type const *t1, Type const *t2,
+                        MatchFlags mflags = MF_NONE);
+
+  // create a "using declaration" alias
+  Variable *makeUsingAliasFor(SourceLoc loc, Variable *origVar);
+
+  // see comments at implementation site
+  void handleTypeOfMain(SourceLoc loc, Variable *prior, Type *&type);
+
+  // pass Variable* through this before storing in the AST, so
+  // that the AST only has de-aliased pointers (if desired);
+  // a NULL argument is passed through unchanged
+  Variable *storeVar(Variable *var);
+
+  // this version will do pass-through if 'var' or the thing to which
+  // it is aliased has an overload set; it's for those cases where
+  // subsequent overload resolution needs to pick from the set, before
+  // de-aliasing happens
+  Variable *storeVarIfNotOvl(Variable *var);
+
+  // points of extension: These functions do nothing in the base
+  // Elsa parser, but can be overridden in client analyses to
+  // hook into the type checking process.  See their call sites in
+  // cc_tcheck.cc for more info on when they're called.
+
+  virtual void checkFuncAnnotations(FunctionType *ft, D_func *syntax);
+
+  // this is called after all the fields of 'ct' have been set, and
+  // we've popped its scope off the stack
+  virtual void addedNewCompound(CompoundType *ct);
+
+  // return # of array elements initialized
+  virtual int countInitializers(SourceLoc loc, Type *type, IN_compound const *cpd);
+
+  // called when a variable is successfully added; note that there
+  // is a similar mechanism in Scope itself, which can be used when
+  // less context is necessary
+  virtual void addedNewVariable(Scope *s, Variable *v);
+
+  // search in an overload set for an element, given its type
+  Variable *findInOverloadSet(OverloadSet *oset,
+                              FunctionType *ft, CVFlags receiverCV);
+  Variable *findInOverloadSet(OverloadSet *oset,
+                              FunctionType *ft);   // use ft->getReceiverCV()
+
+  // 7/27/04: removed:
+  //   make_PQ_fullyQualifiedName
+  //   make_PQ_qualifiedName
+  //   make_PQ_possiblyTemplatizedName
+  //   make_PQ_templateArgs
+  //   make_PQ_fullyQualifiedDtorName
+  //   buildASTTypeId
+  //   inner_buildASTTypeId
+  //   buildTypedefSpecifier
+
+  // 2005-02-14: partially resurrected
+  PQName *makeFullyQualifiedName(Scope *s, PQName *name);
+  PQName *makeQualifiedName(Scope *s, PQName *name);
+  /*fakelist*/TemplateArgument *makeTemplateArgs(TemplateInfo *ti);
+  ASTTypeId *buildASTTypeId(Type *type);
+
+  // make AST nodes, as if they have been tcheck'd
+  E_intLit *build_E_intLit(int i);
+  E_variable *build_E_variable(Variable *var);
+  E_addrOf *build_E_addrOf(Expression *underlying);
+
+  // make a function type for an implicitly declared function at its
+  // call site: "int ()()"
+  FunctionType *makeImplicitDeclFuncType();
+
+  // make function variable for an implicitly declared function at its
+  // call site with type makeImplicitDeclFuncType() above
+  Variable *makeImplicitDeclFuncVar(StringRef name);
+
+  // declare a function that can accept basically anything; mainly
+  // used for functions the translator itself interprets
+  Variable *declareSpecialFunction(char const *name);
+
+  // see implementation; this is here b/c gnu.cc wants to call it
+  Type *computeArraySizeFromCompoundInit(SourceLoc tgt_loc, Type *tgt_type,
+                                         Type *src_type, Initializer *init);
+
+  // if 'type' is not a complete type, attempt to make it into one
+  // (by template instantiation); if it cannot be, then emit an
+  // error message (using 'action') and return false
+  bool ensureCompleteType(char const *action, Type *type);
+  bool ensureCompleteCompound(char const *action, CompoundType *ct);
+
+  // support for cppstd 13.4; see implementations for more details
+  Variable *getOverloadedFunctionVar(Expression *e);
+  void setOverloadedFunctionVar(Expression *e, Variable *selVar);
+  Variable *pickMatchingOverloadedFunctionVar(LookupSet &set, Type *type);
+  void possiblySetOverloadedFunctionVar(Expression *expr, Type *paramType,
+                                        LookupSet &set);
+
+  // support for 3.4.2
+  void getAssociatedScopes(SObjList<Scope> &associated, Type *type);
+  void associatedScopeLookup(LookupSet &candidates, StringRef name,
+                             ArrayStack<Type*> const &argTypes, LookupFlags flags);
+  void addCandidates(LookupSet &candidates, Variable *var);
+
+  // see comments at implementation
+  void checkForQualifiedMemberDeclarator(Declarator *decl);
+
+  Scope *createNamespace(SourceLoc loc, StringRef name);
+
+  // ensureClassBodyInstantiated, then CompoundType::getSubobjects
+  void getSubobjects(SObjList<BaseClassSubobj const> &dest,
+                     CompoundType *ct);
+
+  // Evaluate a 'sizeof' applied to type 't', store the result in
+  // 'size', and return the type of the 'sizeof' expression itself.
+  // If 't' was derived from an expression, it is passed as 'expr'.
+  Type *sizeofType(Type *t, int &size, Expression * /*nullable*/ expr);
+
+  Expression *makeConvertedArg(Expression * const arg,
+                               ImplicitConversion const &ic);
+
+  bool elaborateImplicitConversionArgToParam(Type *paramType, Expression *&arg);
+
+  // ------------ new lookup mechanism ---------------
+private:     // funcs
+  void unqualifiedLookup(LookupSet &set, Scope * /*nullable*/ scope,
+                         StringRef name, LookupFlags flags);
+  Variable *lookupScopeVar(Scope * /*nullable*/ scope, StringRef name,
+                           LookupFlags flags);
+  void finishDependentQType(LookupSet &set, DependentQType * /*nullable*/ dqt,
+                            PQName *name);
+  void checkTemplateKeyword(PQName *name);
+
+public:      // funcs
+  // this is the main lookup function in the new design
+  void lookupPQ(LookupSet &set, PQName *name, LookupFlags flags);
+
+  // effectively, this is a second entry point to 'lookupPQ'
+  void lookupPQ_withScope(LookupSet &set, PQName *name, LookupFlags flags, Scope *scope);
+
+  // do the last step of qualified lookup, where the qualifiers
+  // denoted 'scope' and 'name' is the last element of the chain
+  void unqualifiedFinalNameLookup(LookupSet &set, Scope *scope,
+                                  PQName *name, LookupFlags flags);
+
+  // yield just the first element of the lookup set, if any; the
+  // context is going to reject a function name anyway (so it does
+  // not matter if there is more than one)
+  Variable *lookupPQ_one(PQName *name, LookupFlags flags);
+  Variable *unqualifiedLookup_one(StringRef name, LookupFlags flags);
+  Variable *unqualifiedFinalNameLookup_one(Scope *scope, PQName *name,
+                                           LookupFlags flags);
+
+  // lookup "~ct->name" in 'ct'
+  void lookupClassDestructor(LookupSet &set, CompoundType *ct,
+                             LookupFlags flags);
+
+  // handling of DQTs in type specifiers
+  Type *resolveDQTs(SourceLoc loc, Type *t);
+  Type *resolveDQTs_atomic(SourceLoc loc, AtomicType *t);
+  CompoundType *getMatchingTemplateInScope
+    (CompoundType *primary, ObjList<STemplateArgument> const &sargs);
+  AtomicType *resolveDQTs_pi(SourceLoc loc, PseudoInstantiation *pi);
+
+  // ------------ template instantiation stuff ------------
+  // the following methods are implemented in template.cc
+private:     // template funcs
+  CompoundType *findEnclosingTemplateCalled(StringRef name);
+
+  void transferTemplateMemberInfo
+    (SourceLoc instLoc, TS_classSpec *source,
+     TS_classSpec *dest, ObjList<STemplateArgument> const &sargs);
+  void transferTemplateMemberInfo_typeSpec
+    (SourceLoc instLoc, TypeSpecifier *srcTS, CompoundType *sourceCT,
+     TypeSpecifier *destTS, ObjList<STemplateArgument> const &sargs);
+  void transferTemplateMemberInfo_one
+    (SourceLoc instLoc, Variable *srcVar, Variable *destVar,
+     ObjList<STemplateArgument> const &sargs);
+  void transferTemplateMemberInfo_membert
+    (SourceLoc instLoc, Variable *srcVar, Variable *destVar,
+     ObjList<STemplateArgument> const &sargs);
+
+  void insertTemplateArgBindings
+    (Variable *baseV, SObjList<STemplateArgument> const &sargs);
+  void insertTemplateArgBindings
+    (Variable *baseV, ObjList<STemplateArgument> const &sargs);
+  bool insertTemplateArgBindings_oneParamList
+    (Scope *scope, Variable *baseV, SObjListIter<STemplateArgument> &argIter,
+     SObjList<Variable> const &params);
+  void deleteTemplateArgBindings(Scope *limit = NULL);
+
+  void mapPrimaryArgsToSpecArgs(
+    Variable *baseV,
+    ObjList<STemplateArgument> &partialSpecArgs,
+    ObjList<STemplateArgument> &primaryArgs);
+  void mapPrimaryArgsToSpecArgs_oneParamList(
+    SObjList<Variable> const &params,
+    MType &match,
+    ObjList<STemplateArgument> &partialSpecArgs);
+
+  Variable *findCompleteSpecialization(TemplateInfo *tinfo,
+                                       ObjList<STemplateArgument> const &sargs);
+  void bindParametersInMap(MType &map, TemplateInfo *tinfo,
+                           SObjList<STemplateArgument> const &sargs);
+  void bindParametersInMap(MType &map,
+                           SObjList<Variable> const &params,
+                           SObjListIter<STemplateArgument> &argIter);
+
+  Type *pseudoSelfInstantiation(CompoundType *ct, CVFlags cv);
+
+  Variable *makeInstantiationVariable(Variable *templ, Type *instType);
+
+  bool supplyDefaultTemplateArguments
+    (TemplateInfo *primaryTI,
+     ObjList<STemplateArgument> &dest,
+     SObjList<STemplateArgument> const &src);
+  STemplateArgument *makeDefaultTemplateArgument
+    (Variable const *param, MType &map);
+
+  Variable *instantiateClassTemplate_or_PI
+    (CompoundType *ct, ObjList<STemplateArgument> const &args);
+
+public:      // template funcs
+  void setSTemplArgFromExpr(STemplateArgument &sarg, Expression *expr);
+  STemplateArgument variableToSTemplateArgument(Variable *var);
+
+  // load the bindings with any explicit template arguments; return true if successful
+  bool loadBindingsWithExplTemplArgs(Variable *var, ObjList<STemplateArgument> const &args,
+                                     MType &match, InferArgFlags iflags);
+  // infer template arguments from the function arguments; return true if successful
+  bool inferTemplArgsFromFuncArgs(Variable *var,
+                                  TypeListIter &argsListIter,
+//                                    FakeList<ArgExpression> *funcArgs,
+                                  MType &match,
+                                  InferArgFlags iflags);
+  // get both the explicit and implicit function template arguments
+  bool getFuncTemplArgs
+    (MType &match,
+     ObjList<STemplateArgument> &sargs,
+     PQName const *final,
+     Variable *var,
+     TypeListIter &argListIter,
+     InferArgFlags iflags);
+  void getFuncTemplArgs_oneParamList
+    (MType &match,
+     ObjList<STemplateArgument> &sargs,
+     InferArgFlags iflags,
+     bool &haveAllArgs,
+     //ObjListIter<STemplateArgument> &piArgIter,
+     SObjList<Variable> const &paramList);
+  bool getArgumentsFromMatch
+    (MType &match, ObjList<STemplateArgument> &sargs,
+     InferArgFlags iflags, Variable *primary);
+
+  // Given a primary, find the most specific specialization for the
+  // given template arguments 'sargs'; for full generality we allow
+  // the primary itself as a "trivial specialization" and may return
+  // that.
+  Variable *findMostSpecific(Variable *baseV, ObjList<STemplateArgument> const &sargs);
+
+  // Prepare the argument scope for the present typechecking of the
+  // cloned AST for effecting the instantiation of the template;
+  // Please see Scott's extensive comments at the implementation.
+  void prepArgScopeForTemlCloneTcheck
+    (ObjList<SavedScopePair> &poppedScopes, SObjList<Scope> &pushedScopes,
+     Scope *foundScope);
+
+  // Undo prepArgScopeForTemlCloneTcheck().
+  void unPrepArgScopeForTemlCloneTcheck
+    (ObjList<SavedScopePair> &poppedScopes, SObjList<Scope> &pushedScopes);
+
+  // function template instantiation chain
+  Variable *instantiateFunctionTemplate
+    (SourceLoc loc,
+     Variable *primary,
+     ObjList<STemplateArgument> const &sargs);
+  Variable *instantiateFunctionTemplate
+    (SourceLoc loc, Variable *primary, MType &match);
+  void ensureFuncBodyTChecked(Variable *instV);    // try inst defn
+  void instantiateFunctionBody(Variable *instV);   // inst defn
+  void instantiateFunctionBodyNow(Variable *instV, SourceLoc loc);
+
+  // given a template function that was just made non-forward,
+  // instantiate all of its forward-declared instances
+  void instantiateForwardFunctions(Variable *primary);
+
+  // ensure that at least 'neededDefaults' default args are available
+  void instantiateDefaultArgs(Variable *instV, int neededDefaults);
+
+  // class template instantiation chain
+  Variable *instantiateClassTemplate               // inst decl 1
+    (SourceLoc loc,
+     Variable *primary,
+     SObjList<STemplateArgument> const &sargs);
+  Variable *instantiateClassTemplate               // inst decl 2
+    (SourceLoc loc,
+     Variable *primary,
+     ObjList<STemplateArgument> const &sargs);
+  void instantiateClassBody(Variable *inst);       // inst defn
+
+  // instantiate the given class' body, *if* it is an instantiation
+  // and instantiation is possible but hasn't already been done; note
+  // that most of the time you want to call ensureCompleteType, not
+  // this function
+  void ensureClassBodyInstantiated(CompoundType *ct);
+
+  // do 'ensureClassBodyInstantiated' for all parameters
+  void instantiateTemplatesInParams(FunctionType *ft);
+
+  // instantiate functions used in 'ic'
+  void instantiateTemplatesInConversion(ImplicitConversion &ic);
+
+  // given a template class that was just made non-forward,
+  // instantiate all of its forward-declared instances
+  void instantiateForwardClasses(Variable *baseV);
+
+  // given a class or function template instantiation, process
+  // an "explicit instantiation" (14.7.2) request for it
+  void explicitlyInstantiate(Variable *inst, DeclFlags instFlags);
+
+  // find template scope corresp. to this var
+  Scope *findParameterizingScope(Variable *bareQualifierVar,
+                                 bool argsHaveVariables);
+
+  // remove/restore scopes below 'bound'
+  void removeScopesInside(ObjList<Scope> &dest, Scope *bound);
+  void restoreScopesInside(ObjList<Scope> &src, Scope *bound);
+
+  // merging template parameter lists from different declarations
+  bool mergeParameterLists(Variable *prior,
+                           SObjList<Variable> &destParams,
+                           SObjList<Variable> const &srcParams);
+  bool mergeTemplateInfos(Variable *prior, TemplateInfo *dest,
+                          TemplateInfo const *src);
+
+  // apply template arguments to make concrete types, or throw
+  // xTypeDeduction to indicate failure
+  Type *applyArgumentMapToType(MType &map, Type *origSrc);
+  Type *applyArgumentMapToAtomicType
+    (MType &map, AtomicType *origSrc, CVFlags srcCV);
+  Type *applyArgumentMap_applyCV(CVFlags cv, Type *type);
+  Type *applyArgumentMapToReceiverType(MType &map, Type *origSrc);
+  void applyArgumentMapToTemplateArgs
+    (MType &map, ObjList<STemplateArgument> &dest,
+                                 ObjList<STemplateArgument> const &srcArgs);
+  STemplateArgument applyArgumentMapToExpression
+    (MType &map, Expression *e);
+  STemplateArgument applyArgumentMapToQualifiedName
+    (MType &map, PQ_qualifier *qual);
+  CompoundType *applyArgumentMap_instClass
+    (MType &map, Variable *primary,
+     ObjList<STemplateArgument> const &sargs);
+  STemplateArgument applyArgumentMapToPQName
+    (MType &map, Scope *scope, PQName *name);
+  void applyArgumentMap_ensureComplete(CompoundType *ct);
+  Type *applyArgumentMapToQualifiedType
+    (MType &map, CompoundType *ct, PQName *name);
+
+  // defined in notopt.cc
+  Type *applyArgumentMapToType_helper(MType &map, Type *origSrc);
+
+  // specialization support
+  Variable *makeExplicitFunctionSpecialization
+    (SourceLoc loc, DeclFlags dflags, PQName *name, FunctionType *ft);
+  Variable *makeSpecializationVariable
+    (SourceLoc loc, DeclFlags dflags, Variable *templ, FunctionType *type,
+     SObjList<STemplateArgument> const &args);
+
+  bool verifyCompatibleTemplateParameters(Scope *scope, CompoundType *prior);
+
+  Variable *explicitFunctionInstantiation(PQName *name, Type *type,
+                                          DeclFlags instFlags);
+
+  Variable *findInstantiation(TemplateInfo *tinfo,
+                              ObjList<STemplateArgument> const &sargs);
+};
+
+
+// when prepArgScopeForTemplCloneTcheck saves and restores scopes,
+// it needs to remember the delegation pointers ....
+class SavedScopePair {
+public:      // data
+  Scope *scope;                 // (nullable owner) main saved scope
+  Scope *parameterizingScope;   // (nullable serf) delegation pointer
+
+private:     // disallowed
+  SavedScopePair(SavedScopePair&);
+  void operator=(SavedScopePair&);
+
+public:      // funcs
+  SavedScopePair(Scope *s);     // delegation pointer set to NULL
+  ~SavedScopePair();
+};
+
+
+// set/reset 'disambiguateOnly'
+class DisambiguateOnlyTemp {
+private:
+  Env &env;       // relevant environment
+  bool prev;      // previous value of 'disambiguateOnly'
+  bool active;    // when false, we do nothing
+
+public:
+  DisambiguateOnlyTemp(Env &e, bool disOnly)
+    : env(e),
+      active(disOnly) {
+    if (active) {
+      prev = e.setDisambiguateOnly(true);
+    } else {
+      prev = false;      // initialize to squelch compiler warning
+    }
+  }
+
+  ~DisambiguateOnlyTemp() {
+    if (active) {
+      env.setDisambiguateOnly(prev);
+    }
+  }
+};
+
+
+// isolate template instantiation from affecting other things that
+// might be going on in the instantiation request context, in
+// particular disambiguation
+class InstantiationContextIsolator {
+public:      // data
+  Env &env;                    // tcheck env
+  int origNestingLevel;        // original value of env.disambiguationNestingLevel
+  bool origSecondPass;         // original value of env.secondPassTcheck
+  ErrorList origErrors;        // errors extant before instantiation
+
+private:     // disallowed
+  InstantiationContextIsolator(InstantiationContextIsolator&);
+  void operator=(InstantiationContextIsolator&);
+
+public:      // funcs
+  InstantiationContextIsolator(Env &env, SourceLoc loc);
+  ~InstantiationContextIsolator();
+};
+
+
+// little hack to suppress errors in a given segment
+class SuppressErrors {
+private:
+  Env &env;               // relevant environment
+  ErrorList existing;     // errors before the operation
+
+public:
+  SuppressErrors(Env &e) : env(e) {
+    // squirrel away the good messages
+    existing.takeMessages(env.errors);
+  }
+
+  ~SuppressErrors() {
+    // get rid of any messages added in the meantime
+    env.errors.deleteAll();
+
+    // put back the good ones
+    env.errors.takeMessages(existing);
+  }
+};
+
+
+// check default arguments during pass 2
+class DefaultArgumentChecker : public ASTVisitor {
+public:
+  Env &env;
+  bool isInstantiation;
+
+public:
+  DefaultArgumentChecker(Env &e, bool i)
+    : env(e), isInstantiation(i) {}
+
+  virtual bool visitIDeclarator(IDeclarator *obj);
+  virtual bool visitTypeSpecifier(TypeSpecifier *obj);
+};
+
+
+// save env's error messages, then later restore them, as part of
+// disambiguation activities
+class DisambiguationErrorTrapper {
+public:      // data
+  Env &env;
+  ErrorList existingErrors;       // saved messages
+
+public:      // funcs
+  DisambiguationErrorTrapper(Env &env);
+  ~DisambiguationErrorTrapper();
+};
+
+
+// misc
+bool isCopyConstructor(Variable const *funcVar, CompoundType *ct);
+bool isCopyAssignOp(Variable const *funcVar, CompoundType *ct);
+void addCompilerSuppliedDecls(Env &env, SourceLoc loc, CompoundType *ct);
+bool equalOrIsomorphic(Type const *a, Type const *b);
+
+
+#endif // CC_ENV_H

Added: vendor/elsa/current/elsa/cc_err.cc
===================================================================
--- vendor/elsa/current/elsa/cc_err.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_err.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,213 @@
+// cc_err.cc            see license.txt for copyright and terms of use
+// code for cc_err.h
+
+#include "cc_err.h"      // this module
+#include "trace.h"       // tracingSys
+#include "strutil.h"     // trimWhitespace
+
+
+// ----------------- ErrorMsg -----------------
+ErrorMsg::~ErrorMsg()
+{}
+
+
+string ErrorMsg::toString() const
+{
+  stringBuilder sb;
+  sb << ::toString(loc) << ": ";
+  if (flags & EF_WARNING) {
+    sb << "warning";
+  }
+  else {
+    sb << "error";
+  }
+  sb << ": " << msg;
+
+  bool msgHasNL = !!strchr(sb.c_str(), '\n');
+  bool addedNewline = false;
+
+  if (instLoc[0] && msgHasNL) {
+    // for a multi-line message, put instLoc on its own line
+    // and with no leading whitespace
+    sb << "\n" << trimWhitespace(instLoc);
+  }
+  else {
+    sb << instLoc;
+  }
+
+  char const *extra = NULL;
+  if (flags & EF_FROM_TEMPLATE)  {
+    if (!(flags & EF_WARNING)) {
+      extra = "(from template; would be suppressed in permissive mode)";
+    }
+    else if (flags & EF_STRICT_ERROR) {
+      extra = "(from template; would have been an error in strict mode)";
+    }
+  }
+
+  if (extra) {
+    if (msgHasNL && !addedNewline) {
+      sb << "\n";
+    }
+    else {
+      sb << " ";
+    }
+    sb << extra;
+  }
+
+  return sb;
+}
+
+
+// ---------------- ErrorList -----------------
+ErrorList::ErrorList()
+  : list()
+{}
+
+ErrorList::~ErrorList()
+{
+  list.deleteAll();
+}
+
+
+void ErrorList::addError(ErrorMsg * /*owner*/ obj)
+{
+  list.prepend(obj);    // O(1)
+}
+
+void ErrorList::prependError(ErrorMsg * /*owner*/ obj)
+{
+  list.append(obj);     // O(n)
+}
+
+
+void ErrorList::takeMessages(ErrorList &src)
+{ 
+  if (list.isEmpty()) {
+    // this is a common case, and 'concat' is O(1) in this case
+    list.concat(src.list);
+    return;
+  }
+
+  // put all of my messages (which semantically come first) onto the
+  // end of the 'src' list; this takes time proportional to the
+  // length of 'src.list'
+  src.list.concat(list);
+
+  // now put them back onto my list, which will take O(1) since
+  // my list is now empty
+  list.concat(src.list);
+}
+
+
+void ErrorList::prependMessages(ErrorList &src)
+{
+  list.concat(src.list);
+}
+
+
+void ErrorList::markAllAsWarnings()
+{
+  markAllWithFlag(EF_WARNING);
+}
+
+void ErrorList::markAllAsFromDisamb()
+{
+  markAllWithFlag(EF_FROM_DISAMB);
+}
+
+
+void ErrorList::markAllWithFlag(ErrorFlags flags)
+{
+  FOREACH_OBJLIST_NC(ErrorMsg, list, iter) {
+    iter.data()->flags |= flags;
+  }
+}
+
+
+void ErrorList::filter(bool (*pred)(ErrorMsg *msg))
+{
+  ObjListMutator<ErrorMsg> mut(list);
+  while (!mut.isDone()) {
+    if (pred(mut.data())) {
+      // keep it
+      mut.adv();
+    }
+    else {
+      // drop it
+      mut.deleteIt();
+    }
+  }
+}
+
+
+int ErrorList::count() const
+{
+  return list.count();
+}
+
+int ErrorList::numErrors() const
+{
+  return count() - numWarnings();
+}
+
+int ErrorList::numWarnings() const
+{
+  return countWithAnyFlag(EF_WARNING);
+}
+
+
+bool ErrorList::hasDisambErrors() const
+{
+  return countWithAnyFlag(EF_DISAMBIGUATES) > 0;
+}
+
+
+int ErrorList::countWithAnyFlag(ErrorFlags flags) const
+{
+  int ct=0;
+  FOREACH_OBJLIST(ErrorMsg, list, iter) {
+    if (iter.data()->flags & flags) {
+      ct++;
+    }
+  }
+  return ct;
+}
+
+
+bool ErrorList::hasFromNonDisambErrors() const
+{
+  return countWithAnyFlag(EF_WARNING | EF_FROM_DISAMB | EF_FROM_TEMPLATE) <
+         count();
+}
+
+
+void ErrorList::print(ostream &os) const
+{
+  os << printToString();
+}
+
+
+string ErrorList::printToString() const
+{
+  stringBuilder sb;
+
+  // need to temporarily reverse it, but I promise to restore it
+  // when I'm done
+  ObjList<ErrorMsg> &nclist = const_cast<ObjList<ErrorMsg>&>(list);
+
+  bool printWarnings = !tracingSys("nowarnings");
+
+  nclist.reverse();
+  FOREACH_OBJLIST(ErrorMsg, nclist, iter) {
+    if (printWarnings || !iter.data()->isWarning()) {
+      sb << iter.data()->toString() << "\n";
+    }
+  }
+  nclist.reverse();
+
+  return sb;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc_err.h
===================================================================
--- vendor/elsa/current/elsa/cc_err.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_err.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,166 @@
+// cc_err.h            see license.txt for copyright and terms of use
+// objects for representing errors in C++ code
+
+#ifndef CC_ERR_H
+#define CC_ERR_H
+
+#include "macros.h"    // ENUM_BITWISE_OR
+#include "str.h"       // string
+#include "srcloc.h"    // SourceLoc
+
+#include <ostream.h>   // ostream
+
+
+// flags on errors
+enum ErrorFlags {
+  // ordinary error
+  EF_NONE          = 0x00,
+
+  // informative, but not an error; typically, such messages should
+  // have a switch to disable them
+  EF_WARNING       = 0x01,
+
+  // This flag means the error will not be supressed in template code.
+  // Most errors inside templates are suppressed since they may be due
+  // to having incomplete information; but an EF_STRONG error is one
+  // where we are sure that the code really is invalid.  In theory, as
+  // cppstd does not require diagnosis of errors in uninstantiated
+  // template code, changing an EF_STRONG to EF_NONE should not cause
+  // Elsa to become nonconformant, merely less convenient.  Nevertheless,
+  // some of our regression tests contain (intentional) errors that are 
+  // diagnosed only because of EF_STRONG.
+  //
+  // 2005-08-08: Removed EF_STRONG_WARNING, replacing uses of it with
+  // EF_STRONG|EF_WARNING instead.
+  EF_STRONG        = 0x02,
+
+  // when this is true, the error message should be considered
+  // when disambiguation; when it's false, it's not a sufficiently
+  // severe error to warrant discarding an ambiguous alternative;
+  // for the most part, only environment lookup failures are
+  // considered to disambiguate
+  EF_DISAMBIGUATES = 0x04,
+
+  // This flag means this error arose during an attempt to tcheck an
+  // alternative that might not be the correct interpretation, and
+  // during that attempt, an x_assert was raised.  Consequently, the
+  // presence of this error message in the error list *cannot* be
+  // used to justify reducing the severity of the x_assert.
+  EF_FROM_DISAMB   = 0x08,
+  
+  // This flag means the error arose during type checking of an
+  // uninstantiated template body.  In permissive mode, such messages
+  // are turned into warnings.
+  EF_FROM_TEMPLATE = 0x10,
+  
+  // When an error is turned into a warning due to permissive mode,
+  // this flag is set; i.e., it would have been an error in strict
+  // mode.
+  EF_STRICT_ERROR  = 0x20,
+
+  EF_ALL           = 0x3F
+};
+ENUM_BITWISE_OPS(ErrorFlags, EF_ALL)
+
+
+// an error message from the typechecker; I plan to expand
+// this to contain lots of information about the error, but
+// for now it's just a string like every other typechecker
+// produces
+class ErrorMsg {
+public:
+  SourceLoc loc;          // where the error happened
+  string msg;             // english explanation
+  ErrorFlags flags;       // various
+  
+  // string of instantiation locations leading to the error; if
+  // no instantiations are involved, this should be "", which does
+  // not require any allocation to store (you can also pass NULL
+  // to mean "")
+  string instLoc;
+
+public:
+  ErrorMsg(SourceLoc L, rostring m, ErrorFlags f)
+    : loc(L), msg(m), flags(f), instLoc() {}
+  ErrorMsg(SourceLoc L, rostring m, ErrorFlags f, rostring i)
+    : loc(L), msg(m), flags(f), instLoc(i) {}
+  ~ErrorMsg();
+
+  bool isWarning() const
+    { return !!(flags & EF_WARNING); }
+  bool disambiguates() const
+    { return !!(flags & EF_DISAMBIGUATES); }
+
+  string toString() const;
+};
+
+
+// list of errors; a reference to this will be passed to functions
+// that want to report errors to the user
+class ErrorList {
+private:           
+  // the error objects are actually stored in reverse order, such
+  // that (effectively) appending is fast and prepending is slow;
+  // this field is private because I want to isolate knowledge of
+  // this reverse ordering
+  ObjList<ErrorMsg> list;
+
+public:
+  ErrorList();                      // empty list initially
+  virtual/*...*/ ~ErrorList();      // deallocates error objects
+
+  // add an error to the end of list (actually the beginning of
+  // 'list', but clients don't know that, nor should they care)
+  virtual void addError(ErrorMsg * /*owner*/ obj);
+
+  // add an error to the beginning; this is unusual, and generally
+  // should only be done when it is known that there aren't very
+  // many error objects in the list
+  void prependError(ErrorMsg * /*owner*/ obj);
+
+  // take all of the error messages in 'src' and (semantically)
+  // append them after messages in 'this'; this operation leaves
+  // 'src' empty, and takes time no more than proportional to the
+  // length of the 'src' list; it's O(1) if 'this' is empty
+  void takeMessages(ErrorList &src);         // append
+  
+  // this one takes time proportional to 'this' list
+  void prependMessages(ErrorList &src);      // prepend 
+
+  // mark all of the messages with EF_WARNING
+  void markAllAsWarnings();
+  
+  // mark all with EF_FROM_DISAMB
+  void markAllAsFromDisamb();
+                                         
+  // mark with arbitrary flags
+  void markAllWithFlag(ErrorFlags flags);
+
+  // delete all of the existing messages
+  void deleteAll() { list.deleteAll(); }
+
+  // keep only messages meeting a specific criteria
+  void filter(bool (*pred)(ErrorMsg *msg));
+
+  // various counts of error objects
+  int count() const;            // total
+  int numErrors() const;        // # that are not EF_WARNING
+  int numWarnings() const;      // # that *are* EF_WARNING
+      
+  // number of errors with any flags set in 'flags'
+  int countWithAnyFlag(ErrorFlags flags) const;
+
+  // true if any are EF_DISAMBIGUATES
+  bool hasDisambErrors() const;
+  bool isEmpty() const { return list.isEmpty(); }
+                                      
+  // did any of the errors arise from outside a disambiguation process?
+  bool hasFromNonDisambErrors() const;
+
+  // print all the errors, one per line, in order
+  void print(ostream &os) const;
+  string printToString() const;
+};
+
+
+#endif // CC_ERR_H

Added: vendor/elsa/current/elsa/cc_flags.cc
===================================================================
--- vendor/elsa/current/elsa/cc_flags.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_flags.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,759 @@
+// cc_flags.cc            see license.txt for copyright and terms of use
+// code for cc_flags.h
+
+#include "cc_flags.h"     // this module
+#include "macros.h"       // STATIC_ASSERT
+#include "xassert.h"      // xassert
+#include "trace.h"        // tracingSys
+#include "strtokpc.h"     // StrtokParseC
+#include "exc.h"          // xformat
+#include <ctype.h>        // toupper
+
+
+// the check for array[limit-1] is meant to ensure that there
+// are as many specified entries as there are total entries
+#define MAKE_TOSTRING(T, limit, array)        \
+  char const *toString(T index)               \
+  {                                           \
+    xassert((unsigned)index < limit);         \
+    xassert(array[limit-1] != NULL);          \
+    return array[index];                      \
+  }
+
+
+// given a table like {"a","bb","ccc"} and prefix "P", produce a table
+// like {"PA","PBB","PCCC"}
+char **buildPrefixUppercaseMap(char const *prefix, char const * const *src,
+                               int numEntries)
+{
+  // table itself
+  char **ret = new char*[numEntries];
+
+  // fill the entries
+  for (int i=0; i<numEntries; i++) {
+    // prefix, then src[i]
+    int len = strlen(prefix)+strlen(src[i]);
+    ret[i] = new char[len+1];
+    strcpy(ret[i], prefix);
+    strcat(ret[i], src[i]);
+
+    // uppercase
+    for (int j=0; j<len; j++) {
+      ret[i][j] = toupper(ret[i][j]);
+    }
+  }
+
+  return ret;
+}
+
+
+// find the index of a string in 'names' that equals 'str', or
+// throw xFormat on error
+int findInMap(char const * const *names, int numNames,
+              char const *kind, char const *str)
+{
+  for (int i=0; i<numNames; i++) {
+    if (0==strcmp(names[i], str)) {
+      return i;
+    }
+  }
+  xformat(stringc << "unknown " << kind << ": " << str);
+  return 0;    // silence warning
+}
+
+
+// -------------------- TypeIntr -------------------------
+char const * const typeIntrNames[NUM_TYPEINTRS] = {
+  "struct",
+  "class",
+  "union",
+  "enum"
+};
+
+MAKE_TOSTRING(TypeIntr, NUM_TYPEINTRS, typeIntrNames)
+
+static char const * const *typeIntrPrefixNames()
+{
+  static char const * const *names = 0;
+  if (!names) {
+    names = buildPrefixUppercaseMap("TI_", typeIntrNames, NUM_TYPEINTRS);
+  }
+  return names;
+}
+
+char const *toXml(TypeIntr id)
+{
+  xassert((unsigned)id < (unsigned)NUM_TYPEINTRS);
+  return typeIntrPrefixNames()[id];
+}
+
+void fromXml(TypeIntr &out, char const *str)
+{
+  out = (TypeIntr)findInMap(typeIntrPrefixNames(), NUM_TYPEINTRS,
+                            "TypeIntr", str);
+}
+
+
+// ---------------- CVFlags -------------
+char const * const cvFlagNames[NUM_CVFLAGS] = {
+  "const",
+  "volatile",
+  "restrict",
+  "owner"
+};
+
+
+string bitmapString(int bitmap, char const * const *names, int numFlags,
+                    char const *delim)
+{
+  // make sure I haven't added a flag without adding a string for it
+  xassert(names[numFlags-1] != NULL);
+
+  stringBuilder sb;
+  int count=0;
+  for (int i=0; i<numFlags; i++) {
+    if (bitmap & (1 << i)) {
+      if (count++) {
+        sb << delim;
+      }
+      sb << names[i];
+    }
+  }
+
+  return sb;
+}
+
+string toString(CVFlags cv)
+{
+  return bitmapString(cv >> CV_SHIFT_AMOUNT, cvFlagNames, NUM_CVFLAGS, " ");
+}
+
+string toXml(CVFlags id)
+{
+  return bitmapString(id >> CV_SHIFT_AMOUNT, cvFlagNames, NUM_CVFLAGS, "|");
+}
+
+
+// Given the string 'str' which contains several space-delimited
+// flag names drawn from 'names', return a bitmap that consists
+// of the corresponding flag bits.
+//
+// For best performance, 'str' should have its flags in numerically
+// increasing order (this routine does not sort them first).
+int fromBitmapString(char const * const *names, int numFlags,
+                     char const *kind, char const *str, char delim)
+{
+  StrtokParseC tok(str);
+
+  int ret = 0;       // set of flags that have been found in 'str'
+  int tokIndex = 0;  // progress in 'tok'
+
+  char const *curToken = tok.nextToken(delim);
+
+  // loop while still flag names in 'tok' yet to be processed
+  while (curToken != NULL) {
+    int origTokIndex = tokIndex;
+
+    // loop over names in 'names'
+    for (int flag = 0; flag<numFlags; flag++) {
+      if (0==strcmp(names[flag], curToken)) {
+        // the current string is the current flag
+        ret |= (1 << flag);
+        tokIndex++;
+        curToken = tok.nextToken(delim);
+        if (curToken == NULL) break;
+      }
+    }
+
+    // made progress?
+    if (origTokIndex == tokIndex) {
+      // failed to make progress; this string isn't anywhere
+      // in the 'names' array
+      xformat(stringc << "unknown " << kind << ": " << curToken);
+    }
+  }
+
+  return ret;
+}
+
+void fromXml(CVFlags &out, char const *str)
+{
+  int tmp = fromBitmapString(cvFlagNames, NUM_CVFLAGS, "CVFlag", str, '|');
+  out = (CVFlags)(tmp << CV_SHIFT_AMOUNT);
+}
+
+// ------------------- DeclFlags --------------
+char const * const declFlagNames[NUM_DECLFLAGS] = {
+  "auto",           // 0
+  "register",
+  "static",
+  "extern",
+  "mutable",        // 4
+  "inline",
+  "virtual",
+  "explicit",
+  "friend",
+  "typedef",        // 9
+
+  "(enumerator)",
+  "(global)",
+  "(initialized)",
+  "(builtin)",
+  "(bound tparam)", // 14
+  "(addrtaken)",
+  "(parameter)",
+  "(universal)",
+  "(existential)",
+  "(member)",       // 19
+  "(definition)",
+  "(inline_defn)",
+  "(implicit)",
+  "(forward)",
+  "(temporary)",    // 24
+
+  "(unused)",
+  "namespace",
+  "(extern \"C\")",
+  "(selfname)",
+  "(templ param)",  // 29
+  "(using alias)",
+  "(bitfield)",
+};
+
+
+string toString(DeclFlags df)
+{
+  return bitmapString(df, declFlagNames, NUM_DECLFLAGS, " ");
+}
+
+string toXml(DeclFlags id)
+{
+  return bitmapString(id, declFlagNames, NUM_DECLFLAGS, "|");
+}
+
+void fromXml(DeclFlags &out, char const *str)
+{
+  out = (DeclFlags)fromBitmapString(declFlagNames, NUM_DECLFLAGS,
+                                    "DeclFlag", str, '|');
+}
+
+
+// ----------------------- ScopeKind ----------------------------
+char const *toString(ScopeKind sk)
+{
+  static char const * const arr[] = {
+    "unknown",
+    "global",
+    "parameter",
+    "function",
+    "class",
+    "template_params",
+    "template_args",
+    "namespace",
+  };
+  STATIC_ASSERT(TABLESIZE(arr) == NUM_SCOPEKINDS);
+
+  xassert((unsigned)sk < NUM_SCOPEKINDS);
+  return arr[sk];
+}
+
+
+// ---------------------- SimpleTypeId --------------------------
+bool isValid(SimpleTypeId id)
+{
+  return 0 <= id && id <= NUM_SIMPLE_TYPES;
+}
+
+
+#define S(x) ((SimpleTypeFlags)(x))    // work around bitwise-OR in initializers..
+static SimpleTypeInfo const simpleTypeInfoArray[] = {
+  //name                   size,    flags
+  { "char",                   1,    S(STF_INTEGER                          ) },
+  { "unsigned char",          1,    S(STF_INTEGER | STF_UNSIGNED           ) },
+  { "signed char",            1,    S(STF_INTEGER                          ) },
+  { "bool",                   4,    S(STF_INTEGER                          ) },
+  { "int",                    4,    S(STF_INTEGER | STF_PROM               ) },
+  { "unsigned int",           4,    S(STF_INTEGER | STF_PROM | STF_UNSIGNED) },
+  { "long int",               4,    S(STF_INTEGER | STF_PROM               ) },
+  { "unsigned long int",      4,    S(STF_INTEGER | STF_PROM | STF_UNSIGNED) },
+  { "long long int",          8,    S(STF_INTEGER | STF_PROM               ) },
+  { "unsigned long long int", 8,    S(STF_INTEGER | STF_PROM | STF_UNSIGNED) },
+  { "short int",              2,    S(STF_INTEGER                          ) },
+  { "unsigned short int",     2,    S(STF_INTEGER | STF_UNSIGNED           ) },
+  { "wchar_t",                2,    S(STF_INTEGER                          ) },
+  { "float",                  4,    S(STF_FLOAT                            ) },
+  { "double",                 8,    S(STF_FLOAT | STF_PROM                 ) },
+  { "long double",           10,    S(STF_FLOAT                            ) },
+  { "float _Complex",         8,    S(STF_FLOAT                            ) },
+  { "double _Complex",       16,    S(STF_FLOAT                            ) },
+  { "long double _Complex",  20,    S(STF_FLOAT                            ) },
+  { "float _Imaginary",       4,    S(STF_FLOAT                            ) },
+  { "double _Imaginary",      8,    S(STF_FLOAT                            ) },
+  { "long double _Imaginary",10,    S(STF_FLOAT                            ) },
+  { "void",                   1,    S(STF_NONE                             ) },    // gnu: sizeof(void) is 1
+
+  // these should go away early on in typechecking
+  { "...",                    0,    S(STF_NONE                             ) },
+  { "/*cdtor*/",              0,    S(STF_NONE                             ) },    // dsw: don't want to print <cdtor>
+  { "(error)",                0,    S(STF_NONE                             ) },
+  { "(dependent)",            0,    S(STF_NONE                             ) },
+  { "(implicit-int)",         0,    S(STF_NONE                             ) },
+  { "(notfound)",             0,    S(STF_NONE                             ) },
+
+
+  { "(prom_int)",             0,    S(STF_NONE                             ) },
+  { "(prom_arith)",           0,    S(STF_NONE                             ) },
+  { "(integral)",             0,    S(STF_NONE                             ) },
+  { "(arith)",                0,    S(STF_NONE                             ) },
+  { "(arith_nobool)",         0,    S(STF_NONE                             ) },
+  { "(any_obj)",              0,    S(STF_NONE                             ) },
+  { "(non_void)",             0,    S(STF_NONE                             ) },
+  { "(any_type)",             0,    S(STF_NONE                             ) },
+
+
+  { "(pret_strip_ref)",       0,    S(STF_NONE                             ) },
+  { "(pret_ptm)",             0,    S(STF_NONE                             ) },
+  { "(pret_arith_conv)",      0,    S(STF_NONE                             ) },
+  { "(pret_first)",           0,    S(STF_NONE                             ) },
+  { "(pret_first_ptr2ref)",   0,    S(STF_NONE                             ) },
+  { "(pret_second)",          0,    S(STF_NONE                             ) },
+  { "(pret_second_ptr2ref)",  0,    S(STF_NONE                             ) },
+};
+#undef S
+
+SimpleTypeInfo const &simpleTypeInfo(SimpleTypeId id)
+{
+  STATIC_ASSERT(TABLESIZE(simpleTypeInfoArray) == NUM_SIMPLE_TYPES);
+  xassert(isValid(id));
+  return simpleTypeInfoArray[id];
+}
+
+
+bool isComplexOrImaginary(SimpleTypeId id)
+{
+  return ST_FLOAT_COMPLEX <= id && id <= ST_DOUBLE_IMAGINARY;
+}
+
+
+#define MAKE_USUAL_ENUM_TO_FROM_XML(TYPE, numElements)            \
+  char const *toXml(TYPE id)                                      \
+  {                                                               \
+    return toString(id);   /* overloaded */                       \
+  }                                                               \
+                                                                  \
+  void fromXml(TYPE &out, char const *str)                        \
+  {                                                               \
+    for (int id=0; id < numElements; id++) {                      \
+      TYPE typedId = (TYPE)id;                                    \
+      if (0==strcmp(toString(typedId), str)) {                    \
+        out = typedId;                                            \
+        return;                                                   \
+      }                                                           \
+    }                                                             \
+    xfailure(stringc << "bad " #TYPE ": '" << str << "'");        \
+  }
+
+// Some of the strings have angle brackets.  But, those cases should
+// not appear in the tree that gets serialized.
+MAKE_USUAL_ENUM_TO_FROM_XML(SimpleTypeId, NUM_SIMPLE_TYPES);
+
+
+// ------------------------ UnaryOp -----------------------------
+char const * const unaryOpNames[NUM_UNARYOPS] = {
+  "+",
+  "-",
+  "!",
+  "~"
+};
+
+MAKE_TOSTRING(UnaryOp, NUM_UNARYOPS, unaryOpNames)
+MAKE_USUAL_ENUM_TO_FROM_XML(UnaryOp, NUM_UNARYOPS);
+
+
+char const * const effectOpNames[NUM_EFFECTOPS] = {
+  "++/*postfix*/",
+  "--/*postfix*/",
+  "++/*prefix*/",
+  "--/*prefix*/",
+};
+
+MAKE_TOSTRING(EffectOp, NUM_EFFECTOPS, effectOpNames)
+MAKE_USUAL_ENUM_TO_FROM_XML(EffectOp, NUM_EFFECTOPS);
+
+bool isPostfix(EffectOp op)
+{
+  return op <= EFF_POSTDEC;
+}
+
+
+// ---------------------- BinaryOp -------------------------
+char const * const binaryOpNames[NUM_BINARYOPS] = {
+  "==",
+  "!=",
+  "<",
+  ">",
+  "<=",
+  ">=",
+
+  "*",
+  "/",
+  "%",
+  "+",
+  "-",
+  "<<",
+  ">>",
+  "&",
+  "^",
+  "|",
+  "&&",
+  "||",
+  ",",
+
+  "<?",
+  ">?",
+
+  "[]",
+
+  "=",
+
+  ".*",
+  "->*",
+
+  "==>",
+  "<==>",
+};
+
+MAKE_TOSTRING(BinaryOp, NUM_BINARYOPS, binaryOpNames)
+MAKE_USUAL_ENUM_TO_FROM_XML(BinaryOp, NUM_BINARYOPS);
+
+bool isPredicateCombinator(BinaryOp op)
+{
+  return op==BIN_AND || op==BIN_OR || op==BIN_IMPLIES || op==BIN_EQUIVALENT;
+}
+
+bool isRelational(BinaryOp op)
+{
+  return BIN_EQUAL <= op && op <= BIN_GREATEREQ;
+}
+
+bool isInequality(BinaryOp op)
+{
+  return BIN_LESS <= op && op <= BIN_GREATEREQ;
+}
+
+bool isOverloadable(BinaryOp op)
+{
+  return BIN_EQUAL <= op && op <= BIN_BRACKETS ||
+         op == BIN_ARROW_STAR;
+}
+
+
+// ------------------- AccessKeyword -------------------
+char const * const accessKeywordNames[NUM_ACCESS_KEYWORDS] = {
+  "public",
+  "protected",
+  "private",
+  "unspecified"
+};
+
+MAKE_TOSTRING(AccessKeyword, NUM_ACCESS_KEYWORDS, accessKeywordNames)
+MAKE_USUAL_ENUM_TO_FROM_XML(AccessKeyword, NUM_ACCESS_KEYWORDS);
+
+
+// -------------------- CastKeyword --------------------
+char const * const castKeywordNames[NUM_CAST_KEYWORDS] = {
+  "dynamic_cast",
+  "static_cast",
+  "reinterpret_cast",
+  "const_cast"
+};
+
+MAKE_TOSTRING(CastKeyword, NUM_CAST_KEYWORDS, castKeywordNames)
+MAKE_USUAL_ENUM_TO_FROM_XML(CastKeyword, NUM_CAST_KEYWORDS);
+
+
+// -------------------- OverloadableOp --------------------
+char const * const overloadableOpNames[NUM_OVERLOADABLE_OPS] = {
+  "!",
+  "~",
+
+  "++",
+  "--",
+
+  "+",
+  "-",
+  "*",
+  "&",
+
+  "/",
+  "%",
+  "<<",
+  ">>",
+  "^",
+  "|",
+
+  "=",
+  "+=",
+  "-=",
+  "*=",
+  "/=",
+  "%=",
+  "<<=",
+  ">>=",
+  "&=",
+  "^=",
+  "|=",
+
+  "==",
+  "!=",
+  "<",
+  ">",
+  "<=",
+  ">=",
+
+  "&&",
+  "||",
+
+  "->",
+  "->*",
+
+  "[]",
+  "()",
+  ",",
+  "?:",
+
+  "<?",
+  ">?",
+};
+
+MAKE_TOSTRING(OverloadableOp, NUM_OVERLOADABLE_OPS, overloadableOpNames)
+MAKE_USUAL_ENUM_TO_FROM_XML(OverloadableOp, NUM_OVERLOADABLE_OPS);
+
+
+char const * const operatorFunctionNames[NUM_OVERLOADABLE_OPS] = {
+  "operator!",
+  "operator~",
+
+  "operator++",
+  "operator--",
+
+  "operator+",
+  "operator-",
+  "operator*",
+  "operator&",
+
+  "operator/",
+  "operator%",
+  "operator<<",
+  "operator>>",
+  "operator^",
+  "operator|",
+
+  "operator=",
+  "operator+=",
+  "operator-=",
+  "operator*=",
+  "operator/=",
+  "operator%=",
+  "operator<<=",
+  "operator>>=",
+  "operator&=",
+  "operator^=",
+  "operator|=",
+
+  "operator==",
+  "operator!=",
+  "operator<",
+  "operator>",
+  "operator<=",
+  "operator>=",
+
+  "operator&&",
+  "operator||",
+
+  "operator->",
+  "operator->*",
+
+  "operator[]",
+  "operator()",
+  "operator,",
+  "operator?",
+
+  "operator<?",
+  "operator>?",
+};
+
+
+OverloadableOp toOverloadableOp(UnaryOp op)
+{
+  static OverloadableOp const map[] = {
+    OP_PLUS,
+    OP_MINUS,
+    OP_NOT,
+    OP_BITNOT
+  };
+  ASSERT_TABLESIZE(map, NUM_UNARYOPS);
+  xassert(validCode(op));
+  return map[op];
+}
+
+OverloadableOp toOverloadableOp(EffectOp op)
+{
+  static OverloadableOp const map[] = {
+    OP_PLUSPLUS,
+    OP_MINUSMINUS,
+    OP_PLUSPLUS,
+    OP_MINUSMINUS,
+  };
+  ASSERT_TABLESIZE(map, NUM_EFFECTOPS);
+  xassert(validCode(op));
+  return map[op];
+}
+
+OverloadableOp toOverloadableOp(BinaryOp op, bool isAssignment)
+{
+  xassert(validCode(op));
+
+  // in the table, this means that an operator cannot be overloaded
+  #define BAD_ENTRY NUM_OVERLOADABLE_OPS
+  OverloadableOp ret = BAD_ENTRY;
+
+  if (!isAssignment) {
+    static OverloadableOp const map[] = {
+      OP_EQUAL,
+      OP_NOTEQUAL,
+      OP_LESS,
+      OP_GREATER,
+      OP_LESSEQ,
+      OP_GREATEREQ,
+
+      OP_STAR,
+      OP_DIV,
+      OP_MOD,
+      OP_PLUS,
+      OP_MINUS,
+      OP_LSHIFT,
+      OP_RSHIFT,
+      OP_AMPERSAND,
+      OP_BITXOR,
+      OP_BITOR,
+      OP_AND,
+      OP_OR,
+      OP_COMMA,
+
+      OP_MINIMUM,
+      OP_MAXIMUM,
+
+      OP_BRACKETS,
+
+      BAD_ENTRY,      // isAssignment is false
+
+      BAD_ENTRY,      // cannot overload
+      OP_ARROW_STAR,
+
+      BAD_ENTRY,      // extension..
+      BAD_ENTRY,
+    };
+    ASSERT_TABLESIZE(map, NUM_BINARYOPS);
+    ret = map[op];
+  }
+
+  else {
+    static OverloadableOp const map[] = {
+      BAD_ENTRY,
+      BAD_ENTRY,
+      BAD_ENTRY,
+      BAD_ENTRY,
+      BAD_ENTRY,
+      BAD_ENTRY,
+
+      OP_MULTEQ,
+      OP_DIVEQ,
+      OP_MODEQ,
+      OP_PLUSEQ,
+      OP_MINUSEQ,
+      OP_LSHIFTEQ,
+      OP_RSHIFTEQ,
+      OP_BITANDEQ,
+      OP_BITXOREQ,
+      OP_BITOREQ,
+      BAD_ENTRY,
+      BAD_ENTRY,
+      BAD_ENTRY,
+
+      BAD_ENTRY,
+      BAD_ENTRY,
+
+      BAD_ENTRY,
+
+      OP_ASSIGN,
+
+      BAD_ENTRY,
+      BAD_ENTRY,
+
+      BAD_ENTRY,
+      BAD_ENTRY,
+    };
+    ASSERT_TABLESIZE(map, NUM_BINARYOPS);
+    ret = map[op];
+  }
+
+  xassert(ret != BAD_ENTRY);    // otherwise why did you try to map it?
+  return ret;
+
+  #undef BAD_ENTRY
+}
+
+// ------------------------ UberModifiers ---------------------
+char const * const uberModifierNames[UM_NUM_FLAGS] = {
+  "auto",            // 0x00000001
+  "register",
+  "static",
+  "extern",
+  "mutable",         // 0x00000010
+  "inline",
+  "virtual",
+  "explicit",
+  "friend",          // 0x00000100
+  "typedef",
+
+  "const",
+  "volatile",
+  "restrict",        // 0x00001000
+
+  "wchar_t",
+  "bool",
+  "short",
+  "int",             // 0x00010000
+  "long",
+  "signed",
+  "unsigned",
+  "float",           // 0x00100000
+  "double",
+  "void",
+  "long long",
+  "char",            // 0x01000000
+  "complex",
+  "imaginary"
+};
+
+string toString(UberModifiers m)
+{
+  xassert(uberModifierNames[UM_NUM_FLAGS-1] != NULL);
+  return bitmapString(m, uberModifierNames, UM_NUM_FLAGS, " ");
+}
+
+
+// ---------------------- SpecialExpr -----------------
+char const *toString(SpecialExpr se)
+{
+  switch (se) {
+    default: xfailure("bad se code");
+    case SE_NONE:       return "SE_NONE";
+    case SE_ZERO:       return "SE_ZERO";
+    case SE_STRINGLIT:  return "SE_STRINGLIT";
+  }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc_flags.h
===================================================================
--- vendor/elsa/current/elsa/cc_flags.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_flags.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,577 @@
+// cc_flags.h            see license.txt for copyright and terms of use
+// enumerated flags for parsing C, C++
+
+// Basically, this module is a set of enums that are used by at
+// least two different modules in the C/C++ front end (if they
+// were only used by one module, they'd be declared in that
+// module instead).  It's intended to be a lightweight module,
+// dependent on almost nothing else.
+//
+// Each enum has a 'toString' that yields a printable representation.
+// If it yields 'char const *', then it's guaranteed to be a valid
+// pointer with unchanging contents throughout execution.
+//
+// Those that are OR-able together have the necessary operators
+// declared (ENUM_BITWISE_OPS), and their 'toString' uses bitwise-OR
+// syntax.
+
+#ifndef CC_FLAGS_H
+#define CC_FLAGS_H
+
+#include "str.h"     // string
+#include "macros.h"  // ENUM_BITWISE_OPS
+
+// ----------------------- TypeIntr ----------------------
+// type introducer keyword
+// NOTE: keep consistent with CompoundType::Keyword (cc_type.h)
+enum TypeIntr {
+  TI_STRUCT,
+  TI_CLASS,
+  TI_UNION,
+  TI_ENUM,
+  NUM_TYPEINTRS
+};
+
+extern char const * const typeIntrNames[NUM_TYPEINTRS];    // "struct", ...
+char const *toString(TypeIntr tr);
+char const *toXml(TypeIntr tr);
+void fromXml(TypeIntr &out, char const *str);
+
+
+// --------------------- CVFlags ---------------------
+// set: which of "const" and/or "volatile" is specified;
+// I leave the lower 8 bits to represent SimpleTypeId, so I can
+// freely OR them together during parsing;
+// values in common with UberModifier must line up
+enum CVFlags {
+  CV_NONE     = 0x0000,
+  CV_CONST    = 0x0400,
+  CV_VOLATILE = 0x0800,
+  CV_RESTRICT = 0x1000,     // C99
+  CV_OWNER    = 0x2000,     // experimental extension
+  CV_ALL      = 0x2C00,
+
+  CV_SHIFT_AMOUNT = 10,     // shift right this many bits before counting for cvFlagNames
+  NUM_CVFLAGS = 4           // # bits set to 1 in CV_ALL
+};
+
+extern char const * const cvFlagNames[NUM_CVFLAGS];      // 0="const", 1="volatile", 2="owner"
+string toString(CVFlags cv);
+string toXml(CVFlags cv);
+void fromXml(CVFlags &out, char const *str);
+
+ENUM_BITWISE_OPS(CVFlags, CV_ALL)
+
+// experiment: superset operator
+inline bool operator>= (CVFlags cv1, CVFlags cv2)
+  { return (cv1 & cv2) == cv2; }
+
+
+// ----------------------- DeclFlags ----------------------
+// These flags tell what keywords were attached to a variable when it
+// was declared.  They also reflect classifications of various kinds;
+// in particular, they distinguish the various roles that Variables
+// can play (variable, type, enumerator, etc.).  This can be used as
+// a convenient way to toss a new boolean into Variable, though it's
+// close to using all 32 bits, so it might need to be split.
+//
+// NOTE: Changes to this enumeration must be accompanied by
+// updates to 'declFlagNames' in cc_flags.cc.
+enum DeclFlags {
+  DF_NONE        = 0x00000000,
+
+  // syntactic declaration modifiers (UberModifiers)
+  DF_AUTO        = 0x00000001,
+  DF_REGISTER    = 0x00000002,
+  DF_STATIC      = 0x00000004,
+  DF_EXTERN      = 0x00000008,
+  DF_MUTABLE     = 0x00000010,
+  DF_INLINE      = 0x00000020,
+  DF_VIRTUAL     = 0x00000040,
+  DF_EXPLICIT    = 0x00000080,
+  DF_FRIEND      = 0x00000100,
+  DF_TYPEDEF     = 0x00000200,
+
+  DF_NAMESPACE   = 0x04000000,    // names of namespaces
+  DF_SOURCEFLAGS = 0x040003FF,    // all flags that come from keywords in the source
+
+  // semantic flags on Variables
+  DF_ENUMERATOR  = 0x00000400,    // true for values in an 'enum' (enumerators in the terminology of the C++ standard)
+  DF_GLOBAL      = 0x00000800,    // set for globals, unset for locals
+  DF_INITIALIZED = 0x00001000,    // true if has been declared with an initializer (or, for functions, with code)
+  DF_BUILTIN     = 0x00002000,    // true for e.g. __builtin_constant_p -- don't emit later
+  DF_PARAMETER   = 0x00010000,    // true if this is a function parameter or a handler "parameter"
+  DF_MEMBER      = 0x00080000,    // true for members of classes (data, static data, functions); *not* true for namespace members
+  DF_DEFINITION  = 0x00100000,    // set once we've seen this Variable's definition
+  DF_INLINE_DEFN = 0x00200000,    // set for inline function definitions on second pass of tcheck
+  DF_IMPLICIT    = 0x00400000,    // set for C++ implicit typedefs (if also DF_TYPEDEF),
+                                  // and implicit compiler-supplied member decls (if not DF_TYPEDEF)
+  DF_FORWARD     = 0x00800000,    // for syntax which only provides a forward declaration
+  DF_TEMPORARY   = 0x01000000,    // temporary variable introduced by elaboration
+  DF_EXTERN_C    = 0x08000000,    // name is marked extern "C"
+  DF_SELFNAME    = 0x10000000,    // section 9 para 2: name of class inside its own scope
+  DF_BOUND_TPARAM= 0x00004000,    // template parameter bound to a concrete argument
+  DF_TEMPL_PARAM = 0x20000000,    // template parameter (bound only to itself)
+  DF_USING_ALIAS = 0x40000000,    // this is a 'using' alias
+  DF_BITFIELD    = 0x80000000,    // this is a bitfield
+  DF_GNU_EXTERN_INLINE            // dsw: was extern inline (record since might be changed to static inline)
+                 = 0x02000000,
+
+  // These flags are used by the old (direct C -> VC) verifier client
+  // analysis; I will remove them once I finish transitioning to the
+  // VML-based verifier.  In a pinch, one of these values could be
+  // re-used for something that only occurs in C++ code, since the old
+  // verifier only works with C code.
+  DF_ADDRTAKEN   = 0x00008000,    // true if it's address has been (or can be) taken
+  DF_UNIVERSAL   = 0x00020000,    // universally-quantified variable
+  DF_EXISTENTIAL = 0x00040000,    // existentially-quantified
+
+  ALL_DECLFLAGS  = 0xFFFFFFFF,
+  NUM_DECLFLAGS  = 32             // # bits set to 1 in ALL_DECLFLAGS
+};
+
+extern char const * const declFlagNames[NUM_DECLFLAGS];      // 0="inline", 1="virtual", 2="friend", ..
+string toString(DeclFlags df);
+string toXml(DeclFlags df);
+void fromXml(DeclFlags &out, char const *str);
+
+
+ENUM_BITWISE_OPS(DeclFlags, ALL_DECLFLAGS)
+
+inline bool operator>= (DeclFlags df1, DeclFlags df2)
+  { return (df1 & df2) == df2; }
+
+// helper of possibly general purpose
+string bitmapString(int bitmap, char const * const *names,
+                    int numflags, char const *delim);
+
+
+// -------------------------- ScopeKind ------------------------------
+// What kind of (innermost) scope does a variable declaration appear in?
+enum ScopeKind {
+  SK_UNKNOWN,                     // hasn't been registered in a scope yet
+  SK_GLOBAL,                      // toplevel names
+  SK_PARAMETER,                   // parameter list
+  SK_FUNCTION,                    // includes local variables
+  SK_CLASS,                       // class member scope
+  SK_TEMPLATE_PARAMS,             // template paramter list (inside the '<' and '>')
+  SK_TEMPLATE_ARGS,               // bound template arguments, during instantiation
+  SK_NAMESPACE,                   // namespace
+  NUM_SCOPEKINDS
+};
+
+char const *toString(ScopeKind sk);
+
+
+// ------------------------- SimpleTypeId ----------------------------
+// C's built-in scalar types; the representation deliberately does
+// *not* imply any orthogonality of properties (like long vs signed);
+// separate query functions can determine such properties, or signal
+// when it is meaningless to query a given property of a given type
+// (like whether a floating-point type is unsigned)
+enum SimpleTypeId {
+  // types that exist in C++
+  ST_CHAR,
+  ST_UNSIGNED_CHAR,
+  ST_SIGNED_CHAR,
+  ST_BOOL,
+  ST_INT,
+  ST_UNSIGNED_INT,
+  ST_LONG_INT,
+  ST_UNSIGNED_LONG_INT,
+  ST_LONG_LONG,              // GNU/C99 extension
+  ST_UNSIGNED_LONG_LONG,     // GNU/C99 extension
+  ST_SHORT_INT,
+  ST_UNSIGNED_SHORT_INT,
+  ST_WCHAR_T,
+  ST_FLOAT,
+  ST_DOUBLE,
+  ST_LONG_DOUBLE,
+  ST_FLOAT_COMPLEX,          // GNU/C99 (see doc/complex.txt)
+  ST_DOUBLE_COMPLEX,         // GNU/C99
+  ST_LONG_DOUBLE_COMPLEX,    // GNU/C99
+  ST_FLOAT_IMAGINARY,        // C99
+  ST_DOUBLE_IMAGINARY,       // C99
+  ST_LONG_DOUBLE_IMAGINARY,  // C99
+  ST_VOID,                   // last concrete type (see 'isConcreteSimpleType')
+
+  // codes I use as a kind of implementation hack
+  ST_ELLIPSIS,               // used to encode vararg functions
+  ST_CDTOR,                  // "return type" for ctors and dtors
+  ST_ERROR,                  // this type is returned for typechecking errors
+  ST_DEPENDENT,              // depdenent on an uninstantiated template parameter type
+  ST_IMPLINT,                // implicit-int for K&R C
+  ST_NOTFOUND,               // delayed ST_ERROR
+
+  // for polymorphic built-in operators (cppstd 13.6)
+  ST_PROMOTED_INTEGRAL,      // int,uint,long,ulong
+  ST_PROMOTED_ARITHMETIC,    // promoted integral + float,double,longdouble
+  ST_INTEGRAL,               // has STF_INTEGER
+  ST_ARITHMETIC,             // every simple type except void
+  ST_ARITHMETIC_NON_BOOL,    // every simple type except void & bool
+  ST_ANY_OBJ_TYPE,           // any object (non-function, non-void) type
+  ST_ANY_NON_VOID,           // any type except void
+  ST_ANY_TYPE,               // any type, including functions and void
+
+  // for polymorphic builtin *return* ("PRET") type algorithms
+  ST_PRET_STRIP_REF,         // strip reference and volatileness from 1st arg
+  ST_PRET_PTM,               // ptr-to-member: union CVs, 2nd arg atType
+  ST_PRET_ARITH_CONV,        // "usual arithmetic conversions" (5 para 9) on 1st, 2nd arg
+  ST_PRET_FIRST,             // 1st arg type
+  ST_PRET_FIRST_PTR2REF,     // 1st arg ptr type -> ref type
+  ST_PRET_SECOND,            // 2nd arg type
+  ST_PRET_SECOND_PTR2REF,    // 2nd arg ptr type -> ref type
+
+  NUM_SIMPLE_TYPES,
+  ST_BITMASK = 0xFF          // for extraction for OR with CVFlags
+};
+
+// some flags that can be set for simple types
+enum SimpleTypeFlags {
+  STF_NONE       = 0x00,
+  STF_INTEGER    = 0x01,     // "integral type" (3.9.1 para 7)
+  STF_FLOAT      = 0x02,     // "floating point type" (3.9.1 para 8)
+  STF_PROM       = 0x04,     // can be destination of a promotion
+  STF_UNSIGNED   = 0x08,     // explicitly unsigned type
+  STF_ALL        = 0x0F,
+};
+//ENUM_BITWISE_OPS(SimpleTypeFlags, STF_ALL)   // wondering about problems with initializers..
+
+// info about each simple type
+struct SimpleTypeInfo {
+  char const *name;       // e.g. "unsigned char"
+  int reprSize;           // # of bytes to store
+  SimpleTypeFlags flags;  // various boolean attributes
+};
+
+bool isValid(SimpleTypeId id);                          // bounds check
+SimpleTypeInfo const &simpleTypeInfo(SimpleTypeId id);
+
+inline char const *simpleTypeName(SimpleTypeId id)  { return simpleTypeInfo(id).name; }
+inline int simpleTypeReprSize(SimpleTypeId id)      { return simpleTypeInfo(id).reprSize; }
+inline bool isIntegerType(SimpleTypeId id)          { return !!(simpleTypeInfo(id).flags & STF_INTEGER); }
+inline bool isFloatType(SimpleTypeId id)            { return !!(simpleTypeInfo(id).flags & STF_FLOAT); }
+inline bool isExplicitlyUnsigned(SimpleTypeId id)   { return !!(simpleTypeInfo(id).flags & STF_UNSIGNED); }
+
+inline bool isArithmeticType(SimpleTypeId id)    // 3.9.1 para 8
+  { return !!(simpleTypeInfo(id).flags & (STF_FLOAT | STF_INTEGER)); }
+
+// true if this is not one of the polymorphic types, impl. hacks, etc.
+inline bool isConcreteSimpleType(SimpleTypeId id)
+  { return id <= ST_VOID; }
+
+bool isComplexOrImaginary(SimpleTypeId id);
+
+inline char const *toString(SimpleTypeId id)        { return simpleTypeName(id); }
+char const *toXml(SimpleTypeId id);
+void fromXml(SimpleTypeId &out, char const *str);
+
+
+// ---------------------------- UnaryOp ---------------------------
+enum UnaryOp {
+  UNY_PLUS,      // +
+  UNY_MINUS,     // -
+  UNY_NOT,       // !
+  UNY_BITNOT,    // ~
+  NUM_UNARYOPS
+};
+
+inline bool validCode(UnaryOp op)
+  { return (unsigned)op < NUM_UNARYOPS; }
+
+extern char const * const unaryOpNames[NUM_UNARYOPS];     // "+", ...
+char const *toString(UnaryOp op);
+char const *toXml(UnaryOp op);
+void fromXml(UnaryOp &out, char const *str);
+
+
+// ------------------------- EffectOp -------------------------
+// unary operator with a side effect
+enum EffectOp {
+  EFF_POSTINC,   // ++ (postfix)
+  EFF_POSTDEC,   // -- (postfix)
+  EFF_PREINC,    // ++
+  EFF_PREDEC,    // --
+  NUM_EFFECTOPS
+};
+
+inline bool validCode(EffectOp op)
+  { return (unsigned)op < NUM_EFFECTOPS; }
+
+extern char const * const effectOpNames[NUM_EFFECTOPS];   // "++", ...
+char const *toString(EffectOp op);
+char const *toXml(EffectOp op);
+void fromXml(EffectOp &out, char const *str);
+bool isPostfix(EffectOp op);
+inline bool isPrefix(EffectOp op) { return !isPostfix(op); }
+
+
+// ------------------------ BinaryOp --------------------------
+enum BinaryOp {
+  // the relationals come first, and in this order, to correspond
+  // to RelationOp in predicate.ast (which is now in another
+  // repository entirely...)
+  BIN_EQUAL,     // ==
+  BIN_NOTEQUAL,  // !=
+  BIN_LESS,      // <
+  BIN_GREATER,   // >
+  BIN_LESSEQ,    // <=
+  BIN_GREATEREQ, // >=
+
+  BIN_MULT,      // *
+  BIN_DIV,       // /
+  BIN_MOD,       // %
+  BIN_PLUS,      // +
+  BIN_MINUS,     // -
+  BIN_LSHIFT,    // <<
+  BIN_RSHIFT,    // >>
+  BIN_BITAND,    // &
+  BIN_BITXOR,    // ^
+  BIN_BITOR,     // |
+  BIN_AND,       // &&
+  BIN_OR,        // ||
+  BIN_COMMA,     // ,
+
+  // gcc extensions
+  BIN_MINIMUM,   // <?
+  BIN_MAXIMUM,   // >?
+
+  // this exists only between parsing and typechecking
+  BIN_BRACKETS,  // []
+
+  BIN_ASSIGN,    // = (used to denote simple assignments in AST, as opposed to (say) "+=")
+
+  // C++ operators
+  BIN_DOT_STAR,    // .*
+  BIN_ARROW_STAR,  // ->*
+
+  // theorem prover extension
+  BIN_IMPLIES,     // ==>
+  BIN_EQUIVALENT,  // <==>
+
+  NUM_BINARYOPS
+};
+
+inline bool validCode(BinaryOp op)
+  { return (unsigned)op < NUM_BINARYOPS; }
+
+extern char const * const binaryOpNames[NUM_BINARYOPS];   // "*", ..
+char const *toString(BinaryOp op);
+char const *toXml(BinaryOp op);
+void fromXml(BinaryOp &out, char const *str);
+
+bool isPredicateCombinator(BinaryOp op);     // &&, ||, ==>, <==>
+bool isRelational(BinaryOp op);              // == thru >=
+bool isInequality(BinaryOp op);              // <, >, <=, >=
+bool isOverloadable(BinaryOp op);
+
+
+// ---------------- access control ------------
+// these are listed from least restrictive to most restrictive,
+// so < can be used to test for retriction level
+enum AccessKeyword {
+  AK_PUBLIC,
+  AK_PROTECTED,
+  AK_PRIVATE,
+  AK_UNSPECIFIED,      // not explicitly specified; typechecking changes it later
+
+  NUM_ACCESS_KEYWORDS
+};
+
+extern char const * const accessKeywordNames[NUM_ACCESS_KEYWORDS];
+char const *toString(AccessKeyword key);
+char const *toXml(AccessKeyword key);
+void fromXml(AccessKeyword &out, char const *str);
+
+// ---------------- cast keywords -------------
+enum CastKeyword {
+  CK_DYNAMIC,
+  CK_STATIC,
+  CK_REINTERPRET,
+  CK_CONST,
+
+  NUM_CAST_KEYWORDS
+};
+
+extern char const * const castKeywordNames[NUM_CAST_KEYWORDS];
+char const *toString(CastKeyword key);
+char const *toXml(CastKeyword key);
+void fromXml(CastKeyword &out, char const *str);
+
+
+// --------------- overloadable operators -------------
+// This is all of the unary and binary operators that are overloadable
+// in C++.  While it repeats operators that are also declared above in
+// some form, it makes the design more orthogonal: the operators above
+// are for use in *expressions*, while these are for use in operator
+// *names*, and there is not a 1-1 correspondence.  In a few places,
+// I've deliberately used different names (e.g. OP_STAR) than the name
+// of the operator above, to emphasize that there's less intrinsic
+// meaning to the operator names here.
+enum OverloadableOp {
+  // unary only
+  OP_NOT,          // !
+  OP_BITNOT,       // ~
+
+  // unary, both prefix and postfix; latter is declared as 2-arg function
+  OP_PLUSPLUS,     // ++
+  OP_MINUSMINUS,   // --
+
+  // unary or binary
+  OP_PLUS,         // +
+  OP_MINUS,        // -
+  OP_STAR,         // *
+  OP_AMPERSAND,    // &
+
+  // arithmetic
+  OP_DIV,          // /
+  OP_MOD,          // %
+  OP_LSHIFT,       // <<
+  OP_RSHIFT,       // >>
+  OP_BITXOR,       // ^
+  OP_BITOR,        // |
+
+  // arithmetic+assignment
+  OP_ASSIGN,       // =
+  OP_PLUSEQ,       // +=
+  OP_MINUSEQ,      // -=
+  OP_MULTEQ,       // *=
+  OP_DIVEQ,        // /=
+  OP_MODEQ,        // %=
+  OP_LSHIFTEQ,     // <<=
+  OP_RSHIFTEQ,     // >>=
+  OP_BITANDEQ,     // &=
+  OP_BITXOREQ,     // ^=
+  OP_BITOREQ,      // |=
+
+  // comparison
+  OP_EQUAL,        // ==
+  OP_NOTEQUAL,     // !=
+  OP_LESS,         // <
+  OP_GREATER,      // >
+  OP_LESSEQ,       // <=
+  OP_GREATEREQ,    // >=
+
+  // logical
+  OP_AND,          // &&
+  OP_OR,           // ||
+
+  // arrows
+  OP_ARROW,        // ->
+  OP_ARROW_STAR,   // ->*
+
+  // misc
+  OP_BRACKETS,     // []
+  OP_PARENS,       // ()
+  OP_COMMA,        // ,
+  OP_QUESTION,     // ?:  (not overloadable, but resolution used nonetheless)
+
+  // gcc extensions
+  OP_MINIMUM,      // <?
+  OP_MAXIMUM,      // >?
+
+  NUM_OVERLOADABLE_OPS
+};
+
+inline bool validCode(OverloadableOp op)
+  { return (unsigned)op < NUM_OVERLOADABLE_OPS; }
+
+extern char const * const overloadableOpNames[NUM_OVERLOADABLE_OPS];    // "!", ...
+char const *toString(OverloadableOp op);
+char const *toXml(OverloadableOp op);
+void fromXml(OverloadableOp &out, char const *str);
+
+// yields things like "operator+"
+extern char const * const operatorFunctionNames[NUM_OVERLOADABLE_OPS];
+
+// map from the other operator sets into the operator name that
+// would be used to overload it
+OverloadableOp toOverloadableOp(UnaryOp op);
+OverloadableOp toOverloadableOp(EffectOp op);
+OverloadableOp toOverloadableOp(BinaryOp op, bool isAssignment=false);
+
+
+// -------------------- uber modifiers -----------------
+// the uber modifiers are a superset of all the keywords that
+// can appear in a type specifier; see cc.gr, nonterm DeclSpecifier
+enum UberModifiers {
+  UM_NONE         = 0,
+
+  // decl flags
+  UM_AUTO         = 0x00000001,
+  UM_REGISTER     = 0x00000002,
+  UM_STATIC       = 0x00000004,
+  UM_EXTERN       = 0x00000008,
+  UM_MUTABLE      = 0x00000010,
+
+  UM_INLINE       = 0x00000020,
+  UM_VIRTUAL      = 0x00000040,
+  UM_EXPLICIT     = 0x00000080,
+
+  UM_FRIEND       = 0x00000100,
+  UM_TYPEDEF      = 0x00000200,
+
+  UM_DECLFLAGS    = 0x000003FF,
+
+  // cv-qualifier
+  UM_CONST        = 0x00000400,
+  UM_VOLATILE     = 0x00000800,
+  UM_RESTRICT     = 0x00001000,    // C99
+
+  UM_CVFLAGS      = 0x00001C00,
+
+  // type keywords
+  UM_WCHAR_T      = 0x00002000,
+  UM_BOOL         = 0x00004000,
+  UM_SHORT        = 0x00008000,
+  UM_INT          = 0x00010000,
+  UM_LONG         = 0x00020000,
+  UM_SIGNED       = 0x00040000,
+  UM_UNSIGNED     = 0x00080000,
+  UM_FLOAT        = 0x00100000,
+  UM_DOUBLE       = 0x00200000,
+  UM_VOID         = 0x00400000,
+  UM_LONG_LONG    = 0x00800000,    // GNU extension
+  UM_CHAR         = 0x01000000,    // large value b/c got bumped by UM_RESTRICT
+  UM_COMPLEX      = 0x02000000,    // C99/GNU
+  UM_IMAGINARY    = 0x04000000,    // C99
+
+  UM_TYPEKEYS     = 0x07FFE000,
+
+  UM_ALL_FLAGS    = 0x07FFFFFF,
+  UM_NUM_FLAGS    = 27             // # bits set in UM_ALL_FLAGS
+};
+
+// string repr.
+extern char const * const uberModifierNames[UM_NUM_FLAGS];
+string toString(UberModifiers m);
+
+// select particular subsets
+inline DeclFlags uberDeclFlags(UberModifiers m)
+  { return (DeclFlags)(m & UM_DECLFLAGS); }
+inline CVFlags uberCVFlags(UberModifiers m)
+  { return (CVFlags)(m & UM_CVFLAGS); }
+
+// two more related functions, uberSimpleType and uberCombine,
+// are declared in ccparse.h
+
+// I do *not* define operators to combine the flags with | and &
+// because I want those operations to always be done by dedicated
+// functions like 'uberDeclFlags'
+
+
+// ------------------ special literal expressions ----------------
+// some literal expressions get special treatment; this enum
+// can be used to identify which kind of special expression
+// something is, or that it is not special
+enum SpecialExpr {
+  SE_NONE,          // not special
+  SE_ZERO,          // integer literal 0
+  SE_STRINGLIT,     // a string literal
+  NUM_SPECIAL_EXPRS
+};
+
+char const *toString(SpecialExpr se);
+
+
+#endif // CC_FLAGS_H

Added: vendor/elsa/current/elsa/cc_lang.cc
===================================================================
--- vendor/elsa/current/elsa/cc_lang.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_lang.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,339 @@
+// cc_lang.cc            see license.txt for copyright and terms of use
+// code for cc_lang.h
+
+#include "cc_lang.h"     // this module
+#include "trace.h"       // tracingSys
+#include "xassert.h"     // xfailure
+
+#include <string.h>      // memset
+
+
+static void setWarning(Bool3 &b, bool enable)
+{
+  if (enable) {
+    if (b == B3_TRUE) {
+      b = B3_WARN;       // accept with warning
+    }
+  }
+  else {
+    if (b == B3_WARN) {
+      b = B3_TRUE;       // accept silently
+    }
+  }
+}
+
+void CCLang::setAllWarnings(bool enable)
+{
+  setWarning(allowImplicitFunctionDecls, enable);
+  setWarning(allowImplicitIntForOperators, enable);
+  setWarning(allowQualifiedMemberDeclarations, enable);
+  setWarning(allowModifiersWithTypedefNames, enable);
+  setWarning(allowAnonymousStructs, enable);
+  setWarning(allowGcc2HeaderSyntax, enable);
+  setWarning(allowRepeatedTypeSpecifierKeywords, enable);
+  setWarning(allowCVAppliedToFunctionTypes, enable);
+  setWarning(allowDefinitionsInWrongScopes, enable);
+  setWarning(allowDuplicateParameterNames, enable);
+  setWarning(allowExplicitSpecWithoutParams, enable);
+  setWarning(allowStaticAfterNonStatic, enable);
+}
+
+
+// ---------------------- ANSI and K&R C ----------------------
+void CCLang::ANSI_C89()
+{
+  // just in case I forget to initialize something....
+  memset(this, 0, sizeof(*this));
+
+  isCplusplus = false;
+  declareGNUBuiltins = false;
+
+  tagsAreTypes = false;
+  recognizeCppKeywords = false;
+  implicitFuncVariable = false;
+  gccFuncBehavior = GFB_none;
+  noInnerClasses = true;
+  uninitializedGlobalDataIsCommon = true;
+  emptyParamsMeansNoInfo = true;
+  strictArraySizeRequirements = false;
+  assumeNoSizeArrayHasSizeOne = false;
+  allowOverloading = false;
+  compoundSelfName = false;
+  allowImplicitFunctionDecls = B3_TRUE;        // C89 does not require prototypes
+  allowImplicitInt = true;
+  allowDynamicallySizedArrays = false;
+  allowIncompleteEnums = false;
+  allowMemberWithClassName = true;
+  nonstandardAssignmentOperator = false;
+  allowExternCThrowMismatch = true;
+  allowImplicitIntForMain = false;
+  predefined_Bool = false;
+
+  handleExternInlineSpecially = false;
+  inlineImpliesStaticLinkage = false;
+  stringLitCharsAreConst = false; // Didn't check C89; C99 says they are non-const
+
+  // C99 spec: Section 6.5.4, footnote 85: "A cast does not yield an lvalue".
+  lvalueFlowsThroughCast = false;
+
+  restrictIsAKeyword = false;
+
+  allowNewlinesInStringLits = false;
+  allowImplicitIntForOperators = B3_FALSE;
+  allowQualifiedMemberDeclarations = B3_FALSE;
+  allowModifiersWithTypedefNames = B3_FALSE;
+  allowAnonymousStructs = B3_FALSE;
+
+  gcc2StdEqualsGlobalHacks = false;
+  allowGcc2HeaderSyntax = B3_FALSE;
+  allowRepeatedTypeSpecifierKeywords = B3_FALSE;
+  allowCVAppliedToFunctionTypes = B3_FALSE;
+  allowDefinitionsInWrongScopes = B3_FALSE;
+  allowDuplicateParameterNames = B3_FALSE;
+  allowExplicitSpecWithoutParams = B3_FALSE;
+  allowStaticAfterNonStatic =  B3_WARN;
+}
+
+void CCLang::KandR_C()
+{
+  ANSI_C89();
+
+  allowImplicitInt = true;
+}
+
+void CCLang::ANSI_C99_extensions()
+{
+  implicitFuncVariable = true;
+  predefined_Bool = true;
+  restrictIsAKeyword = true;
+}
+
+void CCLang::ANSI_C99()
+{
+  ANSI_C89();
+
+  // new features
+  ANSI_C99_extensions();
+
+  // removed C89 features
+  allowImplicitInt = false;
+  allowImplicitFunctionDecls = B3_FALSE;
+}
+
+
+// ------------------------ GNU C ------------------------
+void CCLang::GNU_C_extensions()
+{
+  gccFuncBehavior = GFB_string;
+  allowDynamicallySizedArrays = true;
+  assumeNoSizeArrayHasSizeOne = true;
+  handleExternInlineSpecially = true;
+  declareGNUBuiltins = true;
+
+  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Lvalues.html
+  lvalueFlowsThroughCast = true;
+
+  allowNewlinesInStringLits = true;
+
+  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Incomplete-Enums.html
+  allowIncompleteEnums = true;
+
+  allowModifiersWithTypedefNames = B3_TRUE;
+  allowAnonymousStructs = B3_TRUE;
+  allowRepeatedTypeSpecifierKeywords = B3_TRUE;
+  allowCVAppliedToFunctionTypes = B3_TRUE;
+}
+
+void CCLang::GNU_C()
+{
+  ANSI_C89();
+
+  ANSI_C99_extensions();
+  GNU_C_extensions();
+}
+
+void CCLang::GNU_KandR_C()
+{
+  KandR_C();
+
+  GNU_C_extensions();
+
+  // this seems wrong, but Oink's tests want it this way...
+  ANSI_C99_extensions();
+}
+
+void CCLang::GNU2_KandR_C()
+{
+  GNU_KandR_C();
+
+  // dsw: seems to not be true for gcc 2.96 at least
+  predefined_Bool = false;
+}
+
+
+// ---------------------------- C++ ----------------------------
+void CCLang::ANSI_Cplusplus()
+{
+  // just in case...
+  memset(this, 0, sizeof(*this));
+
+  isCplusplus = true;
+  declareGNUBuiltins = false;
+
+  tagsAreTypes = true;
+  recognizeCppKeywords = true;
+  implicitFuncVariable = false;
+  gccFuncBehavior = GFB_none;
+  noInnerClasses = false;
+  uninitializedGlobalDataIsCommon = false;
+  emptyParamsMeansNoInfo = false;
+
+  strictArraySizeRequirements = true;
+  assumeNoSizeArrayHasSizeOne = false;
+
+  allowOverloading = true;
+  compoundSelfName = true;
+
+  allowImplicitFunctionDecls = B3_FALSE;
+  allowImplicitInt = false;
+  allowDynamicallySizedArrays = false;
+  allowIncompleteEnums = false;
+  allowMemberWithClassName = false;
+
+  // indeed this is nonstandard but everyone seems to do it this way ...
+  nonstandardAssignmentOperator = true;
+
+  allowExternCThrowMismatch = false;
+  allowImplicitIntForMain = false;
+
+  predefined_Bool = false;
+  handleExternInlineSpecially = false;
+  inlineImpliesStaticLinkage = true;
+  stringLitCharsAreConst = true; // Cppstd says they are const.
+  lvalueFlowsThroughCast = false;
+  restrictIsAKeyword = false;
+
+  allowNewlinesInStringLits = false;
+  allowImplicitIntForOperators = B3_FALSE;
+  allowQualifiedMemberDeclarations = B3_FALSE;
+  allowModifiersWithTypedefNames = B3_FALSE;
+  allowAnonymousStructs = B3_FALSE;
+
+  gcc2StdEqualsGlobalHacks = false;
+  allowGcc2HeaderSyntax = B3_FALSE;
+  allowRepeatedTypeSpecifierKeywords = B3_FALSE;
+  allowCVAppliedToFunctionTypes = B3_FALSE;
+  allowDefinitionsInWrongScopes = B3_FALSE;
+  allowDuplicateParameterNames = B3_FALSE;
+  allowExplicitSpecWithoutParams = B3_FALSE;
+  allowStaticAfterNonStatic =  B3_WARN;
+}
+
+void CCLang::GNU_Cplusplus()
+{
+  ANSI_Cplusplus();
+
+  implicitFuncVariable = true;
+  gccFuncBehavior = GFB_variable;
+
+  // is this really right?  Oink tests it like it is ...
+  allowDynamicallySizedArrays = true;
+  strictArraySizeRequirements = false;
+
+  allowMemberWithClassName = true;
+  allowExternCThrowMismatch = true;
+  allowImplicitIntForMain = true;
+
+  declareGNUBuiltins = true;
+
+  allowQualifiedMemberDeclarations = B3_TRUE;
+  allowAnonymousStructs = B3_TRUE;
+
+  gcc2StdEqualsGlobalHacks = true;
+  allowGcc2HeaderSyntax = B3_TRUE;
+  allowDefinitionsInWrongScopes = B3_TRUE;
+  allowDuplicateParameterNames = B3_TRUE;
+  allowExplicitSpecWithoutParams = B3_TRUE;
+}
+
+
+// -------------------------- MSVC ---------------------
+void CCLang::MSVC_bug_compatibility()
+{
+  allowImplicitIntForOperators = B3_TRUE;
+  allowAnonymousStructs = B3_TRUE;
+}
+
+
+// -------------------------- handleExternInlineSpecially ---------------------
+
+// dsw: how to interpret handleExternInlineSpecially
+bool handleExternInline_asPrototype() {
+  return tracingSys("handleExternInline-asPrototype");
+}
+bool handleExternInline_asWeakStaticInline() {
+  return !tracingSys("handleExternInline-asPrototype");
+}
+
+
+// -------------------------- toString ---------------------
+
+string CCLang::toString() {
+  stringBuilder str;
+#define PRINT(X) str << #X " " << X << '\n'
+  PRINT(isCplusplus);
+  PRINT(declareGNUBuiltins);
+  PRINT(tagsAreTypes);
+  PRINT(recognizeCppKeywords);
+  PRINT(implicitFuncVariable);
+
+  // an exception since it is not a bool or a 3-way bool:
+  str << "gccFuncBehavior ";
+  switch(gccFuncBehavior) {
+  default: xfailure("illegal gccFuncBehavior");
+  case GFB_none: str << "GFB_none"; break;
+  case GFB_string: str << "GFB_string"; break;
+  case GFB_variable: str << "GFB_variable"; break;
+  }
+  str << '\n';
+
+  PRINT(noInnerClasses);
+  PRINT(uninitializedGlobalDataIsCommon);
+  PRINT(emptyParamsMeansNoInfo);
+  PRINT(strictArraySizeRequirements);
+  PRINT(assumeNoSizeArrayHasSizeOne);
+  PRINT(allowOverloading);
+  PRINT(compoundSelfName);
+  PRINT(allowImplicitFunctionDecls);
+  PRINT(allowImplicitInt);
+  PRINT(allowDynamicallySizedArrays);
+  PRINT(allowIncompleteEnums);
+  PRINT(allowMemberWithClassName);
+  PRINT(nonstandardAssignmentOperator);
+  PRINT(allowExternCThrowMismatch);
+  PRINT(allowImplicitIntForMain);
+  PRINT(predefined_Bool);
+  PRINT(handleExternInlineSpecially);
+  PRINT(inlineImpliesStaticLinkage);
+  PRINT(stringLitCharsAreConst);
+  PRINT(lvalueFlowsThroughCast);
+  PRINT(restrictIsAKeyword);
+  PRINT(allowNewlinesInStringLits);
+  PRINT(allowImplicitIntForOperators);
+  PRINT(allowQualifiedMemberDeclarations);
+  PRINT(allowModifiersWithTypedefNames);
+  PRINT(allowAnonymousStructs);
+  PRINT(gcc2StdEqualsGlobalHacks);
+  PRINT(allowGcc2HeaderSyntax);
+  PRINT(allowRepeatedTypeSpecifierKeywords);
+  PRINT(allowCVAppliedToFunctionTypes);
+  PRINT(allowDefinitionsInWrongScopes);
+  PRINT(allowDuplicateParameterNames);
+  PRINT(allowExplicitSpecWithoutParams);
+  PRINT(allowStaticAfterNonStatic);
+#undef PRINT
+  return str;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc_lang.h
===================================================================
--- vendor/elsa/current/elsa/cc_lang.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_lang.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,285 @@
+// cc_lang.h            see license.txt for copyright and terms of use
+// language options that the parser (etc.) is sensitive to
+
+// a useful reference:
+//   Incompatibilities Between ISO C and ISO C++
+//   David R. Tribble
+//   http://david.tribble.com/text/cdiffs.htm
+
+#ifndef CCLANG_H
+#define CCLANG_H
+
+#include "str.h"                // string
+
+
+// This type is used for options that nominally either allow or
+// disallow some syntax, but can also trigger a warning.  Values of
+// this type are intended to be tested like booleans in most places.
+enum Bool3 {
+  B3_FALSE = 0,      // syntax not allowed
+  B3_TRUE = 1,       // accepted silently
+  B3_WARN = 2,       // accept with a warning
+};
+
+
+// NOTE: be sure to add a line to the body of toString() if you add
+// another flag
+class CCLang {
+public:
+  // catch-call for behaviors that are unique to C++ but aren't
+  // enumerated above; these behaviors are candidates for being split
+  // out as separate flags, but there currently is no need
+  bool isCplusplus;
+
+  // declare the various GNU __builtin functions; see
+  // Env::addGNUBuiltins in gnu.cc
+  bool declareGNUBuiltins;
+
+  // when this is true, and the parser sees "struct Foo { ... }",
+  // it will pretend it also saw "typedef struct Foo Foo;" -- i.e.,
+  // the structure (or class) tag name is treated as a type name
+  // by itself
+  bool tagsAreTypes;
+
+  // when true, recognize C++ keywords in input stream
+  bool recognizeCppKeywords;
+
+  // when true, every function body gets an implicit
+  //   static char const __func__[] = "function-name";
+  // declaration just inside the opening brace, where function-name is
+  // the name of the function; this is a C99 feature (section 6.4.2.2)
+  bool implicitFuncVariable;
+
+  // behavior of gcc __FUNCTION__ and __PRETTY_FUNCTION__
+  // see also
+  //   http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Function-Names.html
+  //   http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC101
+  enum GCCFuncBehavior {
+    GFB_none,              // ordinary symbols
+    GFB_string,            // string literal (they concatenate!)
+    GFB_variable,          // variables, like __func__
+  } gccFuncBehavior;
+
+  // when true, and we see a class declaration inside something,
+  // pretend it was at toplevel scope anyway; this also applies to
+  // enums, enumerators and typedefs
+  //
+  // dsw: I find that having boolean variables that are in the
+  // negative sense is usually a mistake.  I would reverse the sense
+  // of this one.
+  //
+  // sm: The 'no' is a little misleading.  In the 'false' case,
+  // syntax reflects semantics naturally; only in the 'true' case
+  // is something unusual going on.  A positive-sense name might be
+  // the unwieldy 'turnApparentlyInnerClassesIntoOuterClasses'.
+  bool noInnerClasses;
+
+  // when true, an uninitialized global data object is typechecked as
+  // a common symbol ("C" in the nm(1) manpage) instead of a bss
+  // symbol ("B").  This means that the following is not an error:
+  //   int a; int a;
+  // gcc seems to operate as if this is true, whereas g++ not.
+  //
+  // these are the so-called "tentative" definitions of C; the flag
+  // is somewhat misnamed
+  bool uninitializedGlobalDataIsCommon;
+
+  // when true, if a function has an empty parameter list then it is
+  // treated as supplying no parameter information (C99 6.7.5.3 para 14)
+  bool emptyParamsMeansNoInfo;
+
+  // when true, require all array sizes to be positive; when false,
+  // 0-length arrays are allowed as class/struct fields
+  //
+  // dsw: UPDATE: allow them anywhere; needed for linux kernel
+  bool strictArraySizeRequirements;
+
+  // when true, assume arrays with no size are of size 1 and issue a
+  // warning
+  //
+  // TODO: This is not the proper way to handle C's rules for arrays.
+  // See C99 6.9.2p2, 6.9.2e5, 6.7p7 and 6.7p16.  What we have now
+  // is just a hack for the sake of expedience.
+  bool assumeNoSizeArrayHasSizeOne;
+
+  // when true, we allow overloaded function declarations (same name,
+  // different signature)
+  bool allowOverloading;
+
+  // when true, to every compound type add the name of the type itself
+  bool compoundSelfName;
+
+  // when true, allow a function call to a function that has never
+  // been declared, implicitly declaring the function in the global
+  // scope; this is for C89 (and earlier) support
+  Bool3 allowImplicitFunctionDecls;
+
+  // when true, allow function definitions that omit any return type
+  // to implicitly return 'int'.
+  bool allowImplicitInt;
+
+  // GNU extension: when true, allow local variable arrays to have
+  // sizes that are not constant
+  bool allowDynamicallySizedArrays;
+
+  // GCC extension: when true, you can say things like 'enum Foo;' and
+  // it declares that an enum called Foo will be defined later
+  bool allowIncompleteEnums;
+
+  // C language, and GNU extension for C++: allow a class to have a
+  // member that has the same name as the class
+  bool allowMemberWithClassName;
+
+  // every C++ compiler I have does overload resolution of operator=
+  // differently from what is specified in the standard; this flag
+  // causes Elsa to do the same
+  bool nonstandardAssignmentOperator;
+
+  // permit prototypes to have mismatching exception specs if the
+  // function is extern "C" (TODO: provide more documentation)
+  bool allowExternCThrowMismatch;
+
+  // allow main() to be declared/defined with an implicit 'int'
+  bool allowImplicitIntForMain;
+
+  // when true, "_Bool" is a built-in type keyword (C99)
+  bool predefined_Bool;
+
+  // dsw: when true, a function definition with 'extern' and 'inline'
+  // keywords is handled specially.  How exactly is a function of the
+  // optimization conditions; these are not language conditions so
+  // they are handed by a tracing flag rather than by a language flag.
+  // The tracing flag is 'handleExternInline-asPrototype'.  If true,
+  // then we simply ignore the body of an extern inline.  When false
+  // we handle extern inlines as weak static inlines: the 'extern
+  // inline' is converted to 'static inline' and if another definition
+  // in the translation unit is found, it replaces that of the extern
+  // inline.  These two modes seem to reflect the behavior of gcc
+  // 3.4.6 when optimizations are off and on respectively.
+  bool handleExternInlineSpecially;
+
+  // quarl: whether "inline" implies static linkage.  True in C++ but not in
+  // C.
+  bool inlineImpliesStaticLinkage;
+
+  // dsw: C99 std 6.4.5p5: "For character string literals, the array
+  // elements have type char...."; Cppstd 2.13.4p1: "An ordinary
+  // string literal has type "array of const char" and static storage
+  // duration"; But empirical results show that even in C++, gcc makes
+  // string literals arrays of (nonconst) chars.
+  bool stringLitCharsAreConst;
+
+  // if the argument to a cast is an lvalue, make the cast expression
+  // have lvalue type
+  bool lvalueFlowsThroughCast;
+
+  // when true, 'restrict' is a keyword (note that __restrict and
+  // __restrict__ are always keywords)
+  bool restrictIsAKeyword;
+
+  // ---- bug compatibility flags ----
+  // gcc-2 bug compatibility: permit string literals to contain
+  // (unescaped) newline characters in them
+  bool allowNewlinesInStringLits;
+
+  // MSVC bug compatibility: allow implicit int for operator functions
+  Bool3 allowImplicitIntForOperators;
+
+  // gcc bug compatibility: allow qualified member declarations
+  Bool3 allowQualifiedMemberDeclarations;
+
+  // gcc bug compatibility: allow typedef names to combine with
+  // certain type keywords, e.g., "u32 long", in/gnu/dC0014.c;
+  // eventually, once the client codes have been fixed, it would be
+  // good to delete this, since it involves some extra grammar
+  // productions
+  Bool3 allowModifiersWithTypedefNames;
+
+  // gcc/msvc bug/extension compatibility: allow anonymous structs;
+  // see doc/anon-structs.txt
+  Bool3 allowAnonymousStructs;
+
+  // gcc-2 bug compatibility: In gcc-2, namespace "std::" is actually
+  // an alias for the global scope.  This flag turns on some hacks
+  // to accept some code preprocessed with gcc-2 headers.
+  bool gcc2StdEqualsGlobalHacks;
+
+  // more gcc-2 bug compat: The gcc-2 headers contain some invalid
+  // syntax.  Conceptually, this flag recognizes the invalid syntax
+  // and transforms it into valid syntax for Elsa.  Actually, it just
+  // enables some hacks that have similar effect.
+  Bool3 allowGcc2HeaderSyntax;
+
+  // gcc C-mode bug compat: accept duplicate type specifier keywords
+  // like 'int int'
+  Bool3 allowRepeatedTypeSpecifierKeywords;
+
+  // gcc C-mode bug compat: silently allow const/volatile to be
+  // applied to function types via typedefs; it's meaningless
+  Bool3 allowCVAppliedToFunctionTypes;
+
+  // gcc bug compat: gcc does not enforce the rule that a definition
+  // must be in a scope that encloses the declaration
+  Bool3 allowDefinitionsInWrongScopes;
+
+  // gcc bug compat: in C++ mode, gcc allows prototype parameters to
+  // have the same name (in/gnu/bugs/gb0011.cc)
+  Bool3 allowDuplicateParameterNames;
+
+  // gcc bug compat: gcc does not require "template <>" is some
+  // cases for explicit specializations (in/gnu/bugs/gb0012.cc)
+  Bool3 allowExplicitSpecWithoutParams;
+
+  // quarl: declaring (or defining) a function as static after previously
+  // declaring it without 'static'. gcc-3.4 allows with warning; gcc-4.0
+  // disallows.
+  Bool3 allowStaticAfterNonStatic;
+
+private:     // funcs
+  void setAllWarnings(bool enable);
+
+public:      // funcs
+  CCLang() { ANSI_C89(); }
+
+  // set any B3_TRUE to B3_WARN
+  void enableAllWarnings() { setAllWarnings(true); }
+
+  // set any B3_WARN to B3_TRUE
+  void disableAllWarnings() { setAllWarnings(false); }
+
+  // the following are additive incremental
+
+  // enable gcc C features
+  void GNU_C_extensions();
+
+  // enable C99 features
+  void ANSI_C99_extensions();
+
+  // enable MSVC bug compatibility
+  void MSVC_bug_compatibility();
+
+  // The predefined settings below are something of a best-effort at
+  // reasonable starting configurations.  Every function below sets
+  // *all* of the flags; they are not incremental.  Users are
+  // encouraged to explicitly set fields after activating a predefined
+  // setting to get a specific setting.
+
+  void KandR_C();           // settings for K&R C
+  void ANSI_C89();          // settings for ANSI C89
+  void ANSI_C99();          // settings for ANSI C99
+  void GNU_C();             // settings for GNU C
+  void GNU_KandR_C();       // GNU 3.xx C + K&R compatibility
+  void GNU2_KandR_C();      // GNU 2.xx C + K&R compatibility
+
+  void ANSI_Cplusplus();    // settings for ANSI C++ 98
+  void GNU_Cplusplus();     // settings for GNU C++
+
+  // dsw: I regret having to mention all of the flags yet one more
+  // place, however I think I need this.
+  string toString();
+};
+
+bool handleExternInline_asPrototype();
+bool handleExternInline_asWeakStaticInline();
+
+#endif // CCLANG_H

Added: vendor/elsa/current/elsa/cc_print.ast
===================================================================
--- vendor/elsa/current/elsa/cc_print.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_print.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,142 @@
+// cc_print.ast            see license.txt for copyright and terms of use
+// extension module for cc.ast that supports printing C++
+// syntax from the AST
+
+verbatim {
+  class PrintEnv;               // cc_print.h
+  class CodeOutStream;          // cc_print.h
+}
+
+
+class TranslationUnit {
+  // This is the toplevel entry point to the pretty printer.
+  public void print(PrintEnv &env);
+}
+
+
+class TopForm {
+  pure_virtual void print(PrintEnv &env);
+}
+
+
+class Function {
+  public void print(PrintEnv &env);
+}
+
+
+class Declaration {
+  public void print(PrintEnv &env);
+}
+
+
+class ASTTypeId {
+  public void print(PrintEnv &env);
+}
+
+
+class PQName {
+  pure_virtual void print(PrintEnv &env);
+}
+
+verbatim {
+  // so clients outside cc_print.cc can print these lists; this
+  // does *not* print the surrounding angle brackets
+  void printTemplateArgumentFakeList(PrintEnv &env, FakeList<TemplateArgument> *args);
+}
+
+
+class TypeSpecifier {
+  pure_virtual void print(PrintEnv &env);
+}
+
+
+class BaseClassSpec {
+  public void print(PrintEnv &env);
+}
+
+
+class Member {
+  pure_virtual void print(PrintEnv &env);
+}
+
+
+class Enumerator {
+  public void print(PrintEnv &env);
+}
+
+
+class Declarator {
+  public void print(PrintEnv &env);
+}
+
+
+class IDeclarator {
+  public void print(PrintEnv &env);
+}
+
+
+class ExceptionSpec {
+  public void print(PrintEnv &env);
+}
+
+
+class Statement {
+  public void print(PrintEnv &env);
+  pure_virtual void iprint(PrintEnv &env);
+}
+
+
+class Condition {
+  pure_virtual void print(PrintEnv &env);
+}
+
+
+class Handler {
+  public void print(PrintEnv &env);
+}
+
+
+class FullExpression {
+  public void print(PrintEnv &env);
+}
+
+
+class Expression {
+  public void print(PrintEnv &env);
+  pure_virtual void iprint(PrintEnv &env);
+
+  public string exprToString() const;
+  public string asString() const { return exprToString(); };
+}
+
+verbatim {                               
+  // for debugging
+  char *expr_toString(Expression const *e);
+  int expr_debugPrint(Expression const *e);
+}
+
+
+class Initializer {
+  pure_virtual void print(PrintEnv &env);
+}
+
+
+class TemplateDeclaration {
+  public void print(PrintEnv &env);
+  pure_virtual void iprint(PrintEnv &env);
+}
+
+
+class TemplateParameter {
+  pure_virtual void print(PrintEnv &env);
+}
+
+
+class TemplateArgument {
+  pure_virtual void print(PrintEnv &env);
+}
+
+
+class NamespaceDecl {
+  pure_virtual void print(PrintEnv &env);
+}

Added: vendor/elsa/current/elsa/cc_print.cc
===================================================================
--- vendor/elsa/current/elsa/cc_print.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_print.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2212 @@
+// cc_print.cc            see license.txt for copyright and terms of use
+// code for cc_print.h
+
+// Adapted from cc_tcheck.cc by Daniel Wilkerson dsw at cs.berkeley.edu
+
+#include "cc_print.h"           // this module
+#include "trace.h"              // trace
+#include "strutil.h"            // string utilities
+
+#include <stdlib.h>             // getenv
+
+
+// set this environment variable to see the twalk_layer debugging
+// output
+OStreamOutStream treeWalkOut0(cout);
+TreeWalkOutStream treeWalkOut(treeWalkOut0, getenv("TWALK_VERBOSE"));
+
+// This is a dummy global so that this file will compile both in
+// default mode and in qualifiers mode.
+class dummyType;                // This does nothing.
+dummyType *ql;
+string toString(class dummyType*) {return "";}
+
+// **** class CodeOutStream
+
+CodeOutStream::~CodeOutStream()
+{
+  if (bufferedNewlines) {
+    cout << "**************** ERROR.  "
+         << "You called my destructor before making sure all the buffered newlines\n"
+         << "were flushed (by, say, calling finish())\n";
+  }
+}
+
+// // write N spaces to OUT.
+// static inline
+// void writeSpaces(OutStream &out, size_t n)
+// {
+//   static char const spaces[] =
+//     "                                                  "
+//     "                                                  "
+//     "                                                  "
+//     "                                                  ";
+
+//   static size_t const max_spaces = sizeof spaces - 1;
+
+//   // If we're printing more than this many spaces it's pretty useless anyway,
+//   // since it's only for human viewing pleasure!
+//   while (n > max_spaces) {
+//     out.write(spaces, max_spaces);
+//     n -= max_spaces;
+//   }
+//   out.write(spaces, n);
+// }
+
+// TODO: add write(char*,int len) methods to OutStream et al so we can do
+// 'printIndentation' efficiently
+void CodeOutStream::printIndentation(int n) {
+  // writeSpaces(out, n);
+  for (int i=0; i<n; ++i) {
+    out << ' ' << ' ';
+  }
+}
+
+void CodeOutStream::printWhileInsertingIndentation(int n, rostring message) {
+  int len = message.length();
+  for(int i=0; i<len; ++i) {
+    char c = message[i];
+    out << c;
+    if (c == '\n') printIndentation(n);
+  }
+}
+
+void CodeOutStream::finish()
+{
+  // NOTE: it is probably an error if depth is ever > 0 at this point.
+  //      printf("BUFFERED NEWLINES: %d\n", bufferedNewlines);
+  stringBuilder s;
+  for(;bufferedNewlines>1;bufferedNewlines--) s << "\n";
+  printWhileInsertingIndentation(depth,s);
+  xassert(bufferedNewlines == 1 || bufferedNewlines == 0);
+  if (bufferedNewlines) {
+    bufferedNewlines--;
+    out << '\n';                // don't indent after last one
+  }
+  flush();
+}
+
+CodeOutStream & CodeOutStream::operator << (ostream& (*manipfunc)(ostream& outs))
+{
+  // sm: just assume it's "endl"; the only better thing I could
+  // imagine doing is pointer comparisons with some other well-known
+  // omanips, since we certainly can't execute it...
+  if (bufferedNewlines) {
+    out << endl;
+    printIndentation(depth);
+  } else bufferedNewlines++;
+  out.flush();
+  return *this;
+}
+
+CodeOutStream & CodeOutStream::operator << (char const *message)
+{
+  int len = strlen(message);
+  if (len<1) return *this;
+  string message1 = message;
+
+  int pending_bufferedNewlines = 0;
+  if (message1[len-1] == '\n') {
+    message1[len-1] = '\0';    // whack it
+    pending_bufferedNewlines++;
+  }
+
+  stringBuilder message2;
+  if (bufferedNewlines) {
+    message2 << '\n';
+    bufferedNewlines--;
+  }
+  message2 << message1;
+  bufferedNewlines += pending_bufferedNewlines;
+
+  printWhileInsertingIndentation(depth, message2);
+  return *this;
+}
+
+// **** class PairDelim
+
+PairDelim::PairDelim(CodeOutStream &out, rostring message, rostring open, char const *close0)
+    : close(close0), out(out)
+{
+  out << message;
+  out << ' ';
+  out << open;
+  if (strchr(toCStr(open), '{')) out.down();
+}
+
+PairDelim::PairDelim(CodeOutStream &out, rostring message)
+  : close(""), out(out)
+{
+  out << message;
+  out << ' ';
+}
+
+PairDelim::~PairDelim() {
+  if (strchr(close, '}')) out.up();
+  out << close;
+}
+
+// **** class TreeWalkOutStream
+
+void TreeWalkOutStream::indent() {
+  out << endl;
+  out.flush();
+  for(int i=0; i<depth; ++i) out << ' ';
+  out.flush();
+  out << ":::::";
+  out.flush();
+}
+
+TreeWalkOutStream & TreeWalkOutStream::operator << (ostream& (*manipfunc)(ostream& outs))
+{
+  if (on) out << manipfunc;
+  return *this;
+}
+
+// **** class TreeWalkDebug
+
+TreeWalkDebug::TreeWalkDebug(char *message, TreeWalkOutStream &out)
+  : out(out)
+{
+  out << message << endl;
+  out.flush();
+  out.down();
+}
+
+TreeWalkDebug::~TreeWalkDebug()
+{
+  out.up();
+}
+
+
+// **************** class TypePrinter
+
+TypeLike const *TypePrinter::getTypeLike(Variable const *var)
+{
+  return var->type;
+}
+
+TypeLike const *TypePrinter::getFunctionTypeLike(Function const *func)
+{
+  return func->funcType;
+}
+
+TypeLike const *TypePrinter::getE_constructorTypeLike(E_constructor const *c)
+{
+  return c->type;
+}
+
+// **************** class CTypePrinter
+
+bool CTypePrinter::enabled = true;
+
+void CTypePrinter::print(OutStream &out, TypeLike const *type, char const *name)
+{
+  // temporarily suspend the Type::toCString, Variable::toCString(),
+  // etc. methods
+  Restorer<bool> res0(global_mayUseTypeAndVarToCString, false);
+  xassert(enabled);
+  // see the note at the interface TypePrinter::print()
+  Type const *type0 = static_cast<Type const *>(type);
+  out << print(type0, name);
+  // old way
+//    out << type->toCString(name);
+}
+
+
+// **** AtomicType
+
+string CTypePrinter::print(AtomicType const *atomic)
+{
+  // roll our own virtual dispatch
+  switch(atomic->getTag()) {
+  default: xfailure("bad tag");
+  case AtomicType::T_SIMPLE:              return print(atomic->asSimpleTypeC());
+  case AtomicType::T_COMPOUND:            return print(atomic->asCompoundTypeC());
+  case AtomicType::T_ENUM:                return print(atomic->asEnumTypeC());
+  case AtomicType::T_TYPEVAR:             return print(atomic->asTypeVariableC());
+  case AtomicType::T_PSEUDOINSTANTIATION: return print(atomic->asPseudoInstantiationC());
+  case AtomicType::T_DEPENDENTQTYPE:      return print(atomic->asDependentQTypeC());
+  }
+}
+
+string CTypePrinter::print(SimpleType const *simpleType)
+{
+  return simpleTypeName(simpleType->type);
+}
+
+string CTypePrinter::print(CompoundType const *cpdType)
+{
+  stringBuilder sb;
+
+  TemplateInfo *tinfo = cpdType->templateInfo();
+  bool hasParams = tinfo && tinfo->params.isNotEmpty();
+  if (hasParams) {
+    sb << tinfo->paramsToCString() << ' ';
+  }
+
+  if (!tinfo || hasParams) {
+    // only say 'class' if this is like a class definition, or
+    // if we're not a template, since template instantiations
+    // usually don't include the keyword 'class' (this isn't perfect..
+    // I think I need more context)
+    sb << CompoundType::keywordName(cpdType->keyword) << ' ';
+  }
+
+  // sb << (cpdType->instName? cpdType->instName : "/*anonymous*/");
+
+  // from cc_print.cc, CompoundType::toCString
+  if (cpdType->typedefVar) {
+    sb << cpdType->typedefVar->fullyQualifiedName0();
+  }
+  else {
+    // only reachable during object construction
+    xfailure("80501256-bad6-4d2c-b7d0-8310f5fd9194");
+  }
+
+
+  // template arguments are now in the name
+  // 4/22/04: they were removed from the name a long time ago;
+  //          but I'm just now uncommenting this code
+  // 8/03/04: restored the original purpose of 'instName', so
+  //          once again that is name+args, so this code is not needed
+  //if (tinfo && tinfo->arguments.isNotEmpty()) {
+  //  sb << sargsToString(tinfo->arguments);
+  //}
+
+  return sb;
+}
+
+string CTypePrinter::print(EnumType const *enumType)
+{
+  return stringc << "enum " << (enumType->typedefVar->fullyQualifiedName0());
+}
+
+string CTypePrinter::print(TypeVariable const *typeVar)
+{
+  // use the "typename" syntax instead of "class", to distinguish
+  // this from an ordinary class, and because it's syntax which
+  // more properly suggests the ability to take on *any* type,
+  // not just those of classes
+  //
+  // but, the 'typename' syntax can only be used in some specialized
+  // circumstances.. so I'll suppress it in the general case and add
+  // it explicitly when printing the few constructs that allow it
+  //
+  // 8/09/04: sm: truncated down to just the name, since the extra
+  // clutter was annoying and not that helpful
+  return stringc //<< "/""*typevar"
+//                   << "typedefVar->serialNumber:"
+//                   << (typedefVar ? typedefVar->serialNumber : -1)
+                 //<< "*/"
+                 << typeVar->name;
+}
+
+string CTypePrinter::print(PseudoInstantiation const *pseudoInst)
+{
+  stringBuilder sb0;
+  StringBuilderOutStream out0(sb0);
+  CodeOutStream codeOut(out0);
+  PrintEnv env(*this, &codeOut); // Yuck!
+  // FIX: what about the env.loc?
+
+  codeOut << pseudoInst->name;
+
+  // NOTE: This was inlined from sargsToString; it would read as
+  // follows:
+//    codeOut << sargsToString(pseudoInst->args);
+  codeOut << '<';
+  int ct=0;
+  FOREACH_OBJLIST(STemplateArgument, pseudoInst->args, iter) {
+    if (ct++ > 0) {
+      codeOut << ',' << ' ';
+    }
+    printSTemplateArgument(env, iter.data());
+  }
+  codeOut << " > ";
+
+  codeOut.finish();
+  return sb0;
+}
+
+string CTypePrinter::print(DependentQType const *depType)
+{
+  stringBuilder sb0;
+  StringBuilderOutStream out0(sb0);
+  CodeOutStream codeOut(out0);
+  PrintEnv env(*this, &codeOut); // Yuck!
+  // FIX: what about the env.loc?
+
+  codeOut << "typename " << print(depType->first) << ':' << ':';
+  depType->rest->print(env);
+
+  codeOut.finish();
+  return sb0;
+}
+
+
+// **** [Compound]Type
+
+string CTypePrinter::print(Type const *type)
+{
+  if (type->isCVAtomicType()) {
+    // special case a single atomic type, so as to avoid
+    // printing an extra space
+    CVAtomicType const *cvatomic = type->asCVAtomicTypeC();
+    return stringc
+      << print(cvatomic->atomic)
+      << cvToString(cvatomic->cv);
+  }
+  else {
+    return stringc
+      << printLeft(type)
+      << printRight(type);
+  }
+}
+
+string CTypePrinter::print(Type const *type, char const *name)
+{
+  // print the inner parentheses if the name is omitted
+  bool innerParen = (name && name[0])? false : true;
+
+  #if 0    // wrong
+  // except, if this type is a pointer, then omit the parens anyway;
+  // we only need parens when the type is a function or array and
+  // the name is missing
+  if (isPointerType()) {
+    innerParen = false;
+  }
+  #endif // 0
+
+  stringBuilder s;
+  s << printLeft(type, innerParen);
+  s << (name? name : "/*anon*/");
+  s << printRight(type, innerParen);
+
+  // get rid of extra space
+  while (s.length() >= 1 && s[s.length()-1] == ' ') {
+    s.truncate(s.length() - 1);
+  }
+
+  return s;
+}
+
+string CTypePrinter::printRight(Type const *type, bool innerParen)
+{
+  // roll our own virtual dispatch
+  switch(type->getTag()) {
+  default: xfailure("illegal tag");
+  case Type::T_ATOMIC:          return printRight(type->asCVAtomicTypeC(), innerParen);
+  case Type::T_POINTER:         return printRight(type->asPointerTypeC(), innerParen);
+  case Type::T_REFERENCE:       return printRight(type->asReferenceTypeC(), innerParen);
+  case Type::T_FUNCTION:        return printRight(type->asFunctionTypeC(), innerParen);
+  case Type::T_ARRAY:           return printRight(type->asArrayTypeC(), innerParen);
+  case Type::T_POINTERTOMEMBER: return printRight(type->asPointerToMemberTypeC(), innerParen);
+  }
+}
+
+string CTypePrinter::printLeft(Type const *type, bool innerParen)
+{
+  // roll our own virtual dispatch
+  switch(type->getTag()) {
+  default: xfailure("illegal tag");
+  case Type::T_ATOMIC:          return printLeft(type->asCVAtomicTypeC(), innerParen);
+  case Type::T_POINTER:         return printLeft(type->asPointerTypeC(), innerParen);
+  case Type::T_REFERENCE:       return printLeft(type->asReferenceTypeC(), innerParen);
+  case Type::T_FUNCTION:        return printLeft(type->asFunctionTypeC(), innerParen);
+  case Type::T_ARRAY:           return printLeft(type->asArrayTypeC(), innerParen);
+  case Type::T_POINTERTOMEMBER: return printLeft(type->asPointerToMemberTypeC(), innerParen);
+  }
+}
+
+string CTypePrinter::printLeft(CVAtomicType const *type, bool /*innerParen*/)
+{
+  stringBuilder s;
+  s << print(type->atomic);
+  s << cvToString(type->cv);
+
+  // this is the only mandatory space in the entire syntax
+  // for declarations; it separates the type specifier from
+  // the declarator(s)
+  s << ' ';
+
+  return s;
+}
+
+string CTypePrinter::printRight(CVAtomicType const *type, bool /*innerParen*/)
+{
+  return "";
+}
+
+string CTypePrinter::printLeft(PointerType const *type, bool /*innerParen*/)
+{
+  stringBuilder s;
+
+  // eed 2006-11-22
+  //     special case for __builtin_va_list
+  //     print out any type that is a pointer to "..."
+  //     as __builtin_va_list. This is probably safe...
+  //     [ticket:113]
+  if(type->atType->isCVAtomicType() &&
+     type->atType->asCVAtomicType()->atomic->isSimpleType() &&
+     type->atType->asCVAtomicType()->atomic->asSimpleType()->type == ST_ELLIPSIS)
+  {
+    s << "__builtin_va_list ";
+  }
+  else {
+    s << printLeft(type->atType, false /*innerParen*/);
+    if (type->atType->isFunctionType() ||
+        type->atType->isArrayType()) {
+      s << '(';
+    }
+    s << '*';
+    if (type->cv) {
+      // scott 2003-01-03
+      //     added this space so "Foo * const arf" prints right (t0012.cc)
+      s << cvToString(type->cv) << ' ';
+    }
+  }
+
+  return s;
+}
+
+string CTypePrinter::printRight(PointerType const *type, bool /*innerParen*/)
+{
+  stringBuilder s;
+  if (type->atType->isFunctionType() ||
+      type->atType->isArrayType()) {
+    s << ')';
+  }
+  s << printRight(type->atType, false /*innerParen*/);
+  return s;
+}
+
+string CTypePrinter::printLeft(ReferenceType const *type, bool /*innerParen*/)
+{
+  stringBuilder s;
+  s << printLeft(type->atType, false /*innerParen*/);
+  if (type->atType->isFunctionType() ||
+      type->atType->isArrayType()) {
+    s << '(';
+  }
+  s << '&';
+  return s;
+}
+
+string CTypePrinter::printRight(ReferenceType const *type, bool /*innerParen*/)
+{
+  stringBuilder s;
+  if (type->atType->isFunctionType() ||
+      type->atType->isArrayType()) {
+    s << ')';
+  }
+  s << printRight(type->atType, false /*innerParen*/);
+  return s;
+}
+
+string CTypePrinter::printLeft(FunctionType const *type, bool innerParen)
+{
+  stringBuilder sb;
+
+  // FIX: FUNC TEMPLATE LOSS
+  // template parameters
+//    if (templateInfo) {
+//      sb << templateInfo->paramsToCString() << " ";
+//    }
+
+  // return type and start of enclosing type's description
+  if (type->flags & (/*FF_CONVERSION |*/ FF_CTOR | FF_DTOR)) {
+    // don't print the return type, it's implicit
+
+    // 7/18/03: changed so we print ret type for FF_CONVERSION,
+    // since otherwise I can't tell what it converts to!
+  }
+  else {
+    sb << printLeft(type->retType);
+  }
+
+  // NOTE: we do *not* propagate 'innerParen'!
+  if (innerParen) {
+    sb << '(';
+  }
+
+  return sb;
+}
+
+string CTypePrinter::printRight(FunctionType const *type, bool innerParen)
+{
+  // I split this into two pieces because the Cqual++ concrete
+  // syntax puts $tainted into the middle of my rightString,
+  // since it's following the placement of 'const' and 'volatile'
+  return stringc
+    << printRightUpToQualifiers(type, innerParen)
+    << printRightQualifiers(type, type->getReceiverCV())
+    << printRightAfterQualifiers(type);
+}
+
+string CTypePrinter::printRightUpToQualifiers(FunctionType const *type, bool innerParen)
+{
+  // finish enclosing type
+  stringBuilder sb;
+  if (innerParen) {
+    sb << ')';
+  }
+
+  // arguments
+  sb << '(';
+  int ct=0;
+  SFOREACH_OBJLIST(Variable, type->params, iter) {
+    ct++;
+    if (type->isMethod() && ct==1) {
+      // don't actually print the first parameter;
+      // the 'm' stands for nonstatic member function
+      sb << "/""*m: " << print(iter.data()->type) << " *""/ ";
+      continue;
+    }
+    if (ct >= 3 || (!type->isMethod() && ct>=2)) {
+      sb << ',' << ' ';
+    }
+    sb << printAsParameter(iter.data());
+  }
+
+  if (type->acceptsVarargs()) {
+    if (ct++ > 0) {
+      sb << ',' << ' ';
+    }
+    sb << '.' << '.' << '.';
+  }
+
+  sb << ')';
+
+  return sb;
+}
+
+string CTypePrinter::printRightQualifiers(FunctionType const *type, CVFlags cv)
+{
+  if (cv) {
+    return stringc << ' ' << ::toString(cv);
+  }
+  else {
+    return "";
+  }
+}
+
+string CTypePrinter::printRightAfterQualifiers(FunctionType const *type)
+{
+  stringBuilder sb;
+
+  // exception specs
+  if (type->exnSpec) {
+    sb << " throw(";
+    int ct=0;
+    SFOREACH_OBJLIST(Type, type->exnSpec->types, iter) {
+      if (ct++ > 0) {
+        sb << ',' << ' ';
+      }
+      sb << print(iter.data());
+    }
+    sb << ')';
+  }
+
+  // hook for verifier syntax
+  printExtraRightmostSyntax(type, sb);
+
+  // finish up the return type
+  sb << printRight(type->retType);
+
+  return sb;
+}
+
+void CTypePrinter::printExtraRightmostSyntax(FunctionType const *type, stringBuilder &)
+{}
+
+string CTypePrinter::printLeft(ArrayType const *type, bool /*innerParen*/)
+{
+  return printLeft(type->eltType);
+}
+
+string CTypePrinter::printRight(ArrayType const *type, bool /*innerParen*/)
+{
+  stringBuilder sb;
+
+  if (type->hasSize()) {
+    sb << '[' << type->size << ']';
+  }
+  else {
+    sb << '[' << ']';
+  }
+
+  sb << printRight(type->eltType);
+
+  return sb;
+}
+
+string CTypePrinter::printLeft(PointerToMemberType const *type, bool /*innerParen*/)
+{
+  stringBuilder s;
+  s << printLeft(type->atType, false /*innerParen*/);
+  s << ' ';
+  if (type->atType->isFunctionType() ||
+      type->atType->isArrayType()) {
+    s << '(';
+  }
+  s << type->inClassNAT->name << ':' << ':' << '*';
+  s << cvToString(type->cv);
+  return s;
+}
+
+string CTypePrinter::printRight(PointerToMemberType const *type, bool /*innerParen*/)
+{
+  stringBuilder s;
+  if (type->atType->isFunctionType() ||
+      type->atType->isArrayType()) {
+    s << ')';
+  }
+  s << printRight(type->atType, false /*innerParen*/);
+  return s;
+}
+
+string CTypePrinter::printAsParameter(Variable const *var)
+{
+  stringBuilder sb;
+  if (var->type->isTypeVariable()) {
+    // type variable's name, then the parameter's name (if any)
+    sb << var->type->asTypeVariable()->name;
+    if (var->name) {
+      sb << ' ' << var->name;
+    }
+  }
+  else {
+    sb << print(var->type, var->name);
+  }
+
+  if (var->value) {
+    sb << renderExpressionAsString(" = ", var->value);
+  }
+  return sb;
+}
+
+// **************** class PrintEnv
+
+// (none; placeholder)
+
+// ****************
+
+// WARNING: if you are inclined to inline this function back into its
+// one call site, be sure you are careful that you do not change the
+// semantics of Restorer below: the site of its destructor call is
+// very important to the semantics of the printing, as it changes
+// which OutStream is being printed to.
+string printDeclaration_makeName
+  (PrintEnv &env,
+   Type const *type,
+   PQName const * /*nullable*/ pqname,
+   Variable *var,
+   StringRef finalName)
+{
+  stringBuilder sb0;
+  StringBuilderOutStream out0(sb0);
+  CodeOutStream codeOut0(out0);
+  // NOTE: temporarily change the OutStream in the PrintEnv; see the
+  // WARNING above.
+  Restorer<CodeOutStream*> tempSubstCodeOutInEnv(env.out, &codeOut0);
+
+  if (pqname) {
+    codeOut0 << pqname->qualifierString();
+  }
+  codeOut0 << finalName;
+  if (type->isFunctionType() &&
+      var->templateInfo() &&
+      var->templateInfo()->isCompleteSpecOrInstantiation()) {
+    // print the spec/inst args after the function name;
+    //
+    // NOTE: This was inlined from sargsToString; it used to read as follows:
+    //          codeOut0 << sargsToString(var->templateInfo()->arguments);
+    codeOut0 << '<';
+    int ct=0;
+    FOREACH_OBJLIST_NC(STemplateArgument, var->templateInfo()->arguments, iter) {
+      if (ct++ > 0) {
+        codeOut0 << ',' << ' ';
+      }
+      printSTemplateArgument(env, iter.data());
+    }
+    codeOut0 << " > ";
+  }
+
+  codeOut0 << var->namePrintSuffix();    // hook for verifier
+  codeOut0.finish();
+  return sb0;
+}
+
+// hooks for Oink
+//
+// sm: My intuition is that these hooks and ought to be parallel
+// (i.e., just one hook function), but they are not, either in type
+// signature or in runtime behavior, so I suspect there is a bug here.
+TypeLike const *getDeclarationRetTypeLike(TypeLike const *type);
+Type const *getDeclarationTypeLike(TypeLike const *type);
+
+// Elsa implementations
+TypeLike const *getDeclarationRetTypeLike(TypeLike const *type)
+{
+  return type->asFunctionTypeC()->retType;
+}
+
+Type const *getDeclarationTypeLike(TypeLike const *type)
+{
+  return type;
+}
+
+// function for printing declarations (without the final semicolon);
+// handles a variety of declarations such as:
+//   int x
+//   int x()
+//   C()                    // ctor inside class C
+//   operator delete[]()
+//   char operator()        // conversion operator to 'char'
+void printDeclaration
+  (PrintEnv &env,
+
+  // declflags present in source; not same as 'var->flags' because
+  // the latter is a mixture of flags present in different
+  // declarations
+  DeclFlags dflags,
+
+  // type of the variable; not same as 'var->type' because the latter
+  // can come from a prototype and hence have different parameter
+  // names
+  TypeLike const *type,
+
+  // original name in the source; for now this is redundant with
+  // 'var->name', but we plan to print the qualifiers by looking
+  // at 'pqname'
+  PQName const * /*nullable*/ pqname,
+
+  // associated variable; in the final design, this will only be
+  // used to look up the variable's scope
+  Variable *var)
+{
+  TreeWalkDebug treeDebug("printDeclaration");
+
+  // mask off flags used for internal purposes, so all that's
+  // left is the flags that were present in the source
+  dflags = (DeclFlags)(dflags & DF_SOURCEFLAGS);
+  if (dflags) {
+    // eed 2006-11-22
+    //     Kludgy fix for ticket:124.
+    if ((dflags & (DF_EXTERN | DF_INLINE)) == (DF_EXTERN | DF_INLINE)) {
+      dflags &= ~DF_STATIC;
+    }
+    *env.out << toString(dflags) << " ";
+  }
+
+  // the string name after all of the qualifiers; if this is
+  // a special function, we're getting the encoded version
+  StringRef finalName = pqname? pqname->getName() : NULL;
+
+  if (finalName && streq(finalName, "conversion-operator")) {
+    // special syntax for conversion operators; first the keyword
+    *env.out << "operator ";
+
+    // then the return type and the function designator
+    TypeLike const *retThing = getDeclarationRetTypeLike(type);
+    env.typePrinter.print(*env.out, retThing);
+
+    *env.out << " ()";
+  }
+
+  else if (finalName && streq(finalName, "constructor-special")) {
+    // extract the class name, which can be found by looking up
+    // the name of the scope which contains the associated variable
+    env.typePrinter.print(*env.out, type, var->scope->curCompound->name);
+  }
+
+  else {
+    if (finalName) {
+      Type const *type0 = getDeclarationTypeLike(type);
+      string name = printDeclaration_makeName(env, type0, pqname, var, finalName);
+      env.typePrinter.print(*env.out, type, name.c_str());
+    } else {
+      env.typePrinter.print(*env.out, type, finalName);
+    }
+  }
+}
+
+
+// more specialized version of the previous function
+void printVar(PrintEnv &env, Variable *var, PQName const * /*nullable*/ pqname)
+{
+  TreeWalkDebug treeDebug("printVar");
+
+  TypeLike const *type0 = env.getTypeLike(var);
+
+  printDeclaration(env, var->flags,
+                   type0, pqname, var);
+}
+
+
+// this is a prototype for a function down near E_funCall::iprint
+void printArgExprList(PrintEnv &env, FakeList<ArgExpression> *list);
+
+
+// ------------------- TranslationUnit --------------------
+void TranslationUnit::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TranslationUnit");
+  FOREACH_ASTLIST_NC(TopForm, topForms, iter) {
+    iter.data()->print(env);
+  }
+}
+
+// --------------------- TopForm ---------------------
+void TF_decl::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_decl");
+  env.loc = loc;
+  decl->print(env);
+}
+
+void TF_func::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_func");
+  *env.out << endl;
+  env.loc = loc;
+  f->print(env);
+}
+
+void TF_template::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_template");
+  env.loc = loc;
+  td->print(env);
+}
+
+void TF_explicitInst::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_explicitInst");
+  env.loc = loc;
+  *env.out << "template ";
+  d->print(env);
+}
+
+void TF_linkage::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_linkage");
+  env.loc = loc;
+  *env.out << "extern " << linkageType;
+  PairDelim pair(*env.out, "", " {\n", "}\n");
+  forms->print(env);
+}
+
+void TF_one_linkage::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_one_linkage");
+  env.loc = loc;
+  *env.out << "extern " << linkageType << " ";
+  form->print(env);
+}
+
+void TF_asm::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_asm");
+  env.loc = loc;
+  *env.out << "asm(" << text->text << ");\n";
+}
+
+void TF_namespaceDefn::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_namespaceDefn");
+  env.loc = loc;
+  *env.out << "namespace " << (name? name : "/*anon*/") << " {\n";
+  FOREACH_ASTLIST_NC(TopForm, forms, iter) {
+    iter.data()->print(env);
+  }
+  *env.out << "} /""* namespace " << (name? name : "(anon)") << " */\n";
+}
+
+void TF_namespaceDecl::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TF_namespaceDecl");
+  env.loc = loc;
+  decl->print(env);
+}
+
+
+// --------------------- Function -----------------
+void Function::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("Function");
+  TypeLike const *type0 = env.typePrinter.getFunctionTypeLike(this);
+  Restorer<bool> res0(CTypePrinter::enabled, type0 == funcType);
+
+  printDeclaration(env, dflags,
+                   type0,
+                   nameAndParams->getDeclaratorId(),
+                   nameAndParams->var);
+
+  if (instButNotTchecked()) {
+    // this is an unchecked instantiation
+    *env.out << "; // not instantiated\n";
+    return;
+  }
+
+  if (inits) {
+    *env.out << ":";
+    bool first_time = true;
+    FAKELIST_FOREACH_NC(MemberInit, inits, iter) {
+      if (first_time) first_time = false;
+      else *env.out << ",";
+      // NOTE: eventually will be able to figure out if we are
+      // initializing a base class or a member variable.  There will
+      // be a field added to class MemberInit that will say.
+      PairDelim pair(*env.out, iter->name->toString(), "(", ")");
+      printArgExprList(env, iter->args);
+    }
+  }
+
+  if (handlers) *env.out << "\ntry";
+
+  if (body->stmts.isEmpty()) {
+    // more concise
+    *env.out << " {}\n";
+  }
+  else {
+    body->print(env);
+  }
+
+  if (handlers) {
+    FAKELIST_FOREACH_NC(Handler, handlers, iter) {
+      iter->print(env);
+    }
+  }
+}
+
+
+// MemberInit
+
+// -------------------- Declaration -------------------
+void Declaration::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("Declaration");
+  if(spec->isTS_classSpec()) {
+    spec->asTS_classSpec()->print(env);
+    *env.out << ";\n";
+  }
+  else if(spec->isTS_enumSpec()) {
+    spec->asTS_enumSpec()->print(env);
+    *env.out << ";\n";
+  }
+  else if(spec->isTS_elaborated() && decllist == NULL) {
+    // see Cubewano Trac ticket #112
+
+    // eed 2006-11-21
+    //     template declarations (template <typename T> class C;)
+    //     and friend classes both have a declaration with a spec
+    //     TS_elaborated and a null decllist. I haven't found
+    //     anything else that satisfies those conditions.
+
+    if(dflags & DF_FRIEND) {
+      *env.out << "friend ";
+    }
+
+    spec->asTS_elaborated()->print(env);
+    *env.out << ";\n";
+  }
+
+
+  FAKELIST_FOREACH_NC(Declarator, decllist, iter) {
+    // if there are decl flags that didn't get put into the
+    // Variable (e.g. DF_EXTERN which gets turned off as soon
+    // as a definition is seen), print them first
+    DeclFlags extras = (DeclFlags)(dflags & ~(iter->var->flags));
+    if (extras) {
+      *env.out << toString(extras) << ' ';
+    }
+
+    // TODO: this will not work if there is more than one declarator ...
+
+    iter->print(env);
+    *env.out << ';' << endl;
+  }
+}
+
+// -------------------- ASTTypeId -------------------
+void printInitializerOpt(PrintEnv &env, Initializer /*nullable*/ *init)
+{
+  if (init) {
+    IN_ctor *ctor = dynamic_cast<IN_ctor*>(init);
+    if (ctor) {
+      // sm: don't print "()" as an IN_ctor initializer (cppstd 8.5 para 8)
+      if (ctor->args->isEmpty()) {
+        *env.out << " /*default-ctor-init*/";
+      }
+      else {
+        // dsw:Constructor arguments.
+        PairDelim pair(*env.out, "", "(", ")");
+        ctor->print(env);       // NOTE: You can NOT factor this line out of the if!
+      }
+    } else {
+      *env.out << '=';
+      init->print(env);         // Don't pull this out!
+    }
+  }
+}
+
+void ASTTypeId::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("ASTTypeId");
+
+  TypeLike const *type0 = env.getTypeLike(decl->var);
+
+  env.typePrinter.print(*env.out, type0);
+
+  // sm: ASTTypeId declarators are always abstract, so I think
+  // this conditional never evaluates to true...
+  if (decl->getDeclaratorId()) {
+    *env.out << ' ';
+    decl->getDeclaratorId()->print(env);
+  }
+
+  printInitializerOpt(env, decl->init);
+}
+
+// ---------------------- PQName -------------------
+void printTemplateArgumentList
+  (PrintEnv &env, /*fakelist*/TemplateArgument *args)
+{
+  int ct=0;
+  while (args) {
+    if (!args->isTA_templateUsed()) {
+      if (ct++ > 0) {
+        *env.out << ',' << ' ';
+      }
+      args->print(env);
+    }
+
+    args = args->next;
+  }
+}
+
+void PQ_qualifier::print(PrintEnv &env)
+{
+  if (templateUsed()) {
+    *env.out << "template ";
+  }
+
+  if (qualifier) {
+    *env.out << qualifier;
+    if (templArgs/*isNotEmpty*/) {
+      *env.out << '<';
+      printTemplateArgumentList(env, templArgs);
+      *env.out << " > ";
+    }
+  }
+  *env.out << ':' << ':';
+
+  rest->print(env);
+}
+
+void PQ_name::print(PrintEnv &env)
+{
+  *env.out << name;
+}
+
+void PQ_operator::print(PrintEnv &env)
+{
+  *env.out << fakeName;
+}
+
+void PQ_template::print(PrintEnv &env)
+{
+  if (templateUsed()) {
+    *env.out << "template ";
+  }
+
+  *env.out << name << '<';
+  printTemplateArgumentList(env, templArgs);
+  *env.out << " > ";
+}
+
+
+// --------------------- TypeSpecifier --------------
+void TS_name::print(PrintEnv &env)
+{
+  xassert(0);                   // I'll bet this is never called.
+//    TreeWalkDebug treeDebug("TS_name");
+//    *env.out << toString(ql);          // see string toString(class dummyType*) above
+//    name->print(env);
+}
+
+void TS_simple::print(PrintEnv &env)
+{
+  xassert(0);                   // I'll bet this is never called.
+//    TreeWalkDebug treeDebug("TS_simple");
+//    *env.out << toString(ql);          // see string toString(class dummyType*) above
+}
+
+void TS_elaborated::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TS_elaborated");
+  env.loc = loc;
+  *env.out << toString(ql);          // see string toString(class dummyType*) above
+  *env.out << toString(keyword) << ' ';
+  name->print(env);
+}
+
+void TS_classSpec::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TS_classSpec");
+  *env.out << toString(ql);          // see string toString(class dummyType*) above
+  *env.out << toString(cv);
+  *env.out << toString(keyword) << ' ';
+  if (name) *env.out << name->toString();
+  bool first_time = true;
+  FAKELIST_FOREACH_NC(BaseClassSpec, bases, iter) {
+    if (first_time) {
+      *env.out << ' ' << ':' << ' ';
+      first_time = false;
+    }
+    else *env.out << ',' << ' ';
+    iter->print(env);
+  }
+  PairDelim pair(*env.out, "", "{\n", "}");
+  FOREACH_ASTLIST_NC(Member, members->list, iter2) {
+    iter2.data()->print(env);
+  }
+}
+
+void TS_enumSpec::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TS_classSpec");
+  *env.out << toString(ql);          // see string toString(class dummyType*) above
+  *env.out << toString(cv);
+  *env.out << "enum ";
+  if (name) *env.out << name;
+  PairDelim pair(*env.out, "", "{\n", "}");
+  FAKELIST_FOREACH_NC(Enumerator, elts, iter) {
+    iter->print(env);
+    *env.out << '\n';
+  }
+}
+
+// BaseClass
+void BaseClassSpec::print(PrintEnv &env) {
+  TreeWalkDebug treeDebug("BaseClassSpec");
+  if (isVirtual) *env.out << "virtual ";
+  if (access!=AK_UNSPECIFIED) *env.out << toString(access) << " ";
+  *env.out << name->toString();
+}
+
+// MemberList
+
+// ---------------------- Member ----------------------
+void MR_decl::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("MR_decl");
+  d->print(env);
+}
+
+void MR_func::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("MR_func");
+  f->print(env);
+}
+
+void MR_access::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("MR_access");
+  *env.out << toString(k) << ':' << '\n';
+}
+
+void MR_usingDecl::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("MR_usingDecl");
+  decl->print(env);
+}
+
+void MR_template::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("MR_template");
+  d->print(env);
+}
+
+
+// -------------------- Enumerator --------------------
+void Enumerator::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("Enumerator");
+  *env.out << name;
+  if (expr) {
+    *env.out << '=';
+    expr->print(env);
+  }
+  *env.out << ',' << ' ';
+}
+
+// -------------------- Declarator --------------------
+void Declarator::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("Declarator");
+
+  printVar(env, var, decl->getDeclaratorId());
+  D_bitfield *b = dynamic_cast<D_bitfield*>(decl);
+  if (b) {
+    *env.out << ':';
+    b->bits->print(env);
+  }
+  printInitializerOpt(env, init);
+}
+
+// ------------------- ExceptionSpec --------------------
+void ExceptionSpec::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("ExceptionSpec");
+  *env.out << "throw"; // Scott says this is right.
+  FAKELIST_FOREACH_NC(ASTTypeId, types, iter) {
+    iter->print(env);
+  }
+}
+
+// ---------------------- Statement ---------------------
+void Statement::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("Statement");
+  env.loc = loc;
+  iprint(env);
+  //    *env.out << ";\n";
+}
+
+// no-op
+void S_skip::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_skip::iprint");
+  *env.out << ';' << '\n';
+}
+
+void S_label::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_label::iprint");
+  *env.out << name << ':';
+  s->print(env);
+}
+
+void S_case::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_case::iprint");
+  *env.out << "case";
+  expr->print(env);
+  *env.out << ':';
+  s->print(env);
+}
+
+void S_default::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_default::iprint");
+  *env.out << "default:";
+  s->print(env);
+}
+
+void S_expr::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_expr::iprint");
+  expr->print(env);
+  *env.out << ';' << '\n';
+}
+
+void S_compound::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_compound::iprint");
+  PairDelim pair(*env.out, "", "{\n", "}\n");
+  FOREACH_ASTLIST_NC(Statement, stmts, iter) {
+    iter.data()->print(env);
+  }
+}
+
+void S_if::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_if::iprint");
+  {
+    PairDelim pair(*env.out, "if", "(", ")");
+    cond->print(env);
+  }
+  thenBranch->print(env);
+  *env.out << "else ";
+  elseBranch->print(env);
+}
+
+void S_switch::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_switch::iprint");
+  {
+    PairDelim pair(*env.out, "switch", "(", ")");
+    cond->print(env);
+  }
+  branches->print(env);
+}
+
+void S_while::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_while::iprint");
+  {
+    PairDelim pair(*env.out, "while", "(", ")");
+    cond->print(env);
+  }
+  body->print(env);
+}
+
+void S_doWhile::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_doWhile::iprint");
+  {
+    PairDelim pair(*env.out, "do");
+    body->print(env);
+  }
+  {
+    PairDelim pair(*env.out, "while", "(", ")");
+    expr->print(env);
+  }
+  *env.out << ';' << '\n';
+}
+
+void S_for::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_for::iprint");
+  {
+    PairDelim pair(*env.out, "for", "(", ")");
+    init->print(env);
+    // this one not needed as the declaration provides one
+    //          *env.out << ";";
+    cond->print(env);
+    *env.out << ';';
+    after->print(env);
+  }
+  body->print(env);
+}
+
+void S_break::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_break::iprint");
+  *env.out << "break";
+  *env.out << ';' << '\n';
+}
+
+void S_continue::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_continue::iprint");
+  *env.out << "continue";
+  *env.out << ';' << '\n';
+}
+
+void S_return::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_return::iprint");
+  *env.out << "return";
+  if (expr) expr->print(env);
+  *env.out << ';' << '\n';
+}
+
+void S_goto::iprint(PrintEnv &env)
+{
+  // dsw: When doing a control-flow pass, keep a current function so
+  // we know where to look for the label.
+  TreeWalkDebug treeDebug("S_goto::iprint");
+  *env.out << "goto ";
+  *env.out << target;
+  *env.out << ';' << '\n';
+}
+
+void S_decl::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_decl::iprint");
+  decl->print(env);
+  //      *env.out << ";\n";
+}
+
+void S_try::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_try::iprint");
+  *env.out << "try";
+  body->print(env);
+  FAKELIST_FOREACH_NC(Handler, handlers, iter) {
+    iter->print(env);
+  }
+}
+
+void S_asm::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_asm::iprint");
+  *env.out << "asm(" << text->text << ");\n";
+}
+
+void S_namespaceDecl::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_namespaceDecl::iprint");
+  decl->print(env);
+}
+
+
+// ------------------- Condition --------------------
+// CN = ConditioN
+
+// this situation: if (gronk()) {...
+void CN_expr::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("CN_expr");
+  expr->print(env);
+}
+
+// this situation: if (bool b=gronk()) {...
+void CN_decl::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("CN_decl");
+  typeId->print(env);
+}
+
+// ------------------- Handler ----------------------
+// catch clause
+void Handler::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("Handler");
+  {
+    PairDelim pair(*env.out, "catch", "(", ")");
+    if (isEllipsis()) {
+      *env.out << "...";
+    }
+    else {
+      typeId->print(env);
+    }
+  }
+  body->print(env);
+}
+
+
+// ------------------- Full Expression print -----------------------
+void FullExpression::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("FullExpression");
+  // FIX: for now I omit printing the declarations of the temporaries
+  // since we really don't have a syntax for it.  We would have to
+  // print some curlies somewhere to make it legal to parse it back in
+  // again, and we aren't using E_statement, so it would not reflect
+  // the actual ast.
+  if (expr) {
+    expr->print(env);
+  } else {
+    // 2006-05-25
+    //   TODO: this can happen e.g.
+    //       struct S1 func () {
+    //         struct S1 v;
+    //         ({ return v; });
+    //       }
+    //
+    // xassert(expr && "39ce4334-0ca1-4e19-aaf9-7f27f335a629");
+  }
+}
+
+
+// ------------------- Expression print -----------------------
+
+// dsw: Couldn't we have fewer functions for printing out an
+// expression?  Or at least name them in a way that reveals some sort
+// of system.
+
+void Expression::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("Expression");
+  PairDelim pair(*env.out, "", "(", ")"); // this will put parens around every expression
+  iprint(env);
+}
+
+string Expression::exprToString() const
+{
+  TreeWalkDebug treeDebug("Expression::exprToString");
+  stringBuilder sb;
+  StringBuilderOutStream out0(sb);
+  CodeOutStream codeOut(out0);
+  CTypePrinter typePrinter;
+  Restorer<bool> res0(CTypePrinter::enabled, true);
+  PrintEnv env(typePrinter, &codeOut);
+
+  // sm: I think all the 'print' methods should be 'const', but
+  // I'll leave such a change up to this module's author (dsw)
+  const_cast<Expression*>(this)->print(env);
+  codeOut.flush();
+
+  return sb;
+}
+
+string renderExpressionAsString(char const *prefix, Expression const *e)
+{
+  return stringc << prefix << e->exprToString();
+}
+
+char *expr_toString(Expression const *e)
+{
+  // this function is defined in smbase/strutil.cc
+  return copyToStaticBuffer(e->exprToString().c_str());
+}
+
+int expr_debugPrint(Expression const *e)
+{
+  e->debugPrint(cout, 0);
+  return 0;    // make gdb happy?
+}
+
+
+void E_boolLit::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_boolLit::iprint");
+  *env.out << b;
+}
+
+void E_intLit::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_intLit::iprint");
+  // FIX: do this correctly from the internal representation
+  // fails to print the trailing U for an unsigned int.
+//    *env.out << i;
+  *env.out << text;
+}
+
+void E_floatLit::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_floatLit::iprint");
+  // FIX: do this correctly from the internal representation
+  // this fails to print ".0" for a float/double that happens to lie
+  // on an integer boundary
+//    *env.out << d;
+  // doing it this way also preserves the trailing "f" for float
+  // literals
+  *env.out << text;
+}
+
+void E_stringLit::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_stringLit::iprint");
+
+  E_stringLit *p = this;
+  while (p) {
+    *env.out << p->text;
+    p = p->continuation;
+    if (p) {
+      *env.out << ' ';
+    }
+  }
+}
+
+void E_charLit::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_charLit::iprint");
+  *env.out << text;
+}
+
+void E_this::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_this::iprint");
+  *env.out << "this";
+}
+
+// modified from STemplateArgument::toString()
+void printSTemplateArgument(PrintEnv &env, STemplateArgument const *sta)
+{
+  switch (sta->kind) {
+    default: xfailure("bad kind");
+    case STemplateArgument::STA_NONE:
+      *env.out << string("STA_NONE");
+      break;
+    case STemplateArgument::STA_TYPE:
+      {
+      // FIX: not sure if this is a bug but there is no abstract value
+      // lying around to be printed here so we just print what we
+      // have; enable the normal type printer temporarily in order to
+      // do this
+      Restorer<bool> res0(CTypePrinter::enabled, true);
+      env.typePrinter.print(*env.out, sta->value.t); // assume 'type' if no comment
+      }
+      break;
+    case STemplateArgument::STA_INT:
+      *env.out << stringc << "/*int*/ " << sta->value.i;
+      break;
+    case STemplateArgument::STA_ENUMERATOR:
+      *env.out << stringc << "/*enum*/ " << sta->value.v->name;
+      break;
+    case STemplateArgument::STA_REFERENCE:
+      *env.out << stringc << "/*ref*/ " << sta->value.v->name;
+      break;
+    case STemplateArgument::STA_POINTER:
+      *env.out << stringc << "/*ptr*/ &" << sta->value.v->name;
+      break;
+    case STemplateArgument::STA_MEMBER:
+      *env.out << stringc
+              << "/*member*/ &" << sta->value.v->scope->curCompound->name
+              << "::" << sta->value.v->name;
+      break;
+    case STemplateArgument::STA_DEPEXPR:
+      sta->getDepExpr()->print(env);
+      break;
+    case STemplateArgument::STA_TEMPLATE:
+      *env.out << string("template (?)");
+      break;
+    case STemplateArgument::STA_ATOMIC:
+      *env.out << sta->value.at->toString();
+      break;
+  }
+}
+
+// print template args, if any
+void printTemplateArgs(PrintEnv &env, Variable *var)
+{
+  if (!( var && var->templateInfo() )) {
+    return;
+  }
+
+  TemplateInfo *tinfo = var->templateInfo();
+  int totArgs = tinfo->arguments.count();
+  if (totArgs == 0) {
+    return;
+  }
+
+  // use only arguments that apply to non-inherited parameters
+  int args = totArgs;
+  if (tinfo->isInstantiation()) {
+    args = tinfo->instantiationOf->templateInfo()->params.count();
+    if (args == 0) {
+      return;
+    }
+  }
+
+  // print final 'args' arguments
+  ObjListIter<STemplateArgument> iter(var->templateInfo()->arguments);
+  for (int i=0; i < (totArgs-args); i++) {
+    iter.adv();
+  }
+  *env.out << '<';
+  int ct=0;
+  for (; !iter.isDone(); iter.adv()) {
+    if (ct++ > 0) {
+      *env.out << ',' << ' ';
+    }
+    printSTemplateArgument(env, iter.data());
+  }
+  *env.out << " > ";
+}
+
+void E_variable::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_variable::iprint");
+  if (var && var->isBoundTemplateParam()) {
+    // this is a bound template variable, so print its value instead
+    // of printing its name
+    xassert(var->value);
+    var->value->print(env);
+  }
+  else {
+    *env.out << name->qualifierString() << name->getName();
+    printTemplateArgs(env, var);
+  }
+}
+
+void printArgExprList(PrintEnv &env, FakeList<ArgExpression> *list)
+{
+  TreeWalkDebug treeDebug("printArgExprList");
+  bool first_time = true;
+  FAKELIST_FOREACH_NC(ArgExpression, list, iter) {
+    if (first_time) first_time = false;
+    else *env.out << ',' << ' ';
+    iter->expr->print(env);
+  }
+}
+
+void E_funCall::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_funCall::iprint");
+  func->print(env);
+  PairDelim pair(*env.out, "", "(", ")");
+  printArgExprList(env, args);
+}
+
+void E_constructor::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_constructor::iprint");
+
+  TypeLike const *type0 = env.typePrinter.getE_constructorTypeLike(this);
+  Restorer<bool> res0(CTypePrinter::enabled, type == type0);
+
+  env.typePrinter.print(*env.out, type0);
+  PairDelim pair(*env.out, "", "(", ")");
+  printArgExprList(env, args);
+}
+
+void printVariableName(PrintEnv &env, Variable *var)
+{
+  // I anticipate possibly expanding this to cover more cases
+  // of Variables that need to printed specially, possibly
+  // including printing needed qualifiers.
+
+  if (var->type->isFunctionType() &&
+      var->type->asFunctionType()->isConversionOperator()) {
+    // the name is just "conversion-operator", so print differently
+    *env.out << "/""*conversion*/operator(";
+    Type *t = var->type->asFunctionType()->retType;
+    Restorer<bool> res0(CTypePrinter::enabled, true);
+    env.typePrinter.print(*env.out, t);
+    *env.out << ')';
+    return;
+  }
+
+  // normal case
+  *env.out << var->name;
+}
+
+void E_fieldAcc::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_fieldAcc::iprint");
+  obj->print(env);
+  *env.out << '.';
+  if (field &&
+      !field->type->isDependent()) {
+    printVariableName(env, field);
+    printTemplateArgs(env, field);
+  }
+  else {
+    // the 'field' remains NULL if we're in a template
+    // function and the 'obj' is dependent on the template
+    // arguments.. there are probably a few other places
+    // lurking that will need similar treatment, because
+    // typechecking of templates is very incomplete and in
+    // any event when checking the template *itself* (as
+    // opposed to an instantiation) we never have enough
+    // information to fill in all the variable references..
+    *env.out << fieldName->toString();
+  }
+}
+
+void E_arrow::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_arrow::iprint");
+
+  // E_arrow shouldn't normally be present in code that is to be
+  // prettyprinted, so it doesn't much matter what this does.
+  obj->print(env);
+  *env.out << "->";
+  fieldName->print(env);
+}
+
+void E_sizeof::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_sizeof::iprint");
+  // NOTE parens are not necessary because it's an expression, not a
+  // type.
+  *env.out << "sizeof";
+  expr->print(env);             // putting parens in here so we are safe wrt precedence
+}
+
+// dsw: unary expression?
+void E_unary::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_unary::iprint");
+  *env.out << toString(op);
+  expr->print(env);
+}
+
+void E_effect::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_effect::iprint");
+  if (!isPostfix(op)) *env.out << toString(op);
+  expr->print(env);
+  if (isPostfix(op)) *env.out << toString(op);
+}
+
+// dsw: binary operator.
+void E_binary::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_binary::iprint");
+  e1->print(env);
+  if (op != BIN_BRACKETS) {
+    *env.out << toString(op);
+    e2->print(env);
+  }
+  else {
+    *env.out << "[";
+    e2->print(env);
+    *env.out << "]";
+  }
+}
+
+void E_addrOf::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_addrOf::iprint");
+  *env.out << "&";
+  if (expr->isE_variable()) {
+    // could be forming ptr-to-member, do not parenthesize
+    expr->iprint(env);
+  }
+  else {
+    expr->print(env);
+  }
+}
+
+void E_deref::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_deref::iprint");
+  *env.out << "*";
+  ptr->print(env);
+}
+
+// C-style cast
+void E_cast::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_cast::iprint");
+  {
+    PairDelim pair(*env.out, "", "(", ")");
+    ctype->print(env);
+  }
+  expr->print(env);
+}
+
+// ? : syntax
+void E_cond::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_cond::iprint");
+  cond->print(env);
+  *env.out << "?";
+  // In gcc it is legal to omit the 'then' part;
+  // http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Conditionals.html#Conditionals
+  if (th) {
+    th->print(env);
+  }
+  *env.out << ":";
+  el->print(env);
+}
+
+void E_sizeofType::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_sizeofType::iprint");
+  PairDelim pair(*env.out, "sizeof", "(", ")"); // NOTE yes, you do want the parens because argument is a type.
+  atype->print(env);
+}
+
+void E_assign::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_assign::iprint");
+  target->print(env);
+  if (op!=BIN_ASSIGN) *env.out << toString(op);
+  *env.out << "=";
+  src->print(env);
+}
+
+void E_new::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_new::iprint");
+  if (colonColon) *env.out << "::";
+  *env.out << "new ";
+  if (placementArgs) {
+    PairDelim pair(*env.out, "", "(", ")");
+    printArgExprList(env, placementArgs);
+  }
+
+  if (!arraySize) {
+    // no array size, normal type-id printing is fine
+    atype->print(env);
+  }
+  else {
+    // sm: to correctly print new-declarators with array sizes, we
+    // need to dig down a bit, because the arraySize is printed right
+    // where the variable name would normally go in an ordinary
+    // declarator
+    //
+    // for example, suppose the original syntax was
+    //   new int [n][5];
+    // the type-id of the object being allocated is read as
+    // "array of 5 ints" and 'n' of them are created; so:
+    //   "array of 5 ints"->leftString()   is "int"
+    //   arraySize->print()                is "n"
+    //   "array of 5 ints"->rightString()  is "[5]"
+    Type const *t = atype->decl->var->type;   // type-id in question
+    *env.out << t->leftString() << " [";
+    arraySize->print(env);
+    *env.out << "]" << t->rightString();
+  }
+
+  if (ctorArgs) {
+    PairDelim pair(*env.out, "", "(", ")");
+    printArgExprList(env, ctorArgs->list);
+  }
+}
+
+void E_delete::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_delete::iprint");
+  if (colonColon) *env.out << "::";
+  *env.out << "delete";
+  if (array) *env.out << "[]";
+  // dsw: this can be null because elaboration can remove syntax when
+  // it is replaced with other syntax
+  if (expr) {
+    expr->print(env);
+  }
+}
+
+void E_throw::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_throw::iprint");
+  *env.out << "throw";
+  if (expr) expr->print(env);
+}
+
+// C++-style cast
+void E_keywordCast::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_keywordCast::iprint");
+  *env.out << toString(key);
+  {
+    PairDelim pair(*env.out, "", "<", " > ");
+    ctype->print(env);
+  }
+  PairDelim pair(*env.out, "", "(", ")");
+  expr->print(env);
+}
+
+// RTTI: typeid(expression)
+void E_typeidExpr::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_typeidExpr::iprint");
+  PairDelim pair(*env.out, "typeid", "(", ")");
+  expr->print(env);
+}
+
+// RTTI: typeid(type)
+void E_typeidType::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_typeidType::iprint");
+  PairDelim pair(*env.out, "typeid", "(", ")");
+  ttype->print(env);
+}
+
+void E_grouping::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_grouping::iprint");
+
+  // sm: given that E_grouping is now in the tree, and prints its
+  // parentheses, perhaps we could eliminate some of the
+  // paren-printing above?
+  //PairDelim pair(*env.out, "", "(", ")");
+  //
+  // update:  Actually, it's a problem for E_grouping to print parens
+  // because it messes up idempotency.  And, if we restored idempotency
+  // by turning off paren-printing elsewhere, then we'd have a subtle
+  // long-term problem that AST transformations would be required to
+  // insert E_grouping when composing new expression trees, and that
+  // would suck.  So I'll let E_grouping be a no-op, and continue to
+  // idly plan some sort of precedence-aware paren-inserter mechanism.
+
+  expr->iprint(env);    // iprint means Expression won't put parens either
+}
+
+// ----------------------- Initializer --------------------
+
+// this is under a declaration
+// int x = 3;
+//         ^ only
+void IN_expr::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("IN_expr");
+  e->print(env);
+}
+
+// int x[] = {1, 2, 3};
+//           ^^^^^^^^^ only
+void IN_compound::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("IN_compound");
+  PairDelim pair(*env.out, "", "{\n", "\n}");
+  bool first_time = true;
+  FOREACH_ASTLIST_NC(Initializer, inits, iter) {
+    if (first_time) first_time = false;
+    else *env.out << ",\n";
+    iter.data()->print(env);
+  }
+}
+
+void IN_ctor::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("IN_ctor");
+  printArgExprList(env, args);
+}
+
+// InitLabel
+
+// -------------------- TemplateDeclaration ---------------
+void TemplateDeclaration::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TemplateDeclaration");
+
+  *env.out << "template <";
+  int ct=0;
+  for (TemplateParameter *iter = params; iter; iter = iter->next) {
+    if (ct++ > 0) {
+      *env.out << ", ";
+    }
+    iter->print(env);
+  }
+  *env.out << " >\n";
+
+  iprint(env);
+}
+
+void printFuncInstantiations(PrintEnv &env, Variable const *var)
+{
+  TemplateInfo *ti = var->templateInfo();
+  SFOREACH_OBJLIST(Variable, ti->instantiations, iter) {
+    Variable const *inst = iter.data();
+    if (inst->funcDefn) {
+      inst->funcDefn->print(env);
+    }
+    else {
+      *env.out << inst->toQualifiedString() << ";    // decl but not defn\n";
+    }
+  }
+}
+
+void TD_func::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TD_func");
+  f->print(env);
+
+  // print instantiations
+  Variable *var = f->nameAndParams->var;
+  if (var->isTemplate() &&      // for complete specializations, don't print
+      !var->templateInfo()->isPartialInstantiation()) {     // nor partial inst
+    *env.out << "#if 0    // instantiations of ";
+    // NOTE: inlined from Variable::toCString()
+
+    TypeLike const *type0 = env.getTypeLike(var);
+    env.typePrinter.print(*env.out, type0, (var->name? var->name : "/*anon*/"));
+    *env.out << var->namePrintSuffix() << "\n";
+    printFuncInstantiations(env, var);
+
+    TemplateInfo *varTI = var->templateInfo();
+    if (!varTI->definitionTemplateInfo) {
+      // little bit of a hack: if this does not have a
+      // 'definitionTemplateInfo', then it was defined inline, and
+      // the partial instantiations will be printed when the class
+      // instantiation is
+    }
+    else {
+      // also look in partial instantiations
+      SFOREACH_OBJLIST(Variable, varTI->partialInstantiations, iter) {
+        printFuncInstantiations(env, iter.data());
+      }
+    }
+
+    *env.out << "#endif   // instantiations of " << var->name << "\n\n";
+  }
+}
+
+void TD_decl::iprint(PrintEnv &env)
+{
+  d->print(env);
+
+  // print instantiations
+  if (d->spec->isTS_classSpec()) {
+    CompoundType *ct = d->spec->asTS_classSpec()->ctype;
+    TemplateInfo *ti = ct->typedefVar->templateInfo();
+    if (!ti->isCompleteSpec()) {
+      *env.out << "#if 0    // instantiations of " << ct->name << "\n";
+
+      SFOREACH_OBJLIST(Variable, ti->instantiations, iter) {
+        Variable const *instV = iter.data();
+
+        *env.out << "// ";
+        TypeLike const *type0 = env.getTypeLike(instV);
+        env.typePrinter.print(*env.out, type0);
+        CompoundType *instCT = instV->type->asCompoundType();
+        if (instCT->syntax) {
+          *env.out << "\n";
+          instCT->syntax->print(env);
+          *env.out << ";\n";
+        }
+        else {
+          *env.out << ";     // body not instantiated\n";
+        }
+      }
+      *env.out << "#endif   // instantiations of " << ct->name << "\n\n";
+    }
+  }
+  else {
+    // it could be a forward declaration of a template class;
+    // do nothing more
+  }
+}
+
+void TD_tmember::iprint(PrintEnv &env)
+{
+  d->print(env);
+}
+
+
+// ------------------- TemplateParameter ------------------
+void TP_type::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TP_type");
+  *env.out << "class " << (name? name : "/*anon*/");
+
+  if (defaultType) {
+    *env.out << " = ";
+    defaultType->print(env);
+  }
+}
+
+void TP_nontype::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("TP_nontype");
+  param->print(env);
+}
+
+
+// -------------------- TemplateArgument ------------------
+void TA_type::print(PrintEnv &env)
+{
+  // dig down to prevent printing "/*anon*/" since template
+  // type arguments are always anonymous so it's just clutter
+  Restorer<bool> res0(CTypePrinter::enabled, true);
+  env.typePrinter.print(*env.out, type->decl->var->type);
+}
+
+void TA_nontype::print(PrintEnv &env)
+{
+  expr->print(env);
+}
+
+void TA_templateUsed::print(PrintEnv &env)
+{
+  // the caller should have recognized the presence of TA_templateUsed,
+  // adjusted its printing accordingly, and then skipped this element
+  xfailure("do not print TA_templateUsed");
+}
+
+
+// -------------------- NamespaceDecl ---------------------
+void ND_alias::print(PrintEnv &env)
+{
+  *env.out << "namespace " << alias << " = ";
+  original->print(env);
+  *env.out << ";\n";
+}
+
+void ND_usingDecl::print(PrintEnv &env)
+{
+  *env.out << "using ";
+  name->print(env);
+  *env.out << ";\n";
+}
+
+void ND_usingDir::print(PrintEnv &env)
+{
+  *env.out << "using namespace ";
+  name->print(env);
+  *env.out << ";\n";
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc_print.h
===================================================================
--- vendor/elsa/current/elsa/cc_print.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_print.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,385 @@
+// cc_print.h            see license.txt for copyright and terms of use
+
+// This is a tree walk that prints out a functionally equivalent C++
+// program to the original.  The AST entry points are declared in
+// cc.ast
+
+// Adapted from cc_tcheck.cc by Daniel Wilkerson dsw at cs.berkeley.edu
+
+#ifndef CC_PRINT_H
+#define CC_PRINT_H
+
+#include "cc_ast.h"             // C++ AST; this module
+#include "str.h"                // stringBuilder
+
+#include <iostream.h>           // ostream
+
+// this virtual semi-abstract class is intended to act as a
+// "superclass" for ostream, stringBuilder, and any other "output
+// stream" classes
+class OutStream {
+  public:
+  virtual ~OutStream() {}
+
+  // special-case methods
+  virtual OutStream & operator << (ostream& (*manipfunc)(ostream& outs)) = 0;
+  virtual void flush() = 0;
+
+  // special method to support rostring
+  virtual OutStream & operator << (rostring message) = 0;
+
+  // generic methods
+  #define MAKE_INSERTER(type) \
+    virtual OutStream &operator << (type message) = 0;
+  MAKE_INSERTER(char const *)
+  MAKE_INSERTER(char)
+  MAKE_INSERTER(bool)
+  MAKE_INSERTER(int)
+  MAKE_INSERTER(unsigned int)
+  MAKE_INSERTER(long)
+  MAKE_INSERTER(unsigned long)
+  MAKE_INSERTER(double)
+  #undef MAKE_INSERTER
+};
+
+class StringBuilderOutStream : public OutStream {
+  stringBuilder &buffer;
+
+  public:
+  StringBuilderOutStream(stringBuilder &buffer0) : buffer(buffer0) {}
+
+  // special-case methods
+  virtual StringBuilderOutStream & operator << (ostream& (*manipfunc)(ostream& outs)) {
+    buffer << "\n";             // assume that it is endl
+    return *this;
+  }
+  virtual void flush() {}       // no op
+
+  // special method to support rostring
+  virtual OutStream & operator << (rostring message) {return operator<< (message.c_str());}
+
+  // generic methods
+  #define MAKE_INSERTER(type)        \
+    virtual StringBuilderOutStream &operator << (type message) \
+    {                                \
+      buffer << message;             \
+      return *this;                  \
+    }
+  MAKE_INSERTER(char const *)
+  MAKE_INSERTER(char)
+  MAKE_INSERTER(bool)
+  MAKE_INSERTER(int)
+  MAKE_INSERTER(unsigned int)
+  MAKE_INSERTER(long)
+  MAKE_INSERTER(unsigned long)
+  MAKE_INSERTER(double)
+  #undef MAKE_INSERTER
+};
+
+class OStreamOutStream : public OutStream {
+  ostream &out;
+
+  public:
+  OStreamOutStream(ostream &out0) : out(out0) {}
+
+  // special-case methods
+  virtual OStreamOutStream & operator << (ostream& (*manipfunc)(ostream& outs)) {
+    out << manipfunc;
+    return *this;
+  }
+  virtual void flush() { out.flush(); }
+
+  // special method to support rostring
+  virtual OutStream & operator << (rostring message) {return operator<< (message.c_str());}
+
+  // generic methods
+  #define MAKE_INSERTER(type)        \
+    virtual OStreamOutStream &operator << (type message) \
+    {                                \
+      out << message;                \
+      return *this;                  \
+    }
+  MAKE_INSERTER(char const *)
+  MAKE_INSERTER(char)
+  MAKE_INSERTER(bool)
+  MAKE_INSERTER(int)
+  MAKE_INSERTER(unsigned int)
+  MAKE_INSERTER(long)
+  MAKE_INSERTER(unsigned long)
+  MAKE_INSERTER(double)
+  #undef MAKE_INSERTER
+};
+
+// indents the source code sent to it
+class CodeOutStream : public OutStream {
+  OutStream &out;               // output to here
+  int depth;                    // depth of indentation
+  int bufferedNewlines;         // number of buffered trailing newlines
+
+  public:
+  CodeOutStream(OutStream &out0)
+    : out(out0), depth(0), bufferedNewlines(0)
+  {}
+  virtual ~CodeOutStream();
+
+  // manipulate depth
+  virtual void up()   {depth--;}
+  virtual void down() {depth++;}
+
+  // indentation and formatting support
+  void printIndentation(int n);
+  void printWhileInsertingIndentation(int n, rostring s);
+  void finish();
+
+  // OutStream methods
+  CodeOutStream & operator << (ostream& (*manipfunc)(ostream& outs));
+  void flush() { out.flush(); }
+  CodeOutStream & operator << (char const *message);
+
+  // special method to support rostring
+  virtual CodeOutStream & operator << (rostring message) {return operator<< (message.c_str());}
+
+  // generic methods
+  #define MAKE_INSERTER(type)                     \
+    CodeOutStream & operator << (type message) {  \
+      out << message;                             \
+      return *this;                               \
+    }
+  MAKE_INSERTER(char)
+  MAKE_INSERTER(bool)
+  MAKE_INSERTER(int)
+  MAKE_INSERTER(unsigned int)
+  MAKE_INSERTER(long)
+  MAKE_INSERTER(unsigned long)
+  MAKE_INSERTER(double)
+  #undef MAKE_INSERTER
+};
+
+// print paired delimiters, the second one is delayed until the end of
+// the stack frame; that is, it is printed in the destructor.
+class PairDelim {
+  char const *close;            // FIX: why can't I use an rostring?
+  CodeOutStream &out;
+
+  public:
+  PairDelim(CodeOutStream &out, rostring message, rostring open, char const *close);
+  PairDelim(CodeOutStream &out, rostring message);
+  ~PairDelim();
+};
+
+// an output stream for printing comments that will indent them
+// according to the level of the tree walk
+class TreeWalkOutStream : public OutStream {
+  OutStream &out;
+  bool on;
+  int depth;
+
+  public:
+  TreeWalkOutStream(OutStream &out, bool on = true)
+    : out(out), on(on), depth(0)
+  {}
+
+  public:
+  // manipulate depth
+  virtual void down() {++depth;}
+  virtual void up()   {--depth;}
+
+  private:
+  // indentation and formatting support
+  void indent();
+
+  public:
+  // OutStream methods
+  virtual TreeWalkOutStream & operator << (ostream& (*manipfunc)(ostream& outs));
+  virtual void flush() { out.flush(); }
+
+  // special method to support rostring
+  virtual TreeWalkOutStream & operator << (rostring message) {return operator<< (message.c_str());}
+
+  // generic methods
+  #define MAKE_INSERTER(type)                     \
+    TreeWalkOutStream & operator << (type message) { \
+      if (on) {                                   \
+        indent();                                 \
+        out << message;                           \
+      }                                           \
+      return *this;                               \
+    }
+  MAKE_INSERTER(char const *)
+  MAKE_INSERTER(char)
+  MAKE_INSERTER(bool)
+  MAKE_INSERTER(int)
+  MAKE_INSERTER(unsigned int)
+  MAKE_INSERTER(long)
+  MAKE_INSERTER(unsigned long)
+  MAKE_INSERTER(double)
+  #undef MAKE_INSERTER
+};
+
+extern TreeWalkOutStream treeWalkOut;
+
+// a class to make on the stack at ever frame of the tree walk that
+// will automatically manage the indentation level of the
+// TreeWalkOutStream given
+class TreeWalkDebug {
+  TreeWalkOutStream &out;
+  public:
+  TreeWalkDebug(char *message, TreeWalkOutStream &out = treeWalkOut);
+  ~TreeWalkDebug();
+};
+
+// In Oink, TypeLike is a superclass of Type but here we will just
+// make it synonymous with Type.  oink/cc_print.h.cpatch comments-out
+// this declaration.
+typedef Type TypeLike;
+
+// Interface for classes that know how to print out types
+class TypePrinter {
+  public:
+  virtual ~TypePrinter() {}
+
+  // dsw: type has to be a void* because in the Oink TypePrinter it is
+  // a Value which isn't a type; I don't know of a good way to fix
+  // this other than to invent some abstract interface generalization
+  // called TypeLike that both Type and Value inherit from.  I think
+  // this is too much generality for OO to handle well
+  //
+  // sm: 2005-08-17: I made the default value of 'name' be "".  This
+  // means that in contexts that do not typically have names, "" will
+  // be passed and hence no /*anon*/ will be printed; while in
+  // contexts that usually do have names, but some instance does not
+  // (has a NULL pointer there), /*anon*/ *will* be printed.  Thus,
+  // /*anon*/ is only printed in places where name could go.
+  virtual void print(OutStream &out, TypeLike const *type, char const *name = "") = 0;
+  
+  // retrieve the TypeLike to print for a Variable; in Elsa, this
+  // just gets Variable::type, but Oink does something else
+  virtual TypeLike const *getTypeLike(Variable const *var);
+  
+  // retrieve for a Function, nominally Function::funcType
+  virtual TypeLike const *getFunctionTypeLike(Function const *func);
+  
+  // and for an E_constructor, nominally Expression::type
+  virtual TypeLike const *getE_constructorTypeLike(E_constructor const *c);
+};
+
+// This class knows how to print out Types in C syntax
+class CTypePrinter : public TypePrinter {
+  // dsw: I need to be able to use CTypePrinter class in
+  // ValueTypePrinter to print out the occasional object that has a
+  // type but no abstract value, such as template primaries.  However,
+  // most of the time I need to disable this class so I don't
+  // accidentally use it.
+  public:
+  static bool enabled;
+
+  public:
+  virtual ~CTypePrinter() {}
+
+  // satisfy the interface to TypePrinter
+  virtual void print(OutStream &out, TypeLike const *type, char const *name = NULL);
+
+  protected:
+  // **** AtomicType
+  string print(AtomicType const *atomic);
+
+  string print(SimpleType const *);
+  string print(CompoundType const *);
+  string print(EnumType const *);
+  string print(TypeVariable const *);
+  string print(PseudoInstantiation const *);
+  string print(DependentQType const *);
+
+  // **** [Compound]Type
+  string print(Type const *type);
+  string print(Type const *type, char const *name);
+  string printRight(Type const *type, bool innerParen = true);
+  string printLeft(Type const *type, bool innerParen = true);
+
+  string printLeft(CVAtomicType const *type, bool innerParen = true);
+  string printRight(CVAtomicType const *type, bool innerParen = true);
+  string printLeft(PointerType const *type, bool innerParen = true);
+  string printRight(PointerType const *type, bool innerParen = true);
+  string printLeft(ReferenceType const *type, bool innerParen = true);
+  string printRight(ReferenceType const *type, bool innerParen = true);
+  string printLeft(FunctionType const *type, bool innerParen = true);
+  string printRight(FunctionType const *type, bool innerParen = true);
+  string printRightUpToQualifiers(FunctionType const *type, bool innerParen);
+  string printRightQualifiers(FunctionType const *type, CVFlags cv);
+  string printRightAfterQualifiers(FunctionType const *type);
+  void   printExtraRightmostSyntax(FunctionType const *type, stringBuilder &);
+  string printLeft(ArrayType const *type, bool innerParen = true);
+  string printRight(ArrayType const *type, bool innerParen = true);
+  string printLeft(PointerToMemberType const *type, bool innerParen = true);
+  string printRight(PointerToMemberType const *type, bool innerParen = true);
+
+  // **** Variable
+  string printAsParameter(Variable const *var);
+};
+
+// global context for a pretty-print
+class PrintEnv {
+  public:
+  TypePrinter &typePrinter;
+  CodeOutStream *out;
+  SourceLoc loc;
+
+  public:
+  PrintEnv(TypePrinter &typePrinter0, CodeOutStream *out0)
+    : typePrinter(typePrinter0)
+    , out(out0)
+    , loc(SL_UNKNOWN)
+  {}
+
+  TypeLike const *getTypeLike(Variable const *var)
+    { return typePrinter.getTypeLike(var); }
+
+  void finish() { out->finish(); }
+
+  #define MAKE_INSERTER(type)                    \
+    PrintEnv& operator << (type message) {       \
+      *out << message;                           \
+      return *this;                              \
+    }
+  MAKE_INSERTER(char const *)
+  MAKE_INSERTER(char)
+  MAKE_INSERTER(bool)
+  MAKE_INSERTER(int)
+  MAKE_INSERTER(unsigned int)
+  MAKE_INSERTER(long)
+  MAKE_INSERTER(unsigned long)
+  MAKE_INSERTER(double)
+  MAKE_INSERTER(rostring)
+  #undef MAKE_INSERTER
+};
+
+// version of PrintEnv that prints to a string in the default syntax
+class StringPrintEnv : public PrintEnv {
+public:      // data
+  StringBuilderOutStream sbos;
+  CodeOutStream cos;
+  CTypePrinter tpc;
+
+public:      // code
+  StringPrintEnv(stringBuilder &sb)
+    : PrintEnv(tpc, &cos),
+      sbos(sb),
+      cos(sbos),
+      tpc()
+  {}
+};
+
+
+void printSTemplateArgument(PrintEnv &env, STemplateArgument const *sta);
+
+#define PRINT_AST(AST)                \
+  do {                                \
+    OutStream out0(cout);         \
+    TypePrinter typePrinter0;         \
+    PrintEnv penv0(typePrinter0);     \
+    if (AST) AST->print(penv0, out0); \
+    else out0 << "(PRINT_AST:null)";  \
+    out0 << endl;                     \
+  } while(0)
+
+#endif // CC_PRINT_H

Added: vendor/elsa/current/elsa/cc_scope.cc
===================================================================
--- vendor/elsa/current/elsa/cc_scope.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_scope.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1374 @@
+// cc_scope.cc            see license.txt for copyright and terms of use
+// code for cc_scope.h
+
+#include "cc_scope.h"     // this module
+#include "trace.h"        // trace
+#include "variable.h"     // Variable
+#include "cc_type.h"      // CompoundType
+#include "cc_env.h"       // doh.  Env::error
+#include "mangle.h"       // mangle
+#include "exc.h"          // unwinding
+
+
+Scope::Scope(ScopeKind sk, int cc, SourceLoc initLoc)
+  : variables(),
+    typeTags(),
+    changeCount(cc),
+    onScopeStack(false),
+    canAcceptNames(true),
+    parentScope(),
+    scopeKind(sk),
+    namespaceVar(NULL),
+    templateParams(),
+    parameterizedEntity(NULL),
+    usingEdges(0),            // the arrays start as NULL b/c in the
+    usingEdgesRefct(0),       // common case the sets are empty
+    activeUsingEdges(0),
+    outstandingActiveEdges(0),
+    curCompound(NULL),
+    curAccess(AK_PUBLIC),
+    curFunction(NULL),
+    curLoc(initLoc)
+{
+  xassert(sk != SK_UNKNOWN);
+}
+
+// a ctor for de-serialization
+Scope::Scope(XmlReader&)
+  : variables(),
+    typeTags(),
+    changeCount(0),
+    onScopeStack(false),
+    canAcceptNames(true),
+    parentScope(),
+    scopeKind(SK_UNKNOWN),
+    namespaceVar(NULL),
+    templateParams(),
+    parameterizedEntity(NULL),
+    usingEdges(0),
+    usingEdgesRefct(0),
+    activeUsingEdges(0),
+    outstandingActiveEdges(0),
+    curCompound(NULL),
+    curAccess(AK_PUBLIC),
+    curFunction(NULL),
+    curLoc(SL_UNKNOWN)
+{}
+
+Scope::~Scope()
+{
+  // 8/14/04: I got all of our test suite to go through without
+  // running into what is now the xfailure below, so I think I've got
+  // most of this straightened out.  But this isn't such a big deal if
+  // it fails so I'm going to turn it off again.  If at some point
+  // we are more interested in improving the implementation than in
+  // getting code to go through, I might turn it on again.
+  #if 0
+  if (scopeKind == SK_TEMPLATE_PARAMS && !parameterizedPrimary) {
+    // my intent is that all SK_TEMPLATE_PARAMSs get assigned to some
+    // primary eventually; this warning should be commented-out once
+    // the implementation stabilizes
+    xfailure(stringc << desc() << " has no parameterizedPrimary");
+  }
+  #endif // 0
+
+  // if we were delegated, break the delegation
+  if (isDelegated()) {
+    CompoundType *ct = parameterizedEntity->type->asCompoundType();
+    if (!unwinding()) {
+      xassert(ct->parameterizingScope == this);
+    }
+
+    TRACE("templateParams", desc() << " removing delegation to " << ct->desc());
+
+    ct->parameterizingScope = NULL;
+    parameterizedEntity = NULL;     // irrelevant but harmless
+  }
+
+  if (!unwinding()) {         // if not already raising an exception,
+    xassert(!onScopeStack);   // check that we are not pointed-to
+  }
+}
+
+
+bool Scope::isPermanentScope() const
+{
+  return isGlobalScope() ||
+         isNamespace() ||
+         (curCompound && curCompound->name);
+}
+
+
+bool Scope::isDelegated() const
+{
+  return parameterizedEntity &&
+         parameterizedEntity->type->isCompoundType();
+}
+
+
+Scope *Scope::getDelegationPointer() const
+{
+  if (curCompound) {
+    return curCompound->parameterizingScope;
+  }
+  return NULL;
+}
+
+Scope *Scope::getAndNullifyDelegationPointer()
+{
+  Scope *ret = curCompound->parameterizingScope;
+  xassert(ret);
+  curCompound->parameterizingScope = NULL;
+  return ret;
+}
+
+void Scope::setDelegationPointer(Scope *s)
+{
+  xassert(!curCompound->parameterizingScope);
+  xassert(s);
+  curCompound->parameterizingScope = s;
+}
+
+
+// -------- insertion --------
+template <class T>
+bool insertUnique(StringRefMap<T> &table, char const *key, T *value,
+                  int &changeCount, bool forceReplace)
+{
+  if (!forceReplace && table.get(key)) {
+    return false;
+  }
+
+  // NOTE: it is no longer necessary to remove before adding; add will
+  // just overwrite
+  table.add(key, value);
+  changeCount++;
+  return true;
+}
+
+
+bool Scope::isGlobalTemplateScope() const
+{
+  return isTemplateParamScope() &&
+         (parentScope && parentScope->isGlobalScope());
+}
+
+
+bool Scope::isWithinUninstTemplate() const
+{
+  if (curCompound &&
+      curCompound->templateInfo() &&
+      curCompound->templateInfo()->hasParameters()) {
+    return true;
+  }
+
+  if (parentScope) {
+    return parentScope->isWithinUninstTemplate();
+  }
+  else {
+    return false;
+  }
+}
+
+
+bool Scope::hasTemplateParams() const
+{
+  return isTemplateParamScope() &&
+         templateParams.isNotEmpty();
+}
+
+
+// This function should not modify 'v'; any changes to 'v' should
+// instead be done by 'registerVariable'.
+bool Scope::addVariable(Variable *v, bool forceReplace)
+{
+  xassert(canAcceptNames);
+
+  if (!v->isNamespace()) {
+    // classify the variable for debugging purposes
+    #if DO_TRACE
+      char const *classification =
+        v->hasFlag(DF_TYPEDEF)?    "typedef" :
+        v->type->isFunctionType()? "function" :
+                                   "variable" ;
+    #endif // DO_TRACE
+
+    // does the type contain any error-recovery types?  if so,
+    // then we don't want to add the variable because we could
+    // be trying to disambiguate a declarator, and this would
+    // be the erroneous interpretation which is not supposed to
+    // modify the environment
+    bool containsErrors = v->type->containsErrors();
+    char const *prefix = "";
+    if (containsErrors) {
+      prefix = "[cancel/error] ";
+    }
+
+    if (!curCompound) {
+      // variable outside a class
+      TRACE("env",    prefix << "added " << classification
+                   << " `" << v->name
+                   << "' of type `" << v->type->toString()
+                   << "' at " << toLCString(v->loc)
+                   << " to " << desc());
+    }
+    else {
+      // class member
+      //v->access = curAccess;      // moved into registerVariable()
+      TRACE("env",    prefix << "added " << toString(v->getAccess())
+                   << " member " << classification
+                   << " `" << v->name
+                   << "' of type `" << v->type->toString()
+                   << "' at " << toLCString(v->loc)
+                   << " to " << desc());
+    }
+
+    if (containsErrors) {
+      return true;     // pretend it worked; don't further rock the boat
+    }
+  }
+
+  // moved into registerVariable()
+  //if (isGlobalScope()) {
+  //  v->setFlag(DF_GLOBAL);
+  //}
+
+  if (insertUnique(variables, v->name, v, changeCount, forceReplace)) {
+    afterAddVariable(v);
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+void Scope::afterAddVariable(Variable *v)
+{}
+
+
+bool Scope::addCompound(CompoundType *ct)
+{
+  xassert(canAcceptNames);
+  xassert(ct->typedefVar);
+
+  TRACE("env", "added " << toString(ct->keyword) << " " << ct->name);
+
+  ct->access = curAccess;
+  return addTypeTag(ct->typedefVar);
+}
+
+
+bool Scope::addEnum(EnumType *et)
+{
+  xassert(canAcceptNames);
+  xassert(et->typedefVar);
+
+  TRACE("env", "added enum " << et->name);
+
+  et->access = curAccess;
+  return addTypeTag(et->typedefVar);
+}
+
+
+bool Scope::addTypeTag(Variable *tag)
+{
+  xassert(tag->type->isEnumType() ||
+          tag->type->isCompoundType());
+
+  tag->setAccess(curAccess);
+  return insertUnique(typeTags, tag->name, tag, changeCount, false /*forceReplace*/);
+}
+
+
+// This function is responsble for modifying 'v' in preparation for
+// adding it to this scope.  It's separated out from 'addVariable'
+// because in certain cases the variable is actually not added; but
+// this function should behave as if it always is added.
+void Scope::registerVariable(Variable *v)
+{
+  if (v->getScopeKind() == SK_UNKNOWN) {
+    v->setScopeKind(scopeKind);
+  }
+  else {
+    // this happens to parameters at function definitions: the
+    // variable is created and first entered into the parameter scope,
+    // but then the they are also inserted into the function scope
+    // (because the parameter scope ends at the closing-paren); so
+    // leave the scope kind alone, even though now the variable has
+    // been added to a function scope
+  }
+
+  if (isPermanentScope()) {
+    v->scope = this;
+  }
+
+  if (curCompound) {
+    // take access control from scope's current setting
+    v->setAccess(curAccess);
+  }
+
+  if (isGlobalScope()
+      // FIX: is this right?  dsw: if we are in a template scope that
+      // is in a global scope, you are effectively also a global
+      // unless you are a template parameter
+      //
+      // sm: TODO: what is going on here?  why does this matter?  what
+      // is being set DF_GLOBAL that wouldn't otherwise?
+      //
+      // sm: who pays attention that flag?
+      //    dsw: oink pays attention to that flag!
+      || (isGlobalTemplateScope() && !v->hasFlag(DF_PARAMETER))
+      ) {
+    v->setFlag(DF_GLOBAL);
+  }
+}
+
+
+void Scope::addUniqueVariable(Variable *v)
+{
+  registerVariable(v);
+  bool ok = addVariable(v);
+  xassert(ok);
+}
+
+
+// is 'ancestor' an ancestor of 'child'?
+bool hasAncestor(BaseClassSubobj const *child, BaseClassSubobj const *ancestor)
+{
+  // Unfortunately, I can't do a DFS using the 'visited' fields,
+  // because this query happens right in the middle of *another* DFS
+  // that is using those same fields.  Oh well, just to it without
+  // the 'visited' flags, and take the possibly exponential hit ...
+
+  if (child == ancestor) {
+    return true;
+  }
+
+  SFOREACH_OBJLIST(BaseClassSubobj, child->parents, iter) {
+    if (hasAncestor(iter.data(), ancestor)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+Variable *Scope::lookupVariable_inner
+  (LookupSet &candidates, StringRef name, Env &env, LookupFlags flags)
+{
+  Variable *v1 = NULL;
+
+  // [cppstd sec. 10.2]: class members hide all members from
+  // base classes
+  //
+  // 2005-08-14: calling 'lookupSingleVariable' to fix in/t0527.cc;
+  // this now filters twice, but it should be ok anyway
+  v1 = candidates.filter(lookupSingleVariable(name, flags), flags);
+
+  if (!(flags & LF_IGNORE_USING)) {
+    if (!(flags & LF_QUALIFIED)) {
+      // 7.3.4 para 1: "active using" edges are a source of additional
+      // declarations that can satisfy an unqualified lookup
+      if (activeUsingEdges.isNotEmpty()) {
+        v1 = searchActiveUsingEdges(candidates, name, env, flags, v1);
+      }
+    }
+    else {
+      // 3.4.3.2 para 2: do a DFS on the "using" edge graph, but only
+      // if we haven't already found the name
+      if (!v1 && usingEdges.isNotEmpty()) {
+        v1 = searchUsingEdges(candidates, name, env, flags);
+      }
+    }
+  }
+
+  if (v1) {
+    return v1;
+  }
+
+  if (!curCompound) {
+    // nowhere else to look
+    return NULL;
+  }
+
+  // [ibid] if I can find a class member by looking in multiple
+  // base classes, then it's ambiguous and the program has
+  // an error
+  //
+  // to implement this, I'll walk the list of base classes,
+  // keeping in 'ret' the latest successful lookup, and if I
+  // find another successful lookup then I'll complain
+
+  // recursively examine the subobject hierarchy
+  BaseClassSubobj const *v1Subobj = NULL;
+  curCompound->clearSubobjVisited();
+  lookupVariable_considerBase(name, env, flags,
+                              v1, v1Subobj, &(curCompound->subobj));
+
+  if (v1) {
+    candidates.adds(v1);
+  }
+
+  return v1;
+}
+
+// helper for lookupVariable_inner; if we find a suitable variable, set
+// v1/v1Subobj to refer to it; if we find an ambiguity, report that
+void Scope::lookupVariable_considerBase
+  (StringRef name, Env &env, LookupFlags flags,  // stuff from caller
+   Variable *&v1,                                    // best so far
+   BaseClassSubobj const *&v1Subobj,                 // where 'v1' was found
+   BaseClassSubobj const *v2Subobj)                  // where we're looking now
+{
+  if (v2Subobj->visited) return;
+  v2Subobj->visited = true;
+
+  CompoundType const *v2Base = v2Subobj->ct;
+
+  // look in 'v2Base' for the field
+  Variable *v2 =
+    vfilter(v2Base->variables.get(name), flags);
+  if (v2) {
+    TRACE("lookup", "found " << v2Base->name << "::" << name);
+
+    if (v1) {
+      if (v1 == v2 &&
+          (v1->hasFlag(DF_STATIC) || v1->hasFlag(DF_TYPEDEF))) {
+        // they both refer to the same static entity; that's ok
+        // (10.2 para 2); ALSO: we believe this exception should
+        // apply to types also (DF_TYPEDEF), though the standard
+        // does not explicitly say so (in/t0166.cc is testcase)
+        return;
+      }
+
+      // 9/21/04: It is still possible that this is not an error, if
+      // 'v1' is hidden by 'v2' but (because of virtual inheritance)
+      // 'v1' was nevertheless traversed before 'v2'.  So, check whether
+      // 'v2' hides 'v1'.  See in/d0104.cc.
+      if (hasAncestor(v2Subobj, v1Subobj)) {
+        // ok, just go ahead and let 'v2' replace 'v1'
+        TRACE("lookup", "DAG ancestor conflict suppressed (v2 is lower)");
+      }
+      else if (hasAncestor(v1Subobj, v2Subobj)) {
+        // it could also be the other way around
+        TRACE("lookup", "DAG ancestor conflict suppressed (v1 is lower)");
+
+        // in this case, 'v1' is already the right one
+        return;
+      }
+      else {
+        // ambiguity
+        env.error(stringc
+          << "reference to `" << name << "' is ambiguous, because "
+          << "it could either refer to "
+          << v1Subobj->ct->name << "::" << name << " or "
+          << v2Base->name << "::" << name);
+        return;
+      }
+    }
+
+    // found one; copy it into 'v1', my "best so far"
+    v1 = v2;
+    v1Subobj = v2Subobj;
+
+    // this name hides any in base classes, so this arm of the
+    // search stops here
+    return;
+  }
+
+  // we didn't find it; recursively look into base classes of
+  // 'v2Subobj'
+  SFOREACH_OBJLIST(BaseClassSubobj, v2Subobj->parents, iter) {
+    lookupVariable_considerBase(name, env, flags, v1, v1Subobj, iter.data());
+  }
+}
+
+
+Variable *Scope::lookupVariable(StringRef name, Env &env,
+                                LookupFlags flags)
+{
+  LookupSet candidates;
+  return lookupVariable_set(candidates, name, env, flags);
+}
+
+Variable *Scope::lookupVariable_set
+  (LookupSet &candidates, StringRef name, Env &env, LookupFlags flags)
+{
+  if (flags & LF_INNER_ONLY) {
+    return candidates.filter(variables.get(name), flags);
+  }
+
+  if (curCompound && (flags & LF_ARG_DEP)) {
+    // (in/t0569.cc) Arg-dep lookup only finds friends of classes
+    // [3.4.2p1].  This is iterative search is not very efficient, but
+    // it probably won't be used that often.  Building a more
+    // efficient structure is a bit of a pain since friend sets need
+    // not correspond to existing overload sets.
+    SFOREACH_OBJLIST_NC(Variable, curCompound->friends, iter) {
+      Variable *v = iter.data();
+      if (v->name == name) {
+        candidates.filter(v, flags);
+      }
+    }
+    return candidates.isEmpty() ? NULL : candidates.first();
+  }
+
+  Variable *ret = lookupVariable_inner(candidates, name, env, flags);
+  if (ret) return ret;
+
+  // previously, I had code here which traversed the 'parentScope'
+  // link to find additional places to look for 'name'; however, that
+  // is very bad because:
+  //   - the caller (typically Env::lookupVariable) is already iterating
+  //     through the scope stack, so this will defeat that function's
+  //     'foundScope' return value
+  //   - the 'parentScope' link is NULL for unnamed scopes (at least in
+  //     the current design), so searching along that path leads to
+  //     different behavior depending on whether things are named
+  //
+  // so, if we do not find the name here, we just stop; the caller is
+  // responsible for checking in parent scopes, etc.
+  return NULL;
+}
+
+
+CompoundType const *Scope::lookupCompoundC(StringRef name, Env &env,
+                                           LookupFlags flags) const
+{
+  Variable *v = lookupTypeTag(name, env, flags);
+  if (!v) {
+    return NULL;
+  }
+  else if (!v->type->isCompoundType()) {
+    // TODO: further distinguish between struct/class and union
+    if (!(flags & LF_SUPPRESS_ERROR)) {
+      env.error(stringc << "`" << name << "' is not a struct/class/union");
+    }
+    return NULL;
+  }
+  else {
+    return v->type->asCompoundType();
+  }
+}
+
+
+EnumType const *Scope::lookupEnumC(StringRef name, Env &env,
+                                   LookupFlags flags) const
+{
+  Variable *v = lookupTypeTag(name, env, flags);
+  if (!v) {
+    return NULL;
+  }
+  else if (!v->type->isEnumType()) {
+    if (!(flags & LF_SUPPRESS_ERROR)) {
+      env.error(stringc << "`" << name << "' is not an enum");
+    }
+    return NULL;
+  }
+  else {
+    return v->type->asCVAtomicType()->atomic->asEnumType();
+  }
+}
+
+
+Variable *Scope::lookupTypeTag(StringRef name, Env &env, LookupFlags flags) const
+{
+  Variable *v = vfilter(typeTags.get(name), flags);
+  if (v || (flags & LF_INNER_ONLY)) {
+    return v;
+  }
+
+  // consider bases
+  if (curCompound) {
+    FOREACH_OBJLIST(BaseClass, curCompound->bases, iter) {
+      Variable *v2 = iter.data()->ct->lookupTypeTag(name, env, flags);
+      if (v2) {
+        if (!v) {
+          v = v2;
+        }
+        else if (v != v2) {
+          env.error(stringc << "ambiguous type tag: `" << v->fullyQualifiedName0()
+                            << "' vs. `" << v2->fullyQualifiedName0() << "'");
+        }
+      }
+    }
+  }
+
+  return v;
+}
+
+
+Variable *Scope::lookupSingleVariable(StringRef name, LookupFlags flags)
+{
+  if (flags & LF_QUERY_TAGS) {
+    return vfilter(typeTags.get(name), flags);
+  }
+
+  if (flags & LF_ONLY_TYPES) {
+    // 3.4.4p2,3: what we are implementing is "ignoring any non-type
+    // names that have been declared"; in C++ mode it does not matter
+    // whether we look in the tags or the variables first
+    // (in/t0414.cc), but in C mode we must look in tags first
+    // (in/c/t0019.c)
+    Variable *v = vfilter(typeTags.get(name), flags);
+    if (v) {
+      return v;
+    }
+  }
+
+  if (flags & LF_TYPES_NAMESPACES) {
+    // (in/t0527.cc) try 'variables' (so we see namespaces and
+    // typedefs), but if that yields something but it is not a type or
+    // namespace, then look in the type tags too
+    Variable *v = variables.get(name);
+    if (v && !vfilter(v, flags)) {
+      return vfilter(typeTags.get(name), flags);
+    }
+    else {
+      return v;
+    }
+  }
+
+  return vfilter(variables.get(name), flags);
+}
+
+void Scope::lookup(LookupSet &set, StringRef name, Env &env, LookupFlags flags)
+{
+  lookup(set, name, &env, flags);
+}
+
+void Scope::lookup(LookupSet &set, StringRef name, Env *env, LookupFlags flags)
+{
+  // check in our local map
+  Variable *v = lookupSingleVariable(name, flags);
+
+  // if found, expand overload sets
+  if (v) {
+    set.adds(v);
+  }
+
+  if (flags & LF_INNER_ONLY) {
+    return;        // don't follow 'using' or base class chains
+  }
+
+  // consider 'using' directive edges
+  if (!(flags & LF_IGNORE_USING)) {
+    xassert(env);    // must pass an 'env' if you want 'using' edge traversal
+
+    if (!(flags & LF_QUALIFIED)) {
+      // 7.3.4 para 1: "active using" edges are a source of additional
+      // declarations that can satisfy an unqualified lookup
+      if (activeUsingEdges.isNotEmpty()) {
+        v = searchActiveUsingEdges(set, name, *env, flags, v);
+      }
+    }
+    else {
+      // 3.4.3.2 para 2: do a DFS on the "using" edge graph, but only
+      // if we haven't already found the name
+      if (!v && usingEdges.isNotEmpty()) {
+        v = searchUsingEdges(set, name, *env, flags);
+      }
+    }
+  }
+
+  // if we have found something, stop here, rather than considering
+  // base classes
+  xassert((!!v) == set.isNotEmpty());
+  if (set.isNotEmpty()) {
+    return;
+  }
+
+  // base classes?
+  if (!curCompound) {
+    return;
+  }
+
+  // get all the subobjects (I believe we do not have to call
+  // ensureClassBodyInstantiated since every context will already
+  // require that 'curCompound' be complete.)
+  SObjList<BaseClassSubobj const> subobjs;
+  curCompound->getSubobjects(subobjs);
+
+  // look in each one for 'name', keeping track of which subobject
+  // we find it in, if any
+  xassert(!v);
+  BaseClassSubobj const *vObj = NULL;
+  SFOREACH_OBJLIST(BaseClassSubobj const, subobjs, iter) {
+    BaseClassSubobj const *v2Obj = iter.data();
+    Variable *v2 = v2Obj->ct->lookupSingleVariable(name, flags);
+    if (v2) {
+      TRACE("lookup", "found " << v2Obj->ct->name << "::" << name);
+
+      if (v) {
+        // allow same entity, and static or type or enumerator
+        // (cppstd 10.2 para 5)
+        if (v==v2 && v->hasAnyFlags(DF_STATIC | DF_TYPEDEF | DF_ENUMERATOR)) {
+          continue;
+        }
+
+        // allow hidden entities (cppstd 10.2 para 6)
+        if (hasAncestor(v2Obj, vObj)) {
+          // ok, just go ahead and let 'v2' replace 'v'
+          TRACE("lookup", "DAG ancestor conflict suppressed (v2 is lower)");
+        }
+        else if (hasAncestor(vObj, v2Obj)) {
+          // it could also be the other way around
+          TRACE("lookup", "DAG ancestor conflict suppressed (v is lower)");
+
+          // in this case, 'v1' is already the right one
+          continue;
+        }
+        else {
+          // ambiguity
+          if (env) {
+            env->error(stringc
+              << "reference to `" << name << "' is ambiguous, because "
+              << "it could either refer to "
+              << vObj->ct->name << "::" << name << " or "
+              << v2Obj->ct->name << "::" << name);
+            break;
+          }
+          else {
+            // since not reporting errors, must communicate the problem
+            // via the result set
+            set.removeAll();
+            return;
+          }
+        }
+      }
+
+      // found one; copy it into 'v', my "best so far"
+      v = v2;
+      vObj = v2Obj;
+    }
+  }
+
+  // if the above search yielded something, expand it and return
+  if (v) {
+    set.adds(v);
+  }
+}
+
+
+Variable *Scope::lookup_one(StringRef name, Env &env, LookupFlags flags)
+{
+  return lookup_one(name, &env, flags);
+}
+
+Variable *Scope::lookup_one(StringRef name, Env *env, LookupFlags flags)
+{
+  LookupSet set;
+  lookup(set, name, env, flags);
+  return set.isEmpty()? NULL : set.first();
+}
+
+
+Variable const *Scope::getTypedefNameC() const
+{
+  if (scopeKind == SK_CLASS) {
+    return curCompound->typedefVar;
+  }
+  if (scopeKind == SK_NAMESPACE) {
+    return namespaceVar;
+  }
+  return NULL;
+}
+
+
+bool Scope::encloses(Scope const *s) const
+{
+  // in all situations where this is relevant, 's' has named parent
+  // scopes (since we found it by qualified lookup), so just walk
+  // the scope parent links
+
+  Scope const *me = this;
+  while (s && s!=me) {
+    s = s->parentScope;
+  }
+
+  return s == me;
+}
+
+
+bool Scope::enclosesOrEq(Scope const *s) const
+{
+  return this == s || this->encloses(s);
+}
+
+
+string Scope::scopeName() const
+{
+  if (curCompound) {
+    return curCompound->keywordAndName();
+  }
+  else {
+    Variable const *v = getTypedefNameC();
+    if (v && v->name) {
+      return stringc << toString(scopeKind) << " " << v->name;
+    }
+    else if (isGlobalScope()) {
+      return "global scope";
+    }
+    else {
+      return stringc << "anonymous " << toString(scopeKind) << " scope";
+    }
+  }
+}
+
+
+string Scope::desc() const
+{
+  // name, plus address or serial number
+  #if USE_SERIAL_NUMBERS
+    return stringc << scopeName() << " #" << serialNumber;
+  #else
+    return stringc << scopeName() << " at " << stringf("%p", this);
+  #endif
+}
+
+static void dumpMap(char const *label, StringRefMap<Variable> const &map)
+{
+  cout << "  " << label << ":\n";
+  for (StringRefMap<Variable>::Iter iter(map);
+       !iter.isDone();
+       iter.adv()) {
+    cout << "    " << iter.key() << ": " << iter.value()->toString() << "\n";
+  }
+}
+
+void Scope::gdb() const
+{
+  cout << "Scope dump of " << desc() << ":\n";
+  dumpMap("variables", variables);
+  dumpMap("typeTags", typeTags);
+
+  if (curCompound) {
+    cout << "  friends (found during arg-dep lookup):\n";
+    SFOREACH_OBJLIST(Variable, curCompound->friends, iter) {
+      cout << "    " << iter.data()->toQualifiedString() << "\n";
+    }
+  }
+
+  cout.flush();
+}
+
+
+void Scope::addUsingEdge(Scope *target)
+{
+  TRACE("using", "added using-edge from " << desc()
+              << " to " << target->desc());
+
+  usingEdges.push(target);
+  target->usingEdgesRefct++;
+}
+
+
+void Scope::addActiveUsingEdge(Scope *target)
+{
+  TRACE("using", "added active-using-edge from " << desc()
+              << " to " << target->desc());
+
+  activeUsingEdges.push(target);
+}
+
+void Scope::removeActiveUsingEdge(Scope *target)
+{
+  TRACE("using", "removing active-using-edge from " << desc()
+              << " to " << target->desc());
+
+  if (activeUsingEdges.top() == target) {
+    // we're in luck
+    activeUsingEdges.pop();
+  }
+  else {
+    // find the element that has 'target'
+    for (int i=0; i<activeUsingEdges.length(); i++) {
+      if (activeUsingEdges[i] == target) {
+        // found it, swap with the top element
+        Scope *top = activeUsingEdges.pop();
+        activeUsingEdges[i] = top;
+        return;
+      }
+    }
+
+    xfailure("attempt to remove active-using edge not in the set");
+  }
+}
+
+
+void Scope::scheduleActiveUsingEdge(Env &env, Scope *target)
+{
+  // find the innermost scope that contains both 'this' and 'target',
+  // as this is effectively where target's declarations appear while
+  // we're in this scope
+  Scope *enclosing = env.findEnclosingScope(target);
+  enclosing->addActiveUsingEdge(target);
+
+  // schedule it for removal later
+  outstandingActiveEdges.push(ActiveEdgeRecord(enclosing, target));
+}
+
+
+void Scope::openedScope(Env &env)
+{
+  if (onScopeStack) {
+    xfailure(stringc << "opened twice: " << desc());
+  }
+  onScopeStack = true;
+
+  if (usingEdges.length() == 0) {
+    return;    // common case
+  }
+
+  // it's like I'm "using" myself, and thus all the things that
+  // I have "using" edges to
+  addUsingEdgeTransitively(env, this);
+}
+
+void Scope::closedScope()
+{
+  // remove the "active using" edges I previously added
+  while (outstandingActiveEdges.isNotEmpty()) {
+    ActiveEdgeRecord rec = outstandingActiveEdges.pop();
+
+    // hmm.. I notice that I could just have computed 'source'
+    // again like I did above..
+
+    rec.source->removeActiveUsingEdge(rec.target);
+  }
+
+  xassert(onScopeStack);
+  onScopeStack = false;
+}
+
+
+void Scope::addUsingEdgeTransitively(Env &env, Scope *target)
+{
+  // get set of scopes that are reachable along "using" edges from
+  // 'target'; all get active-using edges, as if they directly
+  // appeared in a using-directive in this scope (7.3.4 para 2)
+  ArrayStack<Scope*> reachable;
+  if (target != this) {
+    // include it in the closure
+    reachable.push(target);
+  }
+  target->getUsingClosure(reachable);
+
+  // all (transitive) "using" edges give rise to "active using" edges
+  for (int i=0; i<reachable.length(); i++) {
+    scheduleActiveUsingEdge(env, reachable[i]);
+  }
+}
+
+
+// search the lists instead of maintaining state in the Scope
+// objects, to keep things simple; if the profiler tells me
+// to make this faster, I can put colors into the objects
+static void pushIfWhite(ArrayStack<Scope*> const &black,
+                        ArrayStack<Scope*> &gray,
+                        Scope *s)
+{
+  // in the black list?
+  int i;
+  for (i=0; i<black.length(); i++) {
+    if (black[i] == s) {
+      return;
+    }
+  }
+
+  // in the gray list?
+  for (i=0; i<gray.length(); i++) {
+    if (gray[i] == s) {
+      return;
+    }
+  }
+
+  // not in either, color is effectively white, so push it
+  gray.push(s);
+}
+
+// DFS over the network of using-directive edges
+void Scope::getUsingClosure(ArrayStack<Scope*> &dest)
+{
+  // set of scopes already searched
+  ArrayStack<Scope*> black;
+
+  // stack of scopes remaining to be searched in the DFS
+  ArrayStack<Scope*> gray;
+
+  // initial condition
+  gray.push(this);
+
+  // process the gray set until empty
+  while (gray.isNotEmpty()) {
+    Scope *s = gray.pop();
+    black.push(s);
+
+    // add 's' to the desination list, except that 'this' is excluded
+    if (s != this) {
+      dest.push(s);
+    }
+
+    // push the "using" edges' targets
+    for (int i=0; i < s->usingEdges.length(); i++) {
+      pushIfWhite(black, gray, s->usingEdges[i]);
+    }
+  }
+}
+
+
+// return true if caller should return 'v'
+bool Scope::foundViaUsingEdge(LookupSet &candidates, Env &env, LookupFlags flags,
+                              Variable *v, Variable *&vfound)
+{
+  if (vfound) {
+    if (!sameEntity(vfound, v)) {
+      if (v->type->isFunctionType() &&
+          vfound->type->isFunctionType()) {
+        // ok; essentially they form an overload set
+      }
+      else {
+        env.error(stringc
+          << "ambiguous lookup: `" << vfound->fullyQualifiedName0()
+          << "' vs. `" << v->fullyQualifiedName0() << "'");
+
+        // originally I kept going in hopes of reporting more
+        // interesting things, but now that the same scope can
+        // appear multiple times on the active-using list, I
+        // get multiple reports of the same thing, so bail after
+        // the first
+        return true;
+      }
+    }
+  }
+  else {
+    vfound = v;
+  }
+
+  candidates.adds(v);
+
+  return false;
+}
+
+
+Variable *Scope::searchActiveUsingEdges
+  (LookupSet &candidates, StringRef name,
+   Env &env, LookupFlags flags, Variable *vfound)
+{
+  // just consider the set of "active using" edges
+  for (int i=0; i<activeUsingEdges.length(); i++) {
+    Scope *s = activeUsingEdges[i];
+
+    // look for 'name' in 's'
+    Variable *v = s->lookupSingleVariable(name, flags);
+    if (v) {
+      if (foundViaUsingEdge(candidates, env, flags, v, vfound /*IN/OUT*/)) {
+        return v;
+      }
+    }
+  }
+
+  return vfound;
+}
+
+
+// another DFS; 3.4.3.2 para 2
+Variable *Scope::searchUsingEdges
+  (LookupSet &candidates, StringRef name, Env &env, LookupFlags flags)
+{
+  // set of scopes already searched
+  ArrayStack<Scope*> black;
+
+  // stack of scopes remaining to be searched in the DFS
+  ArrayStack<Scope*> gray;
+
+  // initial condition
+  gray.push(this);
+  Variable *vfound = NULL;
+
+  // process the gray set until empty
+  while (gray.isNotEmpty()) {
+    Scope *s = gray.pop();
+    black.push(s);
+
+    // does 's' have the name?
+    Variable *v = s->lookupSingleVariable(name, flags);
+    if (v) {
+      if (foundViaUsingEdge(candidates, env, flags, v, vfound /*IN/OUT*/)) {
+        return v;
+      }
+    }
+
+    // if 's' does *not* have the name, then push the things it
+    // points to
+    else {
+      // push the "using" edges' targets
+      for (int i=0; i < s->usingEdges.length(); i++) {
+        pushIfWhite(black, gray, s->usingEdges[i]);
+      }
+    }
+  }
+
+  return vfound;
+}
+
+
+// true if this scope is a member of the global scope
+bool Scope::immediateGlobalScopeChild()
+{
+  return parentScope && parentScope->isGlobalScope();
+}
+
+// are we in a scope where the parent chain terminates in a global?
+// That is, can fullyQualifiedName() be called on this scope without
+// failing?
+bool Scope::linkerVisible()
+{
+  if (parentScope) {
+    return parentScope->linkerVisible();
+  }
+  else {
+    return isGlobalScope();
+  }
+}
+
+
+void fqn_STemplateArgs(stringBuilder &sb, ObjList<STemplateArgument> const &args)
+{
+  sb << sargsToString(args);
+}
+
+
+// FIX: Would be cleaner to implement this as a call to
+// PQ_fullyQualifiedName() below and then to a toString() method.
+// UPDATE: After long discussion with Scott, we determine that that
+// idea is not practical.
+// FIX: This is wrong as it does not take into account template
+// arguments; Should be moved into CompoundType and done right.
+//
+// 8/09/04: sm: mangle=true is the original behavior of this function,
+// mangle=false is the behavior I want
+//
+// 9/20/05: dsw: I inlined it with mangle=false since I didn't need
+// that other behavior.
+string Scope::fullyQualifiedName()
+{
+  // 7/28/04: I just changed things so that children of the global
+  // scope have a non-NULL 'parentScope', and then adjusted this
+  // code so it works like it used to.  I suspect this code could
+  // be simplified in light of the new invariant.
+
+  // a few places are still calling into this when it is the global
+  // scope; since those places should be happy with "", and that is
+  // in fact the "name" of the global scope, let's try this...
+  if (isGlobalScope()) {
+    return "";
+  }
+
+  stringBuilder sb;
+  if (parentScope && !parentScope->isGlobalScope()) {
+    sb = parentScope->fullyQualifiedName();
+    sb << "::";     // put this only *between* names, so none at start
+  }
+  else {
+    if (!immediateGlobalScopeChild()) {
+      // we didn't end up in the global scope; for example a function
+      // in a class in a function
+      xfailure("fullyQualifiedName called on scope that doesn't terminate in the global scope");
+    }
+  }
+
+  xassert(hasName());
+  Variable *v = getTypedefName();
+  xassert(v);
+  if (v->name) {
+    sb << v->name;
+  }
+  else {
+    sb << "anonymous@" << toString(v->loc);    // anonymous namespaces
+  };
+
+  // return if no templates are involved
+  if (!curCompound || !(curCompound->templateInfo())) return sb;
+  TemplateInfo *tinfo = curCompound->templateInfo();
+  if (tinfo->isPrimary()) {
+    if (tinfo->params.isEmpty()) {
+      // it has template info because it is contained inside a
+      // template, but this class is not itself a template, so do not
+      // print template arguments as if it were
+    }
+    else {
+      // print the params like arguments for a primary
+      sb << tinfo->paramsLikeArgsToString();
+    }
+  }
+  else {
+    if (tinfo->isInstantiation()) {
+      if (tinfo->instantiationOf->templateInfo()->isPartialSpec()) {
+        // print the partial spec args first, so then the instantiation
+        // args can be interpreted relative to the partial spec args
+        fqn_STemplateArgs(sb, tinfo->instantiationOf->templateInfo()->arguments);
+      }
+      else {
+        // Kind of a disaster here.  'tinfo->arguments' includes arguments
+        // applied to the templates that enclose this template.  So we
+        // need to just look at the last 'n' arguments where 'n' is the
+        // number of parameters of the template this was actually
+        // instantiated from.
+        //
+        // TODO: The arguments need to be split into two lists.
+
+        // How many arguments should we be printing?
+        int n = tinfo->instantiationOf->templateInfo()->params.count();
+        if (n == 0) {
+          // This isn't even itself a template.
+        }
+        else {
+          // How many arguments do we need to skip?
+          int skip = tinfo->arguments.count() - n;
+          xassert(skip >= 0);
+
+          // set up iterator for skipping
+          SObjList<STemplateArgument> const &slist =
+            objToSObjListC(tinfo->arguments);
+          SObjListIter<STemplateArgument> iter(slist);
+
+          // skip
+          while (skip--) {
+            iter.adv();
+          }
+
+          // finally, print
+          sb << sargsToString(iter);
+        }
+      }
+    }
+    else {
+      fqn_STemplateArgs(sb, tinfo->arguments);
+    }
+  }
+
+  return sb;
+}
+
+
+void Scope::setParameterizedEntity(Variable *entity)
+{
+  xassert(!parameterizedEntity &&            // should do this only once
+          "4d621e9b-fdc9-4646-918c-76bd950d191c");             
+  xassert(isTemplateScope());                // doesn't make sense otherwise
+
+  parameterizedEntity = entity;
+
+  // arrange to delegate lookup to the entity if it is a compound
+  if (entity->type->isCompoundType()) {
+    CompoundType *ct = entity->type->asCompoundType();
+    ct->setDelegationPointer(this);
+
+    TRACE("templateParams", desc() << " now delegated to " << ct->desc());
+  }
+
+  // point all of the template parameters at the template
+  for (StringRefMap<Variable>::Iter iter(variables);
+       !iter.isDone(); iter.adv()) {
+    Variable *param = iter.value();
+
+    // should not already be parameterizing something
+    xassert(!param->getParameterizedEntity());
+
+    // this parameter parameterizes the template 'entity'
+    param->setParameterizedEntity(entity);
+  }
+}
+
+
+Variable *Scope::getScopeVariable() const
+{
+  if (curCompound) {
+    return curCompound->typedefVar;
+  }
+
+  if (isNamespace() || isGlobalScope()) {
+    return namespaceVar;
+  }
+
+  xfailure("getScopeVariable: not a compound or namespace");
+  return NULL;    // silence warning
+}
+
+
+void Scope::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitScope(this)) {
+    return;
+  }
+  traverse_internal(vis);
+  vis.postvisitScope(this);
+}
+
+void Scope::traverse_internal(TypeVisitor &vis)
+{
+  if (vis.visitScope_variables(variables)) {
+    for(PtrMap<char const, Variable>::Iter iter(variables);
+        !iter.isDone();
+        iter.adv()) {
+      StringRef name = iter.key();
+      Variable *var = iter.value();
+      if (vis.visitScope_variables_entry(name, var)) {
+        var->traverse(vis);
+        vis.postvisitScope_variables_entry(name, var);
+      }
+    }
+    vis.postvisitScope_variables(variables);
+  }
+
+  if (vis.visitScope_typeTags(typeTags)) {
+    for(PtrMap<char const, Variable>::Iter iter(typeTags);
+        !iter.isDone();
+        iter.adv()) {
+      StringRef name = iter.key();
+      Variable *var = iter.value();
+      if (vis.visitScope_typeTags_entry(name, var)) {
+        var->traverse(vis);
+        vis.postvisitScope_typeTags_entry(name, var);
+      }
+    }
+    vis.postvisitScope_typeTags(typeTags);
+  }
+
+  if (parentScope) {
+    parentScope->traverse(vis);
+  }
+  if (namespaceVar) {
+    namespaceVar->traverse(vis);
+  }
+
+  if (vis.visitScope_templateParams(templateParams)) {
+    SFOREACH_OBJLIST_NC(Variable, templateParams, iter) {
+      Variable *var = iter.data();
+      if (vis.visitScope_templateParams_item(var)) {
+        var->traverse(vis);
+        vis.postvisitScope_templateParams_item(var);
+      }
+    }
+    vis.postvisitScope_templateParams(templateParams);
+  }
+
+  // I don't think I need this; see Scott's comments in the scope
+  // class
+//    Variable *parameterizedEntity;          // (nullable serf)
+
+  // --------------- for using-directives ----------------
+  // Scott says that I don't need these
+
+  // it is basically a bug that we need to serialize this but we do so
+  // there it is.
+//    CompoundType *curCompound;          // (serf) CompoundType we're building
+//    Should not be being used after typechecking, but in theory could omit.
+  if (curCompound) {
+    curCompound->traverse(vis);
+  }
+}
+
+// EOF

Added: vendor/elsa/current/elsa/cc_scope.h
===================================================================
--- vendor/elsa/current/elsa/cc_scope.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_scope.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,354 @@
+// cc_scope.h            see license.txt for copyright and terms of use
+// a C++ scope, which is used by the Env parsing environment
+// and also by CompoundType to store members
+//
+// see Diagram 1 of doc/cpp_er.html
+
+#ifndef CC_SCOPE_H
+#define CC_SCOPE_H
+
+#include "cc_flags.h"     // AccessKeyword
+#include "srcloc.h"       // SourceLoc
+#include "strtable.h"     // StringRef
+#include "sobjlist.h"     // SObjList
+#include "array.h"        // ArrayStack
+#include "serialno.h"     // INHERIT_SERIAL_BASE
+#include "strmap.h"       // StringRefMap
+#include "lookupset.h"    // LookupSet
+
+// NOTE: We cannot #include cc_type.h b/c cc_type.h #includes cc_scope.h.
+
+class Env;                // cc_env.h
+class Variable;           // variable.h
+class TypeVisitor;        // cc_type.h
+class CompoundType;       // cc_type.h
+class BaseClassSubobj;    // cc_type.h
+class EnumType;           // cc_type.h
+class Function;           // cc.ast
+class TemplateParams;     // cc_type.h
+class PQName;             // cc.ast
+class TranslationUnit;    // cc.ast.gen.h
+class XmlReader;
+
+
+// information about a single scope: the names defined in it,
+// any "current" things being built (class, function, etc.)
+class Scope INHERIT_SERIAL_BASE {
+private:     // types
+  // for recording information about "active using" edges that
+  // need to be cancelled at scope exit
+  class ActiveEdgeRecord {
+  public:
+    Scope *source, *target;     // edge exists from source to target
+    
+  public:
+    ActiveEdgeRecord()
+      : source(NULL), target(NULL) {}
+    ActiveEdgeRecord(Scope *s, Scope *t)
+      : source(s), target(t) {}
+      
+    ActiveEdgeRecord& operator= (ActiveEdgeRecord const &obj)
+      { source=obj.source; target=obj.target; return *this; }
+  };
+
+  // needed to allow serialization and de-serialization
+  friend class XmlTypeWriter;
+  friend class XmlTypeReader;
+
+private:     // data
+  // variables: name -> Variable
+  // note: this includes typedefs (DF_TYPEDEF is set), and it also
+  // includes enumerators (DF_ENUMERATOR is set)
+  StringRefMap<Variable> variables;
+
+  // 2005-02-24: Rather than keeping separate maps for compounds
+  // and enums, I am now going to keep them in a unified map of
+  // type tags to typedef variables.
+  StringRefMap<Variable> typeTags;
+
+  // per-scope change count
+  int changeCount;
+  
+  // true if the scope is currently on the scope stack, meaning
+  // lookups can find it; this is used to ensure that no scope is
+  // ever on the scope stack twice
+  bool onScopeStack;
+
+public:      // data
+  // when this is set to false, the environment knows it should not
+  // put new names into this scope, but rather go further down into
+  // the scope stack to insert the name (used for scopes of template
+  // parameters, after the names have been added)
+  bool canAcceptNames;
+
+  // (serf) This is the parent (enclosing) scope, but only if that
+  // scope has a name (rationale: allow anonymous scopes to be
+  // deallocated).  For classes, this field is only set to non-NULL
+  // after the inner class has been fully constructed, since we can
+  // rely on the Environment's scope stack to look up things in
+  // containing classes while building the inner class for the first
+  // time (why did I do that??).  For namespaces, it's set as soon as
+  // the namespace is created.
+  Scope *parentScope;
+
+  // what kind of scope is this?
+  ScopeKind scopeKind;
+
+  // if this is a namespace, this points to the variable used to
+  // find the namespace during lookups
+  Variable *namespaceVar;
+                                      
+  // If this is a template (SK_TEMPLATE_PARAMS) scope, these are the
+  // template parameters.  We will attach them to functions and
+  // classes contained in this scope, as those functions and classes
+  // are parameterized by these variables.
+  SObjList<Variable> templateParams;
+
+  // If this is SK_TEMPLATE_PARAMS, then the parameters correspond to
+  // some specific template entity (primary, specialization, or
+  // instantiation, whichever is most specific to the situation).
+  // This pointer names that entity.  It is initially NULL, as we
+  // don't immediately know which is being parameterized, but is set
+  // to non-NULL as soon as we know.
+  //
+  // Once this is set to point at a class template entity, this
+  // scope is no longer used for lookups!  Instead, the parameterized
+  // class will delegate lookups directly at the proper time.
+  Variable *parameterizedEntity;          // (nullable serf)
+
+  // --------------- for using-directives ----------------
+  // possible optim:  For most scopes, these three arrays waste 13
+  // words of storage.  I could collect them into a separate structure
+  // and just keep a pointer here, making it non-NULL only when
+  // something gets put into an array.
+
+  // set of "using" edges; these affect lookups transitively when
+  // other scopes have active edges to this one
+  ArrayStack<Scope*> usingEdges;
+
+  // this is the in-degree of the usingEdges network; it is used to
+  // tell when a scope has someone using it, because that means we
+  // may need to recompute the active-using edges
+  int usingEdgesRefct;
+
+  // set of "active using" edges; these directly influence lookups
+  // in this scope
+  ArrayStack<Scope*> activeUsingEdges;
+
+  // set of "active using" edges in other scopes that need to be
+  // retracted once this scope exits
+  ArrayStack<ActiveEdgeRecord> outstandingActiveEdges;
+
+  // ------------- "current" entities -------------------
+  // these are set to allow the typechecking code to know about
+  // the context we're in
+  CompoundType *curCompound;          // (serf) CompoundType we're building
+  AccessKeyword curAccess;            // access disposition in effect
+  Function *curFunction;              // (serf) Function we're analyzing
+  SourceLoc curLoc;                   // latest AST location marker seen
+
+private:     // funcs
+  Variable *lookupVariable_inner
+    (LookupSet &candidates, StringRef name, Env &env, LookupFlags flags);
+  void lookupVariable_considerBase
+    (StringRef name, Env &env, LookupFlags flags,
+     Variable *&v1,
+     BaseClassSubobj const *&v1Subobj,
+     BaseClassSubobj const *v2Subobj);
+
+  // more using-directive stuff
+  void addActiveUsingEdge(Scope *target);
+  void removeActiveUsingEdge(Scope *target);
+  void scheduleActiveUsingEdge(Env &env, Scope *target);
+  bool foundViaUsingEdge(LookupSet &candidates, Env &env, LookupFlags flags,
+                         Variable *v, Variable *&vfound);
+  Variable *searchActiveUsingEdges
+    (LookupSet &candidates, StringRef name,
+     Env &env, LookupFlags flags, Variable *vfound);
+  Variable *searchUsingEdges
+    (LookupSet &candidates, StringRef name, Env &env, LookupFlags flags);
+  void getUsingClosure(ArrayStack<Scope*> &dest);
+
+  // variant of 'lookup' that does not expand overload sets
+  Variable *lookupSingleVariable(StringRef name, LookupFlags flags);
+
+protected:   // funcs
+  // this function is called at the end of addVariable, after the
+  // Variable has been added to the 'variables' map; it's intended
+  // that CompoundType will override this, for the purpose of
+  // maintaining 'dataMembers'
+  virtual void afterAddVariable(Variable *v);
+
+public:      // funcs
+  Scope(ScopeKind sk, int changeCount, SourceLoc initLoc);
+  Scope(XmlReader&);
+  virtual ~Scope();     // virtual to silence warning; destructor is not part of virtualized interface
+
+  int getChangeCount() const { return changeCount; }
+
+  // this is actually for debugging only ....
+  int getNumVariables() const       { return variables.getNumEntries(); }
+
+  // some syntactic sugar on the scope kind
+  bool isGlobalScope() const        { return scopeKind == SK_GLOBAL; }
+  bool isParameterScope() const     { return scopeKind == SK_PARAMETER; }
+  bool isFunctionScope() const      { return scopeKind == SK_FUNCTION; }
+  bool isClassScope() const         { return scopeKind == SK_CLASS; }
+  bool isTemplateParamScope() const { return scopeKind == SK_TEMPLATE_PARAMS; }
+  bool isTemplateArgScope() const   { return scopeKind == SK_TEMPLATE_ARGS; }
+  bool isNamespace() const          { return scopeKind == SK_NAMESPACE; }
+
+  // template params or args ...
+  bool isTemplateScope() const      { return isTemplateParamScope() || isTemplateArgScope(); }
+
+  // true if this scope is guaranteed to stick around until the end of
+  // the translation unit, and hence child scopes' 'parentScope' field
+  // and Variable::scope should be set to point at it
+  bool isPermanentScope() const;
+
+  // are we in a template scope that is in a global scope?
+  bool isGlobalTemplateScope() const;
+  // are we in a scope that at some point above is an uninstantiated
+  // templatized scope?
+  bool isWithinUninstTemplate() const;
+
+  // True if this scope has extant template parameters.  It is not
+  // enough to be a template scope, it must have parameters beyond
+  // an empty "<>".
+  bool hasTemplateParams() const;
+
+  // true if this scope is only accessed via delegation from
+  // a CompoundType
+  bool isDelegated() const;
+
+  // true if this scope is CompoundType and delegates to another
+  bool hasDelegationPointer() const
+    { return !!getDelegationPointer(); }
+  Scope *getDelegationPointer() const;
+  Scope *getAndNullifyDelegationPointer();
+  void setDelegationPointer(Scope *s);
+
+  // insertion; these return false if the corresponding map already
+  // has a binding (unless 'forceReplace' is true)
+  bool addVariable(Variable *v, bool forceReplace=false);
+  bool addCompound(CompoundType *ct);
+  bool addEnum(EnumType *et);
+  bool addTypeTag(Variable *tag);
+
+  // mark 'v' as being a member of this scope, by setting its 'scope'
+  // and 'scopeKind' members (this is not done by 'addVariable')
+  void registerVariable(Variable *v);
+
+  // somewhat common sequence: register, add, assert that the add worked
+  void addUniqueVariable(Variable *v);
+
+  // 2005-02-24: new and improved lookup
+  void lookup(LookupSet &set, StringRef name, Env &env, LookupFlags flags);
+
+  // 2005-08-03: when 'env' is NULL, errors are not reported
+  void lookup(LookupSet &set, StringRef name, Env /*nullable*/ *env,
+              LookupFlags flags);
+
+  // like Env::lookupPQ_one
+  Variable *lookup_one(StringRef name, Env &env, LookupFlags flags);
+  Variable *lookup_one(StringRef name, Env *env, LookupFlags flags);
+
+  // lookup; these return NULL if the name isn't found; 'env' is
+  // passed for the purpose of reporting ambiguity errors
+  Variable *lookupVariable(StringRef name, Env &env, LookupFlags f=LF_NONE);
+  CompoundType const *lookupCompoundC(StringRef name, Env &env, LookupFlags f=LF_NONE) const;
+  EnumType const *lookupEnumC(StringRef name, Env &env, LookupFlags f=LF_NONE) const;
+  
+  // compounds/enums
+  Variable *lookupTypeTag(StringRef name, Env &env, LookupFlags f=LF_NONE) const;
+
+  // non-const versions..
+  CompoundType *lookupCompound(StringRef name, Env &env, LookupFlags f=LF_NONE)
+    { return const_cast<CompoundType*>(lookupCompoundC(name, env, f)); }
+  EnumType *lookupEnum(StringRef name, Env &env, LookupFlags f=LF_NONE)
+    { return const_cast<EnumType*>(lookupEnumC(name, env, f)); }
+
+  // for iterating over the variables
+  StringRefMap<Variable>::Iter getVariableIter() const
+    { return StringRefMap<Variable>::Iter(variables); }
+
+  // and the type tags
+  StringRefMap<Variable>::Iter getTypeTagIter() const
+    { return StringRefMap<Variable>::Iter(typeTags); }
+
+  // lookup within the 'variables' map, without consulting base
+  // classes, etc.; returns NULL if not found
+  Variable *rawLookupVariable(StringRef name)
+    { return variables.get(name); }
+
+  // extended interface for returning sets
+  Variable *lookupVariable_set
+    (LookupSet &candidates, StringRef name, Env &env, LookupFlags flags);
+
+
+  // if this scope has a name, return the typedef variable that
+  // names it; otherwise, return NULL
+  Variable const *getTypedefNameC() const;
+  Variable *getTypedefName() { return const_cast<Variable*>(getTypedefNameC()); }
+  bool hasName() const { return scopeKind==SK_CLASS || scopeKind==SK_NAMESPACE; }
+
+  // true if this scope encloses (has as a nested scope) 's'; this
+  // is proper enclosure: it is not the case that s->encloses(s)
+  bool encloses(Scope const *s) const;
+  
+  // non-proper enclosure
+  bool enclosesOrEq(Scope const *s) const;
+
+  // stuff for using-directives
+  void addUsingEdge(Scope *target);
+  void addUsingEdgeTransitively(Env &env, Scope *target);
+
+  // indication of scope open/close so we can maintain the
+  // connection between "using" and "active using" edges
+  void openedScope(Env &env);
+  void closedScope();
+
+  // dsw: needed this and this was a natural place to put it
+  bool immediateGlobalScopeChild();
+  bool linkerVisible();
+
+  // This is just a unique and possibly human readable string; it is
+  // used in the Oink linker imitator.
+  //
+  // sm: TODO: Change the name so it reflects the mangling activity;
+  // I want "fullyQualifiedName" to do what "fullyQualifiedCName"
+  // does now.
+  //
+  // dsw: I made your way the only way; that is, I just inlined mangle
+  // as set to false
+  string fullyQualifiedName();
+  
+  // more C-like notation for a fully qualified name
+  string fullyQualifiedCName() {
+    // dsw: see the note above; these functions are now identical.
+    return fullyQualifiedName();
+  }
+
+  // set 'parameterizedEntity', checking a few things in the process
+  void setParameterizedEntity(Variable *entity);
+
+  // this scope must be a CompoundType or a namespace; get the
+  // Variable 'v' such that v.getDenotedScope() == this
+  Variable *getScopeVariable() const;
+
+  // dsw: I know this is *almost* the only virtual method, but
+  // traverse() is virtual everywhere else; change it if you like
+  virtual void traverse(TypeVisitor &vis);
+  // this is factored out so that subclasses can call it
+  void traverse_internal(TypeVisitor &vis);
+
+  // name of this scope for use in error messages and such
+  string scopeName() const;
+
+  // for debugging, a quick description of this scope
+  string desc() const;
+  void gdb() const;
+};
+
+
+#endif // CC_SCOPE_H

Added: vendor/elsa/current/elsa/cc_tcheck.ast
===================================================================
--- vendor/elsa/current/elsa/cc_tcheck.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_tcheck.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,784 @@
+// -*- c++ -*-
+// cc_tcheck.ast            see license.txt for copyright and terms of use
+// extension module for cc.ast that defines the entry points
+// for the type checker, and the annotations it produces
+
+// the implementations for the functions declared here are in
+// cc_tcheck.cc and cc_ast_aux.cc
+
+
+// extension modules' first "verbatim" section goes after
+// the initial verbatims from the base, but before any
+// of the classes from the base
+verbatim {
+  #include "variable.h"      // Variable
+  #include "cc_type.h"       // Type, FunctonType, CompoundType
+  #include "template.h"      // STemplateArgument
+  #include "const_eval.h"    // ConstEval
+  #include "macros.h"        // Restorer
+
+  class Env;                 // cc_env.h
+  class ArgumentInfo;        // overload.h
+}
+
+impl_verbatim {
+  // NOTE: do not include xml_type_id.h in the header, because it needs to
+  // include cc.gen.ast.h.
+  #include "xml_type_id.h"   // type system serialization identity
+}
+
+// this code goes into the xml serialization class
+xml_verbatim {
+  /* this is elsa/cc_tcheck.ast */
+  virtual bool shouldSerialize(Variable const *) { return true; }
+}
+
+custom ASTVisitor {
+public:      // custom data extensions
+  // this is true when we are inside the body of a template function
+  // or class (uninstantiated)
+  bool inTemplate;
+}
+custom ASTVisitor_ctor { inTemplate=false; }
+
+
+class TranslationUnit {
+  public(xml_TY) Scope *globalScope = NULL;
+
+  // This is the type checker entry point at the top level.  It
+  // writes error messages (if any) into 'env' and annotations
+  // directly into the AST fields declared below.
+  //
+  // Most of the AST classes have their own 'tcheck' or similar
+  // function, though the exact calling convention (params, etc.)
+  // varies.
+  //
+  // Some classes have an 'itcheck' (internal type check) for the
+  // subclasses, meaning the superclass 'tcheck' does some common
+  // processing and then delegates to the per-subclass 'itcheck.
+  public void tcheck(Env &env);
+}
+
+
+class TopForm {
+  public /*no_ignore*/ TopForm *tcheck(Env &env);
+  pure_virtual void itcheck(Env &env);
+}
+
+
+class Function {
+  // since 'nameAndParams->var' might refer to a previous declaration,
+  // and therefore might have differently-named parameters, I'll add
+  // another field specifically for a version of the FunctionType
+  // which has the parameters for *this* definition
+  public(xml_TY) FunctionType *funcType = NULL;
+
+  // since the body of the function (if a class member) may refer
+  // to the receiver object, I need to write it down so client
+  // analyses can find it
+  //
+  // 7/29/04: combined this with the old 'ctorReceiver'
+  public(xml_TY,xmlShouldSerialize) Variable *receiver = NULL;
+
+  public void printExtras(ostream &os, int indent) const;
+  custom debugPrint { printExtras(os, indent); }
+
+  // if this Function is intended to be a clone of a template body,
+  // but we have not actually cloned the init/body/handlers, then
+  // this is a pointer to the Function to eventually clone, acting
+  // as a thunk; otherwise it is NULL
+  //
+  // 2005-08-07: Don't traverse this!  It would make the resulting
+  // structure not a tree, and isn't for external consumption anyway.
+  // ("const" implies "serf" implies non-tree)
+  public Function const *cloneThunkSource = NULL;
+
+  // return a copy of this Function, but with just a clone thunk
+  public Function *shallowClone() const;
+  custom substituteClone { return shallowClone(); }
+
+  // if 'cloneThunkSource' is not NULL, clone its body elements
+  // to fill out 'this' object; otherwise, do nothing
+  public void finishClone();
+
+  // if 'instV' is not NULL, then force the declarator 'nameAndParams'
+  // to refer to it instead of using the usual lookup/creation
+  // mechanism
+  public void tcheck(Env &env, Variable *instV = NULL);
+
+  // this is where we end up if 'env.checkFunctionBodies' is true
+  public void tcheckBody(Env &env);
+
+  private CompoundType *verifyIsCtor(Env &env, char const *context);
+  private void tcheck_memberInits(Env &env);
+  private void tcheck_handlers(Env &env);
+
+  // this returns true if this is an instantiation of a template
+  // function that has not yet been tcheck'd
+  public bool instButNotTchecked() const;
+
+  // true if this is a function template (uninstantiated)
+  public bool isTemplate() const;
+}
+
+
+class MemberInit {
+  // if this is initializing a data member, tcheck will set this
+  public(xml_TY,xmlShouldSerialize) Variable *member = NULL;
+
+  // if it's a base class ctor call, tcheck will set this instead
+  public(xml_TY) CompoundType *base = NULL;
+
+  // the constructor used to initialize the member or subobject
+  // (can't call it "ctor".. that's an astgen keyword.. doh),
+  // or NULL for non-CompoundTypes
+  public(xml_TY,xmlShouldSerialize) Variable *ctorVar = NULL;
+
+  public void printExtras(ostream &os, int indent) const;
+  custom debugPrint { printExtras(os, indent); }
+
+  custom clone {
+    ret->member = member;
+    ret->base = base;
+    ret->ctorVar = ctorVar;
+  }
+
+  public void tcheck(Env &env, CompoundType *enclosing);
+}
+
+
+class Declaration {
+  public void tcheck(Env &env, DeclaratorContext context);
+}
+
+
+class ASTTypeId {
+  // tcheck params for ASTTypeId
+  public struct Tcheck {
+    // when non-NULL, we're in an E_new, and this points to an
+    // Expression* which should be set to the expression which denotes
+    // the number of elements for new[] to allocate
+    Expression **newSizeExpr;
+
+    // additional declflags to attach to the resulting Variable;
+    // when this includes DF_PARAMETER, it's a function parameter,
+    // which knowledge can be applied towards disambiguation
+    DeclFlags dflags;
+
+    // syntactic context
+    DeclaratorContext context;
+
+  public:
+    Tcheck(DeclFlags df, DeclaratorContext dc)
+      : newSizeExpr(NULL), dflags(df), context(dc) {}
+  };
+
+  // the return value is the ASTTypeId* to store in place of the
+  // one used to invoke the function, to resolve ambiguities
+  public ASTTypeId *tcheck(Env &env, Tcheck &tc);
+  public void mid_tcheck(Env &env, Tcheck &tc);
+
+  public Type *getType() const;      // can use after calling 'tcheck'
+}
+
+
+class PQName {
+  // typecheck the template arguments buried in this PQName
+  //
+  // 8/01/04: Go all the way to looking up the scopes denoted by the
+  // qualifiers.  'scope' is the scope denoted by the qualifiers seen
+  // so far, or NULL to mean "current scope", and 'lflags' might be
+  // LF_DECLARATOR if this PQName is the name of a declarator.
+  //
+  // 2005-03-14: Do not call this directly if the name might be
+  // ambiguous; use 'tcheckPQName' (in cc_tcheck.cc) instead.
+  pure_virtual void tcheck_pq(Env &env, Scope *scope = NULL,
+                              LookupFlags lflags = LF_NONE);
+
+  -> PQ_qualifier {
+       // record the result of looking up just the 'qualifier' portion
+       // (without considering template arguments); this is only set
+       // for the *first* PQ_qualifier in a PQName; it is needed for
+       // applyArgumentMap, since it should not be doing lookup
+       public(xml_TY,xmlShouldSerialize) Variable *qualifierVar = NULL;
+       custom debugPrint {
+         ind(os, indent) << "qualifierVar: " << refersTo(qualifierVar) << "\n";
+       }
+
+       // digested template arguments
+       public(xml_OL,xmlEmbed_List) ObjList<STemplateArgument> sargs;
+     }
+
+  -> PQ_template {
+       public(xml_OL,xmlEmbed_List) ObjList<STemplateArgument> sargs;
+     }
+}
+
+
+class TypeSpecifier {
+  // yield the type named by the specifier; this type may of course
+  // get refined when the declarator is considered
+  public Type *tcheck(Env &env, DeclFlags dflags);
+  pure_virtual Type *itcheck(Env &env, DeclFlags dflags);
+
+  // since several of the type specifiers use names, and names are
+  // scoped, but we don't want later analyses to have to know about
+  // scopes, for those specifiers that use names cc_tcheck writes down
+  // which type it refers to
+
+  -> TS_name {
+       // typedef Variable this name refers to
+       public(xml_TY,xmlShouldSerialize) Variable *var = NULL;
+
+       // if the lookup is *not* dependent (and some other conditions
+       // hold...), this will point to 'var' and be preserved when
+       // the AST is cloned
+       public(xml_TY,xmlShouldSerialize) Variable *nondependentVar = NULL;
+       custom clone { ret->nondependentVar = nondependentVar; }
+     }
+
+  -> TS_elaborated {
+       public(xml_TY) NamedAtomicType *atype = NULL;
+     }
+
+  -> TS_classSpec {
+       public(xml_TY) CompoundType *ctype = NULL;
+       public void tcheckIntoCompound(
+         Env &env, DeclFlags dflags, CompoundType *ct);
+       private void tcheckFunctionBodies(Env &env);
+
+       public void printExtras(ostream &os, int indent) const;
+       custom debugPrint { printExtras(os, indent); }
+     }
+
+  -> TS_enumSpec {
+       public(xml_TY) EnumType *etype = NULL;
+     }
+}
+
+
+class BaseClassSpec {
+  public void printExtras(ostream &os, int indent) const;
+  custom debugPrint { printExtras(os, indent); }
+
+  // the type named by the 'name'
+  public(xml_TY) CompoundType *type = NULL;
+}
+
+
+class Member {
+  pure_virtual void tcheck(Env &env);
+}
+
+
+class Enumerator {
+  public(xml_TY,xmlShouldSerialize) Variable *var; // (serf) introduction record
+  ctor var=NULL;
+
+  // when the enumerator values are computed, I store them here
+  // so I can see them in the AST printout; I only print this
+  // value if 'var' is non-NULL (i.e. the enumerator has been
+  // tcheck'd so the value has been determined)
+  public(xml) int enumValue;
+
+  public void printExtras(ostream &os, int indent) const;
+  custom debugPrint { printExtras(os, indent); }
+
+  // we pass both the base 'enum' and the Type wrapped around it,
+  // since both are needed and it's slightly expensive to compute
+  // one from the other for each enumerator
+  public void tcheck(Env &env, EnumType *parentEnum, Type *parentType);
+}
+
+
+// The "Declarator" AST node appears in many different contexts in the
+// AST, and visitor-based analyses often need to do quite different
+// things depending on which context a declarator appears in.  So,
+// this enumeration lists all the possible contexts.
+enum DeclaratorContext {
+  DC_UNKNOWN,             // dummy value; nothing should have this after tcheck
+
+  DC_FUNCTION,            // Function::nameAndParams
+                          // inside Declaration
+  DC_TF_DECL,             //   TF_decl::decl
+  DC_TF_EXPLICITINST,     //   TF_explicitInst::d
+  DC_MR_DECL,             //   MR_decl::d
+  DC_S_DECL,              //   S_decl::decl
+  DC_TD_DECL,             //   TD_decl::d
+  DC_FEA,                 //   FullExpressionAnnot::declarations
+                          // inside ASTTypeId
+  DC_D_FUNC,              //   D_func::params
+  DC_EXCEPTIONSPEC,       //   ExceptionSpec::types
+  DC_ON_CONVERSION,       //   ON_conversion::type
+  DC_CN_DECL,             //   CN_decl::typeId
+  DC_HANDLER,             //   Handler::typeId
+  DC_E_CAST,              //   E_cast::ctype
+  DC_E_SIZEOFTYPE,        //   E_sizeofType::atype
+  DC_E_NEW,               //   E_new::atype (new)
+  DC_E_KEYWORDCAST,       //   E_keywordCast::ctype
+  DC_E_TYPEIDTYPE,        //   E_typeidType::ttype
+  DC_TP_TYPE,             //   TP_type::defaultType
+  DC_TP_NONTYPE,          //   TP_nontype::param
+  DC_TA_TYPE,             //   TA_type::type
+};
+
+
+class Declarator {
+  // entity declared by this declarator
+  public(xml_TY,xmlShouldSerialize) Variable *var = NULL;// (serf) computed information: name, type, etc.
+  custom clone {ret->var = var;}
+
+  // This field need not be identical to 'var->type'; the 'type' here
+  // comes directly from the declartor syntax, but 'var' might refer
+  // to a previous declaration (e.g. two protoypes of the same
+  // function), and hence 'var->type' might differ in details like
+  // parameter names.  Otherwise, nominally, 'var->type' and 'type'
+  // denote equivalent types.
+  public(xml_TY) Type *type = NULL;
+
+  // syntactic context; sometimes useful to visitors
+  public(xml) DeclaratorContext context = DC_UNKNOWN;
+  custom clone {ret->context = context;}
+
+  public void printExtras(ostream &os, int indent) const;
+  custom debugPrint { printExtras(os, indent); }
+
+  // this class contains the data passed into and out of the
+  // declarator checking functions
+  public struct Tcheck {
+    // Normally, a declarator creates a Variable and inserts it
+    // into the environment.  If this field is non-NULL, then the
+    // declarator simply uses the supplied Variable instead.
+    // Either way, the Variable* is then stored in Declarator::var.
+    Variable *existingVar;
+
+    // on the way in, this is the type computed so far; initially
+    // it's just the type specifier but additional declarators will
+    // layer additional type constructors on top of it and replace
+    // the pointer here with a pointer to the constructed type; at
+    // the end it is the fully-constructed type
+    Type *type;
+
+    // these are the declflags attached to the outer declaration
+    DeclFlags dflags;
+
+    // in a new[] declarator, when we hit the final [size], stash
+    // the size's AST node pointer here; then E_new can collect it
+    Expression *size_E_new;
+
+    // if this is non-NULL, then it points at the D_func responsible
+    // for creating 'type', a FunctionType; this is used to determine
+    // the cv flags of the implicit 'this' parameter of member functions
+    D_func *funcSyntax;
+
+    // syntactic context
+    DeclaratorContext context;
+
+  public:
+    Tcheck(Type *t, DeclFlags d, DeclaratorContext dc)
+      : existingVar (NULL)
+      , type        (t)
+      , dflags      (d)
+      , size_E_new  (NULL)
+      , funcSyntax  (NULL)
+      , context     (dc)
+    {}
+    Tcheck(Tcheck const &obj)
+      : existingVar (obj.existingVar)
+      , type        (obj.type)
+      , dflags      (obj.dflags)
+      , size_E_new  (obj.size_E_new)
+      , funcSyntax  (obj.funcSyntax)
+      , context     (obj.context)
+    {}
+    Tcheck& operator= (Tcheck const &obj) {
+      existingVar = obj.existingVar;
+      type        = obj.type;
+      dflags      = obj.dflags;
+      size_E_new  = obj.size_E_new;
+      funcSyntax  = obj.funcSyntax;
+      context     = obj.context;
+      return *this;
+    }
+
+    bool hasFlag(DeclFlags f) const { return !!(dflags &f); }
+  };
+
+  // determine the type denoted by the combination of 'dt.type' and
+  // the type constructors in this declarator, then make a Variable
+  // that has that type; if this declarator refers to something that
+  // is *already* declared (like a function with a prior prototype),
+  // the 'var' field will be shared among the various declarations; if
+  // not, put it into the environment
+  //
+  // the return value specifies which of possibly ambiguous
+  // alternatives was selected
+  public /*no_ignore*/ Declarator *tcheck(Env &env, Tcheck &dt);
+  public void mid_tcheck(Env &env, Tcheck &dt);
+  public void tcheck_init(Env &env);
+}
+
+
+class IDeclarator {
+  // 8/11/04: There used to be a 'type' field here, but I decided that
+  // analyses probably have no need to know about the types denoted by
+  // IDeclarators, only that denoted by the full Declarator, which is
+  // stored in Declarator::type.
+
+  // external interface; add the type constructor represented by this
+  // IDeclarator to 'dt.type'
+  pure_virtual void tcheck(Env &env, Declarator::Tcheck &dt);
+
+  // returns true if there is a D_grouping that does not have
+  // any D_pointer, D_reference or D_ptrToMember inside it
+  public bool hasInnerGrouping() const;
+
+  -> D_func {
+       // I want to know which D_funcs are members of classes (whether
+       // static or not), but it's not sufficient to just check my
+       // environment context since I get confused by pointers to
+       // functions.. so I set this to true in MR_decl::tcheck and
+       // MR_func::tcheck
+       public(xml) bool isMember = false;
+     }
+
+  -> D_array {
+       // client analyses find it difficult to know whether this
+       // D_array means "array" or "new[] size", so I'm going to
+       // write down in cc_tcheck which one this is
+       public(xml) bool isNewSize = false;
+     }
+
+  -> D_bitfield {
+       // type checker stashes the bitfield size in bits here
+       public(xml) int numBits = 0;
+     }
+}
+
+
+class ExceptionSpec {
+  public FunctionType::ExnSpec *tcheck(Env &env);
+}
+
+
+class OperatorName {
+  public void tcheck(Env &env);
+}
+
+
+class Statement {
+  // typecheck, and return which Statement is selected from among
+  // syntactically ambiguous choices
+  public /*no_ignore*/ Statement *tcheck(Env &env);
+
+  public void mid_tcheck(Env &env, int &);
+  pure_virtual void itcheck(Env &env);
+
+  -> S_case {
+       // the case label must be an integer; this its value
+       public(xml) int labelVal = 0;
+     }
+}
+
+
+class Condition {
+  // typecheck, and return which Condition is selected from among
+  // syntactically ambiguous choices
+  public /*no_ignore*/ Condition *tcheck(Env &env);
+  public void mid_tcheck(Env &env, int &) { itcheck(env); };
+  pure_virtual void itcheck(Env &env);
+}
+
+
+class Handler {
+  public void tcheck(Env &env);
+}
+
+
+class Expression {
+  // type check and yield the type of the expression; this type
+  // gets automatically stored in the 'type' field; the return
+  // value specifies which of possibly ambiguous alternatives
+  // was selected for retention
+  public void tcheck(Env &env, Expression *&ptr);
+  public void mid_tcheck(Env &env, Expression *&replacement);
+
+  // per-type checker; return type this expression eval's to; if
+  // this Expression would like to rewrite itself, then it can put
+  // the new Expression into 'replacement' and the parent AST node
+  // will be updated accordingly; the caller should always put the
+  // receiver object pointer into 'replacement' initially
+  //
+  // the "_x" is for grepping value; think of it as standing for 'eXpression'
+  pure_virtual Type *itcheck_x(Env &env, Expression *&replacement);
+
+  // type computed for this expression; might be a SimpleType for
+  // ST_ERROR, in which case a subsequent attempt to typecheck the
+  // same expression should stop and look for an ambiguous alt.
+  public(xml_TY) Type *type = NULL;
+
+  // this is a violation of the cloning invariant, but it gets fixed
+  // with CloneExprTypesVisitor after the AST has been fully cloned
+  custom clone {
+    ret->type = type;
+  }
+
+  // make the API for getting the type identical to that of FullExpression
+  public Type *getType() { return type; };
+
+  // const-eval; will add an error message to the environment if this
+  // expression is not a constant (and also return false); can only
+  // call this after tchecking; result must be an integer
+  public bool constEval(Env &env, int &result) const;
+
+  // if the function returns true and 'dependent' returns as true, the
+  // expression *is* constant but the precise value is dependent on
+  // template parameters
+  public bool constEval(Env &env, int &result, bool &dependent) const;
+
+  // more control: all info returned in the return value
+  public CValue constEval(ConstEval &env) const;
+  public CValue iconstEval(ConstEval &env) const;
+  public virtual CValue extConstEval(ConstEval &env) const;
+
+  // this attempts to evaluate the expression's address
+  public CValue constEvalAddr(ConstEval &env) const;
+
+  // shared by E_cast and E_keywordCast
+  public CValue constEvalCast(ConstEval &env, ASTTypeId const *ctype,
+                              Expression const *expr) const;
+
+  // return true if this expression has any greater-than operators
+  // that are not buried under an E_grouping; this may modify 'expr'
+  // if it filters out certain ambiguous alternatives
+  public static bool hasUnparenthesizedGT(Expression *&expr);
+  public bool ihasUnparenthesizedGT();
+  public virtual bool extHasUnparenthesizedGT();
+
+  // return what kind of special expression this is, if any
+  public SpecialExpr getSpecial(CCLang &lang) const;
+
+  public void printExtras(ostream &os, int indent) const;
+  custom debugPrint { printExtras(os, indent); }
+
+  // interpretations of literals
+  -> E_intLit      { public(xml) unsigned long i = 0; }
+  -> E_floatLit    { public(xml) double d = 0; }
+  -> E_stringLit   { /* TODO: put a DataBlock here */ }
+  -> E_charLit     { public(xml) unsigned int c = 0; }
+
+  -> E_this {
+       // the receiver parameter to which this 'this' refers; NOTE
+       // that 'receiver' is a *reference* whereas E_this is a
+       // *pointer* (it's like taking the address of 'receiver')
+       public(xml_TY,xmlShouldSerialize) Variable *receiver = NULL;
+       custom clone { ret->receiver = receiver; }
+     }
+
+  -> E_variable {
+       public(xml_TY,xmlShouldSerialize) Variable *var = NULL; // (serf) binding introduction of this name
+       public Type *itcheck_var(Env &env, Expression *&replacement, LookupFlags flags);
+       custom clone { ret->var = var; }
+
+       // extended tcheck interface for lookups that yield sets
+       public Type *itcheck_var_set(Env &env, Expression *&replacement,
+                                    LookupFlags flags, LookupSet &set);
+
+       // similar to TS_name::nondependentVar
+       public(xml_TY,xmlShouldSerialize) Variable *nondependentVar = NULL;
+       custom clone { ret->nondependentVar = nondependentVar; }
+     }
+
+  // these two kinds have their tcheck further split into two stages
+  // so I can use a more specialized disambiguation procedure; the
+  // first stage is sufficient to disambiguate between the two
+  -> E_funCall {
+       public void inner1_itcheck(Env &env, LookupSet &candidates);
+       public Type *inner2_itcheck(Env &env, LookupSet &candidates);
+     }
+  -> E_constructor {
+       public void inner1_itcheck(Env &env);
+       public Type *inner2_itcheck(Env &env, Expression *&replacement);
+
+       // The constructor function being called.  If this is NULL, it
+       // means the constructor is "trivial"; for a no-arg ctor this
+       // means a no-op, and for a copy ctor it means member-wise
+       // assignment implementable with a memcpy.  (This is a
+       // generalization of the Standard's notion of "trivial"; see
+       // cppstd 12.1p5,6.)
+       public(xml_TY,xmlShouldSerialize) Variable *ctorVar = NULL;
+       custom clone { ret->ctorVar = ctorVar; }
+     }
+
+  -> E_fieldAcc {
+       public(xml_TY,xmlShouldSerialize) Variable *field = NULL;
+       public Type *itcheck_fieldAcc(Env &env, LookupFlags flags);
+       public Type *itcheck_fieldAcc_set(Env &env, LookupFlags flags,
+                                         LookupSet &candidates);
+
+       custom clone { ret->field = field; }
+     }
+
+  -> E_sizeof {
+       public(xml) int size = -1; // size of the type of expr
+       custom clone { ret->size = size; }
+     }
+
+  -> E_cast {
+       // idempotency for type definitions in casts
+       public(xml) bool tcheckedType = false;
+     }
+
+  -> E_sizeofType {
+       public(xml) int size = -1; // size of the type
+       custom clone { ret->size = size; }
+
+       // This flag is used in some circumstances in C mode to ensure
+       // a given type expression is only tchecked one time, despite
+       // possible ambiguities.  (See the tcheck method.)
+       public(xml) bool tchecked = false;
+     }
+
+  // Q: should I manually clone all the annotation fields?  Do I
+  // need them all?  Should I make a new mechanism in astgen to do
+  // this automatically?
+
+  -> E_new {
+       // if this is non-NULL, it's the number of elements to allocate via new[]
+       //
+       // 2005-08-07: Don't traverse this!  It is a non-tree pointer.
+       // That is why it says "serf".
+       public(xml_AST) Expression /*nullable serf*/ *arraySize = NULL;
+
+       // constructor being called to initialize the storage
+       public(xml_TY,xmlShouldSerialize) Variable *ctorVar = NULL;
+       custom debugPrint { ind(os,indent) << "ctorVar: " << refersTo(ctorVar) << "\n"; }
+       custom clone { ret->ctorVar = ctorVar; }
+     }
+
+  // extended tcheck interface for lookups that yield sets; see
+  // tcheckExpression_set() in cc_tcheck.cc
+  -> E_addrOf {
+       public Type *itcheck_addrOf_set(Env &env, Expression *&replacement,
+                                       LookupFlags flags, LookupSet &set);
+     }
+  -> E_grouping {
+       public Type *itcheck_grouping_set(Env &env, Expression *&replacement,
+                                         LookupFlags flags, LookupSet &set);
+     }
+  -> E_arrow {
+       public Type *itcheck_arrow_set(Env &env, Expression *&replacement,
+                                      LookupFlags flags, LookupSet &set);
+     }
+}
+
+
+class FullExpression {
+  public void tcheck(Env &env);
+
+  // duplicate the API of Expression and delegate all the calls down
+  // to the Expression *expr member
+  public Type *getType() const
+    { return expr->type; };
+  public bool constEval(Env &env, int &result) const
+    { return expr->constEval(env, result); };
+  public CValue constEval(ConstEval &env) const
+    { return expr->constEval(env); };
+  public CValue iconstEval(ConstEval &env) const
+    { return expr->iconstEval(env); };
+}
+
+
+class ArgExpression {
+  // repeat some of Expression's interface so I can avoid adding
+  // lots of annoying "expr->expr" clutter
+  public Type *getType() const
+    { return expr->type; };
+  public bool constEval(Env &env, int &result) const
+    { return expr->constEval(env, result); };
+  public CValue constEval(ConstEval &env) const
+    { return expr->constEval(env); };
+  public CValue iconstEval(ConstEval &env) const
+    { return expr->iconstEval(env); };
+  public bool hasUnparenthesizedGT()
+    { return Expression::hasUnparenthesizedGT(expr); };
+  public SpecialExpr getSpecial(CCLang &lang) const
+    { return expr->getSpecial(lang); };
+
+  public ArgExpression *tcheck(Env &env, ArgumentInfo &);
+  public void mid_tcheck(Env &env, ArgumentInfo &);
+}
+
+
+class Initializer {
+  // check that the initializer is well-typed, given the type of
+  // the thing it initializes
+  pure_virtual void tcheck(Env &env, Type *type);
+
+  -> IN_ctor() {
+       // constructor function being called
+       public(xml_TY,xmlShouldSerialize) Variable *ctorVar = NULL;
+
+       // true if this was originally an IN_expr that the type
+       // checker rewrote as IN_ctor; needed to implement 8.5p14
+       public(xml,field) bool was_IN_expr = false;
+
+       custom clone {
+         ret->ctorVar = ctorVar;
+         ret->was_IN_expr = was_IN_expr;
+       }
+     }
+}
+
+
+class TemplateDeclaration {
+  public void tcheck(Env &env);
+  pure_virtual void itcheck(Env &env);
+
+  // oy, I wanted 'preemptTraverse' to affect all TemplateDeclarations
+  // at once, but that's a little difficult, so I have to copy it..
+
+  -> TD_func {
+       custom preemptTraverse {
+         // we are now in a template if we already were, or if this
+         // declaration is not a complete specialization
+         Restorer<bool> r(vis.inTemplate, vis.inTemplate || params!=NULL);
+       }
+     }
+
+  -> TD_decl {
+       custom preemptTraverse {
+         Restorer<bool> r(vis.inTemplate, vis.inTemplate || params!=NULL);
+       }
+     }
+
+  -> TD_tmember {
+       custom preemptTraverse {
+         Restorer<bool> r(vis.inTemplate, vis.inTemplate || params!=NULL);
+       }
+     }
+}
+
+
+class TemplateParameter {
+  public /*no_ignore*/ TemplateParameter *tcheck(Env &env);
+  public void mid_tcheck(Env &env, int &dummy);
+  pure_virtual void itcheck(Env &env, int &dummy);
+
+  // parameter Variable
+  public(xml_TY,xmlShouldSerialize) Variable *var = NULL;
+}
+
+
+class TemplateArgument {
+  public /*no_ignore*/ TemplateArgument *tcheck(Env &env, STemplateArgument &sarg);
+  public void mid_tcheck(Env &env, STemplateArgument &sarg);
+  pure_virtual void itcheck(Env &env, STemplateArgument &sarg);
+}
+
+
+class NamespaceDecl {
+  pure_virtual void tcheck(Env &env);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/cc_tcheck.cc
===================================================================
--- vendor/elsa/current/elsa/cc_tcheck.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_tcheck.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9647 @@
+// cc_tcheck.cc            see license.txt for copyright and terms of use
+// C++ typechecker, implemented as methods declared in cc_tcheck.ast
+
+// Throughout, references are made to the ISO C++ Standard:
+//
+// International Organization for Standardization.
+// ISO/IEC 14882:1998: Programming languages -- C++.
+// International Organization for Standardization, Geneva,
+// Switzerland, September 1998.
+//
+// These references are all marked with the string "cppstd".
+
+#include "cc_ast.h"         // C++ AST
+#include "cc_ast_aux.h"     // class LoweredASTVisitor
+#include "cc_env.h"         // Env
+#include "trace.h"          // trace
+#include "cc_print.h"       // PrintEnv
+#include "strutil.h"        // decodeEscapes
+#include "cc_lang.h"        // CCLang
+#include "stdconv.h"        // test_getStandardConversion
+#include "implconv.h"       // test_getImplicitConversion
+#include "overload.h"       // resolveOverload
+#include "generic_amb.h"    // resolveAmbiguity, etc.
+#include "implint.h"        // resolveImplIntAmbig
+#include "ast_build.h"      // makeExprList1, etc.
+#include "strutil.h"        // prefixEquals, pluraln
+#include "macros.h"         // Restorer
+#include "typelistiter.h"   // TypeListIter_FakeList
+#include "owner.h"          // Owner
+#include "mtype.h"          // MType
+
+#include <stdlib.h>         // strtoul, strtod
+#include <ctype.h>          // isdigit
+#include <limits.h>         // INT_MAX, UINT_MAX, LONG_MAX
+
+// D(): debug code
+#ifdef NDEBUG
+  #define D(stuff)
+#else
+  #define D(stuff) stuff
+#endif
+
+
+// forwards in this file
+
+void tcheckPQName(PQName *&name, Env &env, Scope *scope = NULL,
+                  LookupFlags lflags = LF_NONE);
+
+static Variable *outerResolveOverload_ctor
+  (Env &env, SourceLoc loc, Type *type, ArgumentInfoArray &argInfo);
+
+static Variable *outerResolveOverload_explicitSet(
+  Env &env,
+  PQName * /*nullable*/ finalName,
+  SourceLoc loc,
+  StringRef varName,
+  ArgumentInfoArray &argInfo,
+  SObjList<Variable> &candidates);
+
+FakeList<ArgExpression> *tcheckArgExprList(FakeList<ArgExpression> *list, Env &env,
+                                           ArgumentInfoArray &argInfo,
+                                           Type *receiverType = NULL);
+
+Type *resolveOverloadedUnaryOperator(
+  Env &env,
+  Expression *&replacement,
+  //Expression *ths,
+  Expression *expr,
+  OverloadableOp op);
+
+void compareCtorArgsToParams(Env &env, Variable *ctor,
+                             FakeList<ArgExpression> *args,
+                             ArgumentInfoArray &argInfo);
+
+
+
+// return true if the list contains no disambiguating errors
+bool noDisambErrors(ErrorList const &list)
+{
+  return !list.hasDisambErrors();
+}
+
+
+// 'ambiguousNodeName' is a template function in generic_amb.h, but
+// declarators are special, since there's only one node type; the
+// difference lies in the values of the fields (ah, the beauty of C++
+// template specialization..)
+string ambiguousNodeName(Declarator const *n)
+{
+  if (n->init) {
+    return string("Declarator with initializer");
+  }
+  else {
+    return string("Declarator without initializer");
+  }
+}
+
+string ambiguousNodeName(Expression const *e)
+{
+  if (e->isE_new()) {
+    E_new const *en = e->asE_newC();
+
+    // the ambiguity has to do with presence of placement args
+    // and/or ctor args, so report that info
+    stringBuilder sb;
+    sb << "E_new";
+    if (en->placementArgs && en->ctorArgs) {
+      sb << " with placement args and ctor args";
+    }
+    else if (en->placementArgs) {
+      sb << " with placement args";
+    }
+    else if (en->ctorArgs) {
+      sb << " with ctor args";
+    }
+    return sb;
+  }
+  else {
+    return e->kindName();
+  }
+}
+
+
+// little experiment: since I've implemented the "confused by earlier
+// errors" mechanism, there is now a big difference between a segfault
+// and an xfailure (the latter being mapped to "confused" sometimes);
+// so I will try sprinkling this as a way of preventing the segfault
+template <class T>
+inline T *mustBeNonNull(T *ptr)
+{
+  xassert(ptr);
+  return ptr;
+}
+
+
+// ------------------- UninstTemplateErrorFilter ------------------
+// filter that keeps only strong messages
+bool strongMsgFilter(ErrorMsg *msg)
+{
+  if (msg->flags & EF_STRONG) {
+    // keep it
+    return true;
+  }
+  else {
+    // drop it
+    TRACE("error", "dropping error arising from uninst template: " << msg->msg);
+    return false;
+  }
+}
+
+
+// take the errors, and later put them back after filtering
+class UninstTemplateErrorFilter {
+  Env &env;                  // environment
+  ErrorList existingErrors;  // saved messages
+
+public:
+  UninstTemplateErrorFilter(Env &e)
+    : env(e), existingErrors()
+  {
+    if (env.inUninstTemplate()) {
+      existingErrors.takeMessages(env.errors);
+    }
+  }
+
+  ~UninstTemplateErrorFilter()
+  {
+    if (env.inUninstTemplate()) {
+      if (!env.doReportTemplateErrors) {
+        // remove all messages that are not 'strong'
+        // (see doc/permissive.txt)
+        env.errors.filter(strongMsgFilter);
+      }
+
+      // now put back the saved messages
+      env.errors.prependMessages(existingErrors);
+    }
+  }
+};
+
+
+// ------------------- TranslationUnit --------------------
+// dsw: this method is generic enough that perhaps it should be called
+// "applyFlagsToGlobals" or something since you could in theory call
+// it with any kind of flag
+void applyExternC(TopForm *form, DeclFlags flags)
+{
+  ASTSWITCH(TopForm, form) {
+    ASTCASE(TF_decl, d)   d->decl->dflags |= flags;
+    ASTNEXT(TF_func, f)   f->f->dflags |= flags;
+    // just ignore other forms
+    ASTENDCASED
+  }
+}
+
+void TranslationUnit::tcheck(Env &env)
+{
+  // dsw: this is copied from TF_linkage::itcheck(); per Scott's
+  // suggestion, in C mode we just want to pretend that the entire
+  // TranslationUnit was wrapped in an extern "C" {} block.  This way
+  // our mangled names from C and C++ translation units will link
+  // together correctly.
+  if (!env.lang.isCplusplus) {
+    // since there is no 'extern "C"' syntax in C, this block
+    // shouldn't ever get called on this TranslationUnit from both
+    // here and from TF_linkage::itcheck()
+    FOREACH_ASTLIST_NC(TopForm, topForms, iter) {
+      applyExternC(iter.data(), DF_EXTERN_C);
+    }
+  }
+
+  static int topForm = 0;
+  FOREACH_ASTLIST_NC(TopForm, topForms, iter) {
+    ++topForm;
+    TRACE("topform", "--------- topform " << topForm <<
+                     ", at " << toString(iter.data()->loc) <<
+                     " --------");
+    iter.setDataLink( iter.data()->tcheck(env) );
+  }
+}
+
+
+// --------------------- TopForm ---------------------
+TopForm *TopForm::tcheck(Env &env)
+{
+  if (!ambiguity) {
+    itcheck(env);
+    return this;
+  }
+
+  TopForm *ret = resolveImplIntAmbig(env, this);
+  xassert(ret);
+  return ret->tcheck(env);
+}
+
+void TF_decl::itcheck(Env &env)
+{
+  env.setLoc(loc);
+  decl->tcheck(env, DC_TF_DECL);
+}
+
+void TF_func::itcheck(Env &env)
+{
+  env.setLoc(loc);
+  f->tcheck(env);
+}
+
+void TF_template::itcheck(Env &env)
+{
+  env.setLoc(loc);
+  td->tcheck(env);
+}
+
+void TF_explicitInst::itcheck(Env &env)
+{
+  env.setLoc(loc);
+
+  // Q: Why even bother to implement "extern template"?  Why not just
+  // treat it the same as "template"?  After all, Elsa does not
+  // generate code anyway.
+  //
+  // A: It causes problems for input minimization.  If we instantiate
+  // in response to "extern template", then when we go to minimize an
+  // input w.r.t. some failure, Elsa is doing a lot more work than gcc
+  // is, so usually Delta just creates some invalid code that gcc
+  // accepts simply because it is not instantiating a bunch of stuff.
+  //
+  // Therefore, Elsa tries to do the same amount of work as gcc, and
+  // that means implementing "extern template".  This does have the
+  // effect of potentially masking some problems, but it is worth it.
+  // And, you can unmask them by deleting "extern", at which point gcc
+  // will have to instantiate too, so the playing field remains level.
+
+  // little trick: pass the 'instFlags' down into Declarator::mid_tcheck
+  d->dflags |= instFlags;
+
+  d->tcheck(env, DC_TF_EXPLICITINST);
+
+  // class instantiation?
+  if (d->decllist->isEmpty()) {
+    if (d->spec->isTS_elaborated()) {
+      NamedAtomicType *nat = d->spec->asTS_elaborated()->atype;
+      if (!nat) return;    // error recovery
+
+      if (nat->isCompoundType() &&
+          nat->asCompoundType()->isInstantiation()) {
+        env.explicitlyInstantiate(nat->asCompoundType()->typedefVar, instFlags);
+      }
+      else {
+        // catch "template class C;"
+        env.error("explicit instantiation (without declarator) is only for class instantiations");
+      }
+    }
+    else {
+      // catch "template C<int>;"
+      env.error("explicit instantiation (without declarator) requires \"class ...\"");
+    }
+  }
+
+  // function instantiation?
+  else if (d->decllist->count() == 1) {
+    // instantiation is handled by declarator::mid_tcheck
+  }
+
+  else {
+    // other template declarations are limited to one declarator, so I
+    // am simply assuming the same is true of explicit instantiations,
+    // even though 14.7.2 doesn't say so explicitly...
+    env.error("too many declarators in explicit instantiation");
+  }
+}
+
+void TF_linkage::itcheck(Env &env)
+{
+  env.setLoc(loc);
+
+  // dig down and apply DF_EXTERN_C to each form; this is preferable
+  // to a flag in Env because this way I can be sure that DF_EXTERN_C
+  // will only be applied to toplevel symbols
+  if (linkageType == env.quote_C_quote) {
+    FOREACH_ASTLIST_NC(TopForm, forms->topForms, iter) {
+      applyExternC(iter.data(), DF_EXTERN_C);
+    }
+  }
+
+  forms->tcheck(env);
+}
+
+void TF_one_linkage::itcheck(Env &env)
+{
+  env.setLoc(loc);
+
+  // we need to dig down into the form to apply 'extern'
+  // [cppstd 7.5 para 7]
+  DeclFlags toApply = DF_EXTERN;
+  if (linkageType == env.quote_C_quote) {
+    toApply |= DF_EXTERN_C;
+  }
+  applyExternC(form, toApply);
+
+  // typecheck the underlying form
+  form->tcheck(env);
+}
+
+string collectContinuations(E_stringLit *strLit)
+{
+  stringBuilder sb;
+
+  while (strLit) {
+    sb << parseQuotedString(strLit->text);
+    strLit = strLit->continuation;
+  }
+
+  return sb;
+}
+
+void TF_asm::itcheck(Env &env)
+{
+  env.setLoc(loc);
+
+  StringRef t = text->text;
+  if (prefixEquals(t, "\"collectLookupResults")) {
+    // this activates an internal diagnostic that will collect
+    // the E_variable lookup results as warnings, then at the
+    // end of the program, compare them to this string
+    env.collectLookupResults = collectContinuations(text);
+  }
+}
+
+
+void TF_namespaceDefn::itcheck(Env &env)
+{
+  env.setLoc(loc);
+
+  // currently, what does the name refer to in this scope?
+  Variable *existing = NULL;
+  if (name) {
+    existing = env.lookupVariable(name, LF_INNER_ONLY);
+  }
+
+  // violation of 7.3.1 para 2?
+  if (existing && !existing->hasFlag(DF_NAMESPACE)) {
+    env.error(loc, stringc
+      << "attempt to redefine `" << name << "' as a namespace");
+
+    // recovery: pretend it didn't have a name
+    existing = NULL;
+    name = NULL;                // dsw: this causes problems when you add it to the scope
+  }
+
+  Scope *s;
+  if (existing) {
+    // extend existing scope
+    s = existing->scope;
+  }
+  else {
+    // make new namespace
+    s = env.createNamespace(loc, name);
+  }
+
+  // check the namespace body in its scope
+  env.extendScope(s);
+  FOREACH_ASTLIST_NC(TopForm, forms, iter) {
+    iter.setDataLink( iter.data()->tcheck(env) );
+  }
+  env.retractScope(s);
+}
+
+
+void TF_namespaceDecl::itcheck(Env &env)
+{
+  env.setLoc(loc);
+  decl->tcheck(env);
+}
+
+
+// --------------------- Function -----------------
+void Function::tcheck(Env &env, Variable *instV)
+{
+  bool checkBody = env.checkFunctionBodies;
+
+  if (env.secondPassTcheck) {
+    // for the second pass, just force the use of the
+    // variable computed in the first pass
+    xassert(!instV);
+    xassert(nameAndParams->var);
+    instV = nameAndParams->var;
+
+    if (checkBody) {
+      instV->setFlag(DF_DEFINITION);
+    }
+  }
+
+  // are we in a template function?
+  bool inTemplate = env.scope()->hasTemplateParams();
+
+  // only disambiguate, if template
+  DisambiguateOnlyTemp disOnly(env, inTemplate /*disOnly*/);
+  UninstTemplateErrorFilter errorFilter(env);
+
+  // get return type
+  Type *retTypeSpec = retspec->tcheck(env, dflags);
+
+  // supply DF_DEFINITION?
+  DeclFlags dfDefn = (checkBody? DF_DEFINITION : DF_NONE);
+  if (dflags >= (DF_EXTERN | DF_INLINE) &&
+      env.lang.handleExternInlineSpecially &&
+      handleExternInline_asPrototype()) {
+    // gcc treats extern-inline function definitions specially:
+    //
+    //   http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Inline.html
+    //
+    // I will essentially ignore them (just treat them like a
+    // prototype), thus modeling the dynamic semantics of gcc when
+    // optimization is turned off.  My nominal stance is that any
+    // program that has an extern-inline definition that is different
+    // from the ordinary (external) definition has undefined behavior.
+    // A possible future extension is to check that such definitions
+    // agree.
+    //
+    // Ah, but I can't just say 'checkBody = false' here because if
+    // there are ambiguities in the body then lots of things don't
+    // like it.  And anyway, tchecking the body is a good idea.  So I
+    // do something a little more subtle, I claim this isn't a
+    // "definition".
+    dfDefn = DF_NONE;
+  }
+
+  // construct the full type of the function; this will set
+  // nameAndParams->var, which includes a type, but that type might
+  // use different parameter names if there is already a prototype;
+  // dt.type will come back with a function type which always has the
+  // parameter names for this definition
+  Declarator::Tcheck dt(retTypeSpec,
+                        dflags | dfDefn,
+                        DC_FUNCTION);
+  dt.existingVar = instV;
+  nameAndParams = nameAndParams->tcheck(env, dt);
+  xassert(nameAndParams->var);
+
+  // the FunctionDefinition production in cc.gr rejects any parse
+  // that does not have a D_func as the innermost declarator
+  xassert(dt.type->isFunctionType());
+
+  // grab the definition type for later use
+  funcType = dt.type->asFunctionType();
+
+  if (checkBody) {      // so this is a definition and not just a declaration
+    // force the parameter and return types to be complete (8.3.5 para 6)
+    env.ensureCompleteType("use as return type", funcType->retType);
+    SFOREACH_OBJLIST(Variable, funcType->params, iter) {
+      env.ensureCompleteType("use as parameter type", iter.data()->type);
+    }
+  }
+
+  // record the definition scope for this template, since this
+  // information is needed to instantiate it
+  if (nameAndParams->var->templateInfo()) {
+    Scope *s = env.nonTemplateScope();
+    nameAndParams->var->templateInfo()->defnScope = s;
+
+    // for this to fail, the template would have to be at block
+    // scope, but that is not allowed by the grammar
+    xassert(s->isPermanentScope());
+  }
+
+  if (checkBody) {
+    tcheckBody(env);
+  }
+}
+
+void Function::tcheckBody(Env &env)
+{
+  // if this is an instantiation, finish cloning before
+  // trying to tcheck
+  finishClone();
+
+  // once we get into the body of a function, if we end up triggering
+  // additional instantiations, they should *not* see any prevailing
+  // second-pass mode
+  Restorer<bool> re(env.secondPassTcheck, false);
+
+  // location for random purposes..
+  SourceLoc loc = nameAndParams->var->loc;
+
+  // if this function was originally declared in another scope
+  // (main example: it's a class member function), then start
+  // by extending that scope so the function body can access
+  // the class's members
+  ScopeSeq qualifierScopes;
+  CompoundType *inClass = NULL;
+  {
+    Scope *s = nameAndParams->var->scope;
+    if (s) {
+      inClass = s->curCompound;   // might be NULL, that's ok
+
+      // current scope must enclose 's':
+      //   - if 's' is a namespace, 7.3.1.2 para 2 says so
+      //   - if 's' is a class, 9.3 para 2 says so
+      // example of violation: in/std/7.3.1.2b.cc, error 2
+      bool encloses = env.currentScopeAboveTemplEncloses(s);
+      if (!encloses) {
+        if (dflags & DF_FRIEND) {
+          // (t0291.cc) a friend definition is a little funky, and (IMO)
+          // 11.4 isn't terribly clear on this point, so I'll just try
+          // suppressing the error in this case
+        }
+        else {
+          env.diagnose3(env.lang.allowDefinitionsInWrongScopes, env.loc(), stringc
+            << "function definition of `" << *(nameAndParams->getDeclaratorId())
+            << "' must appear in a namespace that encloses the original declaration"
+            << " (gcc bug allows it)");
+        }
+      }
+
+      // these two lines are the key to this whole block..  I'm
+      // keeping the surrounding stuff, though, because it has that
+      // error report above, and simply to avoid disturbing existing
+      // (working) mechanism
+      env.getParentScopes(qualifierScopes, s);
+      env.extendScopeSeq(qualifierScopes);
+
+      // the innermost scope listed in 'qualifierScopes'
+      // should be the same one in which the variable was
+      // declared (could this be triggered by user code?)
+      if (encloses && qualifierScopes.isNotEmpty()) {
+        // sm: 8/11/04: At one point this assertion was weakened to a
+        // condition involving matching types.  That was wrong; the
+        // innermost scope must be *exactly* the declaration scope of
+        // the function, otherwise we'll be looking in the wrong scope
+        // for members, etc.
+        xassert(s == qualifierScopes.top());
+      }
+    }
+  }
+
+  // the parameters will have been entered into the parameter
+  // scope, but that's gone now; make a new scope for the
+  // function body and enter the parameters into that
+  Scope *bodyScope = env.enterScope(SK_PARAMETER, "function parameter bindings");
+  bodyScope->curFunction = this;
+  SFOREACH_OBJLIST_NC(Variable, funcType->params, iter) {
+    Variable *v = iter.data();
+    if (v->name) {
+      env.addVariable(v);
+    }
+  }
+
+  // is this a nonstatic member function?
+  if (funcType->isMethod()) {
+    this->receiver = funcType->getReceiver();
+
+    // this would be redundant--the parameter list already got
+    // added to the environment, and it included '__receiver'
+    //env.addVariable(receiver);
+  }
+
+  // while ctors do not appear to the caller to accept a receiver,
+  // to the ctor itself there *is* a receiver; so synthesize one
+  if (nameAndParams->var->name == env.constructorSpecialName) {
+    xassert(inClass);
+
+    xassert(!receiver);
+    receiver = env.receiverParameter(loc, inClass, CV_NONE,
+                                     NULL /*syntax*/);
+
+    xassert(receiver->type->isReference());   // paranoia
+    env.addVariable(receiver);
+  }
+
+  // have to check the member inits after adding the parameters
+  // to the environment, because the initializing expressions
+  // can refer to the parameters
+  tcheck_memberInits(env);
+
+  // declare the __func__ variable
+  if (env.lang.implicitFuncVariable ||
+      env.lang.gccFuncBehavior == CCLang::GFB_variable) {
+    // static char const __func__[] = "function-name";
+    SourceLoc loc = body->loc;
+    Type *charConst = env.getSimpleType(ST_CHAR, CV_CONST);
+    Type *charConstArr = env.makeArrayType(charConst);
+
+    if (env.lang.implicitFuncVariable) {
+      Variable *funcVar = env.makeVariable(loc, env.string__func__,
+                                           charConstArr, DF_STATIC);
+
+      // I'm not going to add the initializer, because I'd need to make
+      // an Expression AST node (which is no problem) but I don't have
+      // anything to hang it off of, so it would leak.. I could add
+      // a field to Function, but then I'd pay for that even when
+      // 'implicitFuncVariable' is false..
+      env.addVariable(funcVar);
+    }
+
+    // dsw: these two are also gcc; see
+    // http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Function-Names.html#Function%20Names
+    if (env.lang.gccFuncBehavior == CCLang::GFB_variable) {
+      env.addVariable(env.makeVariable(loc, env.string__FUNCTION__,
+                                       charConstArr, DF_STATIC));
+      env.addVariable(env.makeVariable(loc, env.string__PRETTY_FUNCTION__,
+                                       charConstArr, DF_STATIC));
+    }
+  }
+
+  // check the body in the new scope as well
+  Statement *sel = body->tcheck(env);
+  xassert(sel == body);     // compounds are never ambiguous
+
+  if (handlers) {
+    tcheck_handlers(env);
+
+    // TODO: same checks for handlers that S_try::itcheck mentions in
+    // its TODO ...
+  }
+
+  // close the new scope
+  env.exitScope(bodyScope);
+
+  // stop extending the named scope, if there was one
+  env.retractScopeSeq(qualifierScopes);
+
+  if (dflags >= (DF_EXTERN | DF_INLINE) &&
+      env.lang.handleExternInlineSpecially &&
+      handleExternInline_asPrototype()) {
+    // more extern-inline nonsense; skip 'funcDefn' setting
+    return;
+  }
+
+  // this is a function definition; add a pointer from the
+  // associated Variable
+  //
+  // dsw: WARNING: Due to the way function templates are instantiated it is
+  // important to NOT move this line ABOVE this other line which is
+  // above.
+  //    if (!checkBody) {
+  //      return;
+  //    }
+  // That is, it is important for the var of a function Declarator to
+  // not have a funcDefn until after its whole body has been
+  // typechecked.  See comment after 'if (!baseSyntax)' in
+  // Env::instantiateTemplate()
+  //
+  // UPDATE: I've changed this invariant, as I need to point the
+  // funcDefn at the definition even if the body has not been tchecked.
+  Function *&vfd = nameAndParams->var->funcDefn;
+  if (vfd) {
+    if (nameAndParams->var->hasFlag(DF_GNU_EXTERN_INLINE)) {
+      // we should not even get here if we are handling extern inlines
+      // as prototypes as there is no function definition to override
+      xassert(handleExternInline_asWeakStaticInline());
+      // dsw: stomp on the old definition if it was an extern inline
+      vfd = this;
+    } else {
+      xassert(vfd == this);
+    }
+  } else {
+    vfd = this;
+  }
+}
+
+
+CompoundType *Function::verifyIsCtor(Env &env, char const *context)
+{
+  // make sure this function is a class member
+  CompoundType *enclosing = NULL;
+  if (nameAndParams->var->scope) {
+    enclosing = nameAndParams->var->scope->curCompound;
+  }
+  if (!enclosing) {
+    env.error(stringc
+      << context << " are only valid for class member "
+      << "functions (constructors in particular)",
+      EF_DISAMBIGUATES);
+    return NULL;
+  }
+
+  // make sure this function is a constructor; should already have
+  // been mapped to the special name
+  if (nameAndParams->var->name != env.constructorSpecialName) {
+    env.error(stringc
+      << context << " are only valid for constructors",
+      EF_DISAMBIGUATES);
+    return NULL;
+  }
+
+  return enclosing;
+}
+
+
+bool hasDependentActualArgs(FakeList<ArgExpression> *args)
+{
+  FAKELIST_FOREACH(ArgExpression, args, iter) {
+    // <dependent> or TypeVariable or PseudoInstantiation
+    if (iter->expr->type->containsGeneralizedDependent()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// cppstd 12.6.2 covers member initializers
+void Function::tcheck_memberInits(Env &env)
+{
+  if (inits ||
+      nameAndParams->var->name == env.constructorSpecialName) {
+    // this should be a constructor
+    CompoundType *enclosing = verifyIsCtor(env, "ctor member inits");
+    if (!enclosing) {
+      return;
+    }
+
+    // ok, so far so good; now go through and check the member inits
+    // themselves
+    FAKELIST_FOREACH_NC(MemberInit, inits, iter) {
+      iter->tcheck(env, enclosing);
+    }
+  }
+  else {
+    // no inits and doesn't have a ctor name, skip
+  }
+}
+
+void MemberInit::tcheck(Env &env, CompoundType *enclosing)
+{
+  // resolve template arguments in 'name'
+  tcheckPQName(name, env, NULL /*scope*/, LF_NONE);
+
+  // typecheck the arguments
+  //
+  // dsw: I do not want to typecheck the args twice, as it is giving
+  // me problems, so I moved this
+  //
+  // 2005-05-28: (in/t0497.cc) Moved tchecking of arguments up above
+  // place where we might bail due to dependent base class type, so
+  // they will always be disambiguated.  This now invalidates dsw's
+  // comments so we'll see if it causes problems.
+  ArgumentInfoArray argInfo(args->count() + 1);
+  args = tcheckArgExprList(args, env, argInfo);
+
+  // check for a member variable, since they have precedence over
+  // base classes [para 2]; member inits cannot have qualifiers
+  if (!name->hasQualifiers()) {
+    // look for the given name in the class; should be an immediate
+    // member, not one that was inherited
+    Variable *v = enclosing->lookup_one(name->getName(), env, LF_INNER_ONLY);
+    if (v && !v->hasFlag(DF_TYPEDEF)) {     // typedef -> fall down to next area (in/t0390.cc)
+      // only "nonstatic data member"
+      if (v->hasFlag(DF_STATIC) ||
+          v->type->isFunctionType()) {
+        env.error("you can't initialize static data "
+                  "nor member functions in a ctor member init list");
+        return;
+      }
+
+      // annotate the AST
+      member = env.storeVar(v);
+
+      if (!hasDependentActualArgs(args)) {     // in/t0270.cc
+        // decide which of v's possible constructors is being used
+        ctorVar = env.storeVar(
+          outerResolveOverload_ctor(env, env.loc(), v->type, argInfo));
+        compareCtorArgsToParams(env, ctorVar, args, argInfo);
+      }
+
+      // TODO: check that the passed arguments are consistent
+      // with at least one constructor of the variable's type.
+      // dsw: update: isn't this what the assertion that ctorVar is
+      // non-null is doing, since the call to
+      // outerResolveOverload_ctor() will not succeed otherwise?
+
+      // TODO: make sure that we only initialize each member once.
+      // dsw: update: see below; do this in
+      // cc_elaborate.cc:completeNoArgMemberInits()
+
+      // TODO: provide a warning if the order in which the
+      // members are initialized is different from their
+      // declaration order, since the latter determines the
+      // order of side effects.
+      // dsw: update: this would have to be done in
+      // cc_elaborate.cc:completeNoArgMemberInits(), since I re-order
+      // the MemberInits there.
+
+      return;
+    }
+  }
+
+  // not a member name.. what about the name of base class?
+  // since the base class initializer can use any name which
+  // denotes the base class [para 2], first look up the name
+  // in the environment generally
+  //
+  // 2005-04-17: in/k0054.cc: need LF_SELFNAME here
+  //
+  // TODO: get rid of LF_SELFNAME, or at least invert the sense,
+  // so it is the default behavior
+  Variable *baseVar = env.lookupPQ_one(name, LF_SELFNAME);
+  if (baseVar &&
+      baseVar->isType() &&
+      baseVar->type->isCompoundType()) {
+    // as expected
+  }
+  else if (baseVar &&
+           baseVar->isType() &&
+           baseVar->type->isGeneralizedDependent()) {
+    // let it go
+    return;
+  }
+  else {
+    // complain
+    env.error(stringc << "`" << *name << "' does not denote any class");
+    return;
+  }
+  CompoundType *baseClass = baseVar->type->asCompoundType();
+
+  // is this class a direct base, and/or an indirect virtual base?
+  bool directBase = false;
+  bool directVirtual = false;
+  bool indirectVirtual = false;
+  FOREACH_OBJLIST(BaseClass, enclosing->bases, baseIter) {
+    BaseClass const *b = baseIter.data();
+
+    // check for direct base
+    if (b->ct == baseClass) {
+      directBase = true;
+      directVirtual = b->isVirtual;
+    }
+
+    // check for indirect virtual base by looking for virtual
+    // base of a direct base class
+    if (b->ct->hasVirtualBase(baseClass)) {
+      indirectVirtual = true;
+    }
+  }
+
+  // did we find anything?
+  if (!directBase && !indirectVirtual) {
+    // if there are qualifiers, then it can't possibly be an
+    // attempt to initialize a data member
+    char const *norData = name->hasQualifiers()? "" : ", nor a data member,";
+    env.error(stringc
+              << "`" << *name << "' is not a base class" << norData
+              << " so it cannot be initialized here");
+    return;
+  }
+
+  // check for ambiguity [para 2]
+  if (directBase && !directVirtual && indirectVirtual) {
+    env.error(stringc
+              << "`" << *name << "' is both a direct non-virtual base, "
+              << "and an indirect virtual base; therefore the initializer "
+              << "is ambiguous (there's no quick fix--you have to change "
+              << "your inheritance hierarchy or forego initialization)");
+    return;
+  }
+
+  // annotate the AST
+  base = baseClass;
+
+  // TODO: verify correspondence between template arguments
+  // in the initializer name and template arguments in the
+  // base class list
+
+  // TODO: check that the passed arguments are consistent
+  // with the chosen constructor
+
+  // determine which constructor is being called
+  ctorVar = env.storeVar(
+    outerResolveOverload_ctor(env, env.loc(),
+                              baseVar->type,
+                              argInfo));
+  compareCtorArgsToParams(env, ctorVar, args, argInfo);
+}
+
+
+void Function::tcheck_handlers(Env &env)
+{
+  FAKELIST_FOREACH_NC(Handler, handlers, iter) {
+    iter->tcheck(env);
+  }
+}
+
+
+bool Function::instButNotTchecked() const
+{
+  return !!cloneThunkSource;
+}
+
+
+// MemberInit
+
+// -------------------- Declaration -------------------
+void Declaration::tcheck(Env &env, DeclaratorContext context)
+{
+  // if there are no declarators, the type specifier's tchecker
+  // needs to know this (for e.g. 3.3.1 para 5)
+  if (decllist->isEmpty() &&
+      spec->isTS_elaborated() &&
+      context != DC_TF_EXPLICITINST) {     // in/t0557.cc
+    dflags |= DF_FORWARD;
+  }
+
+  // if we're declaring an anonymous type, and there are
+  // some declarators, then give the type a name; we don't
+  // give names to anonymous types with no declarators as
+  // a special exception to allow anonymous unions
+  if (decllist->isNotEmpty()) {
+    if (spec->isTS_classSpec()) {
+      TS_classSpec *cs = spec->asTS_classSpec();
+      if (cs->name == NULL) {
+        // quarl 2006-07-13, 2006-07-14
+        //    We want anonymous structs with typedefs to have consistent names
+        //    across translation units, so that functions with such parameters
+        //    mangle properly for linking.  (g++ mangles typedefed anonymous
+        //    structs the same as named structs.)
+        //
+        //    Since we may encounter "typedef struct { } *foo" in addition to
+        //    "typedef struct { } foo", we can't just name the struct "foo",
+        //    so instead we name it "__anon_struct_foo".
+        //
+        //    Note that gcc doesn't allow non-static-linkage functions to have
+        //    parameters with types declared like "typedef struct { } *foo"
+        //    because those are REALLY anonymous structs; so we could actually
+        //    name THOSE by index.
+
+        char const *relName = NULL;
+
+        if ((dflags & DF_TYPEDEF) && decllist->count() == 1) {
+          IDeclarator *decl = decllist->first()->decl;
+          relName = decl->getDeclaratorId()->getName();
+        }
+
+        cs->name = new PQ_name(SL_UNKNOWN, env.getAnonName(cs->keyword, relName));
+      }
+    }
+
+    if (spec->isTS_enumSpec()) {
+      TS_enumSpec *es = spec->asTS_enumSpec();
+      if (es->name == NULL) {
+        // anonymous enums - same as above
+
+        char const *relName = NULL;
+
+        if ((dflags & DF_TYPEDEF) && decllist->count() == 1) {
+          IDeclarator *decl = decllist->first()->decl;
+          relName = decl->getDeclaratorId()->getName();
+        }
+        es->name = env.getAnonName(TI_ENUM, relName);
+      }
+    }
+  }
+
+  // give warning for anonymous struct
+  //    TODO: this seems to be dead code since cs->name is assigned above if NULL
+  if (decllist->isEmpty() &&
+      spec->isTS_classSpec() &&
+      spec->asTS_classSpec()->name == NULL &&
+      spec->asTS_classSpec()->keyword != TI_UNION) {
+    if (env.lang.allowAnonymousStructs == B3_WARN) {
+      env.warning(spec->loc, "anonymous structs are not legal in C++ "
+                             "(gcc/msvc bug/extension allows it)");
+    }
+    else if (env.lang.allowAnonymousStructs == B3_FALSE) {
+      // it's actually not an error yet, it is just useless, because
+      // it cannot be used
+      env.warning(spec->loc, "useless declaration");
+    }
+  }
+
+  // check the specifier in the prevailing environment
+  Type *specType = spec->tcheck(env, dflags);
+
+  // ---- the following code is adopted from (the old) tcheckFakeExprList ----
+  // (I couldn't just use the same code, templatized as necessary,
+  // because I need my Declarator::Tcheck objects computed anew for
+  // each declarator..)
+  if (decllist) {
+    // check first declarator
+    Declarator::Tcheck dt1(specType, dflags, context);
+    decllist = FakeList<Declarator>::makeList(decllist->first()->tcheck(env, dt1));
+
+    // check subsequent declarators
+    Declarator *prev = decllist->first();
+    while (prev->next) {
+      // some analyses don't want the type re-used, so let
+      // the factory clone it if it wants to
+      Type *dupType = specType;
+
+      Declarator::Tcheck dt2(dupType, dflags, context);
+      prev->next = prev->next->tcheck(env, dt2);
+
+      prev = prev->next;
+    }
+  }
+  // ---- end of code from tcheckFakeExprList ----
+}
+
+
+// -------------------- ASTTypeId -------------------
+ASTTypeId *ASTTypeId::tcheck(Env &env, Tcheck &tc)
+{
+  if (!ambiguity) {
+    mid_tcheck(env, tc);
+    return this;
+  }
+
+  ASTTypeId *ret = resolveImplIntAmbig(env, this);
+  if (ret) {
+    return ret->tcheck(env, tc);
+  }
+
+  // as far as I can tell, the only ambiguities in ASTTypeId are
+  // due to implicit-int, therefore this should not be reached
+  xfailure("unexpected ASTTypeId ambiguity");
+  //return resolveAmbiguity(this, env, "ASTTypeId", false /*priority*/, tc);
+}
+
+void ASTTypeId::mid_tcheck(Env &env, Tcheck &tc)
+{
+  if (spec->isTS_classSpec() && !spec->asTS_classSpec()->name) {
+    // outside a declaration (that is, anyplace ASTTypeId occurs), gcc
+    // does not do anonymous union or struct scope promotion, even in
+    // C++ mode; so make up a name
+    StringRef fakeName = env.getAnonName(spec->asTS_classSpec()->keyword, NULL);
+    spec->asTS_classSpec()->name = new PQ_name(env.loc(), fakeName);
+    TRACE("env", "substituted name " << fakeName <<
+                 " in anon type at " << decl->getLoc());
+  }
+
+  // check type specifier
+  Type *specType = spec->tcheck(env, DF_NONE);
+
+  // pass contextual info to declarator
+  Declarator::Tcheck dt(specType, tc.dflags, tc.context);
+
+  xassert(!tc.newSizeExpr || tc.context == DC_E_NEW);
+
+  // check declarator
+  decl = decl->tcheck(env, dt);
+
+  // retrieve add'l info from declarator's tcheck struct
+  if (tc.newSizeExpr) {
+    *(tc.newSizeExpr) = dt.size_E_new;
+  }
+}
+
+
+Type *ASTTypeId::getType() const
+{
+  xassert(decl->var);
+  return decl->var->type;
+}
+
+
+// ---------------------- PQName -------------------
+void tcheckPQName(PQName *&name, Env &env, Scope *scope, LookupFlags lflags)
+{
+  if (!name->isPQ_qualifier()) {
+    // easy case 1
+    name->tcheck_pq(env, scope, lflags);
+    return;
+  }
+
+  PQ_qualifier *qual = name->asPQ_qualifier();
+  if (!qual->ambiguity) {
+    // easy case
+    qual->tcheck_pq(env, scope, lflags);
+    return;
+  }
+
+  // make sure nothing changes the environment...
+  int beforeChange = env.getChangeCount();
+
+  // all of the ambiguous alternatives must be PQ_qualifiers with
+  // template arguments, or PQ_templates; tcheck the first argument
+  // of each one, and use that to disambiguate
+  while (qual->ambiguity) {
+    // tcheck first arg of 'qual', mostly discarding errors
+    STemplateArgument sarg;
+    {
+      DisambiguationErrorTrapper trapper(env);
+      qual->templArgs->tcheck(env, sarg);
+
+      // discard errors (other than those saved in 'trapper')
+      ErrorList discard;
+      discard.takeMessages(env.errors);
+    }
+
+    // better not have changed the environment!
+    xassert(env.getChangeCount() == beforeChange);
+
+    if (sarg.hasValue()) {
+      // this is the chosen one
+      qual->ambiguity = NULL;
+      name = qual;
+      qual->tcheck_pq(env, scope, lflags);
+      return;
+    }
+
+    // try next
+    if (qual->ambiguity->isPQ_qualifier()) {
+      qual = qual->ambiguity->asPQ_qualifier();
+    }
+    else {
+      xassert(qual->ambiguity->isPQ_template());
+
+      // since all preceding alternatives have failed, and PQ_template
+      // does not have an 'ambiguity' pointer, select it and tcheck it
+      name = qual->ambiguity;
+      name->tcheck_pq(env, scope, lflags);
+      return;
+    }
+  }
+
+  // got to the end of the list, select+tcheck the final one
+  name = qual;
+  qual->tcheck_pq(env, scope, lflags);
+}
+
+
+// The given 'src' is a DAG of 'ambiguity' and 'next' links encoding
+// all possible ways to interpret some syntax as a list of template
+// arguments.  We must pick one such list and store the interpreted
+// arguments in 'dest'.  The strategy is to check the arguments in
+// order, and follow the 'next' link only of the chosen argument at
+// each step.
+bool tcheckTemplateArgumentList(ObjList<STemplateArgument> &dest,
+                                TemplateArgument *&src, Env &env)
+{
+  bool ret = true;
+
+  // normally I would expect 'dest' to be empty, but apparently we
+  // sometimes tcheck PQNames more than once (maybe due to ambiguities
+  // higher up?), and so I will just throw away any previous
+  // results....
+  dest.deleteAll();
+
+  // keep track of the previous node in the list, so we can string
+  // together the final disambiguated sequence
+  TemplateArgument **prev = &src;
+
+  TemplateArgument *ta = *prev;
+  while (ta) {
+    if (!ta->isTA_templateUsed()) {
+      // disambiguate and check 'ta', putting its final result
+      // into 'sarg'
+      STemplateArgument *sarg = new STemplateArgument;
+      ta = ta->tcheck(env, *sarg);
+      if (!sarg->hasValue()) {
+        ret = false;        // some kind of error
+      }
+
+      // remember 'sarg' (in wrong order, will fix below)
+      dest.prepend(sarg);
+    }
+
+    // string up the chosen one
+    xassert(ta->ambiguity == NULL);     // these links should all be cut now
+    *prev = ta;
+
+    // follow the 'next' link in 'ta', as it was the chosen one
+    prev = &(ta->next);
+    ta = *prev;
+  }
+
+  // fix the order of 'dest'
+  dest.reverse();
+  return ret;
+}
+
+void PQ_qualifier::tcheck_pq(Env &env, Scope *scope, LookupFlags lflags)
+{
+  if (!( lflags & LF_DECLARATOR )) {
+    // no need to do scope association stuff
+    tcheckTemplateArgumentList(sargs, templArgs, env);
+    tcheckPQName(rest, env, scope, lflags);
+    return;
+  }
+
+  // In a template declarator context, we want to stage the use of
+  // the template parameters so as to ensure proper association
+  // between parameters and qualifiers.  For example, if we have
+  //
+  //   template <class S>
+  //   template <class T>
+  //   int A<S>::foo(T *t) { ... }
+  //
+  // and we're about to tcheck "A<S>", the SK_TEMPLATE_PARAMS scope
+  // containing T that is currently on the stack must be temporarily
+  // removed so that the template arguments to A cannot see it.
+  //
+  // So, for this and other reasons, find the template argument or
+  // parameter scope that corresponds to 'bareQualifierVar'.
+
+  // begin by looking up the bare name, igoring template arguments
+  Variable *bareQualifierVar = env.lookupOneQualifier_bareName(scope, this, lflags);
+
+  // now check the arguments
+  if (!tcheckTemplateArgumentList(sargs, templArgs, env)) {
+    // error already reported; just finish up and bail
+    tcheckPQName(rest, env, scope, lflags);
+    return;
+  }
+
+  // scope that has my template params
+  Scope *hasParamsForMe = NULL;
+
+  if (!(lflags & LF_EXPLICIT_INST) &&            // not explicit inst request
+      bareQualifierVar) {                        // lookup succeeded
+    if (bareQualifierVar->isTemplate() &&          // names a template
+        sargs.isNotEmpty()) {                      // arguments supplied
+      // 14.7.3p5:
+      //   - if all template args are concrete, and
+      //   - they correspond to an explicit specialization
+      //   - then "template <>" is *not* used (for that class)
+      // t0248.cc tests a couple cases...
+      bool hasVars = containsVariables(sargs);
+      if (!hasVars &&
+          bareQualifierVar->templateInfo()->getSpecialization(sargs)) {
+        // do not associate 'bareQualifier' with any template scope
+      }
+      else {
+        hasParamsForMe = env.findParameterizingScope(bareQualifierVar, hasVars);
+      }
+    }
+
+    // Apparently, it is legal (as in, both GCC and ICC allow it) to
+    // use a typedef to name an explicit specialization.  I think it's
+    // a bit strange, as 14.7.3p17,18 seem to imply a syntactic
+    // correlation between <> in template parameter lists and <> in
+    // declarator-ids, and that correlation is broken if a typedef is
+    // used.  In particular, the syntax could not also be used for a
+    // *partial* specialization, since the parameters would not be
+    // visible at the point the typedef is created.
+    //
+    // However, 7.1.3 seems to say that typedefs are allowed as
+    // synonyms for their referents in any context except those
+    // prohibited by 7.1.3p4, and this is not one of those.
+    //
+    // To implement this, I will try to determine how many levels of
+    // template class implicit specializations are present between
+    // 'bareQualifierVar' and 'scope', and associate each one
+    // with a template parameter list.  (in/t0555.cc)
+    if (bareQualifierVar->isExplicitTypedef() &&
+        bareQualifierVar->type->isCompoundType() &&
+        !bareQualifierVar->isTemplate(true /*considerInherited*/)) {
+      // step 1: find all the classes below 'scope'
+      SObjList<CompoundType> specs;
+      int ct = 0;
+      for (Scope *s = bareQualifierVar->getDenotedScope();
+           s->isClassScope() && s != scope;
+           s = mustBeNonNull(s->parentScope)) {
+        specs.prepend(s->curCompound);        // want outermost first
+        ct++;
+      }
+
+      // step 2: associate those that are implicit specializations
+      SFOREACH_OBJLIST_NC(CompoundType, specs, iter) {
+        TemplateInfo *ti = iter.data()->templateInfo();
+        if (ti && ti->isInstantiation()) {    // aka implicit specialization
+          Scope *paramScope = env.findParameterizingScope(ti->var, false /*hasVars*/);
+          if (!paramScope) {
+            // error already reported
+          }
+          else if (ct > 1) {
+            paramScope->setParameterizedEntity(ti->var);
+
+            TRACE("templateParams",
+              "associated " << paramScope->desc() <<
+              " with " << ti->var->fullyQualifiedName0() <<
+              " (found using typedef expansion)");
+          }
+          else {
+            // this is the last element in the list, 'bareQualifierVar'
+            // itself; don't associate it here; instead, stash it
+            // in 'hasParamsForMe' and let the code below associate it
+            xassert(ct == 1);
+            xassert(iter.data() == bareQualifierVar->type->asCompoundType());
+            hasParamsForMe = paramScope;
+
+            TRACE("templateParams",
+              "later, will associate " << paramScope->desc() <<
+              " with " << ti->var->fullyQualifiedName0() <<
+              " (found using typedef expansion)");
+          }
+        }
+
+        ct--;
+      }
+    }
+  }
+
+  // finish looking up this qualifier
+  bool dependent;
+  bool anyTemplates;        // will be ignored
+  Scope *denotedScope = env.lookupOneQualifier_useArgs(
+    bareQualifierVar,       // scope found w/o using args
+    sargs,                  // template args
+    dependent, anyTemplates, lflags);
+
+  if (denotedScope && denotedScope->curCompound) {
+    // must be a complete type [ref?] (t0245.cc)
+    env.ensureCompleteType("use as qualifier",
+      denotedScope->curCompound->typedefVar->type);
+
+    if (hasParamsForMe) {
+      // in/t0461.cc: My delegation scheme has a flaw, in that I set
+      // a scope as 'delegated' before the thing that delegates to
+      // it is on the scope stack, making the template parameters
+      // effectively invisible for a short period.  This shows up in
+      // an out-of-line ctor definition like A<T>::A<T>(...){}.  So
+      // detect this, and as a hack, check the last bit of the name
+      // *before* setting up the delegation.
+      //
+      // 2005-04-16: in/k0047.cc: generalize by doing this whenever
+      // we're at the next-to-last component of the name
+      if (!rest->isPQ_qualifier()) {
+        tcheckPQName(rest, env, denotedScope, lflags);
+      }
+
+      // cement the association now
+      hasParamsForMe->setParameterizedEntity(denotedScope->curCompound->typedefVar);
+
+      TRACE("templateParams",
+        "associated " << hasParamsForMe->desc() <<
+        " with " << denotedScope->curCompound->instName);
+
+      // if we already tcheck'd the final component above, bail now
+      if (!rest->isPQ_qualifier()) {
+        return;
+      }
+    }
+  }
+
+  tcheckPQName(rest, env, denotedScope, lflags);
+}
+
+void PQ_name::tcheck_pq(Env &env, Scope *, LookupFlags)
+{}
+
+void PQ_operator::tcheck_pq(Env &env, Scope *, LookupFlags)
+{
+  o->tcheck(env);
+}
+
+void PQ_template::tcheck_pq(Env &env, Scope *, LookupFlags lflags)
+{
+  tcheckTemplateArgumentList(sargs, templArgs, env);
+}
+
+
+// -------------- "dependent" name stuff ---------------
+// This section has a few functions that are common to the AST
+// nodes that have to deal with dependent name issues.  (14.6.2)
+
+// lookup has found 'var', and we might want to stash it
+// in 'nondependentVar' too
+void maybeNondependent(Env &env, SourceLoc loc, Variable *&nondependentVar,
+                       Variable *var)
+{
+  if (!var->hasFlag(DF_TYPEDEF) && var->type->isGeneralizedDependent()) {
+    // if this was the name of a variable, but the type refers to some
+    // template params, then this shouldn't be considered
+    // non-dependent (t0276.cc)
+    //
+    // TODO: this can't be right... there is still a fundamental
+    // flaw in how I regard names whose lookup is nondependent but
+    // the thing they look up to is dependent
+    return;
+  }
+
+  if (!var->scope && !var->isTemplateParam()) {
+    // I'm pretty sure I don't need to remember names that are not
+    // in named scopes, other than template params themselves (t0277.cc)
+    return;
+  }
+
+  if (env.inUninstTemplate() &&               // we're in a template
+      !var->type->isSimple(ST_DEPENDENT) &&   // lookup was non-dependent
+      !var->type->isDependentQType() &&       //   (also would be dependent)
+      !var->type->isError() &&                // and not erroneous
+      !var->isMemberOfTemplate()) {           // will be in scope in instantiation
+    TRACE("dependent", toString(loc) << ": " <<
+                       (nondependentVar? "replacing" : "remembering") <<
+                       " non-dependent lookup of `" << var->name <<
+                       "' found var at " << toString(var->loc));
+    nondependentVar = var;
+  }
+}
+
+// if we want to re-use 'nondependentVar', return it; otherwise return NULL
+Variable *maybeReuseNondependent(Env &env, SourceLoc loc, LookupFlags &lflags,
+                                 Variable *nondependentVar)
+{
+  // should I use 'nondependentVar'?
+  if (nondependentVar && !env.inUninstTemplate()) {
+    if (nondependentVar->isTemplateParam()) {
+      // We don't actually want to use 'nondependentVar', because that
+      // Variable was only meaningful to the template definition.  Instead
+      // we want the *corresponding* Variable that is now bound to a
+      // template argument, and LF_TEMPL_PARAM will find it (and skip any
+      // other names).
+      TRACE("dependent", toString(loc) <<
+                         ": previously-remembered non-dependent lookup for `" <<
+                         nondependentVar->name << "' was a template parameter");
+      lflags |= LF_TEMPL_PARAM;
+    }
+    else {
+      // use 'nondependentVar' directly
+      TRACE("dependent", toString(loc) <<
+                         ": using previously-remembered non-dependent lookup for `" <<
+                         nondependentVar->name << "': at " <<
+                         toString(nondependentVar->loc));
+      return nondependentVar;
+    }
+  }
+
+  // do the lookup without using 'nondependentVar'
+  return NULL;
+}
+
+
+// --------------------- TypeSpecifier --------------
+Type *TypeSpecifier::tcheck(Env &env, DeclFlags dflags)
+{
+  env.setLoc(loc);
+
+  Type *t = itcheck(env, dflags);
+  Type *ret = env.tfac.applyCVToType(loc, cv, t, this);
+  if (!ret) {
+    if (t->isFunctionType() && env.lang.allowCVAppliedToFunctionTypes) {
+      env.diagnose3(env.lang.allowCVAppliedToFunctionTypes, loc,
+                    "cannot apply const/volatile to function types (gcc bug allows it)");
+      return t;    // ignore the cv-flags
+    }
+    else {
+      return env.error(t, stringc
+        << "cannot apply const/volatile to type `" << t->toString() << "'");
+    }
+  }
+  return ret;
+}
+
+
+// does 'name' begin with 'qualifier' and end with 'name'?
+bool isTwoPartName(Env &env, PQName *name,
+                   char const *qualifier, char const *final)
+{
+  if (!name->isPQ_qualifier()) {
+    return false;
+  }
+
+  StringRef q = name->asPQ_qualifier()->qualifier;
+  StringRef f = name->getName();
+
+  if (q == env.str(qualifier) && f == env.str(final)) {
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+
+// This function recognizes a PQName that comes from a buggy gcc-2
+// header and in that context is intended to name a dependent type.
+//
+// forms recognized:
+//   g0024.cc: __default_alloc_template<__threads, __inst>::_Obj
+//   g0026.cc: basic_string <charT, traits, Allocator>::Rep
+//   g0026.cc: basic_string <charT, traits, Allocator>::size_type
+bool isBuggyGcc2HeaderDQT(Env &env, PQName *name)
+{
+  if (isTwoPartName(env, name, "__default_alloc_template", "_Obj") ||
+      isTwoPartName(env, name, "basic_string", "Rep") ||
+      isTwoPartName(env, name, "basic_string", "size_type")) {
+    return true;
+  }
+
+  return false;
+}
+
+
+// 7.1.5.2
+Type *TS_name::itcheck(Env &env, DeclFlags dflags)
+{
+  tcheckPQName(name, env, NULL /*scope*/, LF_NONE);
+
+  ErrorFlags eflags = EF_NONE;
+  LookupFlags lflags = LF_EXPECTING_TYPE;
+
+  // should I use 'nondependentVar'?
+  Variable *v = maybeReuseNondependent(env, loc, lflags, nondependentVar);
+  if (v) {
+    var = v;
+    return var->type;
+  }
+
+  if (typenameUsed) {
+    if (!name->hasQualifiers()) {
+      // cppstd 14.6 para 5, excerpt:
+      //   "The keyword typename shall only be applied to qualified
+      //    names, but those names need not be dependent."
+      env.error("the `typename' keyword can only be used with a qualified name");
+    }
+
+    lflags |= LF_TYPENAME;
+  }
+  else {
+    // if the user uses the keyword "typename", then the lookup errors
+    // are non-disambiguating, because the syntax is unambiguous;
+    // otherwise, they are disambiguating (which is the usual case)
+    eflags |= EF_DISAMBIGUATES;
+  }
+
+  if (!env.lang.isCplusplus) {
+    // in C, we never look at a class scope unless the name is
+    // preceded by "." or "->", which it certainly is not in a TS_name
+    // (in/c/dC0013.c)
+    //
+    // this is actually done below as well for E_variable; for the
+    // moment I'm refraining from factoring it for fear of
+    // destabilizing things..
+    lflags |= LF_SKIP_CLASSES;
+  }
+
+  // hack, until LF_SELFNAME becomes the default and I fix the
+  // problems in Env::applyPQNameTemplateArguments: if the name
+  // does not have template arguments, make the self-name visible
+  if (!name->getUnqualifiedName()->isPQ_template()) {
+    lflags |= LF_SELFNAME;
+  }
+
+do_lookup:
+  v = env.lookupPQ_one(name, lflags);
+
+  // gcc-2 hack
+  if (!v &&
+      env.lang.gcc2StdEqualsGlobalHacks &&
+      isTwoPartName(env, name, "std", "string")) {
+    // try looking it up in global scope
+    v = env.lookupPQ_one(name->getUnqualifiedName(), lflags);
+  }
+
+  if (!v) {
+    // a little diagnostic refinement: if the only problem is with the
+    // template arguments, but the name would be a type if the args
+    // were ok, don't call it disambiguating (in/t0454.cc, error 1)
+    if (name->isPQ_template()) {
+      Variable *primary = env.lookupPQ_one(name, lflags | LF_TEMPL_PRIMARY);
+      if (primary && primary->isType() && primary->isTemplate()) {
+        eflags &= ~EF_DISAMBIGUATES;
+      }
+    }
+
+    // NOTE:  Since this is marked as disambiguating, but the same
+    // error message in E_variable::itcheck is not marked as such, it
+    // means we prefer to report the error as if the interpretation as
+    // "variable" were the only one.
+    return env.error(stringc
+      << "there is no type called `" << *name << "'", eflags);
+  }
+
+  if (!v->hasFlag(DF_TYPEDEF)) {
+    if (v->type && v->type->isSimple(ST_DEPENDENT)) {
+      // is this a gcc-2 header bug? (in/gnu/g0024.cc)
+      if (env.lang.allowGcc2HeaderSyntax &&
+          isBuggyGcc2HeaderDQT(env, name)) {
+        env.diagnose3(env.lang.allowGcc2HeaderSyntax, name->loc,
+                      stringc << "dependent type name `" << *name
+                              << "' requires 'typename' keyword (gcc-2 bug allows it)");
+        lflags |= LF_TYPENAME;
+        goto do_lookup;
+      }
+      else {
+        // more informative error message (in/d0111.cc, error 1)
+        return env.error(stringc
+          << "dependent name `" << *name
+          << "' used as a type, but the 'typename' keyword was not supplied", eflags);
+      }
+    }
+    else {
+      return env.error(stringc
+        << "variable name `" << *name << "' used as if it were a type", eflags);
+    }
+  }
+
+  // TODO: access control check
+
+  var = env.storeVar(v);    // annotation
+
+  // should I remember this non-dependent lookup?
+  maybeNondependent(env, loc, nondependentVar, var);
+
+  // 7/27/04: typedefAliases used to be maintained at this point, but
+  // now it is gone
+
+  // there used to be a call to applyCV here, but that's redundant
+  // since the caller (tcheck) calls it too
+  return var->type;
+}
+
+
+Type *TS_simple::itcheck(Env &env, DeclFlags dflags)
+{
+  // This is the one aspect of the implicit-int solution that cannot
+  // be confined to implint.h: having selected an interpretation that
+  // uses implicit int, change it to ST_INT so that analyses don't
+  // have to know about any of this parsing nonsense.
+  if (id == ST_IMPLINT) {
+    // 2005-04-07: I had been doing the following:
+    //   id = ST_INT;
+    // but the problem with that is that there are cases (e.g.,
+    // in/c/k0008.c) where a single TS_simple will appear in more than
+    // one context.  If the first context's tcheck changes 'id' as
+    // above, and the second context is ambiguous, the second context
+    // won't know that it was ST_IMPLINT and will therefore fail to
+    // resolve it properly.
+    //
+    // So my new solution is to *only* put ST_INT into the 'type',
+    // leaving ST_IMPLINT in the 'id' field so later tchecks can see
+    // that it was using implicit-int.  Client analyses should be
+    // unaffected, since they should be looking at 'type', not 'id'.
+    return env.getSimpleType(ST_INT, cv);
+  }
+
+  return env.getSimpleType(id, cv);
+}
+
+
+// This function maps syntax like
+//
+//   "class A"                            // ordinary class
+//   "class A<int>"                       // existing instantiation or specialization
+//   "template <class T> class A"         // template class decl
+//   "template <class T> class A<T*>"     // partial specialization decl
+//   "template <> class A<int>"           // complete specialization decl
+//
+// to a particular CompoundType.  If there are extant template
+// parameters, then 'templateParams' will be set below to non-NULL
+// (but possibly empty).  If the name has template arguments applied
+// to it, then 'templateArgs' will be non-NULL.
+//
+// There are three syntactic contexts for this, identified by the
+// 'dflags' present.  Within each of these I categorize w.r.t. the
+// presence of template parameters and arguments:
+//
+//   "class A ;"          // DF_FORWARD=1  DF_DEFINITION=0
+//
+//     no-params no-args    ordinary forward declaration
+//     params    no-args    fwd decl of template primary
+//     no-params args       old-style explicit instantiation request [ref?]
+//     params    args       fwd decl of explicit specialization
+//
+//   "class A *x ;"       // DF_FORWARD=0  DF_DEFINITION=0
+//
+//     no-params no-args    fwd decl, but might push into outer scope (3.3.1 para 5)
+//     params    no-args    illegal [ref?]
+//     no-params args       use of a template instantiation or specialization
+//     params    args       illegal
+//
+//   "class A { ... } ;"  // DF_FORWARD=0  DF_DEFINITION=1
+//
+//     no-params no-args    ordinary class definition
+//     params    no-args    template primary definition
+//     no-params args       illegal
+//     params    args       template specialization definition
+//
+// Note that the first and third cases are fairly parallel, one being
+// a declaration and the other a definition.  The second case is the
+// odd one out, though it is more like case 1 than case 3.  It is also
+// quite rare, as such uses are almost always written without the
+// "class" keyword.
+CompoundType *checkClasskeyAndName(
+  Env &env,
+  Scope *scope,              // scope in which decl/defn appears
+  SourceLoc loc,             // location of type specifier
+  DeclFlags dflags,          // syntactic and semantic declaration modifiers
+  TypeIntr keyword,          // keyword used
+  PQName *name)              // name, with qualifiers and template args (if any)
+{
+  // context flags
+  bool forward = (dflags & DF_FORWARD);
+  bool definition = (dflags & DF_DEFINITION);
+  xassert(!( forward && definition ));
+
+  // handle 'friend' the same way I do other case 2 decls, even though
+  // that isn't quite right
+  if (dflags & DF_FRIEND) {
+    if (definition) {
+      // 11.4p2
+      env.error("you cannot define a class in a friend definitions");
+      return NULL;
+    }
+    forward = false;
+  }
+
+  // template params?
+  SObjList<Variable> *templateParams =
+    scope->isTemplateParamScope()? &(scope->templateParams) : NULL;
+
+  // template args?
+  ObjList<STemplateArgument> *templateArgs = NULL;
+  if (name) {
+    PQName *unqual = name->getUnqualifiedName();
+    if (unqual->isPQ_template()) {
+      // get the arguments
+      templateArgs = &(unqual->asPQ_template()->sargs);
+    }
+  }
+
+  // indicate when a particular gcc-2 hack is being used...
+  bool gcc2hack_explicitSpec = false;
+
+  // reject illegal combinations
+  if (!forward && !definition && templateParams) {
+    // Actually, this requirement holds regardless of whether there is
+    // a definition, but 'forward' only signals the presence of
+    // declarators in non-definition cases.  So this error should be
+    // caught elsewhere.  The code below will not run into trouble in
+    // this case, so just let it go.
+    //return env.error("templatized class declarations cannot have declarators");
+  }
+  if (definition && !templateParams && templateArgs) {
+    if (env.lang.allowGcc2HeaderSyntax &&
+        name->getName() == env.str("string_char_traits")) {
+      env.diagnose3(env.lang.allowGcc2HeaderSyntax, name->loc,
+                    "explicit class specialization requires \"template <>\" (gcc-2 bug allows it)");
+      gcc2hack_explicitSpec = true;
+
+      // pretend we saw "template <>"
+      templateParams = new SObjList<Variable>;    // will be leaked
+    }
+    else {
+      env.error("class specifier name can have template arguments "
+                "only in a templatized definition");
+      return NULL;
+    }
+  }
+  if (templateParams && templateParams->isEmpty() && !templateArgs) {
+    env.error("complete specialization (\"<>\") requires template args");
+    return NULL;
+  }
+  if (keyword==TI_UNION && (templateParams || templateArgs)) {
+    env.error("template unions are not allowed");
+    return NULL;
+  }
+
+  // see if the environment already has this name
+  CompoundType *ct = NULL;
+  if (name) {
+    // decide how the lookup should be performed
+    LookupFlags lflags = LF_ONLY_TYPES;     // 3.4.4p2,3
+    if (!name->hasQualifiers() && (forward || definition)) {
+      lflags |= LF_INNER_ONLY;
+    }
+    if (templateParams) {
+      lflags |= LF_TEMPL_PRIMARY;
+    }
+    if (!env.lang.isCplusplus) {
+      // in C mode, it is ok to have a typedef and a struct with the
+      // same name (in/c/dC0023.cc)
+      lflags |= LF_QUERY_TAGS;
+    }
+
+    // I need this for in/t0492.cc; this brings me one step closer
+    // to making this flag be on by default
+    lflags |= LF_SELFNAME;
+
+    // do the lookup
+    if (dflags & DF_DEFINITION) {
+      // this is a lookup of the declarator-like type tag of a class
+      // definition; the qualifier scopes have already been pushed
+      // by my caller, so just look in the innermost scope
+      ct = env.lookupCompound(name->getName(), lflags | LF_INNER_ONLY);
+    }
+    else {
+      // this is a lookup of a use; see if the new mechanism can
+      // handle it
+      Variable *tag = env.lookupPQ_one(name, lflags);
+      if (tag) {
+        if (tag->type->isCompoundType()) {
+          if (env.lang.isCplusplus && !tag->hasAnyFlags(DF_IMPLICIT | DF_SELFNAME)) {
+            // found a user-introduced (not implicit) typedef, which
+            // is illegal (3.4.4p2,3; 7.1.5.3p2)
+            env.error(stringc << "`" << *name << "' is a typedef-name, "
+                              << "so cannot be used after '"
+                              << toString(keyword) << "'");
+            return NULL;
+          }
+          ct = tag->type->asCompoundType();
+        }
+        else if (tag->type->isGeneralizedDependent()) {
+          return NULL;
+        }
+        else {
+          env.error(tag->type, stringc
+            << "`" << *name << "' is not a struct/class/union");
+          return NULL;
+        }
+      }
+    }
+
+    // failed lookup is cause for immediate abort in a couple of cases
+    if (!ct &&
+        (name->hasQualifiers() || templateArgs)) {
+      env.error(stringc << "no such " << toString(keyword)
+                        << ": `" << *name << "'");
+      return NULL;
+    }
+  }
+  CompoundType *primary = ct;       // used for specializations
+
+  // if we have template args and params, refine 'ct' down to the
+  // specialization of interest (if already declared)
+  if (templateParams && templateArgs) {
+    // this is supposed to be a specialization
+    TemplateInfo *primaryTI = primary->templateInfo();
+    if (!primaryTI) {
+      env.error("attempt to specialize a non-template");
+      return NULL;
+    }
+
+    // does this specialization already exist?
+    Variable *spec = primaryTI->getSpecialization(*templateArgs);
+    if (spec) {
+      ct = spec->type->asCompoundType();
+    }
+    else {
+      // did we already start to make an implicit instantiation
+      // for these arguments?  (in/t0522.cc)
+      spec = env.findInstantiation(primaryTI, *templateArgs);
+      if (spec) {
+        ct = spec->type->asCompoundType();
+        if (ct->forward) {
+          // body not yet instantiated, we're ok
+          TRACE("template", "changing " << ct->instName <<
+                            " from implicit inst to explicit spec");
+          spec->templateInfo()->changeToExplicitSpec();
+        }
+        else {
+          // cppstd 14.7.3p6
+          env.error(stringc
+            << ct->instName << " has already been implicitly instantiated, "
+            << "so it's too late to provide an explicit specialization");
+          return NULL;
+        }
+      }
+      else {
+        ct = NULL;
+      }
+    }
+  }
+
+  // if already declared, compare to that decl
+  if (ct) {
+    // check that the keywords match
+    if ((int)ct->keyword != (int)keyword) {
+      // it's ok for classes and structs to be confused (7.1.5.3 para 3)
+      if ((keyword==TI_UNION) != (ct->keyword==CompoundType::K_UNION)) {
+        env.error(stringc
+          << "there is already a " << ct->keywordAndName()
+          << ", but here you're defining a " << toString(keyword)
+          << " " << *name);
+        return NULL;
+      }
+
+      // let the definition keyword (of a template primary only)
+      // override any mismatching prior decl
+      if (definition && !templateArgs) {
+        TRACE("env", "changing " << ct->keywordAndName() <<
+                     " to a " << toString(keyword) << endl);
+        ct->keyword = (CompoundType::Keyword)keyword;
+      }
+    }
+
+    // do this before setting 'forward', so that inside
+    // 'verifyCompatibleTemplateParameters' I can tell whether the
+    // old declaration was a definition or not (in/k0022.cc)
+    if (!templateParams && templateArgs) {
+      // this is more like an instantiation than a declaration
+    }
+    else {
+      // check correspondence between extant params and params on 'ct'
+      env.verifyCompatibleTemplateParameters(scope, ct);
+    }
+
+    // definition of something previously declared?
+    if (definition) {
+      if (ct->templateInfo()) {
+        // update the defnScope; this is important for out-of-line definitions
+        // of nested classes, especially template classes
+        TemplateInfo *ti = ct->templateInfo();
+        Scope *defnScope = scope;
+        while (defnScope->isTemplateParamScope()) {
+          defnScope = defnScope->parentScope;
+        }
+        ti->defnScope = defnScope;
+
+        TRACE("template", "template class " <<
+                          (templateArgs? "specialization " : "") <<
+                          "definition: " << ti->templateName() <<
+                          ", defnScope is " << defnScope->desc());
+      }
+
+      if (ct->forward) {
+        // now it is no longer a forward declaration
+        ct->forward = false;
+      }
+      else {
+        env.error(stringc << ct->keywordAndName() << " has already been defined");
+      }
+    }
+  }
+
+  // if not already declared, make a new CompoundType
+  else {
+    // get the raw name for use in creating the CompoundType
+    StringRef stringName = name? name->getName() : NULL;
+
+    // making an ordinary compound, or a template primary?
+    if (!templateArgs) {
+      Scope *destScope = (forward || definition) ?
+        // if forward=true, 3.3.1 para 5 says:
+        //   the elaborated-type-specifier declares the identifier to be a
+        //   class-name in the scope that contains the declaration
+        // if definition=true, I think it works the same [ref?]
+        env.typeAcceptingScope() :
+        // 3.3.1 para 5 says:
+        //   the identifier is declared in the smallest non-class,
+        //   non-function-prototype scope that contains the declaration
+        env.outerScope() ;
+
+      // this sets the parameterized primary of the scope
+      env.makeNewCompound(ct, destScope, stringName, loc, keyword,
+                          !definition /*forward*/, false /*builtin*/);
+
+      if (templateParams) {
+        TRACE("template", "template class " << (definition? "defn" : "decl") <<
+                          ": " << ct->templateInfo()->templateName());
+      }
+    }
+
+    // making a template specialization
+    else {
+      SObjList<STemplateArgument> const &ssargs = objToSObjListC(*templateArgs);
+
+      // make a new type, since a specialization is a distinct template
+      // [cppstd 14.5.4 and 14.7]; but don't add it to any scopes
+      env.makeNewCompound(ct, NULL /*scope*/, stringName, loc, keyword,
+                          !definition /*forward*/, false /*builtin*/);
+
+      if (gcc2hack_explicitSpec) {
+        // we need to fake a TemplateInfo
+        ct->setTemplateInfo(new TemplateInfo(loc));
+      }
+
+      // dsw: need to register it at least, even if it isn't added to
+      // the scope, otherwise I can't print out the name of the type
+      // because at the top scope I don't know the scopeKind
+      env.typeAcceptingScope()->registerVariable(ct->typedefVar);
+
+      // similarly, the parentScope should be set properly
+      env.setParentScope(ct);
+
+      // 'makeNewCompound' will already have put the template *parameters*
+      // into 'specialTI', but not the template arguments
+      TemplateInfo *ctTI = ct->templateInfo();
+      ctTI->copyArguments(ssargs);
+
+      // fix the self-type arguments (only if partial inst)
+      if (ct->selfType->isPseudoInstantiation()) {
+        PseudoInstantiation *selfTypePI = ct->selfType->asPseudoInstantiation();
+        selfTypePI->args.deleteAll();
+        copyTemplateArgs(selfTypePI->args, ssargs);
+      }
+
+      // synthesize an instName to aid in debugging
+      ct->instName = env.str(stringc << ct->name << sargsToString(ctTI->arguments));
+
+      // add this type to the primary's list of specializations; we are not
+      // going to add 'ct' to the environment, so the only way to find the
+      // specialization is to go through the primary template
+      TemplateInfo *primaryTI = primary->templateInfo();
+      primaryTI->addSpecialization(ct->getTypedefVar());
+
+      // the template parameters parameterize the specialization primary
+      //
+      // 8/09/04: moved this below 'makeNewCompound' so the params
+      // aren't regarded as inherited
+      if (!gcc2hack_explicitSpec) {
+        scope->setParameterizedEntity(ct->typedefVar);
+      }
+
+      TRACE("template", (definition? "defn" : "decl") <<
+                        " of specialization of template class " <<
+                        primary->typedefVar->fullyQualifiedName0() <<
+                        ", " << ct->instName);
+    }
+
+    // record the definition scope, for instantiation to use
+    if (templateParams && definition) {
+      ct->templateInfo()->defnScope = env.nonTemplateScope();
+    }
+  }
+
+  return ct;
+}
+
+
+Type *TS_elaborated::itcheck(Env &env, DeclFlags dflags)
+{
+  env.setLoc(loc);
+
+  tcheckPQName(name, env, NULL /*scope*/, LF_NONE);
+
+  if (keyword == TI_ENUM) {
+    Variable *tag = env.lookupPQ_one(name, LF_ONLY_TYPES);
+    if (!tag) {
+      if (!env.lang.allowIncompleteEnums ||
+          name->hasQualifiers()) {
+        return env.error(stringc << "there is no enum called `" << *name << "'",
+                         EF_DISAMBIGUATES);
+      }
+      else {
+        // make a forward-declared enum (gnu/d0083.c)
+        EnumType *et = new EnumType(name->getName());
+        return env.declareEnum(loc, et);
+      }
+    }
+    xassert(tag->isType());      // ensured by LF_ONLY_TYPES
+
+    if (!tag->type->isEnumType()) {
+      return env.error(stringc << "`" << *name << "' is not an enum");
+    }
+    if (!tag->hasFlag(DF_IMPLICIT)) {
+      // found a user-introduced (not implicit) typedef, which
+      // is illegal (3.4.4p2,3)
+      return env.error(stringc << "`" << *name << "' is a typedef-name, "
+                               << "so cannot be used after 'enum'");
+    }
+    EnumType *et = tag->type->asCVAtomicType()->atomic->asEnumType();
+
+    this->atype = et;          // annotation
+    return env.makeType(et);
+  }
+
+  CompoundType *ct =
+    checkClasskeyAndName(env, env.scope(), loc, dflags, keyword, name);
+  if (!ct) {
+    ct = env.errorCompoundType;
+  }
+
+  this->atype = ct;              // annotation
+
+  return ct->typedefVar->type;
+}
+
+
+// typecheck declarator name 'name', pushing the sequence of scopes
+// that necessary to tcheck what follows, and also returning that
+// sequence in 'qualifierScopes' so the caller can undo it
+void tcheckDeclaratorPQName(Env &env, ScopeSeq &qualifierScopes,
+                            PQName *name, LookupFlags lflags)
+{
+  lflags |= LF_DECLARATOR;
+
+  if (name) {
+    // tcheck template arguments
+    tcheckPQName(name, env, NULL /*scope*/, lflags);
+
+    // lookup the name minus the final component; this is the scope
+    Variable *scopeVar = env.lookupPQ_one(name, LF_GET_SCOPE_ONLY | lflags);
+
+    // if that worked, get that scope and its parents, up to the current
+    // innermost scope
+    if (scopeVar) {
+      env.getParentScopes(qualifierScopes, scopeVar);
+    }
+
+    // and push that sequence
+    env.extendScopeSeq(qualifierScopes);
+  }
+}
+
+
+Type *TS_classSpec::itcheck(Env &env, DeclFlags dflags)
+{
+  env.setLoc(loc);
+  dflags |= DF_DEFINITION;
+
+  // if we're on the second pass, then skip almost everything
+  if (env.secondPassTcheck) {
+    // just get the function bodies
+    env.extendScope(ctype);
+    tcheckFunctionBodies(env);
+    env.retractScope(ctype);
+    return ctype->typedefVar->type;
+  }
+
+  // scope in which decl appears; I save this now, before extending
+  // it with qualifier scopes, for cases like in/t0441a.cc
+  Scope *scope = env.scope();
+
+  // lookup and push scopes in the name, if any
+  ScopeSeq qualifierScopes;
+  tcheckDeclaratorPQName(env, qualifierScopes, name, LF_NONE);
+
+  // figure out which class the (keyword, name) pair refers to
+  CompoundType *ct =
+    checkClasskeyAndName(env, scope, loc, dflags, keyword, name);
+  if (!ct) {
+    // error already reported
+    env.retractScopeSeq(qualifierScopes);
+    this->ctype = env.errorCompoundType;
+    return this->ctype->typedefVar->type;
+  }
+
+  this->ctype = ct;           // annotation
+
+  // check the body of the definition
+  tcheckIntoCompound(env, dflags, ct);
+
+  env.retractScopeSeq(qualifierScopes);
+
+  return ct->typedefVar->type;
+}
+
+
+// type check once we know what 'ct' is; this is also called
+// to check newly-cloned AST fragments for template instantiation
+void TS_classSpec::tcheckIntoCompound(
+  Env &env, DeclFlags dflags,    // as in tcheck
+  CompoundType *ct)              // compound into which we're putting declarations
+{
+  // should have set the annotation by now
+  xassert(ctype);
+
+  // are we an inner class?
+  CompoundType *containingClass = env.acceptingScope()->curCompound;
+  if (env.lang.noInnerClasses) {
+    // nullify the above; act as if it's an outer class
+    containingClass = NULL;
+  }
+
+  // let me map from compounds to their AST definition nodes
+  ct->syntax = this;
+
+  // only report serious errors while checking the class,
+  // in the absence of actual template arguments
+  DisambiguateOnlyTemp disOnly(env, ct->isTemplate() /*disOnly*/);
+
+  // we should not be in an ambiguous context, because that would screw
+  // up the environment modifications; if this fails, it could be that
+  // you need to do context isolation using 'DisambiguateNestingTemp'
+  xassert(env.disambiguationNestingLevel == 0);
+
+  // 9/21/04: d0102.cc demonstrates that certain errors that are
+  // marked 'disambiguating' can still be superfluous because of being
+  // in uninstantiated template code.  So I'm going to use a big
+  // hammer here, and throw away all non-EF_STRONG errors once
+  // tchecking of this template finishes.  For the moment, that means
+  // I need to save the existing errors.
+  //
+  // The filtering only happens when the "permissive" tracing flag
+  // is set.
+  UninstTemplateErrorFilter errorFilter(env);
+
+  // open a scope, and install 'ct' as the compound which is
+  // being built; in fact, 'ct' itself is a scope, so we use
+  // that directly
+  //
+  // 8/19/04: Do this before looking at the base class specs, because
+  // any prevailing template params are now attached to 'ct' and hence
+  // only visible there (t0271.cc).
+  env.extendScope(ct);
+
+  // look at the base class specifications
+  if (bases) {
+    FAKELIST_FOREACH_NC(BaseClassSpec, bases, iter) {
+      // resolve any template arguments in the base class name
+      tcheckPQName(iter->name, env, NULL /*scope*/, LF_NONE);
+
+      // cppstd 10, para 1: ignore non-types when looking up
+      // base class names
+      Variable *baseVar = env.lookupPQ_one(iter->name, LF_ONLY_TYPES);
+      if (!baseVar) {
+        env.error(stringc
+          << "no class called `" << *(iter->name) << "' was found",
+          EF_NONE);
+        continue;
+      }
+      xassert(baseVar->hasFlag(DF_TYPEDEF));    // that's what LF_ONLY_TYPES means
+
+      // special case for template parameters
+      if (baseVar->type->isTypeVariable() ||
+          baseVar->type->isPseudoInstantiation() ||
+          baseVar->type->isDependentQType()) {
+        // let it go.. we're doing the pseudo-check of a template;
+        // but there's nothing we can add to the base class list,
+        // and it wouldn't help even if we could, so do nothing
+        TemplateInfo *ti = ct->templateInfo();
+        ti->dependentBases.append(baseVar->type);
+        continue;
+      }
+
+      // cppstd 10, para 1: must be a class type
+      CompoundType *base = baseVar->type->ifCompoundType();
+      if (!base) {
+        env.error(stringc
+          << "`" << *(iter->name) << "' is not a class or "
+          << "struct or union, so it cannot be used as a base class");
+        continue;
+      }
+
+      // also 10 para 1: must be complete type
+      if (!env.ensureCompleteType("use as base class", baseVar->type)) {
+        continue;
+      }
+
+      // fill in the default access mode if the user didn't provide one
+      // [cppstd 11.2 para 2]
+      AccessKeyword acc = iter->access;
+      if (acc == AK_UNSPECIFIED) {
+        acc = (ct->keyword==CompoundType::K_CLASS? AK_PRIVATE : AK_PUBLIC);
+      }
+
+      // add this to the class's list of base classes
+      ct->addBaseClass(new BaseClass(base, acc, iter->isVirtual));
+
+      // annotate the AST with the type we found
+      iter->type = base;
+    }
+
+    // we're finished constructing the inheritance hierarchy
+    if (tracingSys("printHierarchies")) {
+      string h1 = ct->renderSubobjHierarchy();
+      cout << "// ----------------- " << ct->name << " -------------------\n";
+      cout << h1;
+
+      // for debugging; this checks that the 'visited' flags are being
+      // cleared properly, among other things
+      string h2 = ct->renderSubobjHierarchy();
+      if (!h1.equals(h2)) {
+        xfailure("second rendering doesn't match first");
+      }
+    }
+  }
+
+  // look at members: first pass is to enter them into the environment
+  {
+    // don't check function bodies
+    Restorer<bool> r(env.checkFunctionBodies, false);
+
+    FOREACH_ASTLIST_NC(Member, members->list, iter) {
+      Member *member = iter.data();
+      member->tcheck(env);
+    }
+  }
+
+  // 2005-02-17: check default arguments first so they are available
+  // to all function bodies (hmmm... what if a default argument
+  // expression invokes a function that itself has default args,
+  // but appears later in the file?  how could that ever be handled
+  // cleanly?)
+  //
+  // 2005-02-18: Do this here instead of in 'tcheckFunctionBodies'
+  // for greater uniformity with template instantiation.  Also, must
+  // do it above 'addCompilerSuppliedDecls', since the presence of
+  // default args affects whether (e.g.) a copy ctor exists.
+  {
+    DefaultArgumentChecker checker(env, ct->isInstantiation());
+
+    // 2005-05-28: start with 'members' instead of 'this', to skip
+    // around the prune in visitTypeSpecifier
+    members->traverse(checker);
+  }
+
+  // default ctor, copy ctor, operator=; only do this for C++.
+  if (env.lang.isCplusplus) {
+    addCompilerSuppliedDecls(env, loc, ct);
+  }
+
+  // let the CompoundType build additional indexes if it wants
+  ct->finishedClassDefinition(env.conversionOperatorName);
+
+  // second pass: check function bodies
+  // (only if we're not in a context where this is supressed)
+  if (env.checkFunctionBodies) {
+    tcheckFunctionBodies(env);
+  }
+
+  // now retract the class scope from the stack of scopes; do
+  // *not* destroy it!
+  env.retractScope(ct);
+
+  if (containingClass) {
+    // set the constructed scope's 'parentScope' pointer now that
+    // we've removed 'ct' from the Environment scope stack; future
+    // (unqualified) lookups in 'ct' will thus be able to see
+    // into the containing class [cppstd 3.4.1 para 8]
+    ct->parentScope = containingClass;
+  }
+
+  env.addedNewCompound(ct);
+}
+
+
+// This is pass 2 of tchecking a class.  It implements 3.3.6 para 1
+// bullet 1, which specifies that the scope of a class member includes
+// all function bodies.  That means that we have to wait until all
+// the members have been added to the class scope before checking any
+// of the function bodies.  Pass 1 does the former, pass 2 the latter.
+void TS_classSpec::tcheckFunctionBodies(Env &env)
+{
+  xassert(env.checkFunctionBodies);
+
+  CompoundType *ct = env.scope()->curCompound;
+  xassert(ct);
+
+  // inform the members that they are being checked on the second
+  // pass through a class definition
+  Restorer<bool> r(env.secondPassTcheck, true);
+
+  // check function bodies and elaborate ctors and dtors of member
+  // declarations
+  FOREACH_ASTLIST_NC(Member, members->list, iter) {
+    Member *member = iter.data();
+    member->tcheck(env);
+  }
+}
+
+
+Type *TS_enumSpec::itcheck(Env &env, DeclFlags dflags)
+{
+  env.setLoc(loc);
+
+  EnumType *et = NULL;
+  Type *ret = NULL;
+
+  if (env.lang.allowIncompleteEnums && name) {
+    // is this referring to an existing forward-declared enum?
+    et = env.lookupEnum(name, LF_INNER_ONLY);
+    if (et) {
+      ret = env.makeType(et);
+      if (!et->valueIndex.isEmpty()) {
+        // if it has values, it's definitely been defined already
+        env.error(stringc << "multiply defined enum `" << name << "'");
+        return ret;      // ignore this defn
+      }
+    }
+  }
+
+  if (!et) {
+    // declare the new enum
+    et = new EnumType(name);
+    ret = env.declareEnum(loc, et);
+  }
+
+  FAKELIST_FOREACH_NC(Enumerator, elts, iter) {
+    iter->tcheck(env, et, ret);
+  }
+
+  this->etype = et;           // annotation
+  return ret;
+}
+
+
+// BaseClass
+// MemberList
+
+// ---------------------- Member ----------------------
+// cppstd 9.2 para 6:
+//   "A member shall not be auto, extern, or register."
+void checkMemberFlags(Env &env, DeclFlags flags)
+{
+  if (flags & (DF_AUTO | DF_EXTERN | DF_REGISTER)) {
+    env.error("class members cannot be marked `auto', `extern', "
+              "or `register'");
+  }
+}
+
+void MR_decl::tcheck(Env &env)
+{
+  env.setLoc(loc);
+
+  if (!( d->dflags & DF_FRIEND )) {
+    FAKELIST_FOREACH_NC(Declarator, d->decllist, iter) {
+      env.checkForQualifiedMemberDeclarator(iter);
+    }
+  }
+
+  if (env.secondPassTcheck) {
+    // TS_classSpec is only thing of interest
+    if (d->spec->isTS_classSpec()) {
+      d->spec->asTS_classSpec()->tcheck(env, d->dflags);
+    }
+    return;
+  }
+
+  // the declaration knows to add its variables to
+  // the curCompound
+  d->tcheck(env, DC_MR_DECL);
+
+  checkMemberFlags(env, d->dflags);
+}
+
+void MR_func::tcheck(Env &env)
+{
+  env.setLoc(loc);
+
+  if (env.scope()->curCompound->keyword == CompoundType::K_UNION) {
+    // TODO: is this even true?
+    // apparently not, as Mozilla has them; would like to find
+    // a definitive answer
+    //env.error("unions cannot have member functions");
+    //return;
+  }
+
+  if (!( f->dflags & DF_FRIEND )) {
+    env.checkForQualifiedMemberDeclarator(f->nameAndParams);
+  }
+
+  // mark the function as inline, whether or not the
+  // user explicitly did so
+  f->dflags = (DeclFlags)(f->dflags | DF_INLINE);
+
+  // we check the bodies in a second pass, after all the class
+  // members have been added to the class, so that the potential
+  // scope of all class members includes all function bodies
+  // [cppstd sec. 3.3.6]
+  //
+  // the check-body suppression is now handled via a flag in 'env', so
+  // this call site doesn't directly reflect that that is happening
+  f->tcheck(env);
+
+  checkMemberFlags(env, f->dflags);
+}
+
+void MR_access::tcheck(Env &env)
+{
+  if (env.secondPassTcheck) { return; }
+
+  env.setLoc(loc);
+
+  env.scope()->curAccess = k;
+}
+
+void MR_usingDecl::tcheck(Env &env)
+{
+  if (env.secondPassTcheck) { return; }
+
+  env.setLoc(loc);
+  decl->tcheck(env);
+}
+
+void MR_template::tcheck(Env &env)
+{
+  // maybe this will "just work"? crossing fingers..
+  env.setLoc(loc);
+  d->tcheck(env);
+}
+
+
+// -------------------- Enumerator --------------------
+void Enumerator::tcheck(Env &env, EnumType *parentEnum, Type *parentType)
+{
+  var = env.makeVariable(loc, name, parentType, DF_ENUMERATOR);
+
+  enumValue = parentEnum->nextValue;
+  if (expr) {
+    expr->tcheck(env, expr);
+
+    // will either set 'enumValue', or print (add) an error message
+    expr->constEval(env, enumValue);
+  }
+
+  parentEnum->addValue(name, enumValue, var);
+  parentEnum->nextValue = enumValue + 1;
+
+  // cppstd sec. 3.3.1:
+  //   "The point of declaration for an enumerator is immediately after
+  //   its enumerator-definition. [Example:
+  //     const int x = 12;
+  //     { enum { x = x }; }
+  //   Here, the enumerator x is initialized with the value of the
+  //   constant x, namely 12. ]"
+
+  bool forceReplace = false;
+
+  // (in/t0527.cc) will the name conflict with an implicit typedef?
+  Variable *prior = env.unqualifiedLookup_one(name, LF_INNER_ONLY);
+  if (prior && prior->isImplicitTypedef()) {
+    TRACE("env", "replacing implicit typedef " << name <<
+                 " with enumerator");
+    forceReplace = true;
+  }
+
+  if (!env.addVariable(var, forceReplace)) {
+    env.error(stringc
+      << "enumerator " << name << " conflicts with an existing variable "
+      << "or typedef by the same name");
+  }
+}
+
+
+// ----------------- declareNewVariable ---------------
+// This block of helpers, especially 'declareNewVariable', is the
+// heart of the type checker, and the most complicated.
+
+// This function is called whenever a constructed type is passed to a
+// lower-down IDeclarator which *cannot* accept member function types.
+// (sm 7/10/03: I'm now not sure exactly what that means...)
+//
+// sm 8/10/04: the issue is that someone has to call 'doneParams', but
+// that can't be done in one central location, so this does it unless
+// it has already been done, and is called in several places;
+// 'dt.funcSyntax' is used as a flag to tell when it's happened
+void possiblyConsumeFunctionType(Env &env, Declarator::Tcheck &dt,
+                                 bool reportErrors = true)
+{
+  if (dt.funcSyntax) {
+    if (dt.funcSyntax->cv != CV_NONE && reportErrors) {
+      env.error("cannot have const/volatile on nonmember functions");
+    }
+    dt.funcSyntax = NULL;
+
+    // close the parameter list
+    env.doneParams(dt.type->asFunctionType());
+  }
+}
+
+
+// given a 'dt.type' that is a function type, and a 'dt.funcSyntax'
+// that's carrying information about the function declarator syntax,
+// and 'inClass' the class that the function will be considered a
+// member of, attach a 'this' parameter to the function type, and
+// close its parameter list
+void makeMemberFunctionType(Env &env, Declarator::Tcheck &dt,
+                            NamedAtomicType *inClassNAT, SourceLoc loc)
+{
+  // make the implicit 'this' parameter
+  CVFlags thisCV = dt.funcSyntax? dt.funcSyntax->cv : CV_NONE;
+  Variable *receiver = env.receiverParameter(loc, inClassNAT, thisCV, dt.funcSyntax);
+
+  // actually (in/k0031.cc), there is not necessarily a D_func, if a
+  // typedef was used; in that case, the function cannot be 'const' or
+  // 'volatile', and we need to make a copy of the function type so
+  // that we can add the 'this' parameter
+  FunctionType *ft = dt.type->asFunctionType();
+  if (!dt.funcSyntax) {
+    FunctionType *copyFt =
+      env.tfac.makeSimilarFunctionType(SL_UNKNOWN, ft->retType, ft);
+
+    // copy the parameters; it should be ok to share them (shallow copy)
+    copyFt->params = ft->params;
+
+    // use 'copyFt' from here on
+    ft = copyFt;
+  }
+
+  // add the receiver to the function type
+  ft->addReceiver(receiver);
+
+  // close it
+  dt.funcSyntax = NULL;
+  env.doneParams(ft);
+}
+
+
+// Check some restrictions regarding the use of 'operator'; might
+// add some errors to the environment, but otherwise doesn't
+// change anything.  Parameters are same as declareNewVariable, plus
+// 'scope', the scope into which the name will be inserted.
+void checkOperatorOverload(Env &env, Declarator::Tcheck &dt,
+                           SourceLoc loc, PQName const *name,
+                           Scope *scope)
+{
+  if (!dt.type->isFunctionType()) {
+    env.error(loc, "operators must be functions");
+    return;
+  }
+  FunctionType *ft = dt.type->asFunctionType();
+
+  // caller guarantees this will work
+  OperatorName const *oname = name->getUnqualifiedNameC()->asPQ_operatorC()->o;
+  char const *strname = oname->getOperatorName();
+
+  if (scope->curCompound) {
+    // All the operators mentioned in 13.5 must be non-static if they
+    // are implemented by member functions.  (Actually, 13.5.7 does
+    // not explicitly require non-static, but it's clearly intended.)
+    //
+    // That leaves only operators new and delete, which (12.5 para 1)
+    // are always static *even if not explicitly declared so*.
+    if (oname->isON_newDel()) {
+      // actually, this is now done elsewhere (search for "12.5 para 1")
+      //dt.dflags |= DF_STATIC;      // force it to be static
+    }
+    else if (dt.dflags & DF_STATIC) {
+      env.error(loc, "operator member functions (other than new/delete) cannot be static");
+    }
+  }
+
+  // describe the operator
+  enum OperatorDesc {
+    OD_NONE    = 0x00,
+    NONMEMBER  = 0x01,      // can be a non-member function (anything can be a member function)
+    ONEPARAM   = 0x02,      // can accept one parameter
+    TWOPARAMS  = 0x04,      // can accept two parameters
+    ANYPARAMS  = 0x08,      // can accept any number of parameters
+    INCDEC     = 0x10,      // it's ++ or --
+  };
+  OperatorDesc desc = OD_NONE;
+
+  ASTSWITCHC(OperatorName, oname) {
+    ASTCASEC(ON_newDel, n)
+      PRETEND_USED(n);
+      // don't check anything.. I haven't done anything with these yet
+      return;
+
+    ASTNEXTC(ON_operator, o)
+      static int/*OperatorDesc*/ const map[] = {
+        // each group of similar operators is prefixed with a comment
+        // that says which section of cppstd specifies the restrictions
+        // that are enforced here
+
+        // 13.5.1
+        NONMEMBER | ONEPARAM,                       // OP_NOT
+        NONMEMBER | ONEPARAM,                       // OP_BITNOT
+
+        // 13.5.7
+        NONMEMBER | ONEPARAM | TWOPARAMS | INCDEC,  // OP_PLUSPLUS
+        NONMEMBER | ONEPARAM | TWOPARAMS | INCDEC,  // OP_MINUSMINUS
+
+        // 13.5.1, 13.5.2
+        NONMEMBER | ONEPARAM | TWOPARAMS,           // OP_PLUS
+        NONMEMBER | ONEPARAM | TWOPARAMS,           // OP_MINUS
+        NONMEMBER | ONEPARAM | TWOPARAMS,           // OP_STAR
+        NONMEMBER | ONEPARAM | TWOPARAMS,           // OP_AMPERSAND
+
+        // 13.5.2
+        NONMEMBER | TWOPARAMS,                      // OP_DIV
+        NONMEMBER | TWOPARAMS,                      // OP_MOD
+        NONMEMBER | TWOPARAMS,                      // OP_LSHIFT
+        NONMEMBER | TWOPARAMS,                      // OP_RSHIFT
+        NONMEMBER | TWOPARAMS,                      // OP_BITXOR
+        NONMEMBER | TWOPARAMS,                      // OP_BITOR
+
+        // 13.5.3
+        TWOPARAMS,                                  // OP_ASSIGN
+
+        // 13.5.2 (these are handled as ordinary binary operators (13.5 para 9))
+        NONMEMBER | TWOPARAMS,                      // OP_PLUSEQ
+        NONMEMBER | TWOPARAMS,                      // OP_MINUSEQ
+        NONMEMBER | TWOPARAMS,                      // OP_MULTEQ
+        NONMEMBER | TWOPARAMS,                      // OP_DIVEQ
+        NONMEMBER | TWOPARAMS,                      // OP_MODEQ
+        NONMEMBER | TWOPARAMS,                      // OP_LSHIFTEQ
+        NONMEMBER | TWOPARAMS,                      // OP_RSHIFTEQ
+        NONMEMBER | TWOPARAMS,                      // OP_BITANDEQ
+        NONMEMBER | TWOPARAMS,                      // OP_BITXOREQ
+        NONMEMBER | TWOPARAMS,                      // OP_BITOREQ
+
+        // 13.5.2
+        NONMEMBER | TWOPARAMS,                      // OP_EQUAL
+        NONMEMBER | TWOPARAMS,                      // OP_NOTEQUAL
+        NONMEMBER | TWOPARAMS,                      // OP_LESS
+        NONMEMBER | TWOPARAMS,                      // OP_GREATER
+        NONMEMBER | TWOPARAMS,                      // OP_LESSEQ
+        NONMEMBER | TWOPARAMS,                      // OP_GREATEREQ
+
+        // 13.5.2
+        NONMEMBER | TWOPARAMS,                      // OP_AND
+        NONMEMBER | TWOPARAMS,                      // OP_OR
+
+        // 13.5.6
+        ONEPARAM,                                   // OP_ARROW
+
+        // 13.5.2
+        NONMEMBER | TWOPARAMS,                      // OP_ARROW_STAR
+
+        // 13.5.5
+        TWOPARAMS,                                  // OP_BRACKETS
+
+        // 13.5.4
+        ANYPARAMS,                                  // OP_PARENS
+
+        // 13.5.2
+        NONMEMBER | TWOPARAMS,                      // OP_COMMA
+
+        OD_NONE,                                    // OP_QUESTION (not used)
+
+        // I am guessing that <? and >? overload similar to OP_PLUS
+        NONMEMBER | ONEPARAM | TWOPARAMS,           // OP_MINUMUM
+        NONMEMBER | ONEPARAM | TWOPARAMS,           // OP_MAXIMUM
+      };
+      ASSERT_TABLESIZE(map, NUM_OVERLOADABLE_OPS);
+      xassert(validCode(o->op));
+
+      // the table is declared int[] so that I can bitwise-OR
+      // enumerated values without a cast; and overloading operator|
+      // like I do elsewhere is nonportable b/c then an initializing
+      // expression (which is supposed to be a literal) involves a
+      // function call, at least naively...
+      desc = (OperatorDesc)map[o->op];
+
+      break;
+
+    ASTNEXTC(ON_conversion, c)
+      PRETEND_USED(c);
+      desc = ONEPARAM;
+
+    ASTENDCASECD
+  }
+
+  xassert(desc & (ONEPARAM | TWOPARAMS | ANYPARAMS));
+
+  bool isMember = scope->curCompound != NULL;
+  if (!isMember && !(desc & NONMEMBER)) {
+    env.error(loc, stringc << strname << " must be a member function");
+  }
+
+  if (!(desc & ANYPARAMS)) {
+    // count and check parameters
+    int params = ft->params.count();     // includes implicit receiver
+    bool okOneParam = desc & ONEPARAM;
+    bool okTwoParams = desc & TWOPARAMS;
+
+    if ((okOneParam && params==1) ||
+        (okTwoParams && params==2)) {
+      // ok
+    }
+    else {
+      char const *howmany =
+        okOneParam && okTwoParams? "one or two parameters" :
+                      okTwoParams? "two parameters" :
+                                   "one parameter" ;
+      char const *extra =
+        ft->isMethod()? " (including receiver object)" : "";
+      env.error(loc, stringc << strname << " must have " << howmany << extra);
+    }
+
+    if ((desc & INCDEC) && (params==2)) {
+      // second parameter must have type 'int'
+      Type *t = ft->params.nth(1)->type;
+      if (!t->isSimple(ST_INT) ||
+          t->getCVFlags()!=CV_NONE) {
+        env.error(loc, stringc
+          << (isMember? "" : "second ")
+          << "parameter of " << strname
+          << " must have type `int', not `"
+          << t->toString() << "', if it is present");
+      }
+    }
+
+    // cannot have any default arguments
+    SFOREACH_OBJLIST(Variable, ft->params, iter) {
+      if (iter.data()->value != NULL) {
+        env.error(loc, stringc << strname << " cannot have default arguments");
+      }
+    }
+  }
+}
+
+
+bool forAnonymous_isUnion(Env &env, CompoundType::Keyword k)
+{
+  if (k == CompoundType::K_UNION) {
+    return true;
+  }
+
+  if (env.lang.allowAnonymousStructs) {
+    return true;
+  }
+
+  return false;
+}
+
+
+// This function is perhaps the most complicated in this entire
+// module.  It has the responsibility of adding a variable called
+// 'name' to the environment.  But to do this it has to implement the
+// various rules for when declarations conflict, overloading,
+// qualified name lookup, etc.
+//
+// Update: I've now broken some of this mechanism apart and implemented
+// the pieces in Env, so it's perhaps a bit less complicated now.
+//
+// 8/11/04: I renamed it from D_name_tcheck, to reflect that it is no
+// longer done at the bottom of the IDeclarator chain, but instead is
+// done right after processing the IDeclarator,
+// Declarator::mid_tcheck.
+//
+// Note that this function *cannot* return NULL.
+static Variable *declareNewVariable(
+  // environment in which to do general lookups
+  Env &env,
+
+  // contains various information about 'name', notably its type
+  Declarator::Tcheck &dt,
+
+  // true if we're a D_grouping is innermost to a D_pointer/D_reference
+  bool inGrouping,
+
+  // source location where 'name' appeared
+  SourceLoc loc,
+
+  // name being declared
+  PQName *name)
+{
+  // this is used to refer to a pre-existing declaration of the same
+  // name; I moved it up top so my error subroutines can use it
+  Variable *prior = NULL;
+
+  // the unqualified part of 'name', mapped if necessary for
+  // constructor names
+  StringRef unqualifiedName = name? name->getName() : NULL;
+
+  // false until I somehow call doneParams() for function types
+  bool consumedFunction = false;
+
+  // scope in which to insert the name, and to look for pre-existing
+  // declarations
+  Scope *scope = env.acceptingScope(dt.dflags);
+
+  // class that is befriending this entity
+  CompoundType *befriending = NULL;
+
+  goto realStart;
+
+  // This code has a number of places where very different logic paths
+  // lead to the same conclusion.  So, I'm going to put the code for
+  // these conclusions up here (like mini-subroutines), and 'goto'
+  // them when appropriate.  I put them at the top instead of the
+  // bottom since g++ doesn't like me to jump forward over variable
+  // declarations.  They aren't put into real subroutines because they
+  // want to access many of this function's parameters and locals, and
+  // it'd be a hassle to pass them all each time.  In any case, they
+  // would all be tail calls, since once I 'goto' somewhere I don't
+  // come back.
+
+  // an error has been reported, but for error recovery purposes,
+  // return something reasonable
+  makeDummyVar:
+  {
+    if (!consumedFunction) {
+      possiblyConsumeFunctionType(env, dt);
+    }
+
+    // the purpose of this is to allow the caller to have a workable
+    // object, so we can continue making progress diagnosing errors
+    // in the program; this won't be entered in the environment, even
+    // though the 'name' is not NULL
+    Variable *ret = env.makeVariable(loc, unqualifiedName, dt.type, dt.dflags);
+
+    // set up the variable's 'scope' field as if it were properly
+    // entered into the scope; this is for error recovery, in particular
+    // for going on to check the bodies of methods
+    scope->registerVariable(ret);
+
+    return ret;
+  }
+
+realStart:
+  if (!name) {
+    // no name, nothing to enter into environment
+    possiblyConsumeFunctionType(env, dt);
+    return env.makeVariable(loc, NULL, dt.type, dt.dflags);
+  }
+
+  #if 0    // problematic since applies to too many things
+  // C linkage?
+  if (env.linkageIs_C()) {
+    dt.dflags |= DF_EXTERN_C;
+  }
+  #endif // 0
+
+  // friend?
+  bool isFriend = (dt.dflags & DF_FRIEND);
+  if (isFriend) {
+    // TODO: somehow remember the access control implications
+    // of the friend declaration
+
+    // is the scope in which this declaration appears (that is,
+    // skipping any template<> that might be associated directly
+    // with this declaration) itself a template?
+    bool insideTemplate = env.enclosingKindScopeAbove(SK_TEMPLATE_PARAMS, scope);
+
+    if (name->hasQualifiers() || insideTemplate) {
+      // we're befriending something that either is already declared,
+      // or will be declared before it is used; no need to contemplate
+      // adding a declaration, so just make the required Variable
+      // and be done with it
+      //
+      // TODO: can't befriend cv members, e.g. in/t0333.cc
+      //
+      // 2005-05-07: if we're in an uninst template (class), then
+      // the friend declaration is ignored; it will be processed
+      // when the template is instantiated (11.4, 14.5.3, in/t0470.cc)
+      possiblyConsumeFunctionType(env, dt, false /*reportErrors*/);
+      return env.makeVariable(loc, unqualifiedName, dt.type, dt.dflags);
+    }
+    else if (name->isPQ_template()) {
+      // (e.g., in/t0474.cc) We are befriending a template.  Friends
+      // and templates don't get along very well yet.  The most
+      // immediate problem is that I need to look at the set of types
+      // used in the friend declaration, and hypothesize a
+      // corresponding set of template parameters that will be
+      // associated with the friend, rather than being associated with
+      // the class that is granting friendship.  At it is, with the
+      // parameters associated with the class, I fail to realize that
+      // a prior declaration is referring to the same thing.
+      //
+      // However, for right now, I think I can get away with ignoring
+      // the friendship declaration altogether.
+      goto makeDummyVar;
+    }
+    else {
+      // 2005-08-15: record the befriending class so it can
+      // participate in arg-dep lookup
+      if (scope->curCompound) {
+        befriending = scope->curCompound;
+      }
+      else {
+        env.error("friend declaration must appear in class scope");
+      }
+
+      // the main effect of 'friend' in my implementation is to
+      // declare the variable in the innermost non-class, non-
+      // template scope (this isn't perfect; see cppstd 11.4)
+      //
+      // Unfortunately, both GCC and ICC seem to do name injection,
+      // even though that is not what the standard specifies.  So,
+      // making Elsa more standard-compliant on this issue would
+      // create some static, and thus I do name injection too.
+      scope = env.outerScope();
+
+      // turn off the decl flag because it shouldn't end up
+      // in the final Variable
+      dt.dflags = dt.dflags & ~DF_FRIEND;
+    }
+  }
+
+  // ambiguous grouped declarator in a paramter list?
+  if (dt.hasFlag(DF_PARAMETER) && inGrouping) {
+    // the name must *not* correspond to an existing type; this is
+    // how I implement cppstd 8.2 para 7
+    Variable *v = env.lookupPQ_one(name, LF_NONE);
+    if (v && v->hasFlag(DF_TYPEDEF)) {
+      TRACE("disamb", "discarding grouped param declarator of type name");
+      env.error(stringc
+        << "`" << *name << "' is the name of a type, but was used as "
+        << "a grouped parameter declarator; ambiguity resolution should "
+        << "pick a different interpretation, so if the end user ever "
+        << "sees this message then there's a bug in my typechecker",
+        EF_DISAMBIGUATES);
+      goto makeDummyVar;
+    }
+  }
+
+  // member of an anonymous union?  (note that if the union had
+  // declarators, then it would have been given a name by now)
+  if (scope->curCompound &&
+      scope->curCompound->name == NULL &&
+      forAnonymous_isUnion(env, scope->curCompound->keyword)) {
+    // we're declaring a field of an anonymous union, which actually
+    // goes in the enclosing scope
+    scope = env.enclosingScope();
+  }
+
+  // constructor?
+  bool isConstructor = dt.type->isFunctionType() &&
+                       dt.type->asFunctionTypeC()->isConstructor();
+  if (isConstructor) {
+    // if I just use the class name as the name of the constructor,
+    // then that will hide the class's name as a type, which messes
+    // everything up.  so, I'll kludge together another name for
+    // constructors (one which the C++ programmer can't type) and
+    // just make sure I always look up constructors under that name
+    unqualifiedName = env.constructorSpecialName;
+  }
+
+  // are we in a class member list?  we can't be in a member
+  // list if the name is qualified (and if it's qualified then
+  // a class scope has been pushed, so we'd be fooled); see
+  // also Env::checkForQualifiedMemberDeclarator().
+  CompoundType *enclosingClass =
+    name->hasQualifiers()? NULL : scope->curCompound;
+
+  // if we're in the scope of a class at all then we're DF_MEMBER
+  if (scope->curCompound && !isFriend) {
+    dt.dflags |= DF_MEMBER;
+  }
+
+  // if we're not in a class member list, and the type is not a
+  // function type, and 'extern' is not specified, then this is
+  // a definition
+  if (!enclosingClass &&
+      !dt.type->isFunctionType() &&
+      !(dt.dflags & DF_EXTERN)) {
+    dt.dflags |= DF_DEFINITION;
+  }
+
+  // has this variable already been declared?
+  //Variable *prior = NULL;    // moved to the top
+
+  if (name->hasQualifiers()) {
+    // TODO: I think this is wrong, but I'm not sure how.  For one
+    // thing, it's very similar to what happens below for unqualified
+    // names; could those be unified?  Second, the thing above about
+    // how class member declarations can be qualified, but I don't
+    // allow it ...
+
+    // the name has qualifiers, which means it *must* be declared
+    // somewhere; now, Declarator::tcheck will have already pushed the
+    // qualified scope, so we just look up the name in the now-current
+    // environment, which will include that scope
+    prior = scope->lookupVariable(unqualifiedName, env, LF_INNER_ONLY);
+    if (!prior) {
+      env.error(stringc
+        << "undeclared identifier `" << *name << "'");
+      goto makeDummyVar;
+    }
+
+    // ok, so we found a prior declaration; but if it's a member of
+    // an overload set, then we need to pick the right one now for
+    // several reasons:
+    //   - the DF_DEFINITION flag is per-member, not per-set
+    //   - below we'll be checking for type equality again
+    if (prior->overload) {
+      // only functions can be overloaded
+      if (!dt.type->isFunctionType()) {
+        env.error(dt.type, stringc
+          << "the name `" << *name << "' is overloaded, but the type `"
+          << dt.type->toString() << "' isn't even a function; it must "
+          << "be a function and match one of the overloadings");
+        goto makeDummyVar;
+      }
+      FunctionType *dtft = dt.type->asFunctionType();
+
+      // 'dtft' is incomplete for the moment, because we don't know
+      // yet whether it's supposed to be a static member or a
+      // nonstatic member; this is determined by finding a function
+      // whose signature (ignoring 'this' parameter, if any) matches
+      int howMany = prior->overload->set.count();
+      prior = env.findInOverloadSet(prior->overload, dtft, dt.funcSyntax->cv);
+      if (!prior) {
+        env.error(stringc
+          << "the name `" << *name << "' is overloaded, but the type `"
+          << dtft->toString_withCV(dt.funcSyntax->cv)
+          << "' doesn't match any of the "
+          << howMany << " declared overloaded instances",
+          EF_STRONG);
+        goto makeDummyVar;
+      }
+    }
+
+    if (prior->hasFlag(DF_MEMBER)) {
+      // this intends to be the definition of a class member; make sure
+      // the code doesn't try to define a nonstatic data member
+      if (!prior->type->isFunctionType() &&
+          !prior->hasFlag(DF_STATIC)) {
+        env.error(stringc
+          << "cannot define nonstatic data member `" << *name << "'");
+        goto makeDummyVar;
+      }
+    }
+  }
+  else {
+    // has this name already been declared in the innermost scope?
+    prior = env.lookupVariableForDeclaration(scope, unqualifiedName, dt.type,
+      dt.funcSyntax? dt.funcSyntax->cv : CV_NONE);
+  }
+
+  if (scope->curCompound &&
+      !isFriend &&
+      name->getUnqualifiedNameC()->isPQ_operator() &&
+      name->getUnqualifiedNameC()->asPQ_operatorC()->o->isON_newDel()) {
+    // 12.5 para 1: new/delete member functions are static even if
+    // they are not explicitly declared so
+    dt.dflags |= DF_STATIC;
+  }
+
+  // is this a nonstatic member function?
+  //
+  // TODO: This can't be right in the presence of overloaded functions,
+  // since we're just testing the static-ness of the first element of
+  // the overload set!
+  if (dt.type->isFunctionType()) {
+    if (scope->curCompound &&
+        !isFriend &&
+        !isConstructor &&               // ctors don't have a 'this' param
+        !(dt.dflags & DF_STATIC) &&
+        !(dt.dflags & DF_TYPEDEF) &&    // in/t0536.cc
+        (!name->hasQualifiers() ||
+         !prior->type->isFunctionType() ||
+         prior->type->asFunctionTypeC()->isMethod())) {
+      TRACE("memberFunc", "nonstatic member function: " << *name);
+
+      // add the implicit 'this' parameter
+      makeMemberFunctionType(env, dt, scope->curCompound, loc);
+    }
+    else {
+      TRACE("memberFunc", "static or non-member function: " << *name);
+      possiblyConsumeFunctionType(env, dt);
+    }
+  }
+  consumedFunction = true;
+
+  // check restrictions on operator overloading
+  if (name->getUnqualifiedNameC()->isPQ_operator()) {
+    checkOperatorOverload(env, dt, loc, name, scope);
+  }
+
+  // check for overloading; but if there are qualifiers, then we already
+  // did overload resolution above
+  OverloadSet *overloadSet =
+    name->hasQualifiers() ? NULL /* already did it */ :
+    env.getOverloadForDeclaration(prior, dt.type);
+
+  // 8/11/04: Big block of template code obviated by
+  // Declarator::mid_tcheck.
+
+  // make a new variable; see implementation for details
+  Variable *ret =
+    env.createDeclaration(loc, unqualifiedName, dt.type, dt.dflags,
+                          scope, enclosingClass, prior, overloadSet);
+
+  if (befriending) {
+    befriending->friends.prepend(ret);
+  }
+
+  return ret;
+}
+
+
+// -------------------- Declarator --------------------
+Declarator *Declarator::tcheck(Env &env, Tcheck &dt)
+{
+  if (!ambiguity) {
+    mid_tcheck(env, dt);
+    return this;
+  }
+
+  // The reason for the "gcov-begin/end-ignore" below is that this
+  // code is at the mercy of the parser when it comes to the order in
+  // which ambiguous alternatives are presented.  So, I tell 'mygcov'
+  // not to count coverage in the affected region.
+
+  // As best as I can tell from the standard, cppstd sections 6.8 and
+  // 8.2, we always prefer a Declarator interpretation which has no
+  // initializer (if that's valid) to one that does.  I'm not
+  // completely sure because, ironically, the English text there ("the
+  // resolution is to consider any construct that could possibly be a
+  // declaration a declaration") is ambiguous in my opinion.  See the
+  // examples of ambiguous syntax in cc.gr, nonterminal
+  // InitDeclarator.
+  if (this->init == NULL &&
+      ambiguity->init != NULL &&
+      ambiguity->ambiguity == NULL) {                // gcov-begin-ignore
+    // already in priority order
+    return resolveAmbiguity(this, env, "Declarator", true /*priority*/, dt);
+  }
+  else if (this->init != NULL &&
+           ambiguity->init == NULL &&
+           ambiguity->ambiguity == NULL) {
+    // reverse priority order; swap them
+    return swap_then_resolveAmbiguity(this, env, "Declarator", true /*priority*/, dt);
+  }                                                  // gcov-end-ignore
+  else {
+    // if both have an initialzer or both lack an initializer, then
+    // we'll resolve without ambiguity; otherwise we'll probably fail
+    // to resolve, which will be reported as such
+    return resolveAmbiguity(this, env, "Declarator", false /*priority*/, dt);
+  }
+}
+
+
+// array initializer case
+//   static int y[] = {1, 2, 3};
+// or in this case (a gnu extention):
+// http://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Compound-Literals.html#Compound%20Literals
+//   static int y[] = (int []) {1, 2, 3};
+// which is equivalent to:
+//   static int y[] = {1, 2, 3};
+Type *Env::computeArraySizeFromCompoundInit
+  (SourceLoc tgt_loc, Type *tgt_type, Type *src_type, Initializer *init)
+{
+  // If we start at a reference, we have to go down to the raw
+  // ArrayType and then back up to a reference.
+  bool tgt_type_isRef = tgt_type->isReferenceType();
+  tgt_type = tgt_type->asRval();
+  if (tgt_type->isArrayType() && init->isIN_compound()) {
+    ArrayType *at = tgt_type->asArrayType();
+    IN_compound const *cpd = init->asIN_compoundC();
+
+    // count the initializers; this is done via the environment
+    // so the designated-initializer extension can intercept
+    int initLen = countInitializers(loc(), src_type, cpd);
+
+    if (!at->hasSize()) {
+      // replace the computed type with another that has
+      // the size specified; the location isn't perfect, but
+      // getting the right one is a bit of work
+      tgt_type = tfac.setArraySize(tgt_loc, at, initLen);
+    }
+    else {
+      // TODO: cppstd wants me to check that there aren't more
+      // initializers than the array's specified size, but I
+      // don't want to do that check since I might have an error
+      // in my const-eval logic which could break a Mozilla parse
+      // if my count is short
+    }
+  }
+  return tgt_type_isRef ? makeReferenceType(tgt_type): tgt_type;
+}
+
+// provide a well-defined size for the array from the size of the
+// initializer, such as in this case:
+//   char sName[] = "SOAPPropertyBag";
+Type *computeArraySizeFromLiteral(Env &env, Type *tgt_type, Initializer *init)
+{
+  // If we start at a reference, we have to go down to the raw
+  // ArrayType and then back up to a reference.
+  bool tgt_type_isRef = tgt_type->isReferenceType();
+  tgt_type = tgt_type->asRval();
+  if (tgt_type->isArrayType() &&
+      !tgt_type->asArrayType()->hasSize() &&
+      init->isIN_expr() &&
+      init->asIN_expr()->e->type->asRval()->isArrayType() &&
+      init->asIN_expr()->e->type->asRval()->asArrayType()->hasSize()
+      ) {
+    tgt_type->asArrayType()->size =
+      init->asIN_expr()->e->type->asRval()->asArrayType()->size;
+    xassert(tgt_type->asArrayType()->hasSize());
+  }
+  return tgt_type_isRef ? env.makeReferenceType(tgt_type): tgt_type;
+}
+
+// true if the declarator corresponds to a local/global variable declaration
+bool isVariableDC(DeclaratorContext dc)
+{
+  return dc==DC_TF_DECL ||    // global
+         dc==DC_S_DECL ||     // local
+         dc==DC_CN_DECL;      // local in a Condition
+}
+
+// determine if a complete type is required, and if so, check that it
+// is; return false if a complete type is needed but 'type' is not
+bool checkCompleteTypeRules(Env &env, DeclFlags dflags, DeclaratorContext context,
+                            Type *type, Initializer *init)
+{
+  // TODO: According to 15.4 para 1, not only must the type in
+  // DC_EXCEPTIONSPEC be complete (which this code enforces), but if
+  // it is a pointer or reference type, the pointed-to thing must be
+  // complete too!
+
+  if (context == DC_D_FUNC) {
+    // 8.3.5 para 6: ok to be incomplete unless this is a definition;
+    // I'll just allow it (here) in all cases (t0048.cc)
+    return true;
+  }
+
+  if (context == DC_ON_CONVERSION) {
+    // similarly for the return type of a conversion operator (in/t0535.cc)
+    return true;
+  }
+
+  if (context == DC_TA_TYPE) {
+    // mere appearance of a type in an argument list is not enough to
+    // require that it be complete; maybe the function definition will
+    // need it, but that is detected later
+    return true;
+  }
+
+  if (dflags & (DF_TYPEDEF | DF_EXTERN)) {
+    // 7.1.3 does not say that the type named by a typedef must be
+    // complete, so I will allow it to be incomplete (t0079.cc)
+    //
+    // I'm not sure where the exception for 'extern' is specified, but
+    // it clearly exists.... (t0170.cc)
+    return true;
+  }
+
+  if (context == DC_MR_DECL &&
+      (dflags & DF_STATIC)) {
+    // static members don't have to be complete types
+    return true;
+  }
+
+  if (context == DC_TF_DECL &&
+      env.lang.uninitializedGlobalDataIsCommon &&
+      !init) {
+    // tentative global definition, type does not need to be complete;
+    // c99 6.9.2p3 implies this is only allowed if 'static' is not
+    // specified, but gcc does not enforce that so I won't either
+    return true;
+  }
+
+  if (context == DC_TP_TYPE) {
+    // quarl: default parameter to template; see in/k0065.cc
+    return true;
+  }
+
+  if (type->isArrayType()) {
+    if (init) {
+      // The array type might be incomplete now, but the initializer
+      // will take care of it.  (If I instead moved this entire block
+      // below where the init is tchecked, I think I would run into
+      // problems when tchecking the initializer wants a ctor to exist.)
+      // (t0077.cc)
+      return true;
+    }
+
+    if (context == DC_MR_DECL &&
+        !env.lang.strictArraySizeRequirements) {
+      // Allow incomplete array types, so-called "open arrays".
+      // Usually, such things only go at the *end* of a structure, but
+      // we do not check that.
+      return true;
+    }
+
+    #ifdef GNU_EXTENSION
+    if (context == DC_E_COMPOUNDLIT) {
+      // dsw: arrays in ASTTypeId's of compound literals are
+      // allowed to not have a size and not have an initializer:
+      // (gnu/g0014.cc)
+      return true;
+    }
+    #endif // GNU_EXTENSION
+  }
+
+  // ok, we're not in an exceptional circumstance, so the type
+  // must be complete; if we have an error, what will we say?
+  char const *action = 0;
+  switch (context) {
+    default /*catch-all*/:     action = "create an object of"; break;
+    case DC_EXCEPTIONSPEC:     action = "name in exception spec"; break;
+    case DC_E_KEYWORDCAST:     // fallthru
+    case DC_E_CAST:            action = "cast to"; break;
+    case DC_E_SIZEOFTYPE:      action = "compute size of"; break;
+  }
+
+  // check it
+  return env.ensureCompleteType(action, type);
+}
+
+// Is 't' an object type built in to the language, such that it
+// could not possibly have a user-defined constructor?  It needs
+// to not be a class of course, but also not a dependent type that
+// could be instantiated with a class.
+bool isPrimitiveObjectType(Type const *t)
+{
+  if (t->isCVAtomicType()) {
+    AtomicType const *at = t->asCVAtomicTypeC()->atomic;
+    return at->isSimpleType() || at->isEnumType();
+  }
+
+  return t->isPointerType() ||
+         t->isReferenceType() ||
+         t->isPointerToMemberType();
+}
+
+void Declarator::mid_tcheck(Env &env, Tcheck &dt)
+{
+  // true if we're immediately in a class body
+  Scope *enclosingScope = env.scope();
+  bool inClassBody = !!(enclosingScope->curCompound);
+
+  // is this declarator in a templatizable context?  this prevents
+  // confusion when processing the template arguments themselves (which
+  // contain declarators), among other things
+  bool templatizableContext =
+    dt.context == DC_FUNCTION ||   // could be in MR_func or TD_func
+    dt.context == DC_TD_DECL ||
+    dt.context == DC_MR_DECL;
+
+  LookupFlags lflags = LF_NONE;
+  DeclFlags instFlags = DF_NONE;
+  if (dt.context == DC_TF_EXPLICITINST) {
+    // this tells the qualifier lookup code that there are no
+    // template<> parameter lists to worry about
+    lflags |= LF_EXPLICIT_INST;
+
+    // grab the flags that were shuttled by Declarator::dflags
+    // from TF_explicitInst::flags; this works in part because
+    // only one declarator is allowed in an explicit instantiation
+    DeclFlags const mask = DF_EXTERN | DF_STATIC | DF_INLINE;
+    instFlags = dt.dflags & mask;
+    dt.dflags &= ~mask;
+  }
+
+  PQName *name = decl->getDeclaratorId();
+  if (!name && (dt.dflags & DF_TEMPL_PARAM)) {
+    // give names to all template params, because we need to refer
+    // to them in the self-name (in/t0493.cc)
+    name = new PQ_name(this->getLoc(), env.getAnonName("tparam", NULL));
+    this->setDeclaratorId(name);
+  }
+
+  // cppstd sec. 3.4.3 para 3:
+  //    "In a declaration in which the declarator-id is a
+  //    qualified-id, names used before the qualified-id
+  //    being declared are looked up in the defining
+  //    namespace scope; names following the qualified-id
+  //    are looked up in the scope of the member's class
+  //    or namespace."
+  //
+  // This is implemented by the following call.
+  //
+  // TODO: BUG: The names appearing in pointer-to-member constructors
+  // must be looked up *before* pushing the declarator scopes.
+  // (t0436.cc)
+  ScopeSeq qualifierScopes;
+  tcheckDeclaratorPQName(env, qualifierScopes, name, lflags);
+
+  // the type constructed so far might refer to
+  // DependentQTypes that now can (and must) be resolved more
+  // precisely (t0290a.cc, t0438.cc, t0440.cc)
+  if (name) {
+    Type *t = env.resolveDQTs(name->loc, dt.type);
+    if (t) {
+      TRACE("dqt", "resolved " << dt.type->toString() << " to " << t->toString());
+      dt.type = t;
+    }
+  }
+
+  if (init) {
+    dt.dflags |= DF_INITIALIZED;
+  }
+
+  // get the type from the IDeclarator
+  decl->tcheck(env, dt);
+
+  // is this a specialization of a global template function,
+  // or a member template function?
+  if (templatizableContext &&                      // e.g. toplevel
+      enclosingScope->isTemplateParamScope() &&    // "template <...>" above
+      !enclosingScope->parameterizedEntity) {      // that's mine, not my class' (need to wait until after name->tcheck to test this)
+    if (dt.type->isFunctionType()) {
+      // complete specialization?
+      if (enclosingScope->templateParams.isEmpty()) {    // just "template <>"
+        xassert(!dt.existingVar);
+        dt.existingVar = env.makeExplicitFunctionSpecialization
+                           (decl->loc, dt.dflags, name, dt.type->asFunctionType());
+        if (dt.existingVar) {
+          enclosingScope->setParameterizedEntity(dt.existingVar);
+        }
+      }
+
+      else {
+        // either a partial specialization, or a primary; since the
+        // former doesn't exist for functions, there had better not
+        // be any template arguments on the function name
+        if (name->getUnqualifiedName()->isPQ_template()) {
+          env.error("function template partial specialization is not allowed",
+                    EF_STRONG);
+        }
+      }
+    }
+    else {
+      // for class specializations, we should not get here, as the syntax
+      //
+      //   template <>
+      //   class A<int> { ... }  /*declarator goes here*/  ;
+      //
+      // does not have (and cannot have) any declarators
+      env.error("template class declaration must not have declarators", EF_STRONG);
+    }
+  }
+
+  // explicit instantiation?
+  if (dt.context == DC_TF_EXPLICITINST) {
+    dt.existingVar =
+      env.explicitFunctionInstantiation(name, dt.type, instFlags);
+  }
+
+  // DF_FRIEND gets turned off by 'declareNewVariable' ...
+  bool isFriend = !!(dt.dflags & DF_FRIEND);
+
+  if ((dt.dflags >= (DF_EXTERN | DF_INLINE)) && env.lang.handleExternInlineSpecially) {
+    // dsw: We want to add a flag saying that this isn't really an
+    // extern inline.  This is necessary because sometimes we still
+    // need to know later that it started off as an extern inline even
+    // though it is now a static inline.  One such place is if this
+    // function has two definitions in the same translation unit; the
+    // second one stomps on the first, but we only allow this if the
+    // first was an extern inline.
+    dt.dflags |= DF_GNU_EXTERN_INLINE;
+    // if this isn't filled in by now we have a problem
+    xassert(dt.context != DC_UNKNOWN);
+    if (dt.context == DC_FUNCTION && handleExternInline_asWeakStaticInline()) {
+      // convert it to static inline
+      dt.dflags &= ~DF_EXTERN;  // subtract the 'extern'
+      dt.dflags |= DF_STATIC;   // add the 'static'
+    }
+  }
+  // else if (dt.dflags >= (DF_INLINE) && env.lang.inlineImpliesStaticLinkage) {
+  //   if (dt.dflags & DF_MEMBER) {
+  //     // quarl 2006-07-11
+  //     //    Can't set DF_STATIC since DF_MEMBER|DF_STATIC implies static
+  //     //    member.  However, when DF_INLINE|DF_MEMBER can only occur in C++
+  //     //    where inlineImpliesStaticLinkage, so we check for that combination
+  //     //    in isStaticLinkage().  It would be nice to factor DF_STATIC into
+  //     //    DF_STATIC_LINKAGE and DF_STATIC_MEMBER.
+  //   } else {
+  //     dt.dflags |= DF_STATIC;
+  //   }
+  // }
+
+  // dsw: the global function 'main' seems to always be considered to
+  // be DF_EXTERN_C even in C++ mode whether it likes it or not; FIX:
+  // I wonder if this should go down inside the 'if' below that ends
+  // up calling handleTypeOfMain(); I like it here because the
+  // DF_EXTERN_C ends up on the declaration as well I think, whereas
+  // if I put it there it just ends up on the Variable; maybe just on
+  // the Variable would be better and also we wouldn't have to
+  // differnt 'if' statements that are testing different conditions.
+  if (name && name->isPQ_name() && name->asPQ_name()->name == env.string_main) {
+    // quarl: had to add guard for friend declarations; I do think this should
+    // be moved below
+    if (env.scope()->isGlobalScope() ||
+        env.scope()->isClassScope() && (dt.dflags | DF_FRIEND))
+    {
+      dt.dflags |= DF_EXTERN_C;
+    }
+  }
+
+  bool callerPassedInstV = false;
+  if (!dt.existingVar) {
+    // make a Variable, add it to the environment
+    var = env.storeVar(
+      declareNewVariable(env, dt, decl->hasInnerGrouping(), decl->loc, name));
+
+    if (var &&
+        var->name == env.string_main &&
+        var->isGlobal()) {
+      env.handleTypeOfMain(decl->loc, var, dt.type);
+    }
+  }
+  else {
+    // caller already gave me a Variable to use
+    var = dt.existingVar;
+    callerPassedInstV = true;
+
+    // declareNewVariable is normally responsible for adding the receiver
+    // param to 'dt.type', but since I skipped it, I have to do it
+    // here too
+    if (var->type->isFunctionType() &&
+        var->type->asFunctionType()->isMethod()) {
+      TRACE("memberFunc", "nonstatic member function: " << var->name);
+
+      // add the implicit 'this' parameter
+      makeMemberFunctionType(env, dt,
+        var->type->asFunctionType()->getNATOfMember(), decl->loc);
+    }
+    else {
+      TRACE("memberFunc", "static or non-member function: " << var->name);
+      possiblyConsumeFunctionType(env, dt);
+    }
+  }
+  xassert(var);
+
+  type = dt.type;
+  context = dt.context;
+
+  if (decl->isD_bitfield()) {
+    var->setBitfieldSize(decl->asD_bitfield()->numBits);
+  }
+
+  // declarators usually require complete types
+  //
+  // 2005-04-16: moved this down below the call to
+  // 'declareNewVariable' to handle k0051.cc, where we need to match a
+  // definition with a prior declaration to get a complete type
+  if (!checkCompleteTypeRules(env, dt.dflags, context, var->type, init)) {
+    // need to tell the calling context there is a problem
+    type = dt.type = var->type = env.errorType();
+  }
+
+  // handle function template declarations ....
+  TemplateInfo *templateInfo = NULL;
+  if (callerPassedInstV) {
+    // don't try to take it; dt.var probably already has it, etc.
+  }
+  else if (templatizableContext) {
+    if (dt.type->isFunctionType()) {
+      bool allowInherited = true;
+      if (isFriend) {
+        // (k0057.cc) we are processing the declaration of a
+        // templatized friend; since the friend is not actually a
+        // member of the current class, it should not be regarded as
+        // parameterized by the current class's parameters (if any)
+        allowInherited = false;
+      }
+      templateInfo = env.takeFTemplateInfo(allowInherited);
+    }
+    else {
+      // non-templatizable entity
+      //
+      // TODO: I should allow static members of template classes
+      // to be templatizable too
+    }
+  }
+  else {
+    // other contexts: don't try to take it, you're not a
+    // templatizable declarator
+  }
+
+  if (templateInfo) {
+    TRACE("template", "template func " <<
+                      ((dt.dflags & DF_DEFINITION) ? "defn" : "decl")
+                      << ": " << dt.type->toCString(var->fullyQualifiedName0()));
+
+    if (!var->templateInfo()) {
+      // this is a new template decl; attach it to the Variable
+      var->setTemplateInfo(templateInfo);
+
+      // (what was I about to do here?)
+
+    }
+    else {
+      // TODO: merge default arguments
+
+      if (dt.dflags & DF_DEFINITION) {
+        // save this templateInfo for use with the definition
+        //
+        // TODO: this really should just be TemplateParams, not
+        // a full TemplateInfo ...
+        var->templateInfo()->definitionTemplateInfo = templateInfo;
+      }
+      else {
+        // discard this templateInfo
+        delete templateInfo;
+      }
+    }
+
+    // no such thing as a function partial specialization, so this
+    // is automatically the primary
+    if (enclosingScope->isTemplateParamScope() &&
+        !enclosingScope->parameterizedEntity) {
+      enclosingScope->setParameterizedEntity(var);
+    }
+
+    // sm: I'm not sure what this is doing.  It used to only be done when
+    // 'var' had no templateInfo to begin with.  Now I'm doing it always,
+    // which might not be right.
+    if (getDeclaratorId() &&
+        getDeclaratorId()->isPQ_template()) {
+      if (var->type->isFunctionType() &&
+          (var->type->asFunctionType()->isConstructor() ||
+           var->type->asFunctionType()->isDestructor())) {   // k0019.cc
+        // in/t0461.cc: template args on the name are simply naming the
+        // type that this function constructs, so should not be copied
+      }
+      else if (var->templateInfo()->isPrimary()) {           // k0019.cc error 1
+        // need to avoid attaching the arguments in this case, because
+        // that would create a malformed TemplateInfo object
+        env.error(getLoc(), "template primary cannot have template args");
+      }
+      else {
+        copyTemplateArgs(var->templateInfo()->arguments,
+                         getDeclaratorId()->asPQ_templateC()->sargs);
+      }
+    }
+  }
+
+  else /* !templateInfo */ {
+    TemplateInfo *ti = var->templateInfo();
+    if (ti && ti->isInstantiation() &&               // var seems to be an instantiation
+        enclosingScope->isTemplateParamScope() &&    // "template <...>" above
+        enclosingScope->templateParams.isEmpty()) {  // just "template <>"
+      // (in/t0475.cc) This is an explicit specialization of a member
+      // of a class template.  The existing 'var->templateInfo' will
+      // claim this is an (implicit) instantiation, but the explicit
+      // specialization overrides that.
+      ti->changeToExplicitSpec();
+    }
+  }
+
+  // cppstd, sec. 3.3.1:
+  //   "The point of declaration for a name is immediately after
+  //   its complete declarator (clause 8) and before its initializer
+  //   (if any), except as noted below."
+  // (where "below" talks about enumerators, class members, and
+  // class names)
+  //
+  // However, since the bottom of the recursion for IDeclarators
+  // is always D_name, it's equivalent to add the name to the
+  // environment then instead of here.
+
+  // want only declarators corresp. to local/global variables
+  // (it is disturbing that I have to check for so many things...)
+  if (env.lang.isCplusplus &&
+      !dt.hasFlag(DF_EXTERN) &&                 // not an extern decl
+      !dt.hasFlag(DF_TYPEDEF) &&                // not a typedef
+      isVariableDC(dt.context)) {               // local/global variable
+    // 2005-08-05: I now question the wisdom of doing these
+    // transformations, because if the type's constructor is entirely
+    // compiler-supplied, then using an IN_ctor misleadingly suggests
+    // that arbitrary computation could be happening...
+    if (var->type->isCompoundType()) {            // class-valued
+      if (!init) {
+        // cppstd 8.5 paras 7,8,9: treat
+        //   C c;
+        // like
+        //   C c();
+        // except that the latter is not actually allowed since it would
+        // be interpreted as a declaration of a function
+        init = new IN_ctor(decl->loc, NULL /*args*/);
+      }
+      else if (init->isIN_expr()) {
+        // treat
+        //   C c = 5;
+        // like
+        //   C c(5);
+        // except the latter isn't always syntactically allowed (e.g. CN_decl),
+        // and isn't always equivalent [8.5p14]; was_IN_ctor will remember
+
+        // take out the IN_expr
+        IN_expr *inexpr = init->asIN_expr();
+        Expression *e = inexpr->e;
+        inexpr->e = NULL;
+        delete inexpr;
+
+        // put in an IN_ctor
+        IN_ctor *inctor = new IN_ctor(decl->loc, makeExprList1(e));
+        inctor->was_IN_expr = true;
+        init = inctor;
+      }
+    }
+
+    // for non-class types, normalize IN_ctor into IN_expr, as this
+    // makes it clear that no function call is occurring, and is how
+    // constant-value variables are recognized (in/t0512.cc)
+    else if (init &&
+             isPrimitiveObjectType(var->type) &&
+             init->isIN_ctor()) {
+      IN_ctor *inc = init->asIN_ctor();
+      if (inc->args->count() != 1) {
+        env.error(getLoc(), stringc
+          << "expected constructor-style initializer of `"
+          << var->type->toString() << "' to have 1 argument, not "
+          << inc->args->count());
+      }
+      else {
+        // substitute IN_expr
+        init = new IN_expr(getLoc(), inc->args->first()->expr);
+
+        // Above, I dispose of the replaced initializer, but that is
+        // only valid if I am sure that no other AST node is pointing
+        // at it, and I am not.  So, just leave 'inc' alone.  (The
+        // code above may or may not be wrong, but since it has not
+        // been observed to fail I won't mess with it.)
+      }
+    }
+  }
+
+  // tcheck the initializer, unless we're inside a class, in which
+  // case wait for pass two
+  //
+  // 8/06/04: dsw: why wait until pass 2?  I need to change it to pass
+  // 1 to get in/d0088.cc to work and all the other elsa and oink
+  // tests also work
+  //
+  // sm: You're right; I had thought 3.3.6 said that member scopes
+  // included *all* initializers, but it does not, so such scopes only
+  // include *subsequent* initializers, hence pass 1 is the right time.
+  //
+  // 2005-02-17:  I think I Now I understand.  3.3.6 para 1 bullet 1
+  // says that *default arguments* must be tchecked in pass 2, and
+  // that may have been the original intent.  I am changing it so
+  // default arguments are skipped here (checked by
+  // DefaultArgumentChecker); *member initializers* will continue to
+  // be tcheck'd in pass 1.  Testcase: in/t0369.cc.
+  if (dt.context == DC_D_FUNC &&
+      !env.checkFunctionBodies /*pass 1*/) {
+    // skip it
+  }
+  else if (init) {
+    tcheck_init(env);
+    // quarl 2006-07-26
+    //    Check the initializer for compatibility with the declared type.
+    //    This also does some elaborations like function address-of.
+    if (IN_expr *initexpr = init->ifIN_expr()) {
+      if (!type->containsGeneralizedDependent()) {
+        if (!env.elaborateImplicitConversionArgToParam(type, initexpr->e)) {
+          // quarl 2006-07-26
+          //    This should be an error, but since too many test cases currently
+          //    fail this, it's just a warning for now.  getImplicitConversion
+          //    is incomplete.
+          //
+          // SGM 2006-08-05: I am turning this off.  There is nothing
+          // wrong (in the cases I've seen anyway) with the source code
+          // being analyzed, rather there is a bug in Elsa.  We should
+          // either deal with the Elsa bugs, or just be silent about the
+          // problems by default (which is what I am doing now).  There
+          // could be a command line flag to turn this back on, if
+          // desired.
+          #if 0
+          env.warning(/*type,*/ stringc
+                      << "cannot convert initializer type `" << initexpr->e->getType()->toString()
+                      << "' to type `" << type->toString() << "'");
+          #endif // 0
+        }
+      }
+    }
+    // TODO: check compatibility with dflags; e.g. we can't allow
+    // an initializer for a global variable declared with 'extern'
+  }
+
+  // pull the scope back out of the stack; if this is a
+  // declarator attached to a function definition, then
+  // Function::tcheck will re-extend it for analyzing
+  // the function body
+  env.retractScopeSeq(qualifierScopes);
+
+  // If it is a function, is it virtual?  We have to look up the class
+  // hierarchy in order to tell.  NOTE: EVEN IF we are already
+  // explicitly virtual, the code below also builds the
+  // var->virtuallyOverride list of things that we virtually-override,
+  // so we have to do this anyway; that is, don't skip the body if
+  // var->hasFlag(DF_VIRTUAL)
+  if (inClassBody && var->type->isMethod()) {
+    FunctionType *varft = var->type->asFunctionType();
+    CompoundType *myClass = env.scope()->curCompound;
+
+    // search among base classes
+    SObjList<BaseClassSubobj const> subobjs;
+    myClass->getSubobjects(subobjs);
+    SFOREACH_OBJLIST(BaseClassSubobj const, subobjs, iter) {
+      CompoundType *base = iter.data()->ct;
+      if (base == myClass) { continue; }
+
+      // get all variables with this name
+      LookupSet set;
+      base->lookup(set, var->name, NULL /*env*/, LF_INNER_ONLY);
+
+      // look for any virtual functions with matching signatures
+      SFOREACH_OBJLIST_NC(Variable, set, iter2) {
+        Variable *var2 = iter2.data();
+
+        // NOTE: since classes must be presented to the C++ compiler
+        // in an order that is going monotonically down the
+        // inheritance heirarchy, we can rely on this function having
+        // marked any implicitly-virtual methods above it explicitly
+        // virtual by the time the methods of any subclass that may
+        // override them might look at them here.  That is, this
+        // var2->hasFlag(DF_VIRTUAL) test below will work even if var2
+        // was not syntactically marked as virutal by the programmer
+
+        if (var2->hasFlag(DF_VIRTUAL) && var2->type->isFunctionType()) {
+          FunctionType *var2ft = var2->type->asFunctionType();
+          if (var2ft->equalOmittingReceiver(varft) &&
+              var2ft->getReceiverCV() == varft->getReceiverCV()) {
+            // make this one virtual too
+            var->setFlag(DF_VIRTUAL);
+            // this makes a set of all of the possible functions that
+            // we override; please see the note at
+            // Variable::virtuallyOverride
+            if (!var->virtuallyOverride) {
+              var->virtuallyOverride = new SObjSet<Variable*>();
+            }
+            var->virtuallyOverride->add(var2);
+          }
+        }
+      }
+    }
+  }
+}
+
+
+// pulled out so it could be done in pass 1 or pass 2
+void Declarator::tcheck_init(Env &env)
+{
+  xassert(init);
+
+  init->tcheck(env, type);
+
+  // TODO: check the initializer for compatibility with
+  // the declared type
+
+  // TODO: check compatibility with dflags; e.g. we can't allow
+  // an initializer for a global variable declared with 'extern'
+
+  // remember the initializing value, for const values
+  if (init->isIN_expr()) {
+    var->setValue(init->asIN_exprC()->e);
+  }
+
+  // use the initializer size to refine array types
+  // array initializer case
+  var->type = env.computeArraySizeFromCompoundInit(var->loc, var->type, type, init);
+  // array compound literal initializer case
+  var->type = computeArraySizeFromLiteral(env, var->type, init);
+
+  // update 'type' if necessary
+  //
+  // (k0018.cc) check if 'var->type' is an array, rather than just
+  // 'type', so we see the type after parameter type normalization
+  if (var->type->asRval()->isArrayType()) {
+    type->asRval()->asArrayType()->size = var->type->asRval()->asArrayType()->size;
+  }
+}
+
+
+// ------------------ IDeclarator ------------------
+void D_name::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  env.setLoc(loc);
+
+  // 7/27/04: This has been disabled because Declarator::mid_tcheck
+  // takes care of tchecking the name in advance.
+  //if (name) {
+  //  name->tcheck(env);
+  //}
+
+  // do *not* call 'possiblyConsumeFunctionType', since declareNewVariable
+  // will do so if necessary, and in a different way
+}
+
+
+// cppstd, 8.3.2 para 4:
+//   "There shall be no references to references, no arrays of
+//    references, and no pointers to references."
+
+void D_pointer::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  env.setLoc(loc);
+  possiblyConsumeFunctionType(env, dt);
+
+  if (dt.type->isReference()) {
+    env.error("cannot create a pointer to a reference");
+  }
+  else {
+    // apply the pointer type constructor
+    if (!dt.type->isError()) {
+      dt.type = env.tfac.syntaxPointerType(loc, cv, dt.type, this);
+    }
+  }
+
+  // recurse
+  base->tcheck(env, dt);
+}
+
+// almost identical to D_pointer ....
+void D_reference::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  env.setLoc(loc);
+  possiblyConsumeFunctionType(env, dt);
+
+  if (dt.type->isReference()) {
+    env.error("cannot create a reference to a reference");
+  }
+  else {
+    // apply the reference type constructor
+    if (!dt.type->isError()) {
+      dt.type = env.tfac.syntaxReferenceType(loc, dt.type, this);
+    }
+  }
+
+  // recurse
+  base->tcheck(env, dt);
+}
+
+
+// this code adapted from (the old) tcheckFakeExprList; always passes NULL
+// for the 'sizeExpr' argument to ASTTypeId::tcheck
+FakeList<ASTTypeId> *tcheckFakeASTTypeIdList(
+  FakeList<ASTTypeId> *list, Env &env, DeclFlags dflags, DeclaratorContext context)
+{
+  if (!list) {
+    return list;
+  }
+
+  // context for checking (ok to share these across multiple ASTTypeIds)
+  ASTTypeId::Tcheck tc(dflags, context);
+
+  // check first ASTTypeId
+  FakeList<ASTTypeId> *ret
+    = FakeList<ASTTypeId>::makeList(list->first()->tcheck(env, tc));
+
+  // check subsequent expressions, using a pointer that always
+  // points to the node just before the one we're checking
+  ASTTypeId *prev = ret->first();
+  while (prev->next) {
+    prev->next = prev->next->tcheck(env, tc);
+
+    prev = prev->next;
+  }
+
+  return ret;
+}
+
+// implement cppstd 8.3.5 para 3:
+//   "array of T" -> "pointer to T"
+//   "function returning T" -> "pointer to function returning T"
+// also, since f(int) and f(int const) are the same function (not
+// overloadings), strip toplevel cv qualifiers
+static Type *normalizeParameterType(Env &env, SourceLoc loc, Type *t)
+{
+  if (t->isArrayType()) {
+    return env.makePtrType(t->asArrayType()->eltType);
+  }
+  if (t->isFunctionType()) {
+    return env.makePtrType(t);
+  }
+
+  // 2005-05-27: I started to implement stripping of 'cv' from the
+  // parameters, as the comment above suggests, but then realized that
+  // would mean that even inside the definition, parameters' cv is
+  // lost.  Therefore the new plan is to make EF_IGNORE_PARAM_CV
+  // effectively always true, as no function *type* is ever supposed
+  // to have cv on its parameters.
+
+  return t;
+}
+
+
+void D_func::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  env.setLoc(loc);
+  possiblyConsumeFunctionType(env, dt);
+
+  FunctionFlags specialFunc = FF_NONE;
+
+  // handle "fake" return type ST_CDTOR
+  if (dt.type->isSimple(ST_CDTOR)) {
+    if (env.lang.isCplusplus) {
+      // get the name being declared
+      D_name *dname;
+      PQName *name;
+      {
+        // get the D_name one level down (skip D_groupings)
+        IDeclarator *idecl = base;
+        while (idecl->isD_grouping()) {
+          idecl = idecl->asD_grouping()->base;
+        }
+        xassert(idecl->isD_name());    // grammar should ensure this
+        dname = idecl->asD_name();
+
+        // skip qualifiers
+        name = dname->name->getUnqualifiedName();
+      }
+
+      // conversion operator
+      if (name->isPQ_operator()) {
+        if (name->asPQ_operator()->o->isON_conversion()) {
+          ON_conversion *conv = name->asPQ_operator()->o->asON_conversion();
+
+          // compute the named type; this becomes the return type
+          ASTTypeId::Tcheck tc(DF_NONE, DC_ON_CONVERSION);
+          conv->type = conv->type->tcheck(env, tc);
+          dt.type = conv->type->getType();
+          specialFunc = FF_CONVERSION;
+        }
+        else {
+          env.diagnose3(env.lang.allowImplicitIntForOperators, name->loc,
+                        stringc << "cannot declare `" << name->toString()
+                                << "' with no return type (MSVC bug accepts it)");
+          dt.type = env.getSimpleType(ST_INT);     // recovery
+        }
+      }
+
+      // constructor or destructor
+      else {
+        StringRef nameString = name->getName();
+        CompoundType *inClass = env.acceptingScope()->curCompound;
+
+        // destructor
+        if (nameString[0] == '~') {
+          if (!inClass) {
+            env.error("destructors must be class members");
+          }
+          else if (!streq(nameString+1, inClass->name)) {
+            env.error(stringc
+              << "destructor name `" << nameString
+              << "' must match the class name `" << inClass->name << "'");
+          }
+
+          // return type is 'void'
+          dt.type = env.getSimpleType(ST_VOID);
+          specialFunc = FF_DTOR;
+        }
+
+        // constructor
+        else {
+          if (!inClass) {
+            if (!env.lang.allowImplicitInt &&
+                env.lang.allowImplicitIntForMain &&
+                nameString == env.str("main")) {
+              // example: g0018.cc
+              env.warning("obsolete use of implicit int in declaration of main()");
+
+              // change type to 'int'
+              dt.type = env.getSimpleType(ST_INT);
+            }
+            else {
+              env.error("constructors must be class members (and implicit int is not supported)");
+
+              // 2005-03-09: At one point I had the following:
+              //
+              //    return;    // otherwise would segfault below..
+              //
+              // but it appears there is no longer a risk of segfault,
+              // and by removing the 'return' I will consistently
+              // return a FunctionType from a D_func declarator, which
+              // helps other parts of the code.
+            }
+          }
+          else {
+            if (nameString != inClass->name) {
+              // I'm not sure if this can occur...
+              env.error(stringc
+                << "constructor name `" << nameString
+                << "' must match the class name `" << inClass->name << "'");
+            }
+
+            // return type is same as class type
+            dt.type = env.makeType(inClass);
+            specialFunc = FF_CTOR;
+          }
+        }
+      }
+    }
+
+    else {     // C
+      if (env.lang.allowImplicitInt) {
+        // surely this is not adequate, as implicit-int applies to
+        // all declarations, not just those that appear in function
+        // definitions... I think the rest of the implementation is
+        // in Oink?
+        dt.type = env.getSimpleType(ST_INT);
+      }
+      else {
+        env.error("support for omitted return type is currently off");
+      }
+    }
+  }
+
+  // make a new scope for the parameter list
+  Scope *paramScope = env.enterScope(SK_PARAMETER, "D_func parameter list scope");
+
+  // typecheck the parameters; this disambiguates any ambiguous type-ids,
+  // and adds them to the environment
+  params = tcheckFakeASTTypeIdList(params, env, DF_PARAMETER, DC_D_FUNC);
+
+  // build the function type; I do this after type checking the parameters
+  // because it's convenient if 'syntaxFunctionType' can use the results
+  // of checking them
+  FunctionType *ft = env.tfac.syntaxFunctionType(loc, dt.type, this, env.tunit);
+  ft->flags = specialFunc;
+  #ifdef KANDR_EXTENSION
+    if (kAndR_params) {
+      ft->setFlag(FF_KANDR_DEFN);
+    }
+  #endif
+  dt.funcSyntax = this;
+
+  // add them, now that the list has been disambiguated
+  int ct=0;
+  FAKELIST_FOREACH_NC(ASTTypeId, params, iter) {
+    ct++;
+    Variable *v = iter->decl->var;
+
+    if (v->type->isSimple(ST_VOID)) {
+      if (ct == 1 &&
+          !iter->next &&
+          !v->name &&
+          !iter->decl->init) {
+        // special case: only parameter is "void" and it doesn't have a name:
+        // same as empty param list
+        break;
+      }
+      env.error("cannot have parameter of type `void', unless it is "
+                "the only parameter, has no parameter name, and has "
+                "no default value");
+      continue;
+    }
+
+    if (v->type->isSimple(ST_ELLIPSIS)) {
+      // no need for as careful checking as for ST_VOID, since the
+      // grammar ensures it's last if it appears at all
+      ft->flags |= FF_VARARGS;
+      break;
+    }
+
+    v->type = normalizeParameterType(env, loc, v->type);
+
+    // get the default argument, if any
+    if (iter->decl->init) {
+      Initializer *i = iter->decl->init;
+      xassert(i->isIN_expr());    // ensured by grammar
+    }
+
+    // dsw: You didn't implement adding DF_PARAMETER to variables that
+    // are parameters; This seems to be the best place to put it.
+    v->setFlag(DF_PARAMETER);
+    ft->addParam(v);
+  }
+
+  // dsw: in K&R C, an empty parameter list means that the number of
+  // arguments is not specified
+  if (env.lang.emptyParamsMeansNoInfo && params->isEmpty()) {
+    ft->flags |= FF_NO_PARAM_INFO;
+  }
+
+  if (specialFunc == FF_CONVERSION) {
+    if (ft->params.isNotEmpty() || ft->acceptsVarargs()) {
+      env.error("conversion operator cannot accept arguments");
+    }
+  }
+
+  // the verifier will type-check the pre/post at this point
+  env.checkFuncAnnotations(ft, this);
+
+  env.exitScope(paramScope);
+
+  if (exnSpec) {
+    ft->exnSpec = exnSpec->tcheck(env);
+  }
+
+  // call this after attaching the exception spec, if any
+  //env.doneParams(ft);
+  // update: doneParams() is done by 'possiblyConsumeFunctionType'
+  // or 'declareNewVariable', depending on what declarator is next in
+  // the chain
+
+  // now that we've constructed this function type, pass it as
+  // the 'base' on to the next-lower declarator
+  dt.type = ft;
+
+  base->tcheck(env, dt);
+}
+
+
+void D_array::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  env.setLoc(loc);
+  possiblyConsumeFunctionType(env, dt);
+
+  // check restrictions in cppstd 8.3.4 para 1
+  if (dt.type->isReference()) {
+    env.error("cannot create an array of references");
+    return;
+  }
+  if (dt.type->isSimple(ST_VOID)) {
+    env.error("cannot create an array of void");
+    return;
+  }
+  if (dt.type->isFunctionType()) {
+    env.error("cannot create an array of functions");
+    return;
+  }
+  // TODO: check for abstract classes
+
+  // cppstd 8.3.4 para 1:
+  //   "cv-qualifier array of T" -> "array of cv-qualifier T"
+  // hmmm.. I don't know what syntax would give rise to
+  // the former, or at least my AST can't represent it.. oh well
+
+  if (size) {
+    // typecheck the 'size' expression
+    size->tcheck(env, size);
+  }
+
+  ArrayType *at;
+
+  if (dt.context == DC_E_NEW) {
+    // we're in a new[] (E_new) type-id
+    if (!size) {
+      env.error("new[] must have an array size specified");
+      at = env.makeArrayType(dt.type);    // error recovery
+    }
+    else {
+      if (base->isD_name()) {
+        // this is the final size expression, it need not be a
+        // compile-time constant; this 'size' is not part of the type
+        // of the objects being allocated, rather it is a dynamic
+        // count of the number of objects to allocate
+        dt.size_E_new = size;
+        this->isNewSize = true;     // annotation
+
+        // now just call into the D_name to finish off the type; dt.type
+        // is left unchanged, because this D_array contributed nothing
+        // to the *type* of the objects we're allocating
+        base->tcheck(env, dt);
+        return;
+      }
+      else {
+        // this is an intermediate size, so it must be a compile-time
+        // constant since it is part of a description of a C++ type
+        int sz;
+        if (!size->constEval(env, sz)) {
+          // error has already been reported; this is for error recovery
+          at = env.makeArrayType(dt.type);
+        }
+        else {
+          // TODO: If 'sz' is dependent, then we need to construct some
+          // kind of ArrayType whose size is an arbitrary expression.
+
+          // constuct the type
+          at = env.makeArrayType(dt.type, sz);
+        }
+      }
+    }
+  }
+
+  else {
+    // we're not in an E_new, so add the size to the type if it's
+    // specified; there are some contexts which require a type (like
+    // definitions), but we'll report those errors elsewhere
+    if (size) {
+      // try to evaluate the size to a constant
+      int sz = 1;
+      ConstEval cenv(env.dependentVar);
+      CValue val = size->constEval(cenv);
+      if (val.isError()) {
+        // size didn't evaluate to a constant
+        sz = ArrayType::NO_SIZE;
+        if ((dt.context == DC_S_DECL ||
+             // dsw: if it is a struct declared local to a function,
+             // then gcc in C mode allows it to have dynamic size
+             (dt.context == DC_MR_DECL && env.enclosingKindScope(SK_FUNCTION)) ||
+             // 2005-05-26: C99 functions can have arrays with dynamic
+             // size; TODO: do a better job recording the semantics of
+             // such declarations, for the benefit of analyses (in/c/dC0021.c)
+             (dt.context == DC_D_FUNC && env.scope()->scopeKind == SK_PARAMETER) ||
+             // 2005-05-31: (in/c/dC0031.c) dynamically-sized arrays in
+             // sizeof and alignof
+             #ifdef GNU_EXTENSION
+               dt.context == DC_E_ALIGNOFTYPE ||
+             #endif
+             dt.context == DC_E_SIZEOFTYPE
+            ) &&
+            env.lang.allowDynamicallySizedArrays) {
+          // allow it anyway
+          sz = ArrayType::DYN_SIZE;
+        }
+        else {
+          // report the error
+          env.error(*(val.getWhy()));
+        }
+        delete val.getWhy();
+      }
+      else if (val.isDependent()) {
+        // let it go
+      }
+      else if (val.isIntegral()) {
+        sz = val.getIntegralValue();
+
+        // check restrictions on array size (c.f. cppstd 8.3.4 para 1)
+        if (env.lang.strictArraySizeRequirements) {
+          if (sz <= 0) {
+            env.error(loc, stringc << "array size must be positive (it is " << sz << ")");
+          }
+        }
+        else {
+          if (sz < 0) {
+            env.error(loc, stringc << "array size must be nonnegative (it is " << sz << ")");
+          }
+        }
+      }
+      else {
+        env.error(loc, "array size must have integral type");
+      }
+
+      at = env.makeArrayType(dt.type, sz);
+    }
+    else {
+      // no size
+      at = env.makeArrayType(dt.type);
+    }
+  }
+
+  // having added this D_array's contribution to the type, pass
+  // that on to the next declarator
+  dt.type = at;
+  base->tcheck(env, dt);
+}
+
+
+void D_bitfield::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  env.setLoc(loc);
+  possiblyConsumeFunctionType(env, dt);
+
+  if (name) {
+    // shouldn't be necessary, but won't hurt
+    tcheckPQName(name, env, NULL, LF_DECLARATOR);
+  }
+
+  bits->tcheck(env, bits);
+
+  // check that the expression is a compile-time constant
+  int n;
+  if (!bits->constEval(env, n)) {
+    env.error("bitfield size must be a constant", EF_NONE);
+  }
+  else {
+    // remember the size of the bit field
+    this->numBits = n;
+  }
+
+  dt.dflags |= DF_BITFIELD;
+}
+
+
+void D_ptrToMember::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  env.setLoc(loc);
+
+  // typecheck the nested name
+  tcheckPQName(nestedName, env, NULL /*scope*/, LF_NONE);
+
+  // enforce [cppstd 8.3.3 para 3]
+  if (dt.type->isReference()) {
+    env.error("you can't make a pointer-to-member refer to a reference type");
+    return;
+
+    // there used to be some recovery code here, but I decided it was
+    // better to just bail entirely rather than tcheck into 'base' with
+    // broken invariants
+  }
+
+  if (dt.type->isVoid()) {
+    env.error("you can't make a pointer-to-member refer to `void'");
+    return;
+  }
+
+  // find the compound to which it refers
+  // (previously I used lookupPQCompound, but I believe that is wrong
+  // because this is a lookup of a nested-name-specifier (8.3.3) and
+  // such lookups are done in the variable space (3.4.3))
+  Variable *ctVar = env.lookupPQ_one(nestedName, LF_ONLY_TYPES);
+  if (!ctVar) {
+    env.error(stringc
+      << "cannot find type `" << nestedName->toString()
+      << "' for pointer-to-member");
+    return;
+  }
+
+  // allow the pointer to point to a member of a class (CompoundType),
+  // *or* a TypeVariable (for templates)
+  NamedAtomicType *nat = ctVar->type->ifNamedAtomicType();
+  if (!nat) {
+    env.error(stringc
+      << "in ptr-to-member, `" << nestedName->toString()
+      << "' does not refer to a class nor is a type variable");
+    return;
+  }
+
+  if (dt.type->isFunctionType()) {
+    // add the 'this' parameter to the function type, so the
+    // full type becomes "pointer to *member* function"
+    makeMemberFunctionType(env, dt, nat, loc);
+  }
+
+  // build the ptr-to-member type constructor
+  dt.type = env.tfac.syntaxPointerToMemberType(loc, nat, cv, dt.type, this);
+
+  // recurse
+  base->tcheck(env, dt);
+}
+
+
+void D_grouping::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  env.setLoc(loc);
+
+  // don't call 'possiblyConsumeFunctionType', since the
+  // D_grouping is supposed to be transparent
+
+  base->tcheck(env, dt);
+}
+
+
+bool IDeclarator::hasInnerGrouping() const
+{
+  bool ret = false;
+
+  IDeclarator const *p = this;
+  while (p) {
+    switch (p->kind()) {
+      // turn off the flag because innermost so far is now
+      // a pointer type constructor
+      case D_POINTER:
+        ret = false;
+        break;
+      case D_REFERENCE:
+        ret = false;
+        break;
+      case D_PTRTOMEMBER:
+        ret = false;
+        break;
+
+      // turn on the flag b/c innermost is now grouping
+      case D_GROUPING:
+        ret = true;
+        break;
+
+      // silence warning..
+      default:
+        break;
+    }
+
+    p = p->getBaseC();
+  }
+
+  return ret;
+}
+
+
+// ------------------- ExceptionSpec --------------------
+FunctionType::ExnSpec *ExceptionSpec::tcheck(Env &env)
+{
+  FunctionType::ExnSpec *ret = new FunctionType::ExnSpec;
+
+  // typecheck the list, disambiguating it
+  types = tcheckFakeASTTypeIdList(types, env, DF_NONE, DC_EXCEPTIONSPEC);
+
+  // add the types to the exception specification
+  FAKELIST_FOREACH_NC(ASTTypeId, types, iter) {
+    ret->types.append(iter->getType());
+  }
+
+  return ret;
+}
+
+
+// ------------------ OperatorName ----------------
+char const *ON_newDel::getOperatorName() const
+{
+  // changed the names so that they can be printed out with these
+  // names and it will be the correct syntax; it means the identifier
+  // has a space in it, which isn't exactly ideal, but the alternative
+  // (ad-hoc decoding) isn't much better
+  return (isNew && isArray)? "operator new[]" :
+         (isNew && !isArray)? "operator new" :
+         (!isNew && isArray)? "operator delete[]" :
+                              "operator delete";
+}
+
+char const *ON_operator::getOperatorName() const
+{
+  xassert(validCode(op));
+  return operatorFunctionNames[op];
+}
+
+char const *ON_conversion::getOperatorName() const
+{
+  // this is the sketchy one..
+  // update: but it seems to be fitting into the design just fine
+  return "conversion-operator";
+}
+
+
+void OperatorName::tcheck(Env &env)
+{
+  if (isON_conversion()) {
+    ON_conversion *conv = asON_conversion();
+
+    // check the "return" type
+    ASTTypeId::Tcheck tc(DF_NONE, DC_ON_CONVERSION);
+    conv->type->tcheck(env, tc);
+  }
+  else {
+    // nothing to do for other kinds of OperatorName
+  }
+}
+
+
+// ---------------------- Statement ---------------------
+Statement *Statement::tcheck(Env &env)
+{
+  env.setLoc(loc);
+
+  int dummy;
+  if (!ambiguity) {
+    // easy case
+    mid_tcheck(env, dummy);
+    return this;
+  }
+
+  Statement *ret = resolveImplIntAmbig(env, this);
+  if (ret) {
+    return ret->tcheck(env);
+  }
+
+  // the only ambiguity for Statements I know if is S_decl vs. S_expr,
+  // and this one is always resolved in favor of S_decl if the S_decl
+  // is a valid interpretation [cppstd, sec. 6.8]
+  if (this->isS_decl() && ambiguity->isS_expr() &&
+      ambiguity->ambiguity == NULL) {                  // gcov-begin-ignore
+    // S_decl is first, run resolver with priority enabled
+    return resolveAmbiguity(this, env, "Statement", true /*priority*/, dummy);
+  }
+  else if (this->isS_expr() && ambiguity->isS_decl() &&
+           ambiguity->ambiguity == NULL) {
+    // swap the expr and decl
+    return swap_then_resolveAmbiguity(this, env, "Statement", true /*priority*/, dummy);
+  }                                                    // gcov-end-ignore
+
+  // unknown ambiguity situation
+  xfailure("unknown statement ambiguity");
+  return this;        // silence warning
+}
+
+
+// dsw: it is too slow to have emacs reload cc.ast.gen.h just to display
+// the body of this method when I'm looking around in the stack in gdb
+void Statement::mid_tcheck(Env &env, int &)
+{
+  itcheck(env);
+}
+
+
+void S_skip::itcheck(Env &env)
+{}
+
+
+void S_label::itcheck(Env &env)
+{
+  // this is a prototypical instance of typechecking a
+  // potentially-ambiguous subtree; we have to change the
+  // pointer to whatever is returned by the tcheck call
+  s = s->tcheck(env);
+
+  // TODO: check that the label is not a duplicate
+}
+
+
+void S_case::itcheck(Env &env)
+{
+  expr->tcheck(env, expr);
+  s = s->tcheck(env);
+
+  // TODO: check that the expression is of a type that makes
+  // sense for a switch statement, and that this isn't a
+  // duplicate case
+
+  // UPDATE: dsw: whatever you do here, do it in
+  // gnu.cc:S_rangeCase::itcheck() as well
+
+  // compute case label value
+  expr->constEval(env, labelVal);
+}
+
+
+void S_default::itcheck(Env &env)
+{
+  s = s->tcheck(env);
+
+  // TODO: check that there is only one 'default' case
+}
+
+
+void S_expr::itcheck(Env &env)
+{
+  expr->tcheck(env);
+}
+
+
+void S_compound::itcheck(Env &env)
+{
+  Scope *scope = env.enterScope(SK_FUNCTION, "compound statement");
+
+  FOREACH_ASTLIST_NC(Statement, stmts, iter) {
+    // have to potentially change the list nodes themselves
+    iter.setDataLink( iter.data()->tcheck(env) );
+  }
+
+  env.exitScope(scope);
+}
+
+
+// Given a (reference to) a pointer to a statement, make it into an
+// S_compound if it isn't already, so that it will be treated as having
+// its own local scope (cppstd 6.4 para 1, 6.5 para 2).  Note that we
+// don't need this for try-blocks, because their substatements are
+// *required* to be compound statements already.
+void implicitLocalScope(Statement *&stmt)
+{
+  if (!stmt->isS_compound()) {
+    Statement *orig = stmt;
+    stmt = new S_compound(orig->loc, new ASTList<Statement>(orig));
+  }
+}
+
+
+void S_if::itcheck(Env &env)
+{
+  // if 'cond' declares a variable, its scope is the
+  // body of the "if"
+  Scope *scope = env.enterScope(SK_FUNCTION, "condition in an 'if' statement");
+
+  // 6.4 para 1
+  implicitLocalScope(thenBranch);
+  implicitLocalScope(elseBranch);
+
+  cond = cond->tcheck(env);
+  thenBranch = thenBranch->tcheck(env);
+  elseBranch = elseBranch->tcheck(env);
+
+  env.exitScope(scope);
+}
+
+
+void S_switch::itcheck(Env &env)
+{
+  Scope *scope = env.enterScope(SK_FUNCTION, "condition in a 'switch' statement");
+
+  // 6.4 para 1
+  implicitLocalScope(branches);
+
+  cond = cond->tcheck(env);
+  branches = branches->tcheck(env);
+
+  env.exitScope(scope);
+}
+
+
+void S_while::itcheck(Env &env)
+{
+  Scope *scope = env.enterScope(SK_FUNCTION, "condition in a 'while' statement");
+
+  // 6.5 para 2
+  implicitLocalScope(body);
+
+  cond = cond->tcheck(env);
+  body = body->tcheck(env);
+
+  env.exitScope(scope);
+}
+
+
+void S_doWhile::itcheck(Env &env)
+{
+  // 6.5 para 2
+  implicitLocalScope(body);
+
+  body = body->tcheck(env);
+  expr->tcheck(env);
+
+  // TODO: verify that 'expr' makes sense in a boolean context
+}
+
+
+void S_for::itcheck(Env &env)
+{
+  Scope *scope = env.enterScope(SK_FUNCTION, "condition in a 'for' statement");
+
+  // 6.5 para 2
+  implicitLocalScope(body);
+
+  init = init->tcheck(env);
+  cond = cond->tcheck(env);
+  after->tcheck(env);
+  body = body->tcheck(env);
+
+  env.exitScope(scope);
+}
+
+
+void S_break::itcheck(Env &env)
+{
+  // TODO: verify we're in the context of a 'switch'
+}
+
+
+void S_continue::itcheck(Env &env)
+{
+  // TODO: verify we're in the context of a 'switch'
+}
+
+
+void S_return::itcheck(Env &env)
+{
+  if (expr) {
+    expr->tcheck(env);
+
+    // TODO: verify that 'expr' is compatible with the current
+    // function's declared return type
+  }
+
+  else {
+    // TODO: check that the function is declared to return 'void'
+  }
+}
+
+
+void S_goto::itcheck(Env &env)
+{
+  // TODO: verify the target is an existing label
+}
+
+
+void S_decl::itcheck(Env &env)
+{
+  decl->tcheck(env, DC_S_DECL);
+}
+
+
+void S_try::itcheck(Env &env)
+{
+  body->tcheck(env);
+
+  FAKELIST_FOREACH_NC(Handler, handlers, iter) {
+    iter->tcheck(env);
+  }
+
+  // TODO: verify the handlers make sense in sequence:
+  //   - nothing follows a "..." specifier
+  //   - no duplicates
+  //   - a supertype shouldn't be caught after a subtype
+}
+
+
+void S_asm::itcheck(Env &)
+{}
+
+
+void S_namespaceDecl::itcheck(Env &env)
+{
+  decl->tcheck(env);
+}
+
+
+// ------------------- Condition --------------------
+Condition *Condition::tcheck(Env &env)
+{
+  int dummy;
+  if (!ambiguity) {
+    // easy case
+    mid_tcheck(env, dummy);
+    return this;
+  }
+
+  // generic resolution: whatever tchecks is selected
+  return resolveAmbiguity(this, env, "Condition", false /*priority*/, dummy);
+}
+
+void CN_expr::itcheck(Env &env)
+{
+  expr->tcheck(env);
+
+  // TODO: verify 'expr' makes sense in a boolean or switch context
+}
+
+
+void CN_decl::itcheck(Env &env)
+{
+  ASTTypeId::Tcheck tc(DF_NONE, DC_CN_DECL);
+  typeId = typeId->tcheck(env, tc);
+
+  // TODO: verify the type of the variable declared makes sense
+  // in a boolean or switch context
+}
+
+
+// ------------------- Handler ----------------------
+void Handler::tcheck(Env &env)
+{
+  Scope *scope = env.enterScope(SK_FUNCTION, "exception handler");
+
+  // originally, I only did this for the non-isEllpsis() case, to
+  // avoid creating a type with ST_ELLIPSIS in it.. but oink/qual
+  // finds it convenient, so now we tcheck 'typeId' always
+  //
+  // dsw: DF_PARAMETER: we think of the handler as an anonymous inline
+  // function that is simultaneously defined and called in the same
+  // place
+  ASTTypeId::Tcheck tc(DF_PARAMETER, DC_HANDLER);
+  typeId = typeId->tcheck(env, tc);
+
+  body->tcheck(env);
+
+  env.exitScope(scope);
+}
+
+
+// ------------------- Expression tcheck -----------------------
+Type *makeLvalType(TypeFactory &tfac, Type *underlying)
+{
+  if (underlying->isLval()) {
+    // this happens for example if a variable is declared to
+    // a reference type
+    return underlying;
+  }
+  else if (underlying->isFunctionType()) {
+    // don't make references to functions
+    return underlying;
+
+    // at one point I added a similar prohibition against
+    // references to arrays, but that was wrong, e.g.:
+    //   int (&a)[];
+  }
+  else {
+    return tfac.makeReferenceType(underlying);
+  }
+}
+
+Type *makeLvalType(Env &env, Type *underlying)
+{
+  return makeLvalType(env.tfac, underlying);
+}
+
+
+// make the type of a field 'field', but is being accessed in an
+// object whose reference is qualified with 'cv'
+Type *makeFieldLvalType(Env &env, Variable *var, CVFlags cv)
+{
+  Type *t = var->type;
+  if (t->isReferenceType() || t->isFunctionType()) {
+    return t;
+  }
+
+  if (var->hasFlag(DF_MUTABLE)) {
+    cv = cv & ~CV_CONST;    // mutable defeats const (in/t0529.cc) [7.1.1p9]
+  }
+
+  t = env.tfac.applyCVToType(env.loc(), cv, t, NULL /*syntax*/);
+  return env.tfac.makeReferenceType(t);
+}
+
+
+// There are several things going on with the replacement pointer.
+//
+// First, since Expressions can be ambiguous, when we select among
+// ambiguous Expressions, the replacement is used to tell which one
+// to use.  The caller then stores that instead of the original
+// pointer.
+//
+// Second, to support elaboration of implicit function calls, an
+// Expression node can decide to replace itself with a different
+// kind of node (e.g. overloaded operators), or to insert another
+// Expression above it (e.g. user-defined conversion functions).
+//
+// Finally, the obvious design would call for 'replacement' being
+// a return value from 'tcheck', but I found that it was too easy
+// to forget to update the original pointer.  So I changed the
+// interface so that the original pointer cannot be forgotten, since
+// a reference to it is now a parameter.
+
+
+void Expression::tcheck(Env &env, Expression *&replacement)
+{
+  // the replacement point should always start out in agreement with
+  // the receiver object of the 'tcheck' call; consequently,
+  // Expressions can leave it as-is and no replacement will happen
+  xassert(replacement == this);
+
+  if (!ambiguity) {
+    mid_tcheck(env, replacement);
+    return;
+  }
+
+  // There is one very common ambiguity, between E_funCall and
+  // E_constructor, and this ambiguity happens to frequently stack
+  // upon itself, leading to worst-case exponential tcheck time.
+  // Since it can be resolved easily in most cases, I special-case the
+  // resolution.
+  if ( ( (this->isE_funCall() &&
+          this->ambiguity->isE_constructor() ) ||
+         (this->isE_constructor() &&
+          this->ambiguity->isE_funCall()) ) &&
+      this->ambiguity->ambiguity == NULL) {
+    E_funCall *call;
+    E_constructor *ctor;
+    if (this->isE_funCall()) {
+      call = this->asE_funCall();             // gcov-begin-ignore
+      ctor = ambiguity->asE_constructor();
+    }
+    else {
+      ctor = this->asE_constructor();
+      call = ambiguity->asE_funCall();
+    }                                         // gcov-end-ignore
+
+    // The code that follows is essentially resolveAmbiguity(),
+    // specialized to two particular kinds of nodes, but only
+    // tchecking the first part of each node to disambiguate.
+    IFDEBUG( SourceLoc loc = env.loc(); )
+    TRACE("disamb", toString(loc) << ": ambiguous: E_funCall vs. E_constructor");
+
+    // grab errors
+    ErrorList existing;
+    existing.takeMessages(env.errors);
+
+    // common case: function call
+    TRACE("disamb", toString(loc) << ": considering E_funCall");
+    LookupSet candidates;
+    call->inner1_itcheck(env, candidates);
+    if (noDisambErrors(env.errors)) {
+      // ok, finish up; it's safe to assume that the E_constructor
+      // interpretation would fail if we tried it
+      TRACE("disamb", toString(loc) << ": selected E_funCall");
+      env.errors.prependMessages(existing);
+      call->type = call->inner2_itcheck(env, candidates);
+      call->ambiguity = NULL;
+      replacement = call;
+      return;
+    }
+
+    // grab the errors from trying E_funCall
+    ErrorList funCallErrors;
+    funCallErrors.takeMessages(env.errors);
+
+    // try the E_constructor interpretation
+    TRACE("disamb", toString(loc) << ": considering E_constructor");
+    ctor->inner1_itcheck(env);
+    if (noDisambErrors(env.errors)) {
+      // ok, finish up
+      TRACE("disamb", toString(loc) << ": selected E_constructor");
+      env.errors.prependMessages(existing);
+
+      // a little tricky because E_constructor::inner2_itcheck is
+      // allowed to yield a replacement AST node
+      replacement = ctor;
+      Type *t = ctor->inner2_itcheck(env, replacement);
+
+      replacement->type = t;
+      replacement->ambiguity = NULL;
+      return;
+    }
+
+    // both failed.. just leave the errors from the function call
+    // interpretation since that's the more likely intent
+    env.errors.deleteAll();
+    env.errors.takeMessages(existing);
+    env.errors.takeMessages(funCallErrors);
+
+    // 10/20/04: Need to give a type anyway.
+    this->type = env.errorType();
+
+    // finish up
+    replacement = this;     // redundant but harmless
+    return;
+  }
+
+  // some other ambiguity, use the generic mechanism; the return value
+  // is ignored, because the selected alternative will be stored in
+  // 'replacement'
+  resolveAmbiguity(this, env, "Expression", false /*priority*/, replacement);
+}
+
+
+void Expression::mid_tcheck(Env &env, Expression *&replacement)
+{
+  // 2005-03-10: There used to be code here that would re-use an
+  // already-computed type.  That code had been disabled for a long
+  // time because it did not work; for example, the type of an
+  // expression can depend on the context in which it appears.  So I
+  // have now removed the code altogether, leaving only this note as a
+  // reminder that that approach (along with several variations) was
+  // tried and it failed.
+
+  // during ambiguity resolution, 'replacement' is set to whatever
+  // the original (first in the ambiguity list) Expression pointer
+  // was; reset it to 'this', as that will be our "replacement"
+  // unless the Expression wants to do something else
+  replacement = this;
+
+  // check it, and store the result
+  Type *t = itcheck_x(env, replacement);
+
+  // elaborate the AST by storing the computed type, *unless*
+  // we're only disambiguating (because in that case many of
+  // the types will be ST_ERROR anyway)
+  //if (!env.onlyDisambiguating()) {
+  //  type = t;
+  //}
+  //
+  // update: made it unconditional again because after tcheck()
+  // the callers expect to be able to dig in and find the type;
+  // I guess I'll at some point have to write a visitor to
+  // clear the computed types if I want to actually check the
+  // template bodies after arguments are presented
+
+  // dsw: putting the cloneType here means I can remove *many* of them
+  // elsewhere, namely wherever an itcheck_x() returns.  This causes a
+  // bit of garbage, since some of the types returned are partially
+  // from somewhere else and partially made right there, such as
+  // "return makeLvalType(t)" where "t" is an already existing type.
+  // The only way I can think of to optimize that is to turn it in to
+  // "return makeLvalType(env.tfac.cloneType(t))" and get rid of the
+  // clone here; but that would be error prone and labor-intensive, so
+  // I don't do it.
+  replacement->type = t;
+}
+
+
+Type *E_boolLit::itcheck_x(Env &env, Expression *&replacement)
+{
+  // cppstd 2.13.5 para 1
+  return env.getSimpleType(ST_BOOL);
+}
+
+
+// return true if type 'id' can represent value 'i'
+bool canRepresent(SimpleTypeId id, unsigned long i)
+{
+  // I arbitrarily choose to make this determination according to the
+  // representations available under the compiler that compiles Elsa,
+  // since that's convenient and likely to correspond with what
+  // happens when the source code in question is "really" compiled.
+
+  switch (id) {
+    default: xfailure("bad type id");
+
+    case ST_INT:                 return i <= INT_MAX;
+    case ST_UNSIGNED_INT:        return i <= UINT_MAX;
+    case ST_LONG_INT:            return i <= LONG_MAX;
+
+    case ST_UNSIGNED_LONG_INT:
+    case ST_LONG_LONG:
+    case ST_UNSIGNED_LONG_LONG:
+      // I don't want to force the host compiler to have 'long long',
+      // so I'm just going to claim that every value is representable
+      // by these three types.  Also, given that I passed 'i' in as
+      // 'unsigned long', it's pretty much a given that it will be
+      // representable.
+      return true;
+  }
+}
+
+Type *E_intLit::itcheck_x(Env &env, Expression *&replacement)
+{
+  // cppstd 2.13.1 para 2
+
+  char const *p = text;
+
+  // what radix? (and advance 'p' past it)
+  int radix = 10;
+  if (*p == '0') {
+    p++;
+    if (*p == 'x' || *p == 'X') {
+      radix = 16;
+      p++;
+    }
+    else {
+      radix = 8;
+    }
+  }
+
+  // what value? (tacit assumption: host compiler's 'unsigned long'
+  // is big enough to make these distinctions)
+  i = strtoul(p, NULL /*endp*/, radix);
+
+  // what suffix?
+  while (isdigit(*p)) {
+    p++;
+  }
+  bool hasU = false;
+  int hasL = 0;
+  if (*p == 'u' || *p == 'U') {
+    hasU = true;
+    p++;
+  }
+  if (*p == 'l' || *p == 'L') {
+    hasL = 1;
+    p++;
+    if (*p == 'l' || *p == 'L') {
+      hasL = 2;
+      p++;
+    }
+  }
+  if (*p == 'u' || *p == 'U') {
+    hasU = true;
+  }
+
+  // The radix and suffix determine a sequence of types, and we choose
+  // the smallest from the sequence that can represent the given value.
+
+  // There are three nominal sequences, one containing unsigned types,
+  // one with only signed types, and one with both.  In the tables
+  // below, I will represent a sequence by pointing into one or the
+  // other nominal sequence; the pointed-to element is the first
+  // element in the effective sequence.  Sequences terminate with
+  // ST_VOID.
+  static SimpleTypeId const signedSeq[] = {
+    ST_INT,                 // 0
+    ST_LONG_INT,            // 1
+    ST_LONG_LONG,           // 2
+    ST_VOID
+  };
+  static SimpleTypeId const unsignedSeq[] = {
+    ST_UNSIGNED_INT,        // 0
+    ST_UNSIGNED_LONG_INT,   // 1
+    ST_UNSIGNED_LONG_LONG,  // 2
+    ST_VOID
+  };
+  static SimpleTypeId const mixedSeq[] = {
+    ST_INT,                 // 0
+    ST_UNSIGNED_INT,        // 1
+    ST_LONG_INT,            // 2
+    ST_UNSIGNED_LONG_INT,   // 3
+    ST_LONG_LONG,           // 4
+    ST_UNSIGNED_LONG_LONG,  // 5
+    ST_VOID
+  };
+
+  // The following table layout is inspired by the table in C99
+  // 6.4.4.1 para 5.
+
+  // C99: (hasU + 2*hasL) x isNotDecimal -> typeSequence
+  static SimpleTypeId const * const c99Map[6][2] = {
+      // radix:  decimal              hex/oct
+    // suffix:
+    /* none */ { signedSeq+0,         mixedSeq+0 },
+    /* U */    { unsignedSeq+0,       unsignedSeq+0 },
+    /* L */    { signedSeq+1,         mixedSeq+2 },
+    /* UL */   { unsignedSeq+1,       unsignedSeq+1 },
+    /* LL */   { signedSeq+2,         mixedSeq+4 },
+    /* ULL */  { unsignedSeq+2,       unsignedSeq+2 }
+  };
+
+  // The difference is in C++, the radix is only relevant when there
+  // is no suffix.  Also, cppstd doesn't specify anything for 'long
+  // long' (since that type does not exist in that language), so I'm
+  // extrapolating its rules to that case.  Entries in the cppMap
+  // that differ from c99Map are marked with "/*d*/".
+
+  // C++: (hasU + 2*hasL) x isNotDecimal -> typeSequence
+  static SimpleTypeId const * const cppMap[6][2] = {
+      // radix:  decimal              hex/oct
+    // suffix:
+    /* none */ { signedSeq+0,         mixedSeq+0 },
+    /* U */    { unsignedSeq+0,       unsignedSeq+0 },
+    /* L */    { mixedSeq+2/*d*/,     mixedSeq+2 },
+    /* UL */   { unsignedSeq+1,       unsignedSeq+1 },
+    /* LL */   { mixedSeq+4/*d*/,     mixedSeq+4 },
+    /* ULL */  { unsignedSeq+2,       unsignedSeq+2 }
+  };
+
+  // compute the sequence to use
+  SimpleTypeId const *seq =
+    env.lang.isCplusplus? cppMap[hasU + 2*hasL][radix!=10] :
+                          c99Map[hasU + 2*hasL][radix!=10] ;
+
+  // At this point, we pick the type that is the first type in 'seq'
+  // that can represent the value.
+  SimpleTypeId id = *seq;
+  while (*(seq+1) != ST_VOID &&
+         !canRepresent(id, i)) {
+    seq++;
+    id = *seq;
+  }
+
+  return env.getSimpleType(id);
+}
+
+
+Type *E_floatLit::itcheck_x(Env &env, Expression *&replacement)
+{
+  d = strtod(text, NULL /*endp*/);
+
+  // what is the final character?
+  char final = text[strlen(text)-1];
+  if (final == 'f' || final == 'F') {
+    return env.getSimpleType(ST_FLOAT);
+  }
+  if (final == 'l' || final == 'L') {
+    return env.getSimpleType(ST_LONG_DOUBLE);
+  }
+
+  return env.getSimpleType(ST_DOUBLE);
+}
+
+
+Type *E_stringLit::itcheck_x(Env &env, Expression *&replacement)
+{
+  // cppstd 2.13.4 para 1
+
+  // wide character?
+  SimpleTypeId id = text[0]=='L'? ST_WCHAR_T : ST_CHAR;
+
+  // TODO: this is wrong because I'm not properly tracking the string
+  // size if it has escape sequences
+  int len = 0;
+  E_stringLit *p = this;
+  while (p) {
+    len += strlen(p->text) - 2;   // don't include surrounding quotes
+    if (p->text[0]=='L') len--;   // don't count 'L' if present
+    p = p->continuation;
+  }
+
+  {
+    // quarl 2006-07-13
+    //    Build the dequoted full text.
+    //
+    //    TODO: could just clobber text+continuations with fullText.  Or just
+    //    do this in parsing...
+    stringBuilder sb(len);
+    p = this;
+    do {
+      char const *s = p->text;
+      if (*s == 'L') ++s;
+      int l = strlen(s);
+      if (l >= 2 && s[0] == '\"' && s[l-1] == '\"') {
+        sb.append(s+1, l-2);
+      } else {
+        // see in/gnu/d0122.c for missing quotes
+        sb.append(s, l);
+      }
+      p = p->continuation;
+    } while(p);
+    fullTextNQ = env.str(sb);
+  }
+
+  CVFlags stringLitCharCVFlags = CV_NONE;
+  if (env.lang.stringLitCharsAreConst) {
+    stringLitCharCVFlags = CV_CONST;
+  }
+  Type *charConst = env.getSimpleType(id, stringLitCharCVFlags);
+  Type *arrayType = env.makeArrayType(charConst, len+1);    // +1 for implicit final NUL
+
+  // C++ 5.1p2, C99 6.5.1p4: string literals are lvalues (in/k0036.cc)
+  Type *ret = makeLvalType(env, arrayType);
+
+  // apply the same type to the continuations, for visitors' benefit
+  for (p = continuation; p; p = p->continuation) {
+    p->type = ret;
+  }
+
+  return ret;
+}
+
+
+void quotedUnescape(ArrayStack<char> &dest, char const *src,
+                    char delim, bool allowNewlines)
+{
+  // strip quotes or ticks
+  decodeEscapes(dest, substring(src+1, strlen(src)-2),
+                delim, allowNewlines);
+}
+
+Type *E_charLit::itcheck_x(Env &env, Expression *&replacement)
+{
+  // cppstd 2.13.2 paras 1 and 2
+
+  SimpleTypeId id = ST_CHAR;
+
+  if (!env.lang.isCplusplus) {
+    // nominal type of character literals in C is int, not char
+    id = ST_INT;
+  }
+
+  char const *srcText = text;
+  if (*srcText == 'L') {
+    id = ST_WCHAR_T;
+    srcText++;
+  }
+
+  ArrayStack<char> temp;
+  quotedUnescape(temp, srcText, '\'', false /*allowNewlines*/);
+  if (temp.length() == 0) {
+    return env.error("character literal with no characters");
+  }
+  else if (temp.length() > 1) {
+    // below I only store the first byte
+    //
+    // technically, this is ok, since multicharacter literal values
+    // are implementation-defined; but Elsa is not so much its own
+    // implementation as an approximation of some nominal "real"
+    // compiler, which will no doubt do something smarter, so Elsa
+    // should too
+    env.warning("multicharacter literals not properly implemented");
+    if (id == ST_CHAR) {
+      // multicharacter non-wide character literal has type int
+      id = ST_INT;
+    }
+  }
+
+  // 2005-08-12: The first cast to 'unsigned char' will make sure that
+  // negative chars (which come from things like '\xFF') get stored as
+  // small positive ints in [128,255].  This is far from perfect, but
+  // will do for now.
+  c = (unsigned int)(unsigned char)temp[0];
+
+  if (!env.lang.isCplusplus && id == ST_WCHAR_T) {
+    // in C, 'wchar_t' is not built-in, it is defined; so we
+    // have to look it up
+    Variable *v = env.globalScope()->lookupVariable(env.str("wchar_t"), env);
+    if (!v) {
+      return env.error("you must #include <stddef.h> before using wchar_t");
+    }
+    else {
+      return v->type;
+    }
+  }
+
+  return env.getSimpleType(id);
+}
+
+
+Type *E_this::itcheck_x(Env &env, Expression *&replacement)
+{
+  // we should be in a method with a receiver parameter
+  receiver = env.lookupVariable(env.receiverName);
+  if (!receiver) {
+    return env.error("can only use 'this' in a nonstatic method");
+  }
+
+  // compute type: *pointer* to the thing 'receiverVar' is
+  // a *reference* to
+  return env.makePointerType(CV_NONE, receiver->type->asRval());
+}
+
+
+E_fieldAcc *wrapWithImplicitThis(Env &env, Variable *var, PQName *name)
+{
+  // make *this
+  E_this *ths = new E_this;
+  Expression *thisRef = new E_deref(ths);
+  thisRef->tcheck(env, thisRef);
+
+  // sm: this assertion can fail if the method we are in right now
+  // is static; the error has been reported, so just proceed
+  //xassert(ths->receiver);
+
+  CVFlags atTypeCV = CV_NONE;
+  if (!ths->type->isError()) {
+    atTypeCV = ths->type->getAtType()->getCVFlags();
+  }
+
+  // no need to tcheck as the variable has already been looked up
+  E_fieldAcc *efieldAcc = new E_fieldAcc(thisRef, name);
+  efieldAcc->field = var;
+
+  // E_fieldAcc::itcheck_fieldAcc() does something a little more
+  // complicated, but we don't need that since the situation is
+  // more constrained here
+  efieldAcc->type = makeFieldLvalType(env, var, atTypeCV);
+
+  return efieldAcc;
+}
+
+
+Type *E_variable::itcheck_x(Env &env, Expression *&replacement)
+{
+  return itcheck_var(env, replacement, LF_NONE);
+}
+
+Type *E_variable::itcheck_var(Env &env, Expression *&replacement, LookupFlags flags)
+{
+  LookupSet dummy;
+  return itcheck_var_set(env, replacement, flags, dummy);
+}
+
+Type *E_variable::itcheck_var_set(Env &env, Expression *&replacement,
+                                  LookupFlags flags, LookupSet &candidates)
+{
+  tcheckPQName(name, env, NULL /*scope*/, LF_NONE);
+
+  // re-use dependent?
+  Variable *v = maybeReuseNondependent(env, name->loc, flags, nondependentVar);
+  if (v) {
+    var = v;
+
+    // 2005-02-20: 'add' instead of 'adds', because when we remember a
+    // non-dependent lookup, we do *not* want to re-do overload
+    // resolution
+    candidates.add(v);
+  }
+  else {
+    // in/c/k0015.c: in C, struct members are only visible after the
+    // "." or "->" (which is not E_variable)
+    //
+    // this is done above for TS_name as well..
+    if (!env.lang.isCplusplus) {
+      flags |= LF_SKIP_CLASSES;
+    }
+
+    // do lookup normally
+    env.lookupPQ(candidates, name, flags);
+
+    // gcc-2 hack
+    if (candidates.isEmpty() &&
+        env.lang.gcc2StdEqualsGlobalHacks &&
+        isTwoPartName(env, name, "std", "getline")) {
+      // try looking it up in global scope
+      env.lookupPQ(candidates, name->getUnqualifiedName(), flags);
+    }
+
+    // compatibility with prior logic flow
+    if (candidates.isNotEmpty()) {
+      v = candidates.first();
+    }
+
+    if (v && v->hasFlag(DF_TYPEDEF)) {
+      return env.error(name->loc, stringc
+        << "`" << *name << "' used as a variable, but it's actually a type",
+        EF_DISAMBIGUATES);
+    }
+
+    // 2005-02-18: cppstd 14.2 para 2: if template arguments are
+    // supplied, then the name must look up to a template name
+    if (v != env.dependentVar &&
+        name->getUnqualifiedName()->isPQ_template()) {
+      if (!v || !v->namesTemplateFunction()) {
+        // would disambiguate use of '<' as less-than
+        env.error(name->loc, stringc
+          << "explicit template arguments were provided after `"
+          << name->toString_noTemplArgs()
+          << "', but that is not the name of a template function",
+          EF_DISAMBIGUATES);
+      }
+    }
+
+    if (!v) {
+      // dsw: In K and R C it seems to be legal to call a function
+      // variable that has never been declareed.  At this point we
+      // notice this fact and if we are in K and R C we insert a
+      // variable with signature "int ()(...)" which is what I recall as
+      // the correct signature for such an implicit variable.
+      if (env.lang.allowImplicitFunctionDecls &&
+          (flags & LF_FUNCTION_NAME) &&
+          name->isPQ_name()) {
+        if (env.lang.allowImplicitFunctionDecls == B3_WARN) {
+          env.warning(name->loc, stringc << "implicit declaration of `" << *name << "'");
+        }
+
+        v = env.makeImplicitDeclFuncVar(name->asPQ_name()->name);
+      }
+      else {
+        if (flags & LF_SUPPRESS_NONEXIST) {
+          // return a special type and do not insert an error message;
+          // this is like a pending error that the caller should
+          // resolve, either by making it a real error or (by using
+          // argument dependent lookup) fix; ST_NOTFOUND should never
+          // appear in the output of type checking
+          return env.getSimpleType(ST_NOTFOUND);
+        }
+        else {
+          // 10/23/02: I've now changed this to non-disambiguating,
+          // prompted by the need to allow template bodies to call
+          // undeclared functions in a "dependent" context [cppstd 14.6
+          // para 8].  See the note in TS_name::itcheck.
+          return env.error(name->loc, stringc
+                           << "there is no variable called `" << *name << "'",
+                           EF_NONE);
+        }
+      }
+    }
+    xassert(v);
+
+    // TODO: access control check
+
+    var = env.storeVarIfNotOvl(v);
+
+    // should I remember this non-dependent lookup?
+    maybeNondependent(env, name->loc, nondependentVar, var);
+  }
+
+  if (var->isTemplateParam()) {
+    // this variable is actually a bound meta-variable (template
+    // argument), so it is *not* to be regarded as a reference
+    // (14.1 para 6)
+    return var->type;
+  }
+
+  // 2005-05-28: enumerators are not lvalues
+  if (var->hasFlag(DF_ENUMERATOR)) {
+    return var->type;
+  }
+
+  // elaborate 'this->'
+  if (!(flags & LF_NO_IMPL_THIS) &&
+      var->isNonStaticMember()) {
+    replacement = wrapWithImplicitThis(env, var, name);
+    return replacement->type;
+  }
+
+  // return a reference because this is an lvalue
+  return makeLvalType(env, var->type);
+}
+
+
+// ------------- BEGIN: outerResolveOverload ------------------
+#if 0     // not needed
+// return true iff all the variables are non-methods; this is
+// temporary, otherwise I'd make it a method on class OverloadSet
+static bool allNonMethods(SObjList<Variable> &set)
+{
+  SFOREACH_OBJLIST(Variable, set, iter) {
+    if (iter.data()->type->asFunctionType()->isMethod()) return false;
+  }
+  return true;
+}
+
+// return true iff all the variables are methods; this is temporary,
+// otherwise I'd make it a method on class OverloadSet
+static bool allMethods(SObjList<Variable> &set)
+{
+  SFOREACH_OBJLIST(Variable, set, iter) {
+//      cout << "iter.data()->type->asFunctionType() " << iter.data()->type->asFunctionType()->toCString() << endl;
+    if (!iter.data()->type->asFunctionType()->isMethod()) return false;
+  }
+  return true;
+}
+#endif // 0
+
+
+// set an ArgumentInfo according to an expression; this can only be
+// used when the argument cannot be an overloaded function name
+// (tcheckArgExprList handles the case where it can)
+void getArgumentInfo(Env &env, ArgumentInfo &ai, Expression *e)
+{
+  ai.special = e->getSpecial(env.lang);
+  ai.type = e->type;
+}
+
+
+// Given a Variable that might denote an overloaded set of functions,
+// and the syntax of the arguments that are to be passed to the
+// function ultimately chosen, pick one of the functions using
+// overload resolution; return NULL if overload resolution fails for
+// any reason. 'loc' is the location of the call site, for error
+// reporting purposes.  (The arguments have already been tcheck'd.)
+//
+// This function mediates between the type checker, which knows about
+// syntax and context, and the overload module's 'resolveOverload',
+// which knows about neither.  In essence, it's everything that is
+// common to overload resolution needed in various AST locations
+// that isn't already covered by 'resolveOverload' itself.
+//
+// Note that it is up to the caller to do AST rewriting as necessary
+// to reflect the chosen function.  Rationale: the caller is in a
+// better position to know what things need to be rewritten, since it
+// is fully aware of the syntactic context.
+//
+// The contract w.r.t. errors is: the caller must provide a non-NULL
+// 'var', and if I return NULL, I will also add an error message, so
+// the caller does not have to do so.
+static Variable *outerResolveOverload(Env &env,
+                                      PQName * /*nullable*/ finalName,
+                                      SourceLoc loc, Variable *var,
+                                      ArgumentInfoArray &argInfo)
+{
+  // if no overload set, nothing to resolve
+  if (!var->overload) {
+    return var;
+  }
+
+  return outerResolveOverload_explicitSet(env, finalName, loc, var->name,
+                                          argInfo, var->overload->set);
+}
+
+static Variable *outerResolveOverload_explicitSet(
+  Env &env,
+  PQName * /*nullable*/ finalName,
+  SourceLoc loc,
+  StringRef varName,
+  ArgumentInfoArray &argInfo,
+  SObjList<Variable> &candidates)
+{
+  // special case: does 'finalName' directly name a particular
+  // conversion operator?  e.g. in/t0226.cc
+  if (finalName &&
+      finalName->isPQ_operator() &&
+      finalName->asPQ_operator()->o->isON_conversion()) {
+    ON_conversion *conv = finalName->asPQ_operator()->o->asON_conversion();
+    Type *namedType = conv->type->getType();
+
+    // find the operator in the overload set
+    SFOREACH_OBJLIST_NC(Variable, candidates, iter) {
+      Type *iterRet = iter.data()->type->asFunctionType()->retType;
+      if (iterRet->equals(namedType)) {
+        return iter.data();
+      }
+    }
+
+    env.error(stringc << "cannot find conversion operator yielding `"
+                      << namedType->toString() << "'");
+    return NULL;
+  }
+
+  OVERLOADINDTRACE(::toString(loc)
+        << ": overloaded(" << candidates.count()
+        << ") call to " << varName);      // if I make this fully qualified, d0053.cc fails...
+
+  // 2005-02-23: There used to be code here that would bail on
+  // overload resolution if any of the arguments was dependent.
+  // However, that caused a problem (e.g. in/t0386.cc) because if the
+  // receiver object is implicit, it does not matter if it is
+  // dependent, but we cannot tell from here whether it was implicit.
+  // Therefore I have moved the obligation of skipping overload
+  // resolution to the caller, who *can* tell.
+
+  // resolve overloading
+  bool wasAmbig;     // ignored, since error will be reported
+  return resolveOverload(env, loc, &env.errors,
+                         OF_METHODS,    // TODO: always assume OF_METHODS in 'resolveOverload'
+                         candidates, finalName, argInfo, wasAmbig);
+}
+
+
+// version of 'outerResolveOverload' for constructors; 'type' is the
+// type of the object being constructed
+static Variable *outerResolveOverload_ctor
+  (Env &env, SourceLoc loc, Type *type, ArgumentInfoArray &argInfo)
+{
+  // skip overload resolution if any dependent args (in/t0412.cc)
+  for (int i=0; i<argInfo.size(); i++) {
+    Type *t = argInfo[i].type;
+    if (t && t->containsGeneralizedDependent()) {
+      return NULL;
+    }
+  }
+
+  Variable *ret = NULL;
+  // dsw: FIX: should I be generating error messages if I get a weird
+  // type here, or if I get a weird var below?
+  //
+  // sm: at one point this code said 'asRval' but I think that is wrong
+  // since we should not be treating the construction of a reference
+  // the same as the construction of an object
+  if (type->isCompoundType()) {
+    env.ensureCompleteType("construct", type);
+    CompoundType *ct = type->asCompoundType();
+    Variable *ctor = ct->getNamedField(env.constructorSpecialName, env, LF_INNER_ONLY);
+    xassert(ctor);
+    Variable *chosen = outerResolveOverload(env,
+                                            NULL, // finalName; none for a ctor
+                                            loc,
+                                            ctor,
+                                            argInfo);
+    if (chosen) {
+      ret = chosen;
+    } else {
+      ret = ctor;
+    }
+  }
+  // dsw: Note var can be NULL here for ctors for built-in types like
+  // int; see t0080.cc
+  return ret;
+}
+// ------------- END: outerResolveOverload ------------------
+
+
+#if 0    // not needed, but saving in case I do
+Expression **skipGroupsPtr(Expression **e, ArrayStack<Expression*> &intermediates)
+{
+  if ((*e)->isE_grouping()) {
+    intermediates.push(*e);
+    return skipGroupsPtr(&( (*e)->asE_grouping()->expr ), intermediates);
+  }
+  else {
+    return e;
+  }
+}
+#endif // 0
+
+
+// There are a few variants of Expression that can return a lookup
+// set, which is needed in some contexts.  This function dispatches
+// appropriately from a context that can accept a set, depending on
+// whether 'expr' can return one.  The existence of this function
+// avoids the need to expand the parameter list of Expression::tcheck
+// everywhere.  I am reserving the suffix "_set" for this family
+// of functions.
+void tcheckExpression_set(Env &env, Expression *&expr,
+                          LookupFlags flags, LookupSet &set)
+{
+  Expression *origExpr = expr;
+
+  Type *t;
+  ASTSWITCH(Expression, expr) {
+    ASTCASE(E_variable, evar)
+      t = evar->itcheck_var_set(env, expr, flags, set);
+
+    ASTNEXT(E_fieldAcc, eacc)
+      t = eacc->itcheck_fieldAcc_set(env, /*no expr*/ flags, set);
+
+    ASTNEXT(E_addrOf, ea)
+      t = ea->itcheck_addrOf_set(env, expr, flags, set);
+
+    ASTNEXT(E_grouping, eg)
+      t = eg->itcheck_grouping_set(env, expr, flags, set);
+
+    ASTNEXT(E_arrow, ea)
+      t = ea->itcheck_arrow_set(env, expr, flags, set);
+
+    ASTDEFAULT
+      // 'expr' is not a variant that knows what to do with 'set',
+      // so tcheck it normally; implicitly, 'expr->type' gets
+      // set appropriately
+      expr->tcheck(env, expr);
+      return;
+
+    ASTENDCASE
+  }
+
+  // the above assumed that the *original* was unambiguous, as it
+  // totally ignored the ambiguity link; check that now
+  xassert(origExpr->ambiguity == NULL);
+
+  // must explicitly set 'expr->type' since we did not call
+  // into Expression::tcheck
+  expr->type = t;
+}
+
+
+// This function typechecks an argument list at a function call
+// (E_funCall) or similar (E_constructor, etc.).  It fills in an
+// ArgumentInfo array for possible use in overload resolution.  One
+// complication is the need to deal with the possibility that an
+// argument names an overloaded function, in which case we have to
+// pass all the possibilities on to overload resolution.
+FakeList<ArgExpression> *tcheckArgExprList(FakeList<ArgExpression> *list, Env &env,
+                                           ArgumentInfoArray &argInfo,
+                                           Type *receiverType /*= NULL*/)
+{
+  // always begin with the receiver, even if it is only a placeholder
+  argInfo[0].special = SE_NONE;
+  argInfo[0].type = receiverType? makeLvalType(env, receiverType) : NULL;
+
+  // work through list, with an extra level of indirection so I can
+  // modify the list links
+  ArgExpression *first = list->first();
+  ArgExpression **cur = &first;
+  int i = 1;
+  for (; *cur; cur = &((*cur)->next), i++) {
+    argInfo.ensureIndexDoubler(i);
+    ArgumentInfo &info = argInfo[i];
+
+    *cur = (*cur)->tcheck(env, info);
+  }
+
+  // Initially, 'argInfo' had a size that was set by the caller, but
+  // it does not always know the right size since the expression list
+  // can be ambiguous (e.g., in/t0467.cc).  So, this code takes the
+  // initial size as essentially a hint, but ensures when the expr
+  // list is fully disambiguated, the size is set properly.
+  argInfo.setSize(i);
+
+  return FakeList<ArgExpression>::makeList(first);
+}
+
+ArgExpression *ArgExpression::tcheck(Env &env, ArgumentInfo &info)
+{
+  if (!ambiguity) {
+    mid_tcheck(env, info);
+    return this;
+  }
+
+  return resolveAmbiguity(this, env, "ArgExpression", false /*priority*/, info);
+}
+
+// function or pointer to function
+static bool isFunctionTypeOr(Type *t)
+{
+  if (t->isFunctionType()) {
+    return true;
+  }
+  if (t->isPointerType() && t->getAtType()->isFunctionType()) {
+    return true;
+  }
+
+  // could also be a pointer to a member function
+  if (t->isPointerToMemberType() && t->getAtType()->isFunctionType()) {
+    return true;
+  }
+
+  return false;
+}
+
+void tcheckArgumentExpression(Env &env, Expression *&expr, ArgumentInfo &info)
+{
+  // if the expression is an E_variable, possibly with an E_addrOf,
+  // then we could do address-of overloaded function resolution,
+  // so get a lookup set if possible
+  LookupSet set;
+  tcheckExpression_set(env, expr/*INOUT*/, LF_NONE /*?? LF_TEMPL_PRIMARY*/, set);
+
+  if (set.isNotEmpty() &&
+      isFunctionTypeOr(expr->type) &&
+      (set.count() >= 2 || set.first()->isTemplate(false /*inh*/))) {
+    info.special = SE_NONE;
+    info.overloadSet = set;
+  }
+  else {
+    info.special = expr->getSpecial(env.lang);
+    info.type = expr->type;
+  }
+}
+
+void ArgExpression::mid_tcheck(Env &env, ArgumentInfo &info)
+{
+  tcheckArgumentExpression(env, expr/*INOUT*/, info);
+}
+
+
+int compareArgsToParams(Env &env, FunctionType *ft, FakeList<ArgExpression> *args,
+                        ArgumentInfoArray &argInfo)
+{
+  int defaultArgsUsed = 0;
+
+  if (ft->flags & FF_NO_PARAM_INFO) {
+    // we want to convert certain argument types closer to int, e.g. functions
+    // to function pointers.
+
+    for (FakeList<ArgExpression> *argIter = args;
+         !argIter->isEmpty();
+         argIter = argIter->butFirst()) {
+      ArgExpression *arg = argIter->first();
+
+      if (arg->expr->type->isFunctionType()) {
+        // add implicit &
+        ImplicitConversion ic;
+        ic.kind = ImplicitConversion::IC_STANDARD;
+        ic.scs = SC_FUNC_TO_PTR;
+        arg->expr = env.makeConvertedArg(arg->expr, ic);
+      }
+    }
+
+    return defaultArgsUsed;
+  }
+
+  SObjListIterNC<Variable> paramIter(ft->params);
+  int paramIndex = 1;
+  FakeList<ArgExpression> *argIter = args;
+
+  // for now, skip receiver object
+  //
+  // TODO (elaboration, admission): consider the receiver object as well
+  if (ft->isMethod()) {
+    paramIter.adv();
+  }
+
+  // iterate over both lists
+  for (; !paramIter.isDone() && !argIter->isEmpty();
+       paramIter.adv(), paramIndex++, argIter = argIter->butFirst()) {
+    Variable *param = paramIter.data();
+    ArgExpression *arg = argIter->first();
+
+    // Normalize arguments passed to transparent unions.
+    // http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Type-Attributes.html
+    //
+    // We only do this in C mode because our experiments indicate that
+    // GCC does not do the transparent union thing in C++ mode.
+    if (!env.lang.isCplusplus && param->type->isUnionType()) {
+      CompoundType *ct = param->type->asCompoundType();
+      if (ct->isTransparentUnion) {
+        // look for a member of the union that has the same type
+        // as the argument
+        SFOREACH_OBJLIST(Variable, ct->dataMembers, memberIter) {
+          Variable const *memb = memberIter.data();
+
+          StandardConversion sc = getStandardConversion(NULL /*errorMsg*/,
+            SE_NONE, arg->expr->type, memb->type);
+          if (sc != SC_ERROR) {
+            // success
+            TRACE("transparent_union", env.locStr() <<
+              ": converted arg type `" << arg->expr->type->toString() <<
+              "' to union member " << memb->name);
+
+            // build a compound literal for it; this has a pointer
+            // to the original 'arg->expr' inside it
+            SourceLoc loc = env.loc();
+            Designator *d = new FieldDesignator(loc, memb->name);
+            ASTList<Initializer> *inits = new ASTList<Initializer>;
+            inits->append(new IN_designated(loc,
+                                            FakeList<Designator>::makeList(d),
+                                            new IN_expr(loc, arg->expr)));
+            ASTTypeId *ati = env.buildASTTypeId(param->type);
+            E_compoundLit *ecl =
+              new E_compoundLit(ati, new IN_compound(loc, inits));
+
+            // now stick this new thing into arg->expr, so the whole
+            // thing is still a tree
+            arg->expr = ecl;
+
+            // since we're in C mode, it should be quite safe to go
+            // ahead and re-tcheck this (the original 'arg->expr' is
+            // what is being tcheck'd twice)
+            arg->expr->tcheck(env, arg->expr);
+
+            // stop iterating over members
+            break;
+          }
+        }
+
+        // we might not have found any matching member, but I don't
+        // care b/c I am not trying to diagnose errors, just
+        // normalize away some extension syntax
+      }
+      else {
+        // not a transparent union, do nothing special
+      }
+    }
+
+    if (!env.doCompareArgsToParams) {
+      // do not do the usual argument checking; but we keep iterating
+      // so that we can normalize transparent unions
+      continue;
+    }
+
+    // check correspondence between 'args' and 'argInfo'
+    xassert(!argInfo[paramIndex].type ||
+            arg->getType() == argInfo[paramIndex].type);
+
+    // is the argument the name of an overloaded function? [cppstd 13.4]
+    env.possiblySetOverloadedFunctionVar(arg->expr, param->type,
+                                         argInfo[paramIndex].overloadSet);
+
+    // dsw: I changed this from isGeneralizedDependent() to
+    // containsGeneralizedDependent() because that is what I am doing
+    // at the other call site to
+    // elaborateImplicitConversionArgToParam()
+    if (!param->type->containsGeneralizedDependent()) {
+      if (env.elaborateImplicitConversionArgToParam(param->type, arg->expr)) {
+        xassert(arg->ambiguity == NULL);
+      } else {
+        env.error(arg->getType(), stringc
+                  << "cannot convert argument type `" << arg->getType()->toString()
+                  << "' to parameter " << paramIndex
+                  << " type `" << param->type->toString() << "'");
+      }
+    }
+
+  }
+
+  if (!env.doCompareArgsToParams) {
+    // Only reason for sticking around this long was to normalize
+    // transparent unions..
+    return defaultArgsUsed;
+  }
+
+  if (argIter->isEmpty()) {
+    // check that all remaining parameters have default arguments
+    for (; !paramIter.isDone(); paramIter.adv(), paramIndex++) {
+      if (!paramIter.data()->value) {
+        env.error(stringc
+          << "no argument supplied for parameter " << paramIndex);
+      }
+      else {
+        // TODO (elaboration): modify the call site to explicitly
+        // insert the default-argument expression (is that possible?
+        // might it run into problems with evaluation contexts?)
+        defaultArgsUsed++;
+      }
+    }
+  }
+  else if (paramIter.isDone() && !ft->acceptsVarargs()) {
+    env.error("too many arguments supplied");
+  }
+
+  return defaultArgsUsed;
+}
+
+void compareCtorArgsToParams(Env &env, Variable *ctor,
+                             FakeList<ArgExpression> *args,
+                             ArgumentInfoArray &argInfo)
+{
+  env.ensureFuncBodyTChecked(ctor);
+
+  if (ctor) {
+    int defaultArgsUsed = compareArgsToParams(env, ctor->type->asFunctionType(),
+                                              args, argInfo);
+    if (defaultArgsUsed) {
+      env.instantiateDefaultArgs(ctor, defaultArgsUsed);
+    }
+                
+    // in/dk1027.cc: instantiate the dtor too
+    //
+    // navigating up to get the class is inelegant..
+    //
+    // this isn't perfect, b/c I'm instantiating the dtor for "new
+    // Foo" as well as other declarations of Foo, but it's probably
+    // close enough
+    CompoundType *ct = ctor->scope->curCompound;
+    xassert(ct);
+    
+    // ugh, hacking it again
+    Variable *dtor = ct->rawLookupVariable(env.str(stringc << "~" << ct->name));
+    if (!dtor) {
+      // not sure if this is possible, but don't care to fully analyze
+      // right now
+      return;
+    }
+    
+    // instantiate it if necessary
+    env.ensureFuncBodyTChecked(dtor);
+  }
+}
+
+
+static bool hasNamedFunction(Expression *e)
+{
+  return e->isE_variable() || e->isE_fieldAcc();
+}
+
+static Variable *getNamedFunction(Expression *e)
+{
+  if (e->isE_variable()) { return e->asE_variable()->var; }
+  if (e->isE_fieldAcc()) { return e->asE_fieldAcc()->field; }
+  xfailure("no named function");
+  return NULL;   // silence warning
+}
+
+// fwd
+static Type *internalTestingHooks
+  (Env &env, StringRef funcName, FakeList<ArgExpression> *args);
+
+
+// true if the type has no destructor because it's not a compound type
+// nor an array of (an array of ..) compound types
+static bool hasNoopDtor(Type *t)
+{
+  // if it's an array type, then whether it has a no-op dtor depends
+  // entirely on whether the element type has a no-op dtor
+  while (t->isArrayType()) {
+    t = t->asArrayType()->eltType;
+  }
+
+  return !t->isCompoundType();
+}
+
+Type *E_funCall::itcheck_x(Env &env, Expression *&replacement)
+{
+  LookupSet candidates;
+  inner1_itcheck(env, candidates);
+
+  // special case: if someone explicitly called the destructor
+  // of a non-class type, e.g.:
+  //   typedef unsigned uint;
+  //   uint x;
+  //   x.~uint();
+  // then change it into a void-typed simple evaluation:
+  //   (void)x;
+  // since the call itself is a no-op
+  if (func->isE_fieldAcc()) {
+    E_fieldAcc *fa = func->asE_fieldAcc();
+    if (fa->fieldName->getName()[0] == '~' &&
+        hasNoopDtor(fa->obj->type->asRval())) {
+      if (args->isNotEmpty()) {
+        env.error("call to dtor must have no arguments");
+      }
+      ASTTypeId *voidId =
+        new ASTTypeId(new TS_simple(SL_UNKNOWN, ST_VOID),
+                      new Declarator(new D_name(SL_UNKNOWN, NULL /*name*/),
+                                     NULL /*init*/));
+      replacement = new E_cast(voidId, fa->obj);
+      replacement->tcheck(env, replacement);
+      return replacement->type;
+    }
+  }
+
+  return inner2_itcheck(env, candidates);
+}
+
+void E_funCall::inner1_itcheck(Env &env, LookupSet &candidates)
+{
+  // dsw: I need to know the arguments before I'm asked to instantiate
+  // the function template
+  //
+  // check the argument list
+  //
+  // sm: No!  That defeats the entire purpose of inner1/2.  See the
+  // comments above the block that calls inner1/2, and the comments
+  // near the declarations of inner1/2 in cc_tcheck.ast.
+  //args = tcheckArgExprList(args, env);
+
+  // 2005-02-11: Doing this simplifies a number of things.  In general
+  // I think I should move towards a strategy of eliminating
+  // E_groupings wherever I can do so.  Eventually, I'd like it to be
+  // the case that no E_groupings survive type checking.
+  func = func->skipGroups();
+
+  // nominal flags if we're calling a named function
+  LookupFlags specialFlags =
+    LF_TEMPL_PRIMARY |       // we will do template instantiation later
+    LF_FUNCTION_NAME |       // we might allow an implicit declaration
+    LF_NO_IMPL_THIS ;        // don't add 'this->' (must do overload resol'n first)
+
+  if (func->isE_variable() &&
+      !func->asE_variable()->name->hasQualifiers()) {
+      // Unqualified name being looked up in the context of a function
+      // call; cppstd 3.4.2 applies, which is implemented in
+      // inner2_itcheck.  So, here, we don't report an error because
+      // inner2 will do another lookup and report an error if that one
+      // fails too.
+      specialFlags |= LF_SUPPRESS_NONEXIST;
+  }
+
+  // tcheck, passing candidates if possible
+  tcheckExpression_set(env, func, specialFlags, candidates);
+}
+
+
+bool hasDependentTemplateArgs(PQName *name)
+{
+  // I think I only want to look at the final component
+  name = name->getUnqualifiedName();
+
+  if (name->isPQ_template()) {
+    return containsVariables(name->asPQ_template()->sargs);
+  }
+
+  return false;
+}
+
+void possiblyWrapWithImplicitThis(Env &env, Expression *&func,
+                                  E_variable *&fevar, E_fieldAcc *&feacc)
+{
+  if (fevar &&
+      fevar->var &&
+      fevar->var->isNonStaticMember()) {
+    feacc = wrapWithImplicitThis(env, fevar->var, fevar->name);
+    func = feacc;
+    fevar = NULL;
+  }
+}
+
+Type *E_funCall::inner2_itcheck(Env &env, LookupSet &candidates)
+{
+  // inner1 skipped E_groupings already
+  xassert(!func->isE_grouping());
+
+  // is 'func' an E_variable?  a number of special cases kick in if so
+  E_variable *fevar = func->isE_variable()? func->asE_variable() : NULL;
+
+  // similarly for E_fieldAcc
+  E_fieldAcc *feacc = func->isE_fieldAcc()? func->asE_fieldAcc() : NULL;
+
+  // if a method is being invoked, what is the type of the receiver
+  // object?  (may be NULL if none is available)
+  Type *receiverType = feacc? feacc->obj->type : env.implicitReceiverType();
+
+  // check the argument list
+  ArgumentInfoArray argInfo(args->count() + 1);
+  args = tcheckArgExprList(args, env, argInfo, receiverType);
+
+  // for internal testing
+  if (fevar) {
+    Type *ret = internalTestingHooks(env, fevar->name->getName(), args);
+    if (ret) {
+      return ret;
+    }
+  }
+
+  // do any of the arguments have types that are dependent on template params?
+  bool dependentArgs = hasDependentActualArgs(args);
+
+  // what about explicitly-provided template args that are dependent?
+  if (fevar && hasDependentTemplateArgs(fevar->name)) {
+    dependentArgs = true;
+  }
+  if (feacc && hasDependentTemplateArgs(feacc->fieldName)) {
+    dependentArgs = true;
+  }
+
+  // abbreviated processing for dependent lookups
+  if (dependentArgs) {
+    if (fevar && fevar->nondependentVar) {
+      // kill the 'nondependent' lookup
+      TRACE("dependent", toString(fevar->name->loc) <<
+        ": killing the nondependency of " << fevar->nondependentVar->name);
+      fevar->nondependentVar = NULL;
+    }
+
+    // 14.6.2 para 1, 14.6.2.2 para 1
+    return env.dependentType();
+  }
+  else if (feacc && feacc->type->isGeneralizedDependent()) {
+    return env.dependentType();
+  }
+
+  // did we already decide to re-use a previous nondependent lookup
+  // result?  (in/t0387.cc)
+  bool const alreadyDidLookup =
+    !env.inUninstTemplate() &&
+    fevar &&
+    fevar->nondependentVar &&
+    fevar->nondependentVar == fevar->var;
+
+  // 2005-02-18: rewrote function call site name lookup; see doc/lookup.txt
+  if (env.lang.allowOverloading &&
+      !alreadyDidLookup &&
+      (func->type->isSimple(ST_NOTFOUND) ||
+       func->type->asRval()->isFunctionType()) &&
+      (fevar || (feacc &&
+                 // in the case of a call to a compiler-synthesized
+                 // destructor, the 'field' is currently NULL (that might
+                 // change); but in that case overloading is not possible,
+                 // so this code can safely ignore it (e.g. in/t0091.cc)
+                 feacc->field))) {
+    PQName *pqname = fevar? fevar->name : feacc->fieldName;
+
+    // what is the set of names obtained by inner1?
+    //LookupSet candidates;   // use passed-in list
+
+    // augment with arg-dep lookup?
+    if (fevar &&                                // E_variable,
+        !pqname->hasQualifiers() &&             // unqualified,
+        (fevar->type->isSimple(ST_NOTFOUND) ||  // orig lookup failed
+         !fevar->var->isMember())) {            //   or found a nonmember
+      // get additional candidates from associated scopes
+      ArrayStack<Type*> argTypes(args->count());
+      FAKELIST_FOREACH(ArgExpression, args, iter) {
+        argTypes.push(iter->getType());
+      }
+      env.associatedScopeLookup(candidates, pqname->getName(),
+                                argTypes, LF_NONE);
+    }
+
+    if (candidates.isEmpty()) {
+      return fevar->type =
+        env.error(pqname->loc,
+                  stringc << "there is no function called `"
+                          << pqname->getName() << "'"
+                          << env.unsearchedDependentBases(),
+                  EF_NONE);
+    }
+
+    // template args supplied?
+    PQ_template *targs = NULL;
+    if (pqname->getUnqualifiedName()->isPQ_template()) {
+      targs = pqname->getUnqualifiedName()->asPQ_template();
+    }
+
+    // refine candidates by instantiating templates, etc.
+    char const *lastRemovalReason = "(none removed yet)";
+    SObjListMutator<Variable> mut(candidates);
+    while (!mut.isDone()) {
+      Variable *v = mut.data();
+      bool const considerInherited = false;
+      InferArgFlags const iflags = IA_NO_ERRORS;
+
+      // filter out non-templates if we have template arguments
+      if (targs && !v->isTemplate(considerInherited)) {
+        mut.remove();
+        lastRemovalReason = "non-template given template arguments";
+        continue;
+      }
+
+      // instantiate templates
+      if (v->isTemplate(considerInherited)) {
+        // initialize the bindings with those explicitly provided
+        MType match(env);
+        if (targs) {
+          if (!env.loadBindingsWithExplTemplArgs(v, targs->sargs, match, iflags)) {
+            mut.remove();
+            lastRemovalReason = "incompatible explicit template args";
+            continue;
+          }
+        }
+
+        // deduce the rest from the call site (expression) args
+        TypeListIter_FakeList argsIter(args);
+        if (!env.inferTemplArgsFromFuncArgs(v, argsIter, match, iflags)) {
+          mut.remove();
+          lastRemovalReason = "incompatible call site args";
+          continue;
+        }
+
+        // use them to instantiate the template
+        Variable *inst = env.instantiateFunctionTemplate(pqname->loc, v, match);
+        if (!inst) {
+          mut.remove();
+          lastRemovalReason = "could not deduce all template params";
+          continue;
+        }
+
+        // replace the template primary with its instantiation
+        mut.dataRef() = inst;
+      }
+
+      mut.adv();
+    }
+
+    // do we still have any candidates?
+    if (candidates.isEmpty()) {
+      return env.error(pqname->loc, stringc
+               << "call site name lookup failed to yield any candidates; "
+               << "last candidate was removed because: " << lastRemovalReason);
+    }
+
+    // throw the whole mess at overload resolution
+    Variable *chosen;
+    if (candidates.count() > 1) {
+      // pick the best candidate
+      chosen = outerResolveOverload_explicitSet
+        (env, pqname, pqname->loc, pqname->getName(),
+         argInfo, candidates);
+    }
+    else {
+      chosen = candidates.first();
+    }
+
+    if (chosen) {
+      // rewrite AST to reflect choice
+      //
+      // the stored type will be the dealiased type in hopes this
+      // achieves 7.3.3 para 13, "This has no effect on the type of
+      // the function, and in all other respects the function
+      // remains a member of the base class."
+      chosen = env.storeVar(chosen);
+      if (fevar) {
+        fevar->var = chosen;
+        maybeNondependent(env, pqname->loc, fevar->nondependentVar, chosen);   // in/t0385.cc
+      }
+      else {
+        feacc->field = chosen;
+
+        // TODO: I'm pretty sure I need nondependent names for E_fieldAcc too
+        //maybeNondependent(env, pqname->loc, feacc->nondependentVar, chosen);
+      }
+      func->type = chosen->type;
+    }
+    else {
+      return env.errorType();
+    }
+  }
+
+  // the type of the function that is being invoked
+  Type *t = func->type->asRval();
+
+  // check for operator()
+  CompoundType *ct = t->ifCompoundType();
+  if (ct) {
+    // the insertion of implicit 'this->' below will not be reached,
+    // so do it here too
+    possiblyWrapWithImplicitThis(env, func, fevar, feacc);
+
+    env.ensureCompleteType("use as function object", t);
+    Variable *funcVar = ct->getNamedField(env.functionOperatorName, env);
+    if (funcVar) {
+      // resolve overloading
+      getArgumentInfo(env, argInfo[0], func);
+      funcVar = outerResolveOverload(env, NULL /*finalName*/, env.loc(), funcVar,
+                                     argInfo);
+      if (funcVar) {
+        // rewrite AST to reflect use of 'operator()'
+        Expression *object = func;
+        E_fieldAcc *fa = new E_fieldAcc(object,
+          new PQ_operator(SL_UNKNOWN, new ON_operator(OP_PARENS), env.functionOperatorName));
+        fa->field = funcVar;
+        fa->type = funcVar->type;
+        func = fa;
+
+        return funcVar->type->asFunctionType()->retType;
+      }
+      else {
+        return env.errorType();
+      }
+    }
+    else {
+      return env.error(stringc
+        << "object of type `" << t->toString() << "' used as a function, "
+        << "but it has no operator() declared");
+    }
+  }
+
+  // fulfill the promise that inner1 made when it passed
+  // LF_NO_IMPL_THIS, namely that we would add 'this->' later
+  // if needed; here is "later"
+  possiblyWrapWithImplicitThis(env, func, fevar, feacc);
+
+  // make sure this function has been typechecked
+  if (fevar) {
+    // if it is a pointer to a function that function should get
+    // instantiated when its address is taken
+    env.ensureFuncBodyTChecked(fevar->var);
+  }
+  else if (feacc) {
+    env.ensureFuncBodyTChecked(feacc->field);
+  }
+
+  // automatically coerce function pointers into functions
+  // dsw: FIX: It would be nice to actually lower this so the analysis
+  // doesn't have to do it again. (Oink currently does it.)
+  if (t->isPointerType()) {
+    t = t->asPointerTypeC()->atType;
+    // if it is an E_variable then its overload set will be NULL so we
+    // won't be doing overload resolution in this case
+  }
+
+  if (t->isGeneralizedDependent()) {
+    return env.dependentType();      // in/k0021.cc
+  }
+
+  if (!t->isFunctionType()) {
+    return env.error(t, stringc
+      << "you can't use an expression of type `" << t->toString()
+      << "' as a function");
+  }
+
+  FunctionType *ft = t->asFunctionType();
+  env.instantiateTemplatesInParams(ft);
+  env.ensureCompleteType("use as return type in invoked function", ft->retType);
+
+  // receiver object?
+  if (env.doCompareArgsToParams && ft->isMethod()) {
+    Type *receiverType = NULL;
+    if (feacc) {
+      // explicit receiver via '.'
+      receiverType = feacc->obj->type;
+    }
+    else if (func->isE_binary() &&
+             func->asE_binary()->op == BIN_DOT_STAR) {
+      // explicit receiver via '.*'
+      receiverType = func->asE_binary()->e1->type;
+    }
+    else if (func->isE_binary() &&
+             func->asE_binary()->op == BIN_ARROW_STAR) {
+      // explicit receiver via '->*'
+      receiverType = func->asE_binary()->e1->type->asRval();
+
+      // if this weren't true, then the type checker for '->*' would
+      // already have indicated the error and assigned the ST_ERROR
+      // type, so 't' would not be a FunctionType
+      xassert(receiverType->isPointerType());
+
+      receiverType = receiverType->asPointerType()->atType;
+    }
+    else {        // gcov-ignore
+      // now that we wrap with 'this->' explicitly, this code should
+      // not be reachable
+      xfailure("got to implicit receiver code; should not be possible!");
+    }
+
+    if (receiverType) {
+      // 12.4p2: it is legal to invoke a destructor on an object that
+      // is const or volatile, and dtors never have such qualifiers,
+      // so if we are invoking a dtor then remove the qualifiers
+      if (ft->isDestructor() &&
+          receiverType->asRval()->getCVFlags() != CV_NONE) {
+        bool wasRef = receiverType->isReference();
+        receiverType = receiverType->asRval();
+        receiverType = env.tfac.setQualifiers(SL_UNKNOWN, CV_NONE, receiverType, NULL /*syntax*/);
+        if (wasRef) {
+          receiverType = env.tfac.makeReferenceType(receiverType);
+        }
+      }
+
+      // check that the receiver object matches the receiver parameter
+      if (!getImplicitConversion(env,
+             SE_NONE,
+             receiverType,
+             ft->getReceiver()->type,
+             true /*destIsReceiver*/)) {
+        env.error(stringc
+          << "cannot convert argument type `" << receiverType->toString()
+          << "' to receiver parameter type `" << ft->getReceiver()->type->toString()
+          << "'");
+      }
+    }
+    else {
+      // error already reported
+    }
+  }
+
+  // compare argument types to parameters (not guaranteed by overload
+  // resolution since it might not have been done, and even if done,
+  // uses more liberal rules)
+  int defaultArgsUsed = compareArgsToParams(env, ft, args, argInfo);
+
+  // instantiate default args
+  if (defaultArgsUsed) {
+    if (fevar) {
+      env.instantiateDefaultArgs(fevar->var, defaultArgsUsed);
+    }
+    else if (feacc) {
+      env.instantiateDefaultArgs(feacc->field, defaultArgsUsed);
+    }
+  }
+
+  // type of the expr is type of the return value
+  return ft->retType;
+}
+
+
+// special hooks for testing internal algorithms; returns a type
+// for the entire E_funCall expression if it recognizes the form
+// and typechecks it in its entirety
+//
+// actually, the arguments have already been tchecked ...
+static Type *internalTestingHooks
+  (Env &env, StringRef funcName, FakeList<ArgExpression> *args)
+{
+  // check the type of an expression
+  if (funcName == env.special_checkType) {
+    if (args->count() == 2) {
+      Type *t1 = args->nth(0)->getType();
+      Type *t2 = args->nth(1)->getType();
+      if (t1->equals(t2)) {
+        // ok
+      }
+      else {
+        env.error(stringc << "checkType: `" << t1->toString()
+                          << "' != `" << t2->toString() << "'");
+      }
+    }
+    else {
+      env.error("invalid call to __elsa_checkType");
+    }
+  }
+
+  // test vector for 'getStandardConversion'
+  if (funcName == env.special_getStandardConversion) {
+    int expect;
+    if (args->count() == 3 &&
+        args->nth(2)->constEval(env, expect)) {
+      test_getStandardConversion
+        (env,
+         args->nth(0)->getSpecial(env.lang),     // is it special?
+         args->nth(0)->getType(),                // source type
+         args->nth(1)->getType(),                // dest type
+         expect);                                // expected result
+    }
+    else {
+      env.error("invalid call to __getStandardConversion");
+    }
+  }
+
+  // test vector for 'getImplicitConversion'
+  if (funcName == env.special_getImplicitConversion) {
+    int expectKind;
+    int expectSCS;
+    int expectUserLine;
+    int expectSCS2;
+    if (args->count() == 6 &&
+        args->nth(2)->constEval(env, expectKind) &&
+        args->nth(3)->constEval(env, expectSCS) &&
+        args->nth(4)->constEval(env, expectUserLine) &&
+        args->nth(5)->constEval(env, expectSCS2)) {
+      test_getImplicitConversion
+        (env,
+         args->nth(0)->getSpecial(env.lang),     // is it special?
+         args->nth(0)->getType(),                // source type
+         args->nth(1)->getType(),                // dest type
+         expectKind, expectSCS, expectUserLine, expectSCS2);   // expected result
+    }
+    else {
+      env.error("invalid call to __getImplicitConversion");
+    }
+  }
+
+  // test overload resolution
+  if (funcName == env.special_testOverload) {
+    int expectLine;
+    if (args->count() == 2 &&
+        args->nth(1)->constEval(env, expectLine)) {
+
+      if (args->first()->expr->isE_funCall() &&
+          hasNamedFunction(args->first()->expr->asE_funCall()->func)) {
+        // resolution yielded a function call
+        Variable *chosen = getNamedFunction(args->first()->expr->asE_funCall()->func);
+        int actualLine = sourceLocManager->getLine(chosen->loc);
+        if (expectLine != actualLine) {
+          env.error(stringc
+            << "expected overload to choose function on line "
+            << expectLine << ", but it chose line " << actualLine,
+            EF_STRONG);
+        }
+      }
+      else if (expectLine != 0) {
+        // resolution yielded something else
+        env.error("expected overload to choose a function, but it "
+                  "chose a non-function");
+      }
+
+      // propagate return type
+      return args->first()->getType();
+    }
+    else {
+      env.error("invalid call to __testOverload");
+    }
+  }
+
+  // test vector for 'computeLUB'
+  if (funcName == env.special_computeLUB) {
+    int expect;
+    if (args->count() == 4 &&
+        args->nth(3)->constEval(env, expect)) {
+      test_computeLUB
+        (env,
+         args->nth(0)->getType(),        // T1
+         args->nth(1)->getType(),        // T2
+         args->nth(2)->getType(),        // LUB
+         expect);                        // expected result
+    }
+    else {
+      env.error("invalid call to __computeLUB");
+    }
+  }
+
+  // given a call site, check that the function it calls is
+  // (a) defined, and (b) defined at a particular line
+  if (funcName == env.special_checkCalleeDefnLine) {
+    int expectLine;
+    if (args->count() == 2 &&
+        args->nth(1)->constEval(env, expectLine)) {
+
+      if (args->first()->expr->isE_funCall() &&
+          hasNamedFunction(args->first()->expr->asE_funCall()->func)) {
+        // resolution yielded a function call
+        Variable *chosen = getNamedFunction(args->first()->expr->asE_funCall()->func);
+        if (!chosen->funcDefn) {
+          env.error("expected to be calling a defined function");
+        }
+        else {
+          int actualLine = sourceLocManager->getLine(chosen->funcDefn->getLoc());
+          if (expectLine != actualLine) {
+            env.error(stringc
+              << "expected to call function on line "
+              << expectLine << ", but it chose line " << actualLine);
+          }
+        }
+      }
+      else if (expectLine != 0) {
+        // resolution yielded something else
+        env.error("expected overload to choose a function, but it "
+                  "chose a non-function");
+      }
+
+      // propagate return type
+      return args->first()->getType();
+    }
+    else {
+      env.error("invalid call to __checkCalleeDefnLine");
+    }
+  }
+
+
+  // syntax of calls to __test_mtype:
+  //
+  // Form 1: match is expected to succeed
+  //
+  //   __test_mtype((C)0, (P)0, FLAGS,
+  //                "A", (T1)0,           // form of type bindings
+  //                "n", 3,               // form of value bindings
+  //                ...                   // remaining binding pairs
+  //               );
+  //
+  //   where C is the concrete type, P is the pattern type, FLAGS
+  //   is a bitwise OR of MatchFlags, T1 is the proposed type binding
+  //   for variable "A", and 3 is the expected value of variable "n".
+  //
+  // Form 2: match is expected fo fail
+  //
+  //   __test_mtype((C)0, (P)0, FLAGS, false);     // four args total
+  //
+  if (funcName == env.special_test_mtype) {
+    int nArgs = args->count();
+    if (nArgs < 3) {
+      return env.error("__test_mtype requires at least three arguments");
+    }
+
+    Type *conc = args->nth(0)->getType();
+    Type *pat = args->nth(1)->getType();
+    int flags;
+    if (!args->nth(2)->constEval(env, flags)) {
+      return env.error("third argument to __test_mtype must be a constant expression");
+    }
+    if (flags & ~MF_ALL) {
+      return env.error("invalid flags value for __test_mtype");
+    }
+    bool expectSuccess = (nArgs != 4);
+    if (expectSuccess && (nArgs%2 != 1)) {
+      return env.error("__test_mtype requires either four or an odd number of arguments");
+    }
+
+    MType mtype(env);
+    if (mtype.matchTypeNC(conc, pat, (MatchFlags)flags)) {
+      if (expectSuccess) {
+        // successed as expected; check the bindings
+        int i;
+        for (i=0; (i+1)*2+1 < nArgs; i++) {
+          Expression *name = args->nth((i+1)*2+1)->expr;
+          Expression *value = args->nth((i+1)*2+2)->expr;
+
+          // 'name' should be a string literal naming a variable in 'pat'
+          if (!name->isE_stringLit()) {
+            return env.error(stringc << "__test_mtype argument " << (i+1)*2+1+1
+                                     << " must be a string literal");
+          }
+          StringRef nameStr = env.str(parseQuotedString(name->asE_stringLit()->text));
+
+          // it should correspond to an existing binding in 'mtype'
+          STemplateArgument binding(mtype.getBoundValue(nameStr, env.tfac));
+          if (!binding.hasValue()) {
+            return env.error(stringc << "__test_mtype: " << nameStr << " is not bound");
+          }
+
+          // we interpret 'value' depending on what kind of thing is
+          // the 'binding', and hope this won't mask any problems
+          switch (binding.kind) {
+            default:
+              return env.error(stringc << "unexpected binding kind: "
+                                       << toString(binding.kind));
+
+            case STemplateArgument::STA_TYPE:
+              if (!binding.getType()->equals(value->getType())) {
+                return env.error(stringc << "__test_mtype: "
+                  << "expected " << nameStr
+                  << " to be bound to `" << value->getType()->toString()
+                  << "' but it was actually bound to `"
+                  << binding.getType()->toString() << "'");
+              }
+              break;
+
+            case STemplateArgument::STA_INT: {
+              int valueInt;
+              if (!value->constEval(env, valueInt)) {
+                return env.error(stringc << "__test_mtype: "
+                  << nameStr << " was bound to an int, but the provided "
+                  << "expression is not a constant");
+              }
+              if (valueInt != binding.getInt()) {
+                return env.error(stringc << "__test_mtype: "
+                  << "expected " << nameStr
+                  << " to be bound to " << valueInt
+                  << " but it was actually bound to "
+                  << binding.getInt());
+              }
+              break;
+            }
+          }
+        } // end of loop over supplied bindings
+
+        // the user should have supplied as many bindings as there
+        // are bindings in 'mtype'
+        if (mtype.getNumBindings() != i) {
+          return env.error(stringc << "__test_mtype: "
+            << "call site supplied " << pluraln(i , "binding")
+            << ", but match yielded " << mtype.getNumBindings());
+        }
+      }
+      else {
+        return env.error("mtype succeeded, but failure was expected");
+      }
+    }
+    else {
+      if (expectSuccess) {
+        return env.error("mtype failed, but success was expected");
+      }
+      else {
+        // failed as expected
+      }
+    }
+
+    return env.getSimpleType(ST_VOID);
+  }
+
+  // The purpose of this is to be able to exercise some of the error
+  // handling paths.
+  if (funcName == env.special_cause_xfailure) {
+    xfailure("program contains __cause_xfailure");
+  }
+
+  // E_funCall::itcheck should continue, and tcheck this normally
+  return NULL;
+}
+
+
+Type *E_constructor::itcheck_x(Env &env, Expression *&replacement)
+{
+  inner1_itcheck(env);
+
+  return inner2_itcheck(env, replacement);
+}
+
+void E_constructor::inner1_itcheck(Env &env)
+{
+  type = spec->tcheck(env, DF_NONE);
+}
+
+Type *E_constructor::inner2_itcheck(Env &env, Expression *&replacement)
+{
+  xassert(replacement == this);
+
+  // inner1_itcheck sets the type, so if it signaled an error then bail
+  if (type->isError()) {
+    return type;
+  }
+
+  // check arguments
+  ArgumentInfoArray argInfo(args->count() + 1);
+  args = tcheckArgExprList(args, env, argInfo);
+
+  if (!env.ensureCompleteType("construct", type)) {
+    return type;     // recovery: skip what follows
+  }
+
+  // simplify some gratuitous uses of E_constructor
+  if (!type->isLikeCompoundType() && !type->isGeneralizedDependent()) {
+    // you can make a temporary for an int like this (from
+    // in/t0014.cc)
+    //   x = int(6);
+    // or you can use a typedef to get any other type like this (from
+    // t0059.cc)
+    //   typedef char* char_ptr;
+    //   typedef unsigned long ulong;
+    //   return ulong(char_ptr(mFragmentIdentifier)-char_ptr(0));
+    // in those cases, there isn't really any ctor to call, so just
+    // turn it into a cast
+
+    // there had better be exactly one argument to this ctor
+    //
+    // oops.. actually there can be zero; "int()" is valid syntax,
+    // yielding an integer with indeterminate value
+    //
+    // 2005-05-28: (in/t0495.cc) count the args *after* tchecking them
+    if (args->count() > 1) {
+      return env.error(stringc
+        << "function-style cast to `" << type->toString()
+        << "' must have zere or one argument (not "
+        << args->count() << ")");
+    }
+
+    // change it into a cast; this code used to do some 'buildASTTypeId'
+    // contortions, but that's silly since the E_constructor already
+    // carries a perfectly good type specifier ('this->spec'), and so
+    // all we need to do is add an empty declarator
+    ASTTypeId *typeSyntax = new ASTTypeId(this->spec,
+      new Declarator(new D_name(this->spec->loc, NULL /*name*/), NULL /*init*/));
+    if (args->count() == 1) {
+      replacement =
+        new E_cast(typeSyntax, args->first()->expr);
+    }
+    else {   /* zero args */
+      // The correct semantics (e.g. from a verification point of
+      // view) would be to yield a value about which nothing is known,
+      // but there is no simple way to do that in the existing AST.  I
+      // just want to hack past this for now, since I think it will be
+      // very unlikely to cause a real problem, so my solution is to
+      // pretend it's always the value 0.
+      replacement =
+        new E_cast(typeSyntax, env.build_E_intLit(0));
+    }
+    replacement->tcheck(env, replacement);
+    return replacement->type;
+  }
+
+  Variable *ctor = outerResolveOverload_ctor(env, env.loc(), type, argInfo);
+  ctorVar = env.storeVar(ctor);
+  compareCtorArgsToParams(env, ctor, args, argInfo);
+
+  return type;
+}
+
+
+// Maybe this should go in variable.h?  If so, I should be more careful
+// to ensure the case analysis is exhaustive.
+string kindAndType(Variable *v)
+{
+  if (v->isNamespace()) {
+    return stringc << "namespace " << v->fullyQualifiedName0();
+  }
+  else if (v->isType()) {
+    if (v->type->isCompoundType()) {
+      CompoundType *ct = v->type->asCompoundType();
+      return stringc << toString(ct->keyword) << " " << v->fullyQualifiedName0();
+    }
+    else {
+      return stringc << "type `" << v->type->toString() << "'";
+    }
+  }
+  else if (v->type->isFunctionType()) {
+    return stringc << "function of type `" << v->type->toString() << "'";
+  }
+  else {
+    return stringc << "object of type `" << v->type->toString() << "'";
+  }
+}
+
+
+PQ_qualifier *getSecondToLast(PQ_qualifier *name)
+{
+  while (name->rest->isPQ_qualifier()) {
+    name = name->rest->asPQ_qualifier();
+  }
+  return name;
+}
+
+
+// do 'var1' and 'var2' refer to the same class type,
+// as required by 3.4.5p3?
+bool sameCompounds(Variable *var1, Variable *var2)
+{
+  CompoundType *ct1 = var1->type->asCompoundType();
+  CompoundType *ct2 = var2->type->asCompoundType();
+  if (ct1 == ct2) {
+    return true;      // easy case
+  }
+
+  // in/t0481.cc contains an interesting variation where one of the
+  // variables refers to a template, and the other to an instantiation
+  // of that template, through no fault of the programmer.  Since both
+  // gcc and icc accept it, I will too, even though a strict reading
+  // of the standard seems to suggest the opposite.
+  TemplateInfo *ti1 = ct1->templateInfo();
+  TemplateInfo *ti2 = ct2->templateInfo();
+  if (ti1 && ti2 &&                                 // both are template things
+      (ti1->isPrimary() || ti2->isPrimary()) &&     // one is the primary
+      ti1->getPrimary() == ti2->getPrimary()) {     // other is specialization
+    return true;
+  }
+
+  return false;
+}
+
+
+// cppstd sections: 5.2.4, 5.2.5 and 3.4.5
+Type *E_fieldAcc::itcheck_x(Env &env, Expression *&replacement)
+{
+  return itcheck_fieldAcc(env, LF_NONE);
+}
+
+Type *E_fieldAcc::itcheck_fieldAcc(Env &env, LookupFlags flags)
+{
+  LookupSet dummy;
+  return itcheck_fieldAcc_set(env, flags, dummy);
+}
+
+Type *E_fieldAcc::itcheck_fieldAcc_set(Env &env, LookupFlags flags,
+                                       LookupSet &candidates)
+{
+  obj->tcheck(env, obj);
+
+  // tcheck template arguments and ON_conversion types in the
+  // current scope
+  tcheckPQName(fieldName, env, NULL /*scope*/, LF_NONE);
+
+  // want this generally I think
+  flags |= LF_SELFNAME;
+
+  // naming a destructor?
+  StringRef rhsFinalTypeName = fieldName->getName();
+  bool isDestructor = rhsFinalTypeName[0] == '~';
+  if (isDestructor) {
+    rhsFinalTypeName = env.str(rhsFinalTypeName+1);    // skip '~'
+  }
+
+  // component of a __complex__ type?
+  #ifdef GNU_EXTENSION
+  if (rhsFinalTypeName == env.string_realSelector ||
+      rhsFinalTypeName == env.string_imagSelector) {
+    return itcheck_complex_selector(env, flags, candidates);
+  }
+  #endif // GNU_EXTENSION
+
+  // dependent?
+  if (obj->type->containsGeneralizedDependent()) {
+    if (isDestructor) {
+      // 14.6.2.2 para 4; type is function accepting nothing and
+      // returning void
+      FunctionType *ft = env.tfac.makeFunctionType(env.getSimpleType(ST_VOID));
+      env.tfac.doneParams(ft);
+      return ft;
+    }
+    else {
+      // 14.6.2.2 para 1
+      return env.dependentType();
+    }
+  }
+
+  // get the type of 'obj', and check if is a compound
+  Type *lhsType = obj->type->asRval();
+  CompoundType *ct = lhsType->ifCompoundType();
+  if (!ct) {
+    // 5.2.4: pseudo-destructor
+    if (!isDestructor ||
+        !fieldName->getUnqualifiedName()->isPQ_name()) {
+      return env.error(lhsType, fieldName->loc, stringc
+        << "RHS of . or -> must be of the form \"~ identifier\" if the LHS "
+        << "is not a class; the LHS is `" << lhsType->toString() << "'");
+    }
+
+    // this will be set to the type of the RHS
+    Type *rhsType = NULL;
+
+    if (fieldName->hasQualifiers()) {
+      // get pointers to the last three elements in the name
+      PQ_qualifier *thirdLast=NULL, *secondLast=NULL;
+      PQName *last = fieldName;
+      while (last->isPQ_qualifier()) {
+        // shift
+        thirdLast = secondLast;
+        secondLast = last->asPQ_qualifier();
+        last = secondLast->rest;
+      }
+      xassert(secondLast);
+
+      if (secondLast->sargs.isNotEmpty()) {
+        return env.error(fieldName->loc, "cannot have templatized qualifier as "
+          "second-to-last element of RHS of . or -> when LHS is not a class");
+      }
+
+      // these will be set to the lookup results of secondLast and last, resp.
+      Variable *secondVar = NULL;
+      Variable *lastVar = NULL;
+
+      if (!thirdLast) {
+        // 'fieldName' must be of form type-name :: ~ type-name, so
+        // we do unqualified lookups
+        xassert(secondLast->qualifier);   // grammar should ensure this
+        secondVar = env.unqualifiedLookup_one(secondLast->qualifier,
+          /* the name precedes "::" so ... */ LF_QUALIFIER_LOOKUP);
+        lastVar = env.unqualifiedLookup_one(rhsFinalTypeName, flags);
+      }
+
+      else {
+        // 'fieldName' of form Q :: type-name1 :: ~ type-name2, and so
+        // *both* lookups are to be done as if qualified by
+        // 'thirdLast'; to accomplish this, temporarily modify
+        // 'thirdLast' to construct the needed names
+
+        // fieldName := Q :: type-name1
+        PQ_name fakeLast(secondLast->loc, secondLast->qualifier);
+        thirdLast->rest = &fakeLast;
+        secondVar = env.lookupPQ_one(fieldName, flags | LF_QUALIFIER_LOOKUP);
+
+        // fieldName := Q :: type-name2
+        fakeLast.loc = last->loc;
+        fakeLast.name = rhsFinalTypeName;
+        lastVar = env.lookupPQ_one(fieldName, flags);
+
+        // fieldName := original fieldName
+        thirdLast->rest = secondLast;
+      }
+
+      if (!secondVar || !secondVar->isType()) {
+        PQName *n = getSecondToLast(fieldName->asPQ_qualifier());
+        return env.error(n->loc, stringc
+          << "no such type: `" << n->toComponentString() << "'");
+      }
+      if (!lastVar || !lastVar->isType()) {
+        PQName *n = fieldName->getUnqualifiedName();
+        return env.error(n->loc, stringc
+          << "no such type: `" << n->toComponentString() << "'");
+      }
+      if (!lastVar->type->equals(secondVar->type)) {
+        return env.error(fieldName->loc, stringc
+          << "in . or -> expression, when LHS is non-class type "
+          << "(its type is `" << lhsType->toString() << "'), a qualified RHS "
+          << "must be of the form Q :: t1 :: ~t2 where t1 and t2 are "
+          << "the same type, but t1 is `" << secondVar->type->toString()
+          << "' and t2 is `" << lastVar->type->toString() << "'");
+      }
+      rhsType = lastVar->type;
+    }
+
+    else {
+      // RHS of form ~ type-name
+      Variable *v = env.unqualifiedLookup_one(rhsFinalTypeName, flags);
+      if (!v || !v->hasFlag(DF_TYPEDEF)) {
+        return env.error(fieldName->loc,
+          stringc << "no such type: `" << rhsFinalTypeName << "'");
+      }
+      rhsType = v->type;
+    }
+
+    if (!lhsType->equals(rhsType, MF_IGNORE_TOP_CV)) {
+      return env.error(fieldName->loc, stringc
+        << "in . or -> expression, when LHS is non-class type, its type "
+        << "must be the same (modulo cv qualifiers) as the RHS; but the "
+        << "LHS type is `" << lhsType->toString() << "' and the RHS type is `"
+        << rhsType->toString() << "'");
+    }
+
+    // pseudo-destructor invocation
+    //
+    // an older comment read:
+    //   invoking destructor explicitly, which is allowed for all
+    //   types; most of the time, the rewrite in E_funCall::itcheck
+    //   will replace this, but in the case of a type which is an
+    //   array of objects, this will leave the E_fieldAcc's 'field'
+    //   member NULL ...
+    return env.makeDestructorFunctionType(SL_UNKNOWN, NULL /*ct*/);
+  }
+
+  // make sure the type has been completed
+  if (!env.ensureCompleteType("access a member of", lhsType)) {
+    return env.errorType();
+  }
+
+  // I'm just going to say that any field access that involves
+  // a dependent type is itself of dependent type
+  #define HANDLE_DEPENDENT(v)                                     \
+    if (v && v->type && v->type->isGeneralizedDependent()) {      \
+      return env.dependentType();                                 \
+    }
+
+  // case analysis on the presence/kind of qualifiers
+  if (fieldName->isPQ_qualifier() &&
+      fieldName->asPQ_qualifier()->qualifier == NULL) {
+    // global scope qualifier: 3.4.5p5
+    env.lookupPQ(candidates, fieldName, flags);
+  }
+
+  else if (fieldName->isPQ_qualifier()) {
+    // qualified (but not global scope): 3.4.5p4
+    PQ_qualifier *firstQ = fieldName->asPQ_qualifier();
+
+    // unqualified lookup of firstQ
+    Variable *firstQVar1 =
+      env.unqualifiedLookup_one(firstQ->qualifier, LF_QUALIFIER_LOOKUP);
+    HANDLE_DEPENDENT(firstQVar1);
+    if (firstQVar1 &&
+        !firstQVar1->isNamespace() &&
+        !firstQVar1->isClass()) {
+      return env.error(firstQ->loc, stringc
+        << "in " << this->asString() << ", when " << firstQ->qualifier
+        << " is found in the current scope, it must be "
+        << "a class or namespace, not " << kindAndType(firstQVar1));
+    }
+    Scope *firstQScope1 = (!firstQVar1)?             NULL :
+                          firstQVar1->isNamespace()? firstQVar1->scope :
+                                                     firstQVar1->type->asCompoundType();
+
+    // lookup of firstQ in scope of LHS class
+    Variable *firstQVar2 =
+      ct->lookup_one(firstQ->qualifier, env, LF_QUALIFIER_LOOKUP);
+    HANDLE_DEPENDENT(firstQVar2);
+    if (firstQVar2 &&
+        !firstQVar2->isClass()) {
+      return env.error(firstQ->loc, stringc
+        << "in " << this->asString() << ", when " << firstQ->qualifier
+        << " is found in the class of " << obj->asString() << ", it must be "
+        << "a class, not " << kindAndType(firstQVar2));
+    }
+    Scope *firstQScope2 = (!firstQVar2)? NULL :
+                                         firstQVar2->type->asCompoundType();
+
+    // combine the two lookups
+    if (firstQScope1) {
+      if (firstQScope2 && firstQScope1!=firstQScope2) {
+        return env.error(firstQ->loc, stringc
+          << "in " << this->asString() << ", " << firstQ->qualifier
+          << " was found in the current scope as "
+          << kindAndType(firstQVar1) << ", and also in the class of "
+          << obj->asString() << " as "
+          << kindAndType(firstQVar2) << ", but they must be the same");
+      }
+    }
+    else {
+      if (firstQScope2) {
+        firstQScope1 = firstQScope2;     // make 'firstQScope1' the only one
+      }
+      else {
+        return env.error(firstQ->loc, stringc
+          << "no such scope `" << firstQ->qualifier << "'");
+      }
+    }
+
+    // lookup the remainder of 'fieldName', but we already know
+    // that 'firstQ' maps to 'firstQScope1'
+    env.lookupPQ_withScope(candidates, firstQ->rest, flags, firstQScope1);
+  }
+
+  else {
+    // unqualified field name: 3.4.5p1,2,3
+
+    if (isDestructor) {
+      // doc/lookup.txt case 2
+
+      // unqualified lookup
+      Variable *var1 = env.unqualifiedLookup_one(rhsFinalTypeName, flags);
+      HANDLE_DEPENDENT(var1);
+      if (var1 && !var1->isClass()) {
+        return env.error(fieldName->loc, stringc
+          << "in " << this->asString() << ", when " << rhsFinalTypeName
+          << " is found in the current scope, it must be "
+          << "a class, not " << kindAndType(var1));
+      }
+
+      // lookup in class of LHS
+      Variable *var2 = ct->lookup_one(rhsFinalTypeName, env, flags);
+      HANDLE_DEPENDENT(var2);
+      if (var2 && !var2->isClass()) {
+        return env.error(fieldName->loc, stringc
+          << "in " << this->asString() << ", when " << rhsFinalTypeName
+          << " is found in the class of " << obj->asString()
+          << ", it must be a class, not " << kindAndType(var2));
+      }
+
+      // combine
+      if (var1) {
+        if (var2) {
+          if (!sameCompounds(var1, var2)) {
+            return env.error(fieldName->loc, stringc
+              << "in " << this->asString() << ", " << rhsFinalTypeName
+              << " was found in the current scope as "
+              << kindAndType(var1) << ", and also in the class of "
+              << obj->asString() << " as "
+              << kindAndType(var2) << ", but they must be the same");
+          }
+          // we will use 'var2' below
+        }
+        else {
+          // Use 'var2' the rest of the way.
+          //
+          // The reason to prefer 'var2' over 'var1' is a little
+          // subtle.  Normally, they are the same so it does not
+          // matter.  But in a case like in/t0481.cc, 'var2' is a
+          // template instantiation, whereas 'var1' is just a template
+          // primary.  So, use the more specific one.
+          var2 = var1;
+        }
+      }
+      else {
+        if (var2) {
+          // we will use 'var2', so nothing needs to be done
+        }
+        else {
+          return env.error(fieldName->loc, stringc
+            << "no such class `" << rhsFinalTypeName << "'");
+        }
+      }
+
+      // get the destructor of the named class
+      env.lookupClassDestructor(candidates, var2->type->asCompoundType(), flags);
+        //             using 'var2' here    ^^^^
+    }
+
+    else {
+      // doc/lookup.txt cases 1,2,4,5,6
+
+      // lookup 'fieldName' in 'ct', taking any template arguments
+      // or conversion function types into account
+      env.unqualifiedFinalNameLookup(candidates, ct, fieldName, flags);
+    }
+  }
+
+  #undef HANDLE_DEPENDENT
+
+  // investigate what lookup yielded
+  if (candidates.isEmpty()) {
+    TemplateInfo *ti = ct->templateInfo();
+    if (ti && ti->dependentBases.isNotEmpty()) {
+      // (in/t0502.cc) the member could be coming from a dependent
+      // base; do not issue an error (but return ST_ERROR to prevent
+      // the context from trying to do more)
+      return env.errorType();
+    }
+
+    return env.error(lhsType, stringc
+      << "there is no member called `" << *fieldName
+      << "' in " << lhsType->toString());
+  }
+
+  // should only get members of 'ct' or base classes
+  SFOREACH_OBJLIST(Variable, candidates, iter) {
+    Variable const *v = iter.data();
+
+    if (v->scope == ct) {
+      continue;         // easy case
+    }
+
+    if (!v->scope || !v->scope->curCompound) {
+      return env.error(fieldName->loc, stringc
+        << "field `" << *fieldName << "' is not a class member");
+    }
+
+    CompoundType *vClass = v->scope->curCompound;
+    int subobjs = ct->countBaseClassSubobjects(vClass);
+    if (!subobjs) {
+      return env.error(fieldName->loc, stringc
+        << "field `" << *fieldName << "' is a member of "
+        << kindAndType(vClass->typedefVar)
+        << ", which is not a base class of "
+        << kindAndType(ct->typedefVar));
+    }
+
+    // 10.2p2: must not ambiguously refer to fields of distinct
+    // subobjects
+    //
+    // Scope::lookupVariable_considerBase has some overlapping
+    // functionality.  It seems to me that the check here should
+    // subsume the one in Scope, and furthermore I think *both*
+    // implementations may have subtle bugs, but I can't figure out a
+    // test that would properly reveal where the bugs/differences are
+    // (this is just a confusing part of the spec).  So, for the
+    // moment, the functionality remains duplicated.
+    //
+    // For example, I suspect that 'subobjs>1' is too crude because it
+    // does not take into account the notion of "hiding" defined in
+    // 10.2p2.
+    if (!v->hasFlag(DF_STATIC) && subobjs>1) {
+      return env.error(fieldName->loc, stringc
+        << "field `" << *fieldName << "' ambiguously refers to "
+        << "elements of multiple base class subobjects");
+    }
+  }
+
+  // nominal lookup result for remaining checks; if this name is
+  // overloaded, this should get overwritten after overload resolution
+  Variable *f = candidates.first();
+
+  // should not be a type (5.2.5p4b4)
+  if (f->hasFlag(DF_TYPEDEF)) {
+    return env.error(lhsType, stringc
+      << "member `" << *fieldName << "' is a typedef!");
+  }
+
+  // TODO: access control check
+
+  if (!(flags & LF_TEMPL_PRIMARY)) {
+    env.ensureFuncBodyTChecked(f);
+  }
+  field = env.storeVarIfNotOvl(f);
+
+  // type of expression is type of field; possibly as an lval
+  if (obj->type->isLval()) {
+    // TODO: this is wrong if the field names an enumerator (5.2.5p4b5)
+    return makeFieldLvalType(env, field, lhsType->getCVFlags());
+  }
+  else {
+    return field->type;
+  }
+}
+
+
+Type *E_arrow::itcheck_x(Env &env, Expression *&replacement)
+{
+  LookupSet dummy;
+  return itcheck_arrow_set(env, replacement, LF_NONE, dummy);
+}
+
+// Nominally, we rewrite
+//   a->b                 E_arrow(a,b)
+// as
+//   (*a).b               E_fieldAcc(E_deref(a), b)
+//
+// However, 'a' might be an object with operator-> defined, in which
+// case we rewrite the LHS, adding an explicit operator-> call:
+//   (a.operator->()).b   E_fieldAcc(E_funCall(E_fieldAcc(a,operator->), ()), b)
+//
+// Further complicating this is the possibility that we are in a
+// template, and don't know how much rewriting to do because of
+// dependence on template parameters.
+//
+// So, every a->b in the input AST has one of three fates:
+//   - If the type of 'a' does not depend on an template parameters,
+//     and is a pointer type, it is changed into (*a).b.
+//   - If 'a' is not dependent and has class type with operator->
+//     defined, it is changed into (a.operator->())->b.
+//   - If 'a' has dependent type, it is left as a->b, and only further
+//     refined when the instantiation is typechecked.
+//
+// Note that the middle case, rewriting as operator->, yields a form
+// that again contains -> and therefore may be recursively rewritten.
+// The recursion stops in case 1 or 3.  (Incidentally, the code below
+// does the expansion iteratively, not recursively.)
+//
+// Examples of various levels and timings of rewriting can be seen by
+// running ccparse with the prettyPrint tracing flag on in/t0480.cc
+Type *E_arrow::itcheck_arrow_set(Env &env, Expression *&replacement,
+                                 LookupFlags flags, LookupSet &set)
+{
+  // check LHS
+  obj->tcheck(env, obj);
+
+  // overloaded?  if so, replace 'obj'
+  Type *t = obj->type;
+  while (t && !t->isDependent()) {
+    t = resolveOverloadedUnaryOperator(env, obj, obj, OP_ARROW);
+    // keep sticking in 'operator->' until the LHS is not a class
+  }
+
+  // now replace with '*' and '.' and proceed
+  E_fieldAcc *eacc = new E_fieldAcc(new E_deref(obj), fieldName);
+  if (t && t->isDependent()) {
+    // Do not actually do the rewriting, since the degree to which
+    // further rewriting via operator-> is done depends on template
+    // parameters.  We still go ahead and create 'eacc' and use it to
+    // compute the type of this node, though.  (in/t0478.cc)
+  }
+  else {
+    replacement = eacc;
+  }
+  return eacc->itcheck_fieldAcc_set(env, flags, set);
+}
+
+
+Type *E_sizeof::itcheck_x(Env &env, Expression *&replacement)
+{
+  expr->tcheck(env, expr);
+
+  return env.sizeofType(expr->type, size, expr);
+}
+
+
+// do operator overload resolution for a unary operator; return
+// non-NULL if we've replaced this node, and want the caller to
+// return that value
+Type *resolveOverloadedUnaryOperator(
+  Env &env,                  // environment
+  Expression *&replacement,  // OUT: replacement node
+  //Expression *ths,           // expression node that is being resolved (not used)
+  Expression *expr,          // the subexpression of 'this' (already type-checked)
+  OverloadableOp op          // which operator this node is
+) {
+  // 14.6.2.2 para 1
+  if (expr->type->containsGeneralizedDependent()) {
+    return env.dependentType();
+  }
+
+  if (!env.doOperatorOverload()) {
+    return NULL;
+  }
+
+  if (expr->type->asRval()->isCompoundType() ||
+      expr->type->asRval()->isEnumType()) {
+    OVERLOADINDTRACE("found overloadable unary " << toString(op) <<
+                     " near " << env.locStr());
+    StringRef opName = env.operatorName[op];
+
+    // argument information
+    ArgumentInfoArray args(1);
+    getArgumentInfo(env, args[0], expr);
+
+    // prepare resolver
+    OverloadResolver resolver(env, env.loc(), &env.errors,
+                              OF_OPERATOR,
+                              NULL, // I assume operators can't have explicit template arguments
+                              args);
+
+    if (op == OP_AMPERSAND) {
+      // 13.3.1.2 para 9: no viable -> use built-in
+      resolver.emptyCandidatesIsOk = true;
+    }
+
+    // user-defined candidates
+    resolver.addUserOperatorCandidates(expr->type, NULL /*rhsType*/, opName);
+
+    // built-in candidates
+    resolver.addBuiltinUnaryCandidates(op);
+
+    // pick the best candidate
+    bool dummy;
+    Candidate const *winnerCand = resolver.resolveCandidate(dummy);
+    if (winnerCand) {
+      Variable *winner = winnerCand->var;
+
+      if (!winner->hasFlag(DF_BUILTIN)) {
+        OperatorName *oname = new ON_operator(op);
+        PQ_operator *pqo = new PQ_operator(SL_UNKNOWN, oname, opName);
+
+        if (winner->hasFlag(DF_MEMBER)) {
+          // replace '~a' with 'a.operator~()'
+          replacement = new E_funCall(
+            new E_fieldAcc(expr, pqo),               // function
+            FakeList<ArgExpression>::emptyList()     // arguments
+          );
+        }
+        else {
+          // replace '~a' with '<scope>::operator~(a)'
+          replacement = new E_funCall(
+            // function to invoke
+            new E_variable(env.makeFullyQualifiedName(winner->scope, pqo)),
+            // arguments
+            makeExprList1(expr)
+          );
+        }
+
+        // for now, just re-check the whole thing
+        replacement->tcheck(env, replacement);
+        return replacement->type;
+      }
+
+      else {
+        // chose a built-in operator
+
+        // TODO: need to replace the arguments according to their
+        // conversions (if any)
+
+        // get the correct return value, at least
+        Type *ret = resolver.getReturnType(winnerCand);
+        OVERLOADINDTRACE("computed built-in operator return type `" <<
+                         ret->toString() << "'");
+
+        return ret;
+      }
+    }
+  }
+
+  // not replaced
+  return NULL;
+}
+
+
+// similar, but for binary
+Type *resolveOverloadedBinaryOperator(
+  Env &env,                  // environment
+  Expression *&replacement,  // OUT: replacement node
+  //Expression *ths,           // expression node that is being resolved (not used)
+  Expression *e1,            // left subexpression of 'this' (already type-checked)
+  Expression *e2,            // right subexpression, or NULL for postfix inc/dec
+  OverloadableOp op,         // which operator this node is
+  ArgumentInfoArray &argInfo // carries info about overloaded func arg names
+) {
+  // 14.6.2.2 para 1
+  if (e1->type->containsGeneralizedDependent() ||
+      e2 && e2->type->containsGeneralizedDependent()) {
+    return env.dependentType();
+  }
+
+  if (!env.doOperatorOverload()) {
+    return NULL;
+  }
+
+  // check for operator overloading
+  if (e1->type->asRval()->isCompoundType() ||
+      e1->type->asRval()->isEnumType() ||
+      e2 && e2->type->asRval()->isCompoundType() ||
+      e2 && e2->type->asRval()->isEnumType()) {
+    OVERLOADINDTRACE("found overloadable binary " << toString(op) <<
+                     " near " << env.locStr());
+    StringRef opName = env.operatorName[op];
+
+    // for postfix inc/dec, the second parameter is 'int'
+    if (!e2) {
+      argInfo[1] = ArgumentInfo(SE_NONE, env.getSimpleType(ST_INT));
+    }
+
+    // prepare the overload resolver
+    OverloadResolver resolver(env, env.loc(), &env.errors,
+                              OF_OPERATOR,
+                              NULL, // I assume operators can't have explicit template arguments
+                              argInfo, 10 /*numCand*/);
+    if (op == OP_COMMA) {
+      // 13.3.1.2 para 9: no viable -> use built-in
+      resolver.emptyCandidatesIsOk = true;
+    }
+
+    // user-defined candidates
+    resolver.addUserOperatorCandidates(argInfo[0].type, argInfo[1].type, opName);
+
+    // built-in candidates
+    resolver.addBuiltinBinaryCandidates(op, argInfo[0], argInfo[1]);
+
+    // pick one
+    bool dummy;
+    Candidate const *winnerCand = resolver.resolveCandidate(dummy);
+    if (winnerCand) {
+      Variable *winner = winnerCand->var;
+      FunctionType *winnerFt = winner->type->asFunctionType();
+
+      if (!e2) {
+        // synthesize and tcheck a 0 for the second argument to postfix inc/dec
+        e2 = new E_intLit(env.str("0"));
+        e2->tcheck(env, e2);
+      }
+
+      env.possiblySetOverloadedFunctionVar(e1, winnerFt->params.nth(0)->type,
+                                           argInfo[0].overloadSet);
+      env.possiblySetOverloadedFunctionVar(e2, winnerFt->params.nth(1)->type,
+                                           argInfo[1].overloadSet);
+
+      if (!winner->hasFlag(DF_BUILTIN)) {
+        PQ_operator *pqo = new PQ_operator(SL_UNKNOWN, new ON_operator(op), opName);
+        if (winner->hasFlag(DF_MEMBER)) {
+          // replace 'a+b' with 'a.operator+(b)'
+          replacement = new E_funCall(
+            // function to invoke
+            new E_fieldAcc(e1, pqo),
+            // arguments
+            makeExprList1(e2)
+          );
+        }
+        else {
+          // replace 'a+b' with '<scope>::operator+(a,b)'
+          replacement = new E_funCall(
+            // function to invoke
+            new E_variable(env.makeFullyQualifiedName(winner->scope, pqo)),
+            // arguments
+            makeExprList2(e1, e2)
+          );
+        }
+
+        // for now, just re-check the whole thing
+        replacement->tcheck(env, replacement);
+        return replacement->type;
+      }
+
+      else {
+        // chose a built-in operator
+
+        // TODO: need to replace the arguments according to their
+        // conversions (if any)
+        //
+        // This is what causes in/t0148.cc to fail in Oink.
+
+        if (op == OP_BRACKETS) {
+          // built-in a[b] is equivalent to *(a+b)
+          //
+          // 2005-08-09 (in/t0530.cc): but we *cannot* do a recursive
+          // tcheck, because the '*' and '+' are not subject to
+          // overload resolution; so, compute types manually
+          //
+          // Note that this has the effect of making tcheck+prettyPrint
+          // not idempotent, since the output expression *(a+b) will
+          // be subject to overload resolution and therefore can mean
+          // something different ...
+
+          Type *ret = resolver.getReturnType(winnerCand);
+
+          E_binary *bin = new E_binary(e1, BIN_PLUS, e2);
+          bin->type = env.tfac.makePointerType(CV_NONE, ret->asRval());
+
+          E_deref *deref = new E_deref(bin);
+          deref->type = ret;
+
+          replacement = deref;
+          return deref->type;
+        }
+        else {
+          // get the correct return value, at least
+          Type *ret = resolver.getReturnType(winnerCand);
+          OVERLOADINDTRACE("computed built-in operator return type `" <<
+                           ret->toString() << "'");
+          return ret;
+        }
+      }
+    }
+  }
+
+  // not replaced
+  return NULL;
+}
+
+
+bool isArithmeticOrEnumType(Type *t)
+{
+  if (t->isSimpleType()) {
+    return isArithmeticType(t->asSimpleTypeC()->type);
+  }
+  return t->isEnumType();
+}
+
+
+Type *E_unary::itcheck_x(Env &env, Expression *&replacement)
+{
+  expr->tcheck(env, expr);
+
+  // consider the possibility of operator overloading
+  Type *ovlRet = resolveOverloadedUnaryOperator(
+    env, replacement, /*this,*/ expr, toOverloadableOp(op));
+  if (ovlRet) {
+    return ovlRet;
+  }
+
+  Type *t = expr->type->asRval();
+
+  // make sure 'expr' is compatible with given operator
+  switch (op) {
+    default:
+      xfailure("bad operator kind");
+
+    case UNY_PLUS:
+      // 5.3.1 para 6
+      if (isArithmeticOrEnumType(t)) {
+        return env.getSimpleType(applyIntegralPromotions(t));
+      }
+      if (t->isPointerType()) {
+        return t;
+      }
+      return env.error(t, stringc
+        << "argument to unary + must be of arithmetic, enumeration, or pointer type, not `"
+        << t->toString() << "'");
+
+    case UNY_MINUS:
+      // 5.3.1 para 7
+      if (isArithmeticOrEnumType(t)) {
+        return env.getSimpleType(applyIntegralPromotions(t));
+      }
+      return env.error(t, stringc
+        << "argument to unary - must be of arithmetic or enumeration type, not `"
+        << t->toString() << "'");
+
+    case UNY_NOT: {
+      // 5.3.1 para 8
+      Type *t_bool = env.getSimpleType(ST_BOOL);
+      if (!getImplicitConversion(env, expr->getSpecial(env.lang), t, t_bool)) {
+        env.error(t, stringc
+          << "argument to unary ! must be convertible to bool; `"
+          << t->toString() << "' is not");
+      }
+      return t_bool;
+    }
+
+    case UNY_BITNOT:
+      // 5.3.1 para 9
+      if (t->isIntegerType() || t->isEnumType()) {
+        return env.getSimpleType(applyIntegralPromotions(t));
+      }
+      return env.error(t, stringc
+        << "argument to unary ~ must be of integer or enumeration type, not `"
+        << t->toString() << "'");
+
+      // 5.3.1 para 9 also mentions an ambiguity with "~X()", which I
+      // tried to exercise in in/t0343.cc, but I can't seem to get it;
+      // so either Elsa already does what is necessary, or I do not
+      // understand the syntax adequately ....
+  }
+}
+
+
+Type *E_effect::itcheck_x(Env &env, Expression *&replacement)
+{
+  ArgumentInfoArray argInfo(2);
+  tcheckArgumentExpression(env, expr, argInfo[0]);
+
+  if (argInfo[0].overloadSet.isNotEmpty()) {
+    env.error(stringc << "cannot use overloaded function name with " << toString(op));
+  }
+
+  // consider the possibility of operator overloading
+  Type *ovlRet = isPrefix(op)?
+    resolveOverloadedUnaryOperator(
+      env, replacement, /*this,*/ expr, toOverloadableOp(op)) :
+    resolveOverloadedBinaryOperator(
+      env, replacement, /*this,*/ expr, NULL, toOverloadableOp(op), argInfo) ;
+  if (ovlRet) {
+    return ovlRet;
+  }
+
+  // TODO: make sure 'expr' is compatible with given operator
+
+  // dsw: FIX: check that the argument is an lvalue.
+
+  // Cppstd 5.2.6 "Increment and decrement: The value obtained by
+  // applying a postfix ++ ... .  The result is an rvalue."; Cppstd
+  // 5.3.2 "Increment and decrement: The operand of prefix ++ ... .
+  // The value ... is an lvalue."
+  Type *ret = expr->type->asRval();
+  if (op == EFF_PREINC || op == EFF_PREDEC) {
+    ret = env.makeReferenceType(ret);
+  }
+  return ret;
+}
+
+
+bool isComplexOrImaginary(Type *t)
+{
+  t = t->asRval();
+  return t->isSimpleType() &&
+         isComplexOrImaginary(t->asSimpleTypeC()->type);
+}
+
+Type *E_binary::itcheck_x(Env &env, Expression *&replacement)
+{
+  ArgumentInfoArray argInfo(2);
+  tcheckArgumentExpression(env, e1, argInfo[0]);
+  tcheckArgumentExpression(env, e2, argInfo[1]);
+
+  // help disambiguate t0182.cc
+  if (op == BIN_LESS && e1->type->isFunctionType()) {
+    // For C++, this rule is implied by 5.9, which does not permit
+    // conversions for function-typed operands.
+    //
+    // For C, this is implied by 6.5.8, which not only fails to
+    // provide conversions for function-typed operands, but doesn't
+    // even allow relational comparison of pointer-to-function-typed
+    // operands!  Of course, the latter is a ubiquitous extension so
+    // I will continue to allow it.
+    //
+    // Note that both GCC and ICC allow this.  However, I have only
+    // seen it happen in real code twice, and *both* times the real
+    // code actually contained a bug (the programmer intended to
+    // *call* the function, not compare its address), so I do not
+    // intend to replicate their bugs in this case.
+    // (in/gnu/bugs/gb0003.cc)
+    return env.error("cannot apply '<' to a function; instead, call it "
+                     "or explicitly take its address", EF_DISAMBIGUATES);
+  }
+
+  // gnu/c99 complex arithmetic?
+  #ifdef GNU_EXTENSION
+    if (isComplexOrImaginary(e1->type) || isComplexOrImaginary(e2->type)) {
+      return itcheck_complex_arith(env);
+    }
+  #endif // GNU_EXTENSION
+
+  // check for operator overloading
+  if (isOverloadable(op)) {
+    Type *ovlRet = resolveOverloadedBinaryOperator(
+      env, replacement, /*this,*/ e1, e2, toOverloadableOp(op), argInfo);
+    if (ovlRet) {
+      return ovlRet;
+    }
+  }
+
+  // TODO: much of what follows is obviated by the fact that
+  // 'resolveOverloadedBinaryOperator' now returns non-NULL for
+  // built-in operator candidates ...
+
+  if (op == BIN_BRACKETS) {
+    // built-in a[b] is equivalent to *(a+b)
+    replacement = new E_deref(new E_binary(e1, BIN_PLUS, e2));
+    replacement->tcheck(env, replacement);
+    return replacement->type;
+  }
+
+  // get types of arguments, converted to rval, and normalized with
+  // array-to-pointer and function-to-pointer conversions
+  Type *lhsType = env.operandRval(e1->type);
+  Type *rhsType = env.operandRval(e2->type);
+
+  switch (op) {
+    default: xfailure("illegal op code"); break;
+
+    case BIN_EQUAL:               // ==
+    case BIN_NOTEQUAL:            // !=
+    case BIN_LESS:                // <
+    case BIN_GREATER:             // >
+    case BIN_LESSEQ:              // <=
+    case BIN_GREATEREQ:           // >=
+
+    case BIN_AND:                 // &&
+    case BIN_OR:                  // ||
+    case BIN_IMPLIES:             // ==>
+    case BIN_EQUIVALENT:          // <==>
+      return env.getSimpleType(ST_BOOL);
+
+    case BIN_COMMA:
+      // dsw: I changed this to allow the following: &(3, a);
+      return e2->type/*rhsType*/;
+
+    case BIN_PLUS:                // +
+      // case: p + n
+      if (lhsType->isPointerType()) {
+        return lhsType;
+      }
+
+      // case: n + p
+      if (lhsType->isIntegerType() && rhsType->isPointerType()) {
+        return rhsType;         // a pointer type, that is
+      }
+
+      return usualArithmeticConversions(env.tfac, lhsType, rhsType);
+
+    case BIN_MINUS:               // -
+      // case: p - p
+      if (lhsType->isPointerType() && rhsType->isPointerType() ) {
+        return env.getSimpleType(ST_INT);
+      }
+
+      // case: p - n
+      if (lhsType->isPointerType()) {
+        return lhsType;
+      }
+
+      return usualArithmeticConversions(env.tfac, lhsType, rhsType);
+
+    case BIN_MULT:                // *
+    case BIN_DIV:                 // /
+    case BIN_MOD:                 // %
+      // in/t0533.cc
+      return usualArithmeticConversions(env.tfac, lhsType, rhsType);
+
+    case BIN_LSHIFT:              // <<
+    case BIN_RSHIFT:              // >>
+    case BIN_BITAND:              // &
+    case BIN_BITXOR:              // ^
+    case BIN_BITOR:               // |
+    case BIN_MINIMUM:             // <?
+    case BIN_MAXIMUM:             // >?
+      // default behavior of returning the left side is close enough for now.
+      break;
+
+    // BIN_ASSIGN can't appear in E_binary
+
+    case BIN_DOT_STAR:            // .*
+    case BIN_ARROW_STAR:          // ->*
+      // [cppstd 5.5]
+      if (op == BIN_ARROW_STAR) {
+        // left side should be a pointer to a class
+        if (!lhsType->isPointer()) {
+          return env.error(stringc
+            << "left side of ->* must be a pointer, not `"
+            << lhsType->toString() << "'");
+        }
+        lhsType = lhsType->asPointerType()->atType;
+      }
+
+      if (lhsType->isGeneralizedDependent()) {
+        return env.dependentType();    // in/k0001.cc
+      }
+
+      // left side should be a class
+      CompoundType *lhsClass = lhsType->ifCompoundType();
+      if (!lhsClass) {
+        return env.error(op==BIN_DOT_STAR?
+          "left side of .* must be a class or reference to a class" :
+          "left side of ->* must be a pointer to a class");
+      }
+
+      // right side should be a pointer to a member
+      if (!rhsType->isPointerToMemberType()) {
+        return env.error("right side of .* or ->* must be a pointer-to-member");
+      }
+      PointerToMemberType *ptm = rhsType->asPointerToMemberType();
+
+      // actual LHS class must be 'ptm->inClass()', or a
+      // class unambiguously derived from it
+      int subobjs = lhsClass->countBaseClassSubobjects(ptm->inClass());
+      if (subobjs == 0) {
+        return env.error(stringc
+          << "the left side of .* or ->* has type `" << lhsClass->name
+          << "', but this is not equal to or derived from `" << ptm->inClass()->name
+          << "', the class whose members the right side can point at");
+      }
+      else if (subobjs > 1) {
+        return env.error(stringc
+          << "the left side of .* or ->* has type `" << lhsClass->name
+          << "', but this is derived from `" << ptm->inClass()->name
+          << "' ambiguously (in more than one way)");
+      }
+
+      // the return type is essentially the 'atType' of 'ptm'
+      Type *ret = ptm->atType;
+
+      // 8.3.3 para 3: "A pointer to member shall not point to ... a
+      // member with reference type."  Scott says this can't happen
+      // here.
+      xassert(!ret->isReference());
+
+      // [cppstd 5.5 para 6]
+      // but it might be an lvalue if it is a pointer to a data
+      // member, and either
+      //   - op==BIN_ARROW_STAR, or
+      //   - op==BIN_DOT_STAR and 'e1->type' is an lvalue
+      if (op==BIN_ARROW_STAR ||
+          /*must be DOT_STAR*/ e1->type->isLval()) {
+        // this internally handles 'ret' being a function type
+        ret = makeLvalType(env, ret);
+      }
+
+      return ret;
+  }
+
+  // TODO: make sure 'expr' is compatible with given operator
+
+  return lhsType;
+}
+
+
+// someone took the address of 'var', and we must compute
+// the PointerToMemberType of that construct
+static Type *makePTMType(Env &env, Variable *var, SourceLoc loc)
+{
+  // cppstd: 8.3.3 para 3, can't be static
+  xassert(!var->hasFlag(DF_STATIC));
+
+  // this is essentially a consequence of not being static
+  if (var->type->isFunctionType()) {
+    xassert(var->type->asFunctionType()->isMethod());
+  }
+
+  // cppstd: 8.3.3 para 3, can't be cv void
+  if (var->type->isVoid()) {
+    return env.error(loc, "attempted to make a pointer to member to void");
+  }
+  // cppstd: 8.3.3 para 3, can't be a reference
+  if (var->type->isReference()) {
+    return env.error(loc, "attempted to make a pointer to member to a reference");
+  }
+
+  CompoundType *inClass0 = var->scope->curCompound;
+  xassert(inClass0);
+
+  return env.tfac.makePointerToMemberType
+    (inClass0, CV_NONE, var->type);
+}
+
+Type *E_addrOf::itcheck_x(Env &env, Expression *&replacement)
+{
+  LookupSet dummy;
+  return itcheck_addrOf_set(env, replacement, LF_NONE, dummy);
+}
+
+Type *E_addrOf::itcheck_addrOf_set(Env &env, Expression *&replacement,
+                                   LookupFlags flags, LookupSet &set)
+{
+  // might we be forming a pointer-to-member?
+  bool possiblePTM = false;
+  E_variable *evar = NULL;
+  // NOTE: do *not* unwrap any layers of parens:
+  // cppstd 5.3.1 para 3: "A pointer to member is only formed when
+  // an explicit & is used and its operand is a qualified-id not
+  // enclosed in parentheses."
+  if (expr->isE_variable()) {
+    evar = expr->asE_variable();
+
+    // cppstd 5.3.1 para 3: Nor is &unqualified-id a pointer to
+    // member, even within the scope of the unqualified-id's
+    // class.
+    // dsw: Consider the following situation: How do you know you
+    // &x isn't making a pointer to member?  Only because the name
+    // isn't fully qualified.
+    //   struct A {
+    //     int x;
+    //     void f() {int *y = &x;}
+    //   };
+    if (evar->name->hasQualifiers()) {
+      possiblePTM = true;
+
+      // suppress elaboration of 'this'; the situation where 'this'
+      // would be inserted is exactly the situation where a
+      // pointer-to-member is formed
+      flags |= LF_NO_IMPL_THIS;
+    }
+  }
+
+  // check 'expr'
+  tcheckExpression_set(env, expr/*INOUT*/, flags, set);
+
+  if (expr->type->isError()) {
+    // skip further checking because the tree is not necessarily
+    // as the later stages expect; e.g., an E_variable might have
+    // a NULL 'var' field
+    return expr->type;
+  }
+
+  // 14.6.2.2 para 1
+  if (expr->type->containsGeneralizedDependent()) {
+    return env.dependentType();
+  }
+
+  if (possiblePTM) {
+    // TODO: If the variable was the name of an overloaded function,
+    // then we will have not yet done resolution of the name, and
+    // consequently 'evar->var' may not be the correct function.
+
+    // make sure we instantiate any functions that have their address
+    // taken
+    xassert(evar->var);
+    env.ensureFuncBodyTChecked(evar->var);
+
+    if (evar->var->isNonStaticMember()) {
+      return makePTMType(env, evar->var, evar->name->loc);
+    }
+  }
+
+  // ok to take addr of function; special-case it so as not to weaken
+  // what 'isLval' means
+  if (expr->type->isFunctionType()) {
+    return env.makePtrType(expr->type);
+  }
+
+  // consider the possibility of operator overloading
+  Type *ovlRet = resolveOverloadedUnaryOperator(
+    env, replacement, /*this,*/ expr, OP_AMPERSAND);
+  if (ovlRet) {
+    return ovlRet;
+  }
+
+  if (!expr->type->isLval()) {
+    return env.error(expr->type, stringc
+      << "cannot take address of non-lvalue `"
+      << expr->type->toString() << "'");
+  }
+  ReferenceType *rt = expr->type->asReferenceType();
+
+  // change the "&" into a "*"
+  return env.makePtrType(rt->atType);
+}
+
+
+Type *E_deref::itcheck_x(Env &env, Expression *&replacement)
+{
+  ptr->tcheck(env, ptr);
+
+  // check for overloading
+  {
+    Type *ovlRet = resolveOverloadedUnaryOperator(
+      env, replacement, /*this,*/ ptr, OP_STAR);
+    if (ovlRet) {
+      return ovlRet;
+    }
+  }
+
+  // clone the type as it's taken out of one AST node, so it
+  // can then be used as the type of another AST node (this one)
+  Type *rt = ptr->type->asRval();
+
+  if (rt->isFunctionType()) {
+    return rt;                         // deref is idempotent on FunctionType-s
+  }
+
+  if (rt->isPointerType()) {
+    PointerType *pt = rt->asPointerType();
+
+    // dereferencing yields an lvalue
+    return makeLvalType(env, pt->atType);
+  }
+
+  // implicit coercion of array to pointer for dereferencing
+  if (rt->isArrayType()) {
+    return makeLvalType(env, rt->asArrayType()->eltType);
+  }
+
+  return env.error(rt, stringc
+    << "cannot dereference non-pointer type `" << rt->toString() << "'");
+}
+
+
+// This returns true if 'atype' is defining a type.  However,
+// this function is only called in C++ mode, because in C mode
+// it is legal to define a type in a cast.
+bool hasTypeDefn(ASTTypeId *atype)
+{
+  return atype->spec->isTS_classSpec() ||
+         atype->spec->isTS_enumSpec();
+}
+
+Type *E_cast::itcheck_x(Env &env, Expression *&replacement)
+{
+  // check the dest type
+  if (hasTypeDefn(ctype)) {
+    if (env.lang.isCplusplus) {
+      // 5.4p3: not allowed
+      return env.error(ctype->spec->loc, "cannot define types in a cast");
+    }
+    else {
+      // similar to the E_sizeofType case
+      if (!tcheckedType) {
+        InstantiationContextIsolator isolate(env, env.loc());
+        tcheckedType = true;
+
+        ASTTypeId::Tcheck tc(DF_NONE, DC_E_CAST);
+        ctype = ctype->tcheck(env, tc);
+      }
+    }
+  }
+
+  else {
+    // usual behavior
+    ASTTypeId::Tcheck tc(DF_NONE, DC_E_CAST);
+    ctype = ctype->tcheck(env, tc);
+  }
+
+  // check the source expression
+  expr->tcheck(env, expr);
+
+  // TODO: check that the cast makes sense
+
+  Type *ret = ctype->getType();
+
+  // This is a gnu extension: in C mode, if the expr is an lvalue,
+  // make the returned type an lvalue.  This is in direct
+  // contradiction to the C99 spec: Section 6.5.4, footnote 85: "A
+  // cast does not yield an lvalue".
+  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Lvalues.html
+  if (env.lang.lvalueFlowsThroughCast) {
+    if (expr->getType()->isReference() && !ret->isReference()) {
+      ret = env.makeReferenceType(ret);
+    }
+  }
+
+  return ret;
+}
+
+
+// try to convert t1 to t2 as per the rules in 5.16 para 3; return
+// NULL if conversion is not possible, otherwise return type to which
+// 't1' is converted (it is not always exactly 't2') and set 'ic'
+// accordingly
+Type *attemptCondConversion(Env &env, ImplicitConversion &ic /*OUT*/,
+                            Type *t1, Type *t2,
+                            SpecialExpr special1 // dsw: the special for t1
+                            ) {
+  // bullet 1: attempt direct conversion to lvalue
+  if (t2->isLval()) {
+    ic = getImplicitConversion(env, special1, t1, t2);
+    if (ic) {
+      return t2;
+    }
+  }
+
+  // bullet 2
+  CompoundType *t1Class = t1->asRval()->ifCompoundType();
+  CompoundType *t2Class = t2->asRval()->ifCompoundType();
+  if (t1Class && t2Class &&
+      (t1Class->hasBaseClass(t2Class) ||
+       t2Class->hasBaseClass(t1Class))) {
+    // bullet 2.1
+    if (t1Class->hasBaseClass(t2Class) &&
+        t2->asRval()->getCVFlags() >= t1->asRval()->getCVFlags()) {
+      ic.addStdConv(SC_IDENTITY);
+      return t2->asRval();
+    }
+    else {
+      return NULL;
+    }
+  }
+  else {
+    // bullet 2.2
+    t2 = t2->asRval();
+    ic = getImplicitConversion(env, special1, t1, t2);
+    if (ic) {
+      return t2;
+    }
+  }
+
+  return NULL;
+}
+
+
+// "array-to-pointer (4.2) and function-to-pointer (4.3) standard
+// conversions"; (for the moment) functionally identical to
+// 'normalizeParameterType' but specified by a different part of
+// cppstd...
+Type *arrAndFuncToPtr(Env &env, Type *t)
+{
+  if (t->isArrayType()) {
+    return env.makePtrType(t->asArrayType()->eltType);
+  }
+  if (t->isFunctionType()) {
+    return env.makePtrType(t);
+  }
+  return t;
+}
+
+
+// cppstd 5.9 "composite pointer type" computation
+Type *compositePointerType
+  (Env &env, PointerType *t1, PointerType *t2)
+{
+  // if either is pointer to void, result is void
+  if (t1->atType->isVoid() || t2->atType->isVoid()) {
+    CVFlags cv = t1->atType->getCVFlags() | t2->atType->getCVFlags();
+
+    // reuse t1 or t2 if possible
+    if (t1->atType->isVoid() && cv == t1->atType->getCVFlags()) {
+      return t1;
+    }
+    if (t2->atType->isVoid() && cv == t2->atType->getCVFlags()) {
+      return t2;
+    }
+
+    return env.tfac.makePointerType(CV_NONE,
+      env.tfac.getSimpleType(ST_VOID, cv));
+  }
+
+  // types must be similar... aw hell.  I don't understand what the
+  // standard wants, and my limited understanding is at odds with
+  // what both gcc and icc do so.... hammer time
+  bool whatev;
+  return computeLUB(env, t1, t2, whatev);
+}
+
+// cppstd 5.16 computation similar to composite pointer but
+// for pointer-to-member
+Type *compositePointerToMemberType
+  (Env &env, PointerToMemberType *t1, PointerToMemberType *t2)
+{
+  // hammer time
+  bool whatev;
+  return computeLUB(env, t1, t2, whatev);
+}
+
+
+// cppstd 5.16
+Type *E_cond::itcheck_x(Env &env, Expression *&replacement)
+{
+  cond->tcheck(env, cond);
+
+  // para 1: 'cond' converted to bool
+  if (!getImplicitConversion(env, cond->getSpecial(env.lang), cond->type,
+                             env.getSimpleType(ST_BOOL))) {
+    env.error(cond->type, stringc
+      << "cannot convert `" << cond->type->toString()
+      << "' to bool for conditional of ?:");
+  }
+  // TODO (elaboration): rewrite AST if a user-defined conversion was used
+
+  th->tcheck(env, th);
+  el->tcheck(env, el);
+
+  // 14.6.2.2 para 1
+  //
+  // Note that I'm interpreting 14.6.2.2 literally, to the point of
+  // regarding the entire ?: dependent if the condition is, even
+  // though the type of the condition cannot affect the type of the ?:
+  // expression.
+  if (cond->type->containsGeneralizedDependent() ||
+      th->type->containsGeneralizedDependent() ||
+      el->type->containsGeneralizedDependent()) {
+    return env.dependentType();
+  }
+
+  // pull out the types; during the processing below, we might change
+  // these to implement "converted operand used in place of ..."
+  Type *thType = th->type;
+  Type *elType = el->type;
+
+  Type *thRval = th->type->asRval();
+  Type *elRval = el->type->asRval();
+
+  if (!env.lang.isCplusplus) {
+    // ANSI C99 mostly requires that the types be the same, but gcc
+    // doesn't seem to enforce anything, so I won't either; and if
+    // they are different, it isn't clear what the type should be ...
+
+    bool bothLvals = thType->isLval() && elType->isLval();
+
+    // for in/gnu/d0095.c
+    if (thRval->isPointerType() &&
+        thRval->asPointerType()->atType->isVoid()) {
+      return bothLvals? elType : elRval;
+    }
+
+    // for in/c/t0025.c
+    if (elRval->isPointerType() &&
+        thRval->isIntegerType()) {
+      return bothLvals? elType : elRval;
+    }
+
+    return bothLvals? thType : thRval;
+  }
+
+  // para 2: if one or the other has type 'void'
+  {
+    bool thVoid = thRval->isSimple(ST_VOID);
+    bool elVoid = elRval->isSimple(ST_VOID);
+    if (thVoid || elVoid) {
+      if (thVoid && elVoid) {
+        return thRval;         // result has type 'void'
+      }
+
+      // the void-typed expression must be a 'throw' (can it be
+      // parenthesized?  a strict reading of the standard would say
+      // no..), and the whole ?: has the non-void type
+      if (thVoid) {
+        if (!th->isE_throw()) {
+          env.error("void-typed expression in ?: must be a throw-expression");
+        }
+        return arrAndFuncToPtr(env, elRval);
+      }
+      if (elVoid) {
+        if (!el->isE_throw()) {
+          env.error("void-typed expression in ?: must be a throw-expression");
+        }
+        return arrAndFuncToPtr(env, thRval);
+      }
+    }
+  }
+
+  // para 3: different types but at least one is a class type
+  if (!thRval->equals(elRval) &&
+      (thRval->isCompoundType() ||
+       elRval->isCompoundType())) {
+    // try to convert each to the other
+    ImplicitConversion ic_thToEl;
+    Type *thConv = attemptCondConversion(env, ic_thToEl, thType, elType, th->getSpecial(env.lang));
+    ImplicitConversion ic_elToTh;
+    Type *elConv = attemptCondConversion(env, ic_elToTh, elType, thType, el->getSpecial(env.lang));
+
+    if (thConv && elConv) {
+      return env.error("class-valued argument(s) to ?: are ambiguously inter-convertible");
+    }
+
+    if (thConv) {
+      if (ic_thToEl.isAmbiguous()) {
+        return env.error("in ?:, conversion of second arg to type of third is ambiguous");
+      }
+
+      // TODO (elaboration): rewrite AST according to 'ic_thToEl'
+      thType = thConv;
+      thRval = thType->asRval();
+    }
+
+    if (elConv) {
+      if (ic_elToTh.isAmbiguous()) {
+        return env.error("in ?:, conversion of third arg to type of second is ambiguous");
+      }
+
+      // TODO (elaboration): rewrite AST according to 'ic_elToTh'
+      elType = elConv;
+      elRval = elType->asRval();
+    }
+  }
+
+  // para 4: same-type lval -> result is that type
+  if (thType->isLval() &&
+      elType->isLval() &&
+      thType->equals(elType)) {
+    return thType;
+  }
+
+  // para 5: overload resolution
+  if (!thRval->equals(elRval) &&
+      (thRval->isCompoundType() || elRval->isCompoundType())) {
+    // collect argument info
+    ArgumentInfoArray args(2);
+    args[0].special = th->getSpecial(env.lang);
+    args[0].type = thType;
+    args[1].special = el->getSpecial(env.lang);
+    args[1].type = elType;
+
+    // prepare the overload resolver
+    OverloadResolver resolver(env, env.loc(), &env.errors,
+                              OF_NONE,
+                              NULL, // no template arguments
+                              args, 2 /*numCand*/);
+
+    // built-in candidates
+    resolver.addBuiltinBinaryCandidates(OP_QUESTION, args[0], args[1]);
+
+    // pick one
+    bool dummy;
+    Candidate const *winnerCand = resolver.resolveCandidate(dummy);
+    if (winnerCand) {
+      Variable *winner = winnerCand->var;
+      xassert(winner->hasFlag(DF_BUILTIN));
+
+      // TODO (elaboration): need to replace the arguments according
+      // to their conversions (if any)
+
+      // get the correct return value, at least
+      Type *ret = resolver.getReturnType(winnerCand);
+      OVERLOADINDTRACE("computed built-in operator return type `" <<
+                       ret->toString() << "'");
+
+      // para 5 ends by saying (in effect) that 'ret' should be used
+      // as the new 'thType' and 'elType' and then keep going on to
+      // para 6; but I can't see how that would be different from just
+      // returning here...
+      return ret;
+    }
+  }
+
+  // para 6: final standard conversions (conversion to rvalues has
+  // already been done, so use the '*Rval' variables)
+  {
+    thRval = arrAndFuncToPtr(env, thRval);
+    elRval = arrAndFuncToPtr(env, elRval);
+
+    // bullet 1
+    if (thRval->equals(elRval, MF_IGNORE_TOP_CV /*(in/t0499.cc)*/)) {
+      return thRval;
+    }
+
+    // bullet 2
+    if (isArithmeticOrEnumType(thRval) &&
+        isArithmeticOrEnumType(elRval)) {
+      return usualArithmeticConversions(env.tfac, thRval, elRval);
+    }
+
+    // bullet 3
+    if (thRval->isPointerType() && el->getSpecial(env.lang) == SE_ZERO) {
+      return thRval;
+    }
+    if (elRval->isPointerType() && th->getSpecial(env.lang) == SE_ZERO) {
+      return elRval;
+    }
+    if (thRval->isPointerType() && elRval->isPointerType()) {
+      Type *ret = compositePointerType(env,
+        thRval->asPointerType(), elRval->asPointerType());
+      if (!ret) { goto incompatible; }
+      return ret;
+    }
+
+    // bullet 4
+    if (thRval->isPointerToMemberType() && el->getSpecial(env.lang) == SE_ZERO) {
+      return thRval;
+    }
+    if (elRval->isPointerToMemberType() && th->getSpecial(env.lang) == SE_ZERO) {
+      return elRval;
+    }
+    if (thRval->isPointerToMemberType() && elRval->isPointerToMemberType()) {
+      Type *ret = compositePointerToMemberType(env,
+        thRval->asPointerToMemberType(), elRval->asPointerToMemberType());
+      if (!ret) { goto incompatible; }
+      return ret;
+    }
+  }
+
+incompatible:
+  return env.error(stringc
+    << "incompatible ?: argument types `" << thRval->toString()
+    << "' and `" << elRval->toString() << "'");
+}
+
+
+Type *E_sizeofType::itcheck_x(Env &env, Expression *&replacement)
+{
+  if (hasTypeDefn(atype)) {
+    if (env.lang.isCplusplus) {
+      // 5.3.3p5: cannot define types in 'sizeof'; the reason Elsa
+      // enforces this rule is that if we allow type definitions then
+      // there can be bad interactions with disambiguation (in/k0035.cc)
+      return env.error(atype->spec->loc,
+                       "cannot define types in a 'sizeof' expression");
+    }
+    else {
+      // In C mode, it is legal to define types in a 'sizeof'; but
+      // there are far fewer things that can go wrong during
+      // disambiguation, so use a simple idempotency trick
+      // (in/c/dC0019.c)
+      if (!tchecked) {
+        InstantiationContextIsolator isolate(env, env.loc());
+        tchecked = true;
+
+        ASTTypeId::Tcheck tc(DF_NONE, DC_E_SIZEOFTYPE);
+        atype = atype->tcheck(env, tc);
+      }
+    }
+  }
+
+  else {
+    // usual behavior
+    ASTTypeId::Tcheck tc(DF_NONE, DC_E_SIZEOFTYPE);
+    atype = atype->tcheck(env, tc);
+  }
+
+  return env.sizeofType(atype->getType(), size, NULL /*expr*/);
+}
+
+
+// Type check 'expr', given that it is being used to set the value of
+// something with type 'target', and so we can use that as the basis
+// for resolving the address of an overloaded function name.
+void tcheckExpression_possibleAddrOfOverload
+  (Env &env, Expression *&expr, Type *target)
+{
+  LookupSet set;
+  tcheckExpression_set(env, expr, LF_TEMPL_PRIMARY, set);
+  env.possiblySetOverloadedFunctionVar(expr, target, set);
+}
+
+
+Type *E_assign::itcheck_x(Env &env, Expression *&replacement)
+{
+  ArgumentInfoArray argInfo(2);
+  tcheckArgumentExpression(env, target, argInfo[0]);
+  tcheckArgumentExpression(env, src, argInfo[1]);
+
+  // check for operator overloading
+  {
+    Type *ovlRet = resolveOverloadedBinaryOperator(
+      env, replacement, /*this,*/ target, src,
+      toOverloadableOp(op, true /*assignment*/), argInfo);
+    if (ovlRet) {
+      return ovlRet;
+    }
+  }
+
+  // TODO: make sure 'target' and 'src' make sense together with 'op'
+
+  // this finalizes an overloaded function name if the use
+  // of '=' was not overloadable
+  env.possiblySetOverloadedFunctionVar(src, target->type, argInfo[1].overloadSet);
+
+  return target->type;
+}
+
+
+Type *E_new::itcheck_x(Env &env, Expression *&replacement)
+{
+  // check the placement args
+  {
+    ArgumentInfoArray argInfo(placementArgs->count() + 1);
+    placementArgs = tcheckArgExprList(placementArgs, env, argInfo);
+
+    // TODO: check the environment for declaration of an operator 'new'
+    // which accepts the given placement args
+  }
+
+  // typecheck the typeid in E_new context; it returns the
+  // array size for new[] (if any)
+  ASTTypeId::Tcheck tc(DF_NONE, DC_E_NEW);
+  tc.newSizeExpr = &arraySize;
+  atype = atype->tcheck(env, tc);
+
+  // grab the type of the objects to allocate
+  Type *t = atype->getType();
+
+  // if the named type is an incomplete type, that will already have
+  // been detected and reported (when 'atype' was tchecked), and 't'
+  // will be the error type, which is safe to propagate into the code
+  // below and beyond
+
+  // The AST has the capability of recording whether argument parens
+  // (the 'new-initializer' in the terminology of cppstd)
+  // syntactically appeared, and this does matter for static
+  // semantics; see cppstd 5.3.4 para 15.  However, for our purposes,
+  // it will likely suffice to simply pretend that anytime 't' refers
+  // to a class type, missing parens were actually present.
+  if (t->isCompoundType() && !ctorArgs) {
+    ctorArgs = new ArgExpressionListOpt(NULL /*list*/);
+  }
+
+  if (ctorArgs) {
+    ArgumentInfoArray argInfo(ctorArgs->list->count() + 1);
+    ctorArgs->list = tcheckArgExprList(ctorArgs->list, env, argInfo);
+    Variable *ctor0 =
+      outerResolveOverload_ctor(env, env.loc(), t, argInfo);
+    // ctor0 can be null when the type is a simple type, such as an
+    // int; I assume that ctor0 being NULL is the correct behavior in
+    // that case
+    ctorVar = env.storeVar(ctor0);
+    compareCtorArgsToParams(env, ctor0, ctorArgs->list, argInfo);
+  }
+
+  return env.makePtrType(t);
+}
+
+
+Type *E_delete::itcheck_x(Env &env, Expression *&replacement)
+{
+  expr->tcheck(env, expr);
+
+  Type *t = expr->type->asRval();
+
+  if (t->isGeneralizedDependent()) {
+    // fine; in/k0020.cc
+  }
+  else if (!t->isPointer()) {
+    env.error(t, stringc
+      << "can only delete pointers, not `" << t->toString() << "'");
+  }
+
+  return env.getSimpleType(ST_VOID);
+}
+
+
+Type *E_throw::itcheck_x(Env &env, Expression *&replacement)
+{
+  if (expr) {
+    expr->tcheck(env, expr);
+  }
+  else {
+    // TODO: make sure that we're inside a 'catch' clause
+  }
+
+  return env.getSimpleType(ST_VOID);
+}
+
+
+Type *E_keywordCast::itcheck_x(Env &env, Expression *&replacement)
+{
+  if (env.lang.isCplusplus && hasTypeDefn(ctype)) {
+    // 5.2.7p1: not allowed in dynamic_cast
+    // 5.2.9p1: not allowed in static_cast
+    // 5.2.10p1: not allowed in reinterpret_cast
+    // 5.2.11p1: not allowed in const_cast
+    return env.error(ctype->spec->loc, stringc
+      << "cannot define types in a " << toString(key));
+  }
+
+  ASTTypeId::Tcheck tc(DF_NONE, DC_E_KEYWORDCAST);
+  ctype = ctype->tcheck(env, tc);
+  expr->tcheck(env, expr);
+
+  // TODO: make sure that 'expr' can be cast to 'type'
+  // using the 'key'-style cast
+
+  return ctype->getType();
+}
+
+
+Type *E_typeidExpr::itcheck_x(Env &env, Expression *&replacement)
+{
+  expr->tcheck(env, expr);
+  return env.type_info_const_ref();
+}
+
+
+Type *E_typeidType::itcheck_x(Env &env, Expression *&replacement)
+{
+  ASTTypeId::Tcheck tc(DF_NONE, DC_E_TYPEIDTYPE);
+  ttype = ttype->tcheck(env, tc);
+  return env.type_info_const_ref();
+}
+
+
+Type *E_grouping::itcheck_x(Env &env, Expression *&replacement)
+{
+  LookupSet dummy;
+  return itcheck_grouping_set(env, replacement, LF_NONE, dummy);
+}
+
+Type *E_grouping::itcheck_grouping_set(Env &env, Expression *&replacement,
+                                       LookupFlags flags, LookupSet &set)
+{
+  tcheckExpression_set(env, expr, flags, set);
+
+  // 2005-08-14: Let's try throwing away the E_groupings as part
+  // of type checking.
+  replacement = expr;
+
+  return expr->type;
+}
+
+
+// --------------------- Expression constEval ------------------
+// TODO: Currently I do not implement the notion of "value-dependent
+// expression" (cppstd 14.6.2.3).  But, I believe a good way to do
+// that is to extend 'constEval' so it can return a code indicating
+// that the expression *is* constant, but is also value-dependent.
+
+bool Expression::constEval(Env &env, int &result) const
+{
+  bool dependent;
+  return constEval(env, result, dependent);
+}
+
+bool Expression::constEval(Env &env, int &result, bool &dependent) const
+{
+  dependent = false;
+
+  ConstEval cenv(env.dependentVar);
+
+  CValue val = constEval(cenv);
+  if (val.isError()) {
+    env.error(*(val.getWhy()));
+    delete val.getWhy();
+    return false;
+  }
+  else if (val.isDependent()) {
+    dependent = true;
+    return true;
+  }
+  else if (val.isIntegral()) {
+    result = val.getIntegralValue();
+    return true;
+  }
+  else {
+    env.error("expected integral-typed constant expression");
+    return false;
+  }
+}
+
+
+bool Expression::hasUnparenthesizedGT(Expression *&expr)
+{
+  if (expr->ambiguity) {
+    Expression *origExpr = expr;
+
+    // We are asking whether an ambiguous expression has an
+    // unparenthesized greater-than operator (UGTO), because the
+    // parser wants to reject such things.  But this expression is
+    // ambiguous!  So, if some of the alternatives contain UGTO
+    // but others do not, simply remove the UGTO alternatives and
+    // then return false.  If they *all* have UGTO, return true.
+    Expression **alt = &expr;
+    while (*alt) {
+      if ((*alt)->ihasUnparenthesizedGT()) {
+        // remove this one from the list
+        TRACE("cancel", "removed an ambiguous UGTO alternative");
+        *alt = (*alt)->ambiguity;
+      }
+      else {
+        // move to the next element
+        alt = &( (*alt)->ambiguity );
+      }
+    }
+
+    if (expr) {
+      // at least one non-UGTO alternative remains
+      return false;
+    }
+    else {
+      // (in/c/dC0030.c) Do not leave 'expr' nullified, since that can
+      // mess up other queries on this AST; instead, put back the
+      // first one and nullify its ambiguity link.  This
+      // interpretation should still be rejected, but this way it is a
+      // well-formed AST.
+      expr = origExpr;
+      expr->ambiguity = NULL;
+
+      // all have UGTO
+      return true;
+    }
+  }
+
+  // easy case
+  return expr->ihasUnparenthesizedGT();
+}
+
+bool Expression::ihasUnparenthesizedGT()
+{
+  // recursively dig down into any subexpressions which syntactically
+  // aren't enclosed in parentheses or brackets
+  ASTSWITCH(Expression, this) {
+    ASTCASE(E_funCall, f)
+      return hasUnparenthesizedGT(f->func);
+
+    ASTNEXT(E_fieldAcc, f)
+      return hasUnparenthesizedGT(f->obj);
+
+    ASTNEXT(E_unary, u)
+      return hasUnparenthesizedGT(u->expr);
+
+    ASTNEXT(E_effect, e)
+      return hasUnparenthesizedGT(e->expr);
+
+    ASTNEXT(E_binary, b)
+      if (b->op == BIN_GREATER) {
+        // all this just to find one little guy..
+        return true;
+      }
+
+      return hasUnparenthesizedGT(b->e1) ||
+             hasUnparenthesizedGT(b->e2);
+
+    ASTNEXT(E_addrOf, a)
+      return hasUnparenthesizedGT(a->expr);
+
+    ASTNEXT(E_deref, d)
+      return hasUnparenthesizedGT(d->ptr);
+
+    ASTNEXT(E_cast, c)
+      return hasUnparenthesizedGT(c->expr);
+
+    ASTNEXT(E_cond, c)
+      return hasUnparenthesizedGT(c->cond) ||
+             hasUnparenthesizedGT(c->th) ||
+             hasUnparenthesizedGT(c->el);
+
+    ASTNEXT(E_assign, a)
+      return hasUnparenthesizedGT(a->target) ||
+             hasUnparenthesizedGT(a->src);
+
+    ASTNEXT(E_delete, d)
+      return hasUnparenthesizedGT(d->expr);
+
+    ASTNEXT(E_throw, t)
+      return t->expr && hasUnparenthesizedGT(t->expr);
+
+    ASTDEFAULT
+      // everything else, esp. E_grouping, is false
+      return extHasUnparenthesizedGT();
+
+    ASTENDCASE
+  }
+}
+
+bool Expression::extHasUnparenthesizedGT()
+{
+  return false;
+}
+
+
+// can 0 be cast to 't' and still be regarded as a null pointer
+// constant?
+bool allowableNullPtrCastDest(CCLang &lang, Type *t)
+{
+  // C++ (4.10, 5.19)
+  if (t->isIntegerType() || t->isEnumType()) {
+    return true;
+  }
+
+  // C99 6.3.2.3: in C, void* casts are also allowed
+  if (!lang.isCplusplus &&
+      t->isPointerType() &&
+      t->asPointerType()->atType->isVoid()) {
+    return true;
+  }
+
+  return false;
+}
+
+SpecialExpr Expression::getSpecial(CCLang &lang) const
+{
+  ASTSWITCHC(Expression, this) {
+    ASTCASEC(E_intLit, i)
+      return i->i==0? SE_ZERO : SE_NONE;
+
+    ASTNEXTC1(E_stringLit)
+      return SE_STRINGLIT;
+
+    // 9/23/04: oops, forgot this
+    ASTNEXTC(E_grouping, e)
+      return e->expr->getSpecial(lang);
+
+    // 9/24/04: cppstd 4.10: null pointer constant is integral constant
+    // expression (5.19) that evaluates to 0.
+    // cppstd 5.19: "... only type conversions to integral or enumeration
+    // types can be used ..."
+    ASTNEXTC(E_cast, e)
+      if (allowableNullPtrCastDest(lang, e->ctype->getType()) &&
+          e->expr->getSpecial(lang) == SE_ZERO) {
+        return SE_ZERO;
+      }
+      return SE_NONE;
+
+    ASTDEFAULTC
+      return SE_NONE;
+
+    ASTENDCASEC
+  }
+}
+
+
+// ------------------- FullExpression -----------------------
+void FullExpression::tcheck(Env &env)
+{
+  expr->tcheck(env, expr);
+}
+
+
+// ExpressionListOpt
+
+// ----------------------- Initializer --------------------
+void IN_expr::tcheck(Env &env, Type *target)
+{
+  // TODO: check the initializer for compatibility with 'target'
+
+  // limited form of checking: use 'target' to resolve 'e' if it
+  // names an overloaded function
+  tcheckExpression_possibleAddrOfOverload(env, e, target);
+}
+
+
+// initialize 'type' with expressions drawn from 'initIter'
+void initializeAggregate(Env &env, Type *type,
+                         ASTListIterNC<Initializer> &initIter)
+{
+  if (initIter.isDone()) {
+    return;
+  }
+
+  if (initIter.data()->isIN_compound()) {
+    // match this entire bracketing with 'type'
+    initIter.data()->tcheck(env, type);
+    initIter.adv();
+    return;
+  }
+
+  if (type->isArrayType()) {
+    // initialize the array element type with successive initializers
+    ArrayType *at = type->asArrayType();
+
+    int limit = (at->hasSize()? at->size : -1);
+    while (limit != 0 && !initIter.isDone()) {
+      initializeAggregate(env, at->eltType, initIter);
+      limit--;
+    }
+  }
+
+  else if (type->isCompoundType()) {
+    CompoundType *ct = type->asCompoundType();
+
+    if (ct->isAggregate()) {
+      // 8.5.1: initialize successive data fields with successive initializers
+      SObjListIter<Variable> memberIter(ct->dataMembers);
+      if (memberIter.isDone()) {    // no data fields?
+        env.error(stringc << "can't initialize memberless aggregate "
+                          << ct->keywordAndName());
+        initIter.adv();    // avoid infinite loop possibility
+      }
+      while (!memberIter.isDone() && !initIter.isDone()) {
+        initializeAggregate(env, memberIter.data()->type, initIter);
+        memberIter.adv();
+      }
+    }
+    else {
+      Initializer *init = initIter.data();
+      initIter.adv();
+
+      // 8.5p14: initialize using a constructor
+
+      if (init->isIN_ctor()) {
+        init->tcheck(env, type);
+        return;
+      }
+
+      xassert(init->isIN_expr());
+      Expression *&arg = init->asIN_expr()->e;
+      arg->tcheck(env, arg);
+
+      ImplicitConversion ic = getImplicitConversion(env,
+        arg->getSpecial(env.lang),
+        arg->getType(),
+        type,
+        false /*destIsReceiver*/);
+      if (!ic) {
+        env.error(arg->getType(), stringc
+          << "cannot convert initializer type `" << arg->getType()->toString()
+          << "' to type `" << type->toString() << "'");
+      }
+    }
+  }
+
+  else {
+    // down to an element type
+    initIter.data()->tcheck(env, type);
+    initIter.adv();
+  }
+}
+
+
+void IN_compound::tcheck(Env &env, Type *type)
+{
+  // NOTE: I ignore the FullExpressionAnnot *annot
+
+  // kick off a recursion for this list of initializers
+  ASTListIterNC<Initializer> initIter(inits);
+  initializeAggregate(env, type, initIter);
+
+  // we should have consumed them all
+  if (!initIter.isDone()) {
+    // This is a weak error because of designated initializers,
+    // e.g., in/gnu/t0130.cc and in/c99/t0133.cc.  Once we get
+    // the compound_init stuff folded into Elsa I should be able
+    // to turn this into a real error.
+    //
+    // 2005-04-15: for the moment it is more annoying than helpful...
+    //env.weakError(loc, stringc
+    //  << "too many initializers (" << inits.count()
+    //  << ") supplied for `" << type->toString() << "'");
+
+    // tcheck the extra exprs anyway
+    while (!initIter.isDone()) {
+      initIter.data()->tcheck(env, type /*wrong but whatever*/);
+      initIter.adv();
+    }
+  }
+}
+
+
+void IN_ctor::tcheck(Env &env, Type *destType)
+{
+  // check argument expressions
+  ArgumentInfoArray argInfo(args->count() + 1);
+  args = tcheckArgExprList(args, env, argInfo);
+
+  // 8.5p14: if this was originally a copy-initialization (IN_expr),
+  // and the source type is not the same class as or derived class
+  // of the destination type, then we first implicitly convert the
+  // source to the dest
+  if (was_IN_expr) {
+    Expression *src = args->first()->expr;
+    Type *srcType = src->type;
+    if (srcType->isCompoundType() &&
+        destType->isCompoundType() &&
+        srcType->asCompoundType()->hasBaseClass(destType->asCompoundType())) {
+      // this is the scenario where we treat IN_expr the same as
+      // IN_ctor, even for class types, so was_IN_expr is irrelevant
+    }
+    else {
+      // first, do an implicit conversion
+      ImplicitConversion ic = getImplicitConversion(env,
+        src->getSpecial(env.lang),
+        srcType,
+        destType,
+        false /*destIsReceiver*/);
+      if (!ic) {
+        env.error(srcType, stringc
+          << "cannot convert initializer type `" << srcType->toString()
+          << "' to target type `" << destType->toString() << "'");
+        return;
+      }
+
+      // rewrite the AST to reflect the use of any user-defined
+      // conversions
+      if (ic.kind == ImplicitConversion::IC_USER_DEFINED) {
+        if (ic.user->type->asFunctionType()->isConstructor()) {
+          // wrap 'args' in an E_constructor
+          TypeSpecifier *destTS = new TS_type(loc, destType);
+          E_constructor *ector = new E_constructor(destTS, args);
+          ector->type = destType;
+          ector->ctorVar = ic.user;
+          args = FakeList<ArgExpression>::makeList(new ArgExpression(ector));
+
+          // the variable will now be initialized by this 'ector',
+          // which has type 'destType'
+          srcType = destType;
+        }
+        else {
+          // wrap 'args' in an E_funCall of a conversion function
+          E_fieldAcc *efacc = new E_fieldAcc(src, new PQ_variable(loc, ic.user));
+          efacc->type = ic.user->type;
+          efacc->field = ic.user;
+          E_funCall *efc = new E_funCall(efacc, FakeList<ArgExpression>::emptyList());
+          efc->type = ic.user->type->asFunctionType()->retType;
+          args = FakeList<ArgExpression>::makeList(new ArgExpression(efc));
+
+          // variable initialized by result of calling the conversion
+          srcType = efc->type;
+        }
+      }
+
+      argInfo[1].special = SE_NONE;
+      argInfo[1].type = srcType;
+      ctorVar = env.storeVar(
+        outerResolveOverload_ctor(env, loc, destType, argInfo));
+
+      // don't do the final comparison; it will be confused by
+      // the discrepancy between 'args' and 'argInfo', owing to
+      // not having rewritten the AST above
+      return;
+    }
+  }
+
+  ctorVar = env.storeVar(
+    outerResolveOverload_ctor(env, loc, destType, argInfo));
+  compareCtorArgsToParams(env, ctorVar, args, argInfo);
+}
+
+
+// -------------------- TemplateDeclaration ---------------
+void tcheckTemplateParameterList(Env &env, TemplateParameter *&src,
+                                 SObjList<Variable> &tparams)
+{
+  xassert(tparams.isEmpty());
+  int paramCt = 0;
+
+  // keep track of the previous node in the list, so we can string
+  // together the final disambiguated sequence
+  TemplateParameter **prev = &src;
+
+  TemplateParameter *tp = *prev;
+  while (tp) {
+    // disambiguate and check 'tp'
+    tp = tp->tcheck(env);
+
+    // string up the chosen one
+    xassert(tp->ambiguity == NULL);     // these links should all be cut now
+    *prev = tp;
+
+    // add it to 'tparams' (reverse order)
+    tparams.prepend(tp->var);
+    tp->var->setParameterOrdinal(paramCt++);
+
+    // follow the 'next' link in 'tp', as it was the chosen one
+    prev = &(tp->next);
+    tp = *prev;
+  }
+
+  // fix 'tparams'
+  tparams.reverse();
+}
+
+
+void TemplateDeclaration::tcheck(Env &env)
+{
+  // disallow templates inside functions
+  if (env.enclosingKindScope(SK_FUNCTION)) {
+    env.error("template declaration in function or local class");
+    return;
+  }
+
+  // make a new scope to hold the template parameters
+  Scope *paramScope = env.enterScope(SK_TEMPLATE_PARAMS, "template declaration parameters");
+
+  // check each of the parameters, i.e. enter them into the scope
+  // and its 'templateParams' list
+  tcheckTemplateParameterList(env, params, paramScope->templateParams);
+
+  // mark the new scope as unable to accept new names, so
+  // that the function or class being declared will be entered
+  // into the scope above us
+  paramScope->canAcceptNames = false;
+
+  // in what follows, ignore errors that are not disambiguating
+  //bool prev = env.setDisambiguateOnly(true);
+  //
+  // update: moved this inside Function::tcheck and TS_classSpec::tcheck
+  // so that the declarators would still get full checking
+
+  // check the particular declaration
+  itcheck(env);
+
+  // restore prior error mode
+  //env.setDisambiguateOnly(prev);
+
+  // remove the template argument scope
+  env.exitScope(paramScope);
+}
+
+
+void TD_func::itcheck(Env &env)
+{
+  // check the function definition; internally this will get
+  // the template parameters attached to the function type
+  f->tcheck(env);
+
+  // instantiate any instantiations that were requested but delayed
+  // due to not having the definition
+  env.instantiateForwardFunctions(f->nameAndParams->var);
+
+  // 8/11/04: The big block of template code that used to be here
+  // was superceded by activity in Declarator::mid_tcheck.
+}
+
+
+void TD_decl::itcheck(Env &env)
+{
+  if (env.secondPassTcheck) {
+    // TS_classSpec is only thing of interest
+    if (d->spec->isTS_classSpec()) {
+      d->spec->asTS_classSpec()->tcheck(env, d->dflags);
+    }
+    return;
+  }
+
+  // cppstd 14 para 3: there can be at most one declarator
+  // in a template declaration
+  if (d->decllist->count() > 1) {
+    env.error("there can be at most one declarator in a template declaration");
+  }
+
+  // is this like the old TD_class?
+  bool likeTD_class = d->spec->isTS_classSpec() || d->spec->isTS_elaborated();
+
+  // check the declaration; works like TD_func because D_func is the
+  // place we grab template parameters, and that's shared by both
+  // definitions and prototypes
+  DisambiguateOnlyTemp disOnly(env, !likeTD_class);
+  d->tcheck(env, DC_TD_DECL);
+}
+
+
+void TD_tmember::itcheck(Env &env)
+{
+  // just recursively introduce the next level of parameters; the
+  // new take{C,F}TemplateInfo functions know how to get parameters
+  // out of multiple layers of nested template scopes
+  d->tcheck(env);
+}
+
+
+// ------------------- TemplateParameter ------------------
+TemplateParameter *TemplateParameter::tcheck(Env &env)
+{
+  int dummy = 0;
+  if (!ambiguity) {
+    mid_tcheck(env, dummy);
+    return this;
+  }
+
+  return resolveAmbiguity(this, env, "TemplateParameter", false /*priority*/, dummy);
+}
+
+
+void TemplateParameter::mid_tcheck(Env &env, int &dummy)
+{
+  itcheck(env, dummy);
+}
+
+
+void TP_type::itcheck(Env &env, int&)
+{
+  if (!name) {
+    // name them all for uniformity
+    name = env.getAnonName("tparam", NULL);
+  }
+
+  // cppstd 14.1 is a little unclear about whether the type name is
+  // visible to its own default argument; but that would make no
+  // sense, so I'm going to check the default type first
+  //
+  // 2005-04-08: No, the usual point of declaration rules (3.3.1p1)
+  // apply, so it is visible in its default arg.  However, 14.1p14
+  // then says it is illegal to use a template param in its own
+  // default arg.  I'm not sure what I want to do about this...
+  if (defaultType) {
+    ASTTypeId::Tcheck tc(DF_NONE, DC_TP_TYPE);
+    defaultType = defaultType->tcheck(env, tc);
+  }
+
+  // the standard is not clear about whether the user code should
+  // be able to do this:
+  //   template <class T>
+  //   int f(class T &t)      // can use "class T" instead of just "T"?
+  //   { ... }
+  // my approach of making a TypeVariable, instead of calling
+  // it a CompoundType with a flag for 'is type variable', rules
+  // out the subsequent use of "class T" ...
+  //
+  // 2005-04-17: I noticed that in fact 7.1.5.3p2 addresses this, and
+  // agrees it is not legal.
+
+  // make a type variable for this thing
+  TypeVariable *tvar = new TypeVariable(name);
+  CVAtomicType *fullType = env.makeType(tvar);
+
+  // make a typedef variable for this type
+  this->var = env.makeVariable(loc, name, fullType,
+                               DF_TYPEDEF | DF_TEMPL_PARAM);
+  tvar->typedefVar = var;
+  if (defaultType) {
+    var->defaultParamType = defaultType->getType();
+  }
+
+  // if the default argument had an error, then do not add anything to
+  // the environment, because the error could be due to an ambiguity
+  // that is going to be resolved as *not* the current interpretation
+  if (defaultType && defaultType->getType()->isError()) {
+    return;
+  }
+
+  if (name) {
+    // introduce 'name' into the environment
+    if (!env.addVariable(var)) {
+      env.error(stringc
+        << "duplicate template parameter `" << name << "'",
+        EF_NONE);
+    }
+  }
+}
+
+
+void TP_nontype::itcheck(Env &env, int&)
+{
+  // TODO: I believe I want to remove DF_PARAMETER.
+  ASTTypeId::Tcheck tc(DF_PARAMETER | DF_TEMPL_PARAM, DC_TP_NONTYPE);
+
+  // check the parameter; this actually adds it to the environment
+  // too, so we don't need to do so here
+  param = param->tcheck(env, tc);
+  this->var = param->decl->var;
+}
+
+
+// -------------------- TemplateArgument ------------------
+TemplateArgument *TemplateArgument::tcheck(Env &env, STemplateArgument &sarg)
+{
+  if (!ambiguity) {
+    // easy case
+    mid_tcheck(env, sarg);
+    return this;
+  }
+
+  // generic resolution: whatever tchecks is selected
+  return resolveAmbiguity(this, env, "TemplateArgument", false /*priority*/, sarg);
+}
+
+void TemplateArgument::mid_tcheck(Env &env, STemplateArgument &sarg)
+{
+  itcheck(env, sarg);
+}
+
+void TA_type::itcheck(Env &env, STemplateArgument &sarg)
+{
+  ASTTypeId::Tcheck tc(DF_NONE, DC_TA_TYPE);
+  type = type->tcheck(env, tc);
+
+  Type *t = type->getType();
+  sarg.setType(t);
+}
+
+void TA_nontype::itcheck(Env &env, STemplateArgument &sarg)
+{
+  expr->tcheck(env, expr);
+  env.setSTemplArgFromExpr(sarg, expr);
+}
+
+
+void TA_templateUsed::itcheck(Env &env, STemplateArgument &sarg)
+{
+  // nothing to do; leave 'sarg' as STA_NONE
+}
+
+
+// -------------------------- NamespaceDecl -------------------------
+void ND_alias::tcheck(Env &env)
+{
+  // 2005-02-26: at this point the only thing being done is type
+  // checking template arguments, which should not even be present,
+  // but I do it anyway for uniformity
+  tcheckPQName(original, env, NULL /*scope*/, LF_NONE);
+
+  // find the namespace we're talking about
+  Variable *origVar = env.lookupPQ_one(original, LF_ONLY_NAMESPACES);
+  if (!origVar) {
+    env.error(stringc
+      << "could not find namespace `" << *original << "'");
+    return;
+  }
+  xassert(origVar->isNamespace());   // meaning of LF_ONLY_NAMESPACES
+
+  // is the alias already bound to something?
+  Variable *existing = env.lookupVariable(alias, LF_INNER_ONLY);
+  if (existing) {
+    // 7.3.2 para 3: redefinitions are allowed only if they make it
+    // refer to the same thing
+    if (existing->isNamespace() &&
+        existing->scope == origVar->scope) {
+      return;     // ok; nothing needs to be done
+    }
+    else {
+      env.error(stringc
+        << "redefinition of namespace alias `" << alias
+        << "' not allowed because the new definition isn't the same as the old");
+      return;
+    }
+  }
+
+  // make a new namespace variable entry
+  Variable *v = env.makeVariable(env.loc(), alias, NULL /*type*/, DF_NAMESPACE);
+  env.addVariable(v);
+
+  // make it refer to the same namespace as the original one
+  v->scope = origVar->scope;
+
+  // note that, if one cares to, the alias can be distinguished from
+  // the original name in that the scope's 'namespaceVar' still points
+  // to the original one (only)
+}
+
+
+void ND_usingDecl::tcheck(Env &env)
+{
+  if (!name->hasQualifiers()) {
+    env.error("a using-declaration requires a qualified name");
+    return;
+  }
+
+  if (name->getUnqualifiedName()->isPQ_template()) {
+    // cppstd 7.3.3 para 5
+    env.error("you can't use a template-id (template name + template arguments) "
+              "in a using-declaration");
+    return;
+  }
+
+  // lookup the template arguments in the name
+  tcheckPQName(name, env, NULL /*scope*/, LF_NONE);
+
+  // find what we're referring to; if this is a template, then it
+  // names the template primary, not any instantiated version
+  LookupSet set;
+  env.lookupPQ(set, name, LF_TEMPL_PRIMARY);
+  if (set.isEmpty()) {
+    env.error(stringc << "undeclared identifier: `" << *name << "'");
+    return;
+  }
+
+  Variable *origVar = set.first();
+  if (origVar == env.dependentVar) {
+    // if the lookup was dependent, add the name with dependent type
+    // (k0048.cc, t0468.cc)
+    Variable *v = env.makeVariable(name->loc, name->getName(), origVar->type, DF_NONE);
+
+    // add with replacement; if the name already exists, then presumably
+    // we are trying to make an overload set, but without a real function
+    // type it all just degenerates to a dependent-typed set
+    env.addVariable(v, true /*forceReplace*/);
+
+    return;
+  }
+
+  // make aliases for everything in 'set'
+  SFOREACH_OBJLIST_NC(Variable, set, iter) {
+    env.makeUsingAliasFor(name->loc, iter.data());
+  }
+
+  // the example in 7.3.3p10 implies that the structure and enum
+  // tags come along for the ride too
+  //
+  // for a long time this code has been written to only look at the
+  // first element of 'set', and so far I have been unable to write
+  // a test that shows any problem with that
+  Scope *origScope = origVar->scope? origVar->scope : env.globalScope();
+
+  // see if there is a name in the tag space of the same scope
+  // where 'origVar' was found
+  Variable *tag = origScope->lookup_one(origVar->name, env,
+                                        LF_SUPPRESS_ERROR | LF_QUERY_TAGS |
+                                        (name->hasQualifiers()? LF_QUALIFIED : LF_NONE));
+  if (tag) {
+    env.addTypeTag(tag);
+  }
+}
+
+
+void ND_usingDir::tcheck(Env &env)
+{
+  tcheckPQName(name, env, NULL /*scope*/, LF_NONE);
+
+  // find the namespace we're talking about
+  Variable *targetVar = env.lookupPQ_one(name, LF_ONLY_NAMESPACES);
+  if (!targetVar) {
+    env.error(stringc
+      << "could not find namespace `" << *name << "'");
+    return;
+  }
+  xassert(targetVar->isNamespace());   // meaning of LF_ONLY_NAMESPACES
+  Scope *target = targetVar->scope;
+
+  // to implement transitivity of 'using namespace', add a "using"
+  // edge from the current scope to the target scope, if the current
+  // one has a name (and thus could be the target of another 'using
+  // namespace')
+  //
+  // update: for recomputation to work, I need to add the edge
+  // regardless of whether 'cur' has a name
+  Scope *cur = env.scope();
+  cur->addUsingEdge(target);
+
+  if (cur->usingEdgesRefct == 0) {
+    // add the effect of a single "using" edge, which includes
+    // a transitive closure computation
+    cur->addUsingEdgeTransitively(env, target);
+  }
+  else {
+    // someone is using me, which means their transitive closure
+    // is affected, etc.  let's just recompute the whole network
+    // of active-using edges
+    env.refreshScopeOpeningEffects();
+  }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc_tokens.tok
===================================================================
--- vendor/elsa/current/elsa/cc_tokens.tok	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_tokens.tok	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,151 @@
+// cc_tokens.tok  -*- c++ -*-
+// this is the master description of the token classes; from
+// this several other files are generated, and extensions can
+// add new tokens by appending to this file
+
+// flags:
+//   MS(m): token has multiple spellings
+//   NS(n): token is a nonseparator; nonseparators cannot be adjacent
+//   CP(p): token is a keyword only in C++; in C it's an identifier
+
+// enumeration name      description                  : MS NS CP
+// ----------------      ---------------------------  : -- -- --
+
+// end of file
+TOK_EOF,                 "<EOF>",                     :
+
+// non-keyword name
+TOK_NAME,                "<name>",                    : m  n
+
+// classified name (for e.g. cdecl2)
+TOK_TYPE_NAME,           "<type name>",               : m  n
+TOK_VARIABLE_NAME,       "<variable name>",           : m  n
+
+// literals
+TOK_INT_LITERAL,         "<int literal>",             : m  n
+TOK_FLOAT_LITERAL,       "<float literal>",           : m  n
+TOK_STRING_LITERAL,      "<string literal>",          : m
+TOK_CHAR_LITERAL,        "<char literal>",            : m
+
+// keywords
+TOK_ASM,                 "asm",                       :    n
+TOK_AUTO,                "auto",                      :    n
+TOK_BREAK,               "break",                     :    n
+TOK_BOOL,                "bool",                      :    n  p
+TOK_CASE,                "case",                      :    n
+TOK_CATCH,               "catch",                     :    n  p
+TOK_CDECL,               "cdecl",                     :    n
+TOK_CHAR,                "char",                      :    n
+TOK_CLASS,               "class",                     :    n  p
+TOK_CONST,               "const",                     :    n
+TOK_CONST_CAST,          "const_cast",                :    n  p
+TOK_CONTINUE,            "continue",                  :    n
+TOK_DEFAULT,             "default",                   :    n
+TOK_DELETE,              "delete",                    :    n  p
+TOK_DO,                  "do",                        :    n
+TOK_DOUBLE,              "double",                    :    n
+TOK_DYNAMIC_CAST,        "dynamic_cast",              :    n  p
+TOK_ELSE,                "else",                      :    n
+TOK_ENUM,                "enum",                      :    n
+TOK_EXPLICIT,            "explicit",                  :    n  p
+TOK_EXPORT,              "export",                    :    n  p
+TOK_EXTERN,              "extern",                    :    n
+TOK_FALSE,               "false",                     :    n  p
+TOK_FLOAT,               "float",                     :    n
+TOK_FOR,                 "for",                       :    n
+TOK_FRIEND,              "friend",                    :    n  p
+TOK_GOTO,                "goto",                      :    n
+TOK_IF,                  "if",                        :    n
+TOK_INLINE,              "inline",                    :    n
+TOK_INT,                 "int",                       :    n
+TOK_LONG,                "long",                      :    n
+TOK_MUTABLE,             "mutable",                   :    n  p
+TOK_NAMESPACE,           "namespace",                 :    n  p
+TOK_NEW,                 "new",                       :    n  p
+TOK_OPERATOR,            "operator",                  :    n  p
+TOK_PASCAL,              "pascal",                    :    n
+TOK_PRIVATE,             "private",                   :    n  p
+TOK_PROTECTED,           "protected",                 :    n  p
+TOK_PUBLIC,              "public",                    :    n  p
+TOK_REGISTER,            "register",                  :    n
+TOK_REINTERPRET_CAST,    "reinterpret_cast",          :    n  p
+TOK_RETURN,              "return",                    :    n
+TOK_SHORT,               "short",                     :    n
+TOK_SIGNED,              "signed",                    :    n
+TOK_SIZEOF,              "sizeof",                    :    n
+TOK_STATIC,              "static",                    :    n
+TOK_STATIC_CAST,         "static_cast",               :    n  p
+TOK_STRUCT,              "struct",                    :    n
+TOK_SWITCH,              "switch",                    :    n
+TOK_TEMPLATE,            "template",                  :    n  p
+TOK_THIS,                "this",                      :    n  p
+TOK_THROW,               "throw",                     :    n  p
+TOK_TRUE,                "true",                      :    n  p
+TOK_TRY,                 "try",                       :    n  p
+TOK_TYPEDEF,             "typedef",                   :    n
+TOK_TYPEID,              "typeid",                    :    n  p
+TOK_TYPENAME,            "typename",                  :    n  p
+TOK_UNION,               "union",                     :    n
+TOK_UNSIGNED,            "unsigned",                  :    n
+TOK_USING,               "using",                     :    n  p
+TOK_VIRTUAL,             "virtual",                   :    n  p
+TOK_VOID,                "void",                      :    n
+TOK_VOLATILE,            "volatile",                  :    n
+TOK_WCHAR_T,             "wchar_t",                   :    n  p
+TOK_WHILE,               "while",                     :    n
+
+// operators (I don't identify C++ operators because in C they're not identifiers)
+TOK_LPAREN,              "(",                         :
+TOK_RPAREN,              ")",                         :
+TOK_LBRACKET,            "[",                         :
+TOK_RBRACKET,            "]",                         :
+TOK_ARROW,               "->",                        :
+TOK_COLONCOLON,          "::",                        :
+TOK_DOT,                 ".",                         :
+TOK_BANG,                "!",                         :
+TOK_TILDE,               "~",                         :
+TOK_PLUS,                "+",                         :
+TOK_MINUS,               "-",                         :
+TOK_PLUSPLUS,            "++",                        :
+TOK_MINUSMINUS,          "--",                        :
+TOK_AND,                 "&",                         :
+TOK_STAR,                "*",                         :
+TOK_DOTSTAR,             ".*",                        :
+TOK_ARROWSTAR,           "->*",                       :
+TOK_SLASH,               "/",                         :
+TOK_PERCENT,             "%",                         :
+TOK_LEFTSHIFT,           "<<",                        :
+TOK_RIGHTSHIFT,          ">>",                        :
+TOK_LESSTHAN,            "<",                         :
+TOK_LESSEQ,              "<=",                        :
+TOK_GREATERTHAN,         ">",                         :
+TOK_GREATEREQ,           ">=",                        :
+TOK_EQUALEQUAL,          "==",                        :
+TOK_NOTEQUAL,            "!=",                        :
+TOK_XOR,                 "^",                         :
+TOK_OR,                  "|",                         :
+TOK_ANDAND,              "&&",                        :
+TOK_OROR,                "||",                        :
+TOK_QUESTION,            "?",                         :
+TOK_COLON,               ":",                         :
+TOK_EQUAL,               "=",                         :
+TOK_STAREQUAL,           "*=",                        :
+TOK_SLASHEQUAL,          "/=",                        :
+TOK_PERCENTEQUAL,        "%=",                        :
+TOK_PLUSEQUAL,           "+=",                        :
+TOK_MINUSEQUAL,          "-=",                        :
+TOK_ANDEQUAL,            "&=",                        :
+TOK_XOREQUAL,            "^=",                        :
+TOK_OREQUAL,             "|=",                        :
+TOK_LEFTSHIFTEQUAL,      "<<=",                       :
+TOK_RIGHTSHIFTEQUAL,     ">>=",                       :
+TOK_COMMA,               ",",                         :
+TOK_ELLIPSIS,            "...",                       :
+TOK_SEMICOLON,           ";",                         :
+TOK_LBRACE,              "{",                         :
+TOK_RBRACE,              "}",                         :
+
+// dummy terminals used for precedence games
+TOK_PREFER_REDUCE,       "<prefer reduce>",           :
+TOK_PREFER_SHIFT,        "<prefer shift>",            :
+

Added: vendor/elsa/current/elsa/cc_type.cc
===================================================================
--- vendor/elsa/current/elsa/cc_type.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_type.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3005 @@
+// cc_type.cc            see license.txt for copyright and terms of use
+// code for cc_type.h
+
+#include "cc_type.h"    // this module
+#include "trace.h"      // tracingSys
+#include "variable.h"   // Variable
+#include "strutil.h"    // copyToStaticBuffer
+#include "sobjset.h"    // SObjSet
+#include "hashtbl.h"    // lcprngTwoSteps
+#include "asthelp.h"    // ind
+
+// TemplateInfo, etc... it would be sort of nice if this module didn't
+// have to #include template.h, since most of what it does is
+// independent of that, but there are enough little dependencies that
+// for now I just live with it.
+#include "template.h"
+
+// This dependency is to support using MType for equality checking.
+// It causes a transitive dependency on cc.ast, but I rationalize that
+// an MType variant could be created, if necessary, that cut that
+// dependency, especially as none of the call sites in this file
+// explicitly supply MF_MATCH.
+#include "mtype.h"      // MType
+
+// Do *not* add a dependency on cc.ast or cc_env.  cc_type is about
+// the intrinsic properties of types, independent of any particular
+// syntax for denoting them.  (toString() uses C's syntax, but that's
+// just for debugging.)
+
+#include <stdlib.h>     // getenv
+
+
+bool global_mayUseTypeAndVarToCString = true;
+
+// 2005-08-10: the anon things are kind of ugly..
+bool printAnonComment = false;
+
+
+// ------------------- TypeVisitor ----------------
+bool TypeVisitor::visitType(Type *obj)
+  { return true; }
+void TypeVisitor::postvisitType(Type *obj)
+  {  }
+
+bool TypeVisitor::visitFunctionType_params(SObjList<Variable> &params)
+  { return true; }
+void TypeVisitor::postvisitFunctionType_params(SObjList<Variable> &params)
+  { }
+bool TypeVisitor::visitFunctionType_params_item(Variable *param)
+  { return true; }
+void TypeVisitor::postvisitFunctionType_params_item(Variable *param)
+  { }
+
+bool TypeVisitor::visitVariable(Variable *var)
+  { return true; }
+void TypeVisitor::postvisitVariable(Variable *var)
+  { }
+
+bool TypeVisitor::visitAtomicType(AtomicType *obj)
+  { return true; }
+void TypeVisitor::postvisitAtomicType(AtomicType *obj)
+  {  }
+
+bool TypeVisitor::visitEnumType_Value(void /*EnumType::Value*/ *obj)
+  { return true; }
+void TypeVisitor::postvisitEnumType_Value(void /*EnumType::Value*/ *obj)
+  {  }
+
+bool TypeVisitor::visitScope(Scope *obj)
+  { return true; }
+void TypeVisitor::postvisitScope(Scope *obj)
+  {  }
+
+bool TypeVisitor::visitScope_variables(StringRefMap<Variable> &variables)
+  { return true; }
+void TypeVisitor::postvisitScope_variables(StringRefMap<Variable> &variables)
+  {  }
+bool TypeVisitor::visitScope_variables_entry(StringRef name, Variable *var)
+  { return true; }
+void TypeVisitor::postvisitScope_variables_entry(StringRef name, Variable *var)
+  {  }
+
+bool TypeVisitor::visitScope_typeTags(StringRefMap<Variable> &typeTags)
+  { return true; }
+void TypeVisitor::postvisitScope_typeTags(StringRefMap<Variable> &typeTags)
+  {  }
+bool TypeVisitor::visitScope_typeTags_entry(StringRef name, Variable *var)
+  { return true; }
+void TypeVisitor::postvisitScope_typeTags_entry(StringRef name, Variable *var)
+  {  }
+
+bool TypeVisitor::visitScope_templateParams(SObjList<Variable> &templateParams)
+  { return true; }
+void TypeVisitor::postvisitScope_templateParams(SObjList<Variable> &templateParams)
+  {  }
+bool TypeVisitor::visitScope_templateParams_item(Variable *var)
+  { return true; }
+void TypeVisitor::postvisitScope_templateParams_item(Variable *var)
+  {  }
+
+bool TypeVisitor::visitBaseClass(BaseClass *bc)
+  { return true; }
+void TypeVisitor::postvisitBaseClass(BaseClass *bc)
+  {  }
+
+bool TypeVisitor::visitBaseClassSubobj(BaseClassSubobj *bc)
+  { return true; }
+void TypeVisitor::postvisitBaseClassSubobj(BaseClassSubobj *bc)
+  {  }
+
+bool TypeVisitor::visitBaseClassSubobj_parents(SObjList<BaseClassSubobj> &parents)
+  { return true; }
+void TypeVisitor::postvisitBaseClassSubobj_parents(SObjList<BaseClassSubobj> &parents)
+  {  }
+bool TypeVisitor::visitBaseClassSubobj_parents_item(BaseClassSubobj *parent)
+  { return true; }
+void TypeVisitor::postvisitBaseClassSubobj_parents_item(BaseClassSubobj *parent)
+  {  }
+
+bool TypeVisitor::visitSTemplateArgument(STemplateArgument *obj)
+  { return true; }
+void TypeVisitor::postvisitSTemplateArgument(STemplateArgument *obj)
+  {  }
+
+bool TypeVisitor::visitPseudoInstantiation_args(ObjList<STemplateArgument> &args)
+  { return true; }
+void TypeVisitor::postvisitPseudoInstantiation_args(ObjList<STemplateArgument> &args)
+  {  }
+bool TypeVisitor::visitPseudoInstantiation_args_item(STemplateArgument *arg)
+  { return true; }
+void TypeVisitor::postvisitPseudoInstantiation_args_item(STemplateArgument *arg)
+  {  }
+
+bool TypeVisitor::visitDependentQTypePQTArgsList(ObjList<STemplateArgument> &list)
+  { return true; }
+void TypeVisitor::postvisitDependentQTypePQTArgsList(ObjList<STemplateArgument> &list)
+  {  }
+bool TypeVisitor::visitDependentQTypePQTArgsList_item(STemplateArgument *sta)
+  { return true; }
+void TypeVisitor::postvisitDependentQTypePQTArgsList_item(STemplateArgument *sta)
+  {  }
+
+bool TypeVisitor::visitExpression(Expression *obj)
+  {
+    // if this ever fires, at the same location be sure to put a
+    // postvisitExpression()
+    xfailure("wanted to find out if this is ever called; I can't find it if it is");
+    return true;
+  }
+void TypeVisitor::postvisitExpression(Expression *obj)
+  {  }
+
+
+// ------------------ AtomicType -----------------
+ALLOC_STATS_DEFINE(AtomicType)
+
+AtomicType::AtomicType()
+{
+  ALLOC_STATS_IN_CTOR
+}
+
+
+AtomicType::~AtomicType()
+{
+  ALLOC_STATS_IN_DTOR
+}
+
+
+DOWNCAST_IMPL(AtomicType, SimpleType)
+DOWNCAST_IMPL(AtomicType, NamedAtomicType)
+DOWNCAST_IMPL(AtomicType, CompoundType)
+DOWNCAST_IMPL(AtomicType, EnumType)
+DOWNCAST_IMPL(AtomicType, TypeVariable)
+DOWNCAST_IMPL(AtomicType, PseudoInstantiation)
+DOWNCAST_IMPL(AtomicType, DependentQType)
+
+
+void AtomicType::gdb() const
+{
+  cout << toString() << endl;
+}
+
+
+string AtomicType::toString() const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  if (Type::printAsML) {
+    return toMLString();
+  }
+  else {
+    return toCString();
+  }
+}
+
+
+bool AtomicType::isNamedAtomicType() const
+{
+  // default to false; NamedAtomicType overrides
+  return false;
+}
+
+
+bool AtomicType::equals(AtomicType const *obj) const
+{
+  MType match;
+  return match.matchAtomicType(this, obj, MF_NONE);
+}
+
+
+// ------------------ SimpleType -----------------
+SimpleType SimpleType::fixed[NUM_SIMPLE_TYPES] = {
+  SimpleType(ST_CHAR),
+  SimpleType(ST_UNSIGNED_CHAR),
+  SimpleType(ST_SIGNED_CHAR),
+  SimpleType(ST_BOOL),
+  SimpleType(ST_INT),
+  SimpleType(ST_UNSIGNED_INT),
+  SimpleType(ST_LONG_INT),
+  SimpleType(ST_UNSIGNED_LONG_INT),
+  SimpleType(ST_LONG_LONG),
+  SimpleType(ST_UNSIGNED_LONG_LONG),
+  SimpleType(ST_SHORT_INT),
+  SimpleType(ST_UNSIGNED_SHORT_INT),
+  SimpleType(ST_WCHAR_T),
+  SimpleType(ST_FLOAT),
+  SimpleType(ST_DOUBLE),
+  SimpleType(ST_LONG_DOUBLE),
+  SimpleType(ST_FLOAT_COMPLEX),
+  SimpleType(ST_DOUBLE_COMPLEX),
+  SimpleType(ST_LONG_DOUBLE_COMPLEX),
+  SimpleType(ST_FLOAT_IMAGINARY),
+  SimpleType(ST_DOUBLE_IMAGINARY),
+  SimpleType(ST_LONG_DOUBLE_IMAGINARY),
+  SimpleType(ST_VOID),
+
+  SimpleType(ST_ELLIPSIS),
+  SimpleType(ST_CDTOR),
+  SimpleType(ST_ERROR),
+  SimpleType(ST_DEPENDENT),
+  SimpleType(ST_IMPLINT),
+  SimpleType(ST_NOTFOUND),
+
+  SimpleType(ST_PROMOTED_INTEGRAL),
+  SimpleType(ST_PROMOTED_ARITHMETIC),
+  SimpleType(ST_INTEGRAL),
+  SimpleType(ST_ARITHMETIC),
+  SimpleType(ST_ARITHMETIC_NON_BOOL),
+  SimpleType(ST_ANY_OBJ_TYPE),
+  SimpleType(ST_ANY_NON_VOID),
+  SimpleType(ST_ANY_TYPE),
+
+  SimpleType(ST_PRET_STRIP_REF),
+  SimpleType(ST_PRET_PTM),
+  SimpleType(ST_PRET_ARITH_CONV),
+  SimpleType(ST_PRET_FIRST),
+  SimpleType(ST_PRET_FIRST_PTR2REF),
+  SimpleType(ST_PRET_SECOND),
+  SimpleType(ST_PRET_SECOND_PTR2REF),
+};
+
+string SimpleType::toCString() const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  return simpleTypeName(type);
+}
+
+
+int SimpleType::reprSize() const
+{
+  return simpleTypeReprSize(type);
+}
+
+
+void SimpleType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitAtomicType(this)) {
+    return;
+  }
+  vis.postvisitAtomicType(this);
+}
+
+
+// ------------------ NamedAtomicType --------------------
+NamedAtomicType::NamedAtomicType(StringRef n)
+  : name(n),
+    typedefVar(NULL),
+    access(AK_PUBLIC)
+{}
+
+NamedAtomicType::~NamedAtomicType()
+{
+  if (typedefVar) {
+    delete typedefVar;
+  }
+}
+
+
+bool NamedAtomicType::isNamedAtomicType() const
+{
+  return true;
+}
+
+
+// ---------------- BaseClassSubobj ----------------
+void BaseClass::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitBaseClass(this)) {
+    return;
+  }
+  ct->traverse(vis);
+  vis.postvisitBaseClass(this);
+}
+
+
+// ---------------- BaseClassSubobj ----------------
+BaseClassSubobj::BaseClassSubobj(BaseClass const &base)
+  : BaseClass(base),
+    parents(),       // start with an empty list
+    visited(false)   // may as well init; clients expected to clear as needed
+{}
+
+
+BaseClassSubobj::~BaseClassSubobj()
+{
+  // I don't think this code has been tested..
+
+  // virtual parent objects are owned by the containing class'
+  // 'virtualBases' list, but nonvirtual parents are owned
+  // by the hierarchy nodes themselves (i.e. me)
+  while (parents.isNotEmpty()) {
+    BaseClassSubobj *parent = parents.removeFirst();
+
+    if (!parent->isVirtual) {
+      delete parent;
+    }
+  }
+}
+
+
+string BaseClassSubobj::canonName() const
+{
+  return stringc << ct->name << " (" << (void*)this << ")";
+}
+
+
+void BaseClassSubobj::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitBaseClassSubobj(this)) {
+    return;
+  }
+
+  if (vis.visitBaseClassSubobj_parents(parents)) {
+    SFOREACH_OBJLIST_NC(BaseClassSubobj, parents, iter) {
+      BaseClassSubobj *parent = iter.data();
+      if (vis.visitBaseClassSubobj_parents_item(parent)) {
+        parent->traverse(vis);
+        vis.postvisitBaseClassSubobj_parents_item(parent);
+      }
+    }
+    vis.postvisitBaseClassSubobj_parents(parents);
+  }
+
+  vis.postvisitBaseClassSubobj(this);
+}
+
+
+// ------------------ CompoundType -----------------
+CompoundType::CompoundType(Keyword k, StringRef n)
+  : NamedAtomicType(n),
+    Scope(SK_CLASS, 0 /*changeCount*/, SL_UNKNOWN /*dummy loc*/),
+    forward(true),
+    isTransparentUnion(false),
+    keyword(k),
+    bases(),
+    virtualBases(),
+    subobj(BaseClassSubobj(this, AK_PUBLIC, false /*isVirtual*/)),
+    conversionOperators(),
+    instName(n),
+    syntax(NULL),
+    parameterizingScope(NULL),
+    selfType(NULL)
+{
+  curCompound = this;
+  curAccess = (k==K_CLASS? AK_PRIVATE : AK_PUBLIC);
+}
+
+CompoundType::~CompoundType()
+{
+  //bases.deleteAll();    // automatic, and I'd need a cast to do it explicitly because it's 'const' now
+  if (templateInfo()) {
+    delete templateInfo();
+    setTemplateInfo(NULL);      // dsw: I don't like pointers to deleted objects
+  }
+}
+
+
+STATICDEF char const *CompoundType::keywordName(Keyword k)
+{
+  switch (k) {
+    default:          xfailure("bad keyword");
+    case K_STRUCT:    return "struct";
+    case K_CLASS:     return "class";
+    case K_UNION:     return "union";
+  }
+}
+
+
+bool CompoundType::isTemplate(bool considerInherited) const
+{
+  TemplateInfo *tinfo = templateInfo();
+  return tinfo != NULL &&
+         tinfo->hasParametersEx(considerInherited);
+}
+
+
+bool CompoundType::isInstantiation() const
+{
+  TemplateInfo *tinfo = templateInfo();
+  return tinfo != NULL &&
+         tinfo->isInstantiation();
+}
+
+
+Variable *CompoundType::getTypedefVar() const
+{
+  xassert(typedefVar);
+  xassert(typedefVar->type);
+  if (typedefVar->type->isError()) {
+    // this is the error compound type
+  }
+  else {
+    xassert(typedefVar->type->asCompoundTypeC() == this);
+  }
+  return typedefVar;
+}
+
+
+TemplateInfo *CompoundType::templateInfo() const
+{
+  return getTypedefVar()->templateInfo();
+}
+
+void CompoundType::setTemplateInfo(TemplateInfo *templInfo0)
+{
+  if (templInfo0) {
+    getTypedefVar()->setTemplateInfo(templInfo0);
+  }
+}
+
+
+bool CompoundType::hasVirtualFns() const
+{
+  // TODO: this fails to consider members inherited from base classes
+  // ...
+  // UPDATE dsw: I think the code in Declarator::mid_tcheck() is
+  // supposed to push the virtuality down at least for those function
+  // members that implicitly inherit their virtuality from the fact
+  // that they override a virtual member in their superclass.
+
+  for (StringRefMap<Variable>::Iter iter(getVariableIter());
+       !iter.isDone(); iter.adv()) {
+    Variable *var0 = iter.value();
+    if (var0->hasFlag(DF_VIRTUAL)) {
+      xassert(var0->getType()->asRval()->isFunctionType());
+      return true;
+    }
+  }
+  return false;
+}
+
+
+string CompoundType::toCString() const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder sb;
+
+  // typedefVar might be NULL if this object is in the middle
+  // of being built, but I want it to be printable at all times
+  TemplateInfo *tinfo = typedefVar? templateInfo() : NULL;
+
+  bool hasParams = tinfo && tinfo->params.isNotEmpty();
+  if (hasParams) {
+    sb << tinfo->paramsToCString() << " ";
+  }
+
+  if (!tinfo || hasParams) {
+    // only say 'class' if this is like a class definition, or
+    // if we're not a template, since template instantiations
+    // usually don't include the keyword 'class' (this isn't perfect..
+    // I think I need more context)
+    sb << keywordName(keyword) << " ";
+  }
+
+  //sb << (instName? instName : "/*anonymous*/");
+  if (typedefVar) {
+    sb << typedefVar->fullyQualifiedName0();
+  }
+  else {
+    // only reachable during object construction
+    sb << (name? name : "/*anon*/");
+  }
+
+  // template arguments are now in the name
+  // 4/22/04: they were removed from the name a long time ago;
+  //          but I'm just now uncommenting this code
+  // 8/03/04: restored the original purpose of 'instName', so
+  //          once again that is name+args, so this code is not needed
+  //if (tinfo && tinfo->arguments.isNotEmpty()) {
+  //  sb << sargsToString(tinfo->arguments);
+  //}
+
+  return sb;
+}
+
+
+int CompoundType::reprSize() const
+{
+  int total = 0;
+
+  // base classes
+  {
+    SObjList<BaseClassSubobj const> subobjs;
+    getSubobjects(subobjs);
+    SFOREACH_OBJLIST(BaseClassSubobj const, subobjs, iter) {
+      if (iter.data()->ct == this) {
+        // skip my own subobject, as that will be accounted for below
+      }
+      else {
+        total += iter.data()->ct->reprSize();
+      }
+    }
+  }
+
+  // This algorithm is a very crude approximation of the packing and
+  // alignment behavior of some nominal compiler.  Ideally, we'd have
+  // a layout algorithm for each compiler we want to emulate, or
+  // perhaps even a generic algorithm with sufficient
+  // parameterization, but for now it's just a best effort driven by
+  // specific pieces of code that know how big their own structures
+  // are supposed to be.
+  //
+  // Were I to try to do a better job, a good starting point would be
+  // to research any published ABIs I could find for C and C++, as
+  // they would have to specify a layout algorithm.  Presumably, if I
+  // can emulate any published ABI then I will have the flexibility to
+  // emulate any compiler also.
+  //
+  // One test is in/t0513.cc.
+
+  // Maintain information about accumulated members that do not occupy
+  // a complete word.
+  int bits = 0;        // bitfield bits
+  int bytes = 0;       // unaligned bytes
+  int align = 1;       // prevailing alignment in bytes
+
+  // data members
+  SFOREACH_OBJLIST(Variable, dataMembers, iter) {
+    Variable const *v = iter.data();
+
+    if (keyword == K_UNION) {
+      // representation size is max over field sizes
+      total = max(total, v->type->reprSize());
+      continue;
+    }
+
+    if (v->isBitfield()) {
+      // consolidate bytes as bits
+      bits += bytes*8;
+      bytes = 0;
+
+      int membBits = v->getBitfieldSize();
+      bits += membBits;
+
+      // increase alignment to accomodate this member
+      while (membBits > align*8 && align < 4) {
+        align *= 2;
+      }
+
+      continue;
+    }
+
+    // 'v' is not a bitfield, so pack the bits seen so far into
+    // 'align' units
+    if (bits > 0) {
+      total += ((bits + (align*8-1)) / (align*8)) * align;
+      bits = 0;
+    }
+
+    if (v->type->isArrayType() &&
+        !v->type->asArrayTypeC()->hasSize()) {
+      // "open array"; there are checks elsewhere that control whether
+      // Elsa allows this, this at point in the code I can just assume
+      // that they are allowed; they are treated as having size 0, so
+      // just skip it (in/c/dC0032.c)
+      continue;
+    }
+
+    int membSize = v->type->reprSize();
+
+    if (membSize >= align) {
+      // increase alignment if necessary, up to 4 bytes;
+      // this is wrong because you can't tell the alignment
+      // of a structure just from its size
+      while (membSize > align && align < 4) {
+        align *= 2;
+      }
+
+      // consolidate any remaining bytes into 'align' units
+      if (bytes > 0) {
+        total += ((bytes + align-1) / align) * align;
+        bytes = 0;
+      }
+
+      // add 'membSize'
+      total += (membSize / align) * align;
+      bytes += membSize % align;
+    }
+    else {
+      // less than one alignment, just stuff it into 'bytes'; this
+      // is wrong because it doesn't take account of alignment
+      // less than 'align', e.g. 2-byte alignment of a 16-bit qty..
+      // oh well
+      bytes += membSize;
+    }
+  }
+
+  // pad out to the next 'align' boundary
+  bits += bytes*8;
+  total += ((bits + (align*8-1)) / (align*8)) * align;
+
+  return total;
+}
+
+
+void CompoundType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitAtomicType(this)) {
+    return;
+  }
+
+  // traverse the superclass
+  Scope::traverse_internal(vis);
+
+  // 2005-07-28: Disabled because (1) I don't remember why I wanted
+  // it and it is a little weird (why not traverse the params too?),
+  // and (2) it would interfere with XML serialization.
+  //
+  //if (isTemplate()) {
+  //  templateInfo()->traverseArguments(vis);
+  //}
+
+  vis.postvisitAtomicType(this);
+}
+
+
+int CompoundType::numFields() const
+{
+  int ct = 0;
+  for (StringRefMap<Variable>::Iter iter(getVariableIter());
+       !iter.isDone(); iter.adv()) {
+    Variable *v = iter.value();
+
+    // count nonstatic data members
+    if (!v->type->isFunctionType() &&
+        !v->hasFlag(DF_TYPEDEF) &&
+        !v->hasFlag(DF_STATIC)) {
+      ct++;
+    }
+  }
+
+  return ct;
+}
+
+
+void CompoundType::addField(Variable *v)
+{
+  addVariable(v);
+}
+
+
+void CompoundType::afterAddVariable(Variable *v)
+{
+  // if is a data member, not a method, static data, or a typedef
+  if (!v->type->isFunctionType() &&
+      !(v->flags & (DF_STATIC | DF_TYPEDEF | DF_ENUMERATOR | DF_USING_ALIAS))) {
+    dataMembers.append(v);
+  }
+}
+
+
+int CompoundType::getDataMemberPosition(StringRef name) const
+{
+  int index=0;
+  SFOREACH_OBJLIST(Variable, dataMembers, iter) {
+    if (iter.data()->name == name) {
+      return index;
+    }
+    index++;
+  }
+  return -1;     // not found
+}
+
+
+// TODO: Does this handle members of base classes correctly?  What
+// about virtual inheritance?
+int CompoundType::getDataMemberOffset(Variable *dataMember) const
+{
+  int offset = 0;
+  SFOREACH_OBJLIST(Variable, dataMembers, iter) {
+    if (iter.data() == dataMember) {
+      return offset;
+    }
+    offset += iter.data()->type->reprSize();
+  }
+
+  xfailure(stringc << "getDataMemberOffset: no such member: "
+                   << dataMember->name);
+  return 0;  // silence warning
+}
+
+
+void CompoundType::addBaseClass(BaseClass * /*owner*/ newBase)
+{
+  xassert(newBase->access != AK_UNSPECIFIED);
+
+  // add the new base; override 'const' so we can modify the list
+  // (this is the one function allowed to do this)
+  const_cast<ObjList<BaseClass>&>(bases).append(newBase);
+
+  // replicate 'newBase's inheritance hierarchy in the subobject
+  // hierarchy, representing virtual inheritance with explicit sharing
+  makeSubobjHierarchy(&subobj, newBase);
+}
+
+// all of this is done in the context of one class, the one whose
+// tree we're building, so we can access its 'virtualBases' list
+void CompoundType::makeSubobjHierarchy(
+  // the root of the subobject hierarchy we're adding to
+  BaseClassSubobj *subobj,
+
+  // the base class to add to subobj's hierarchy
+  BaseClass const *newBase)
+{
+  if (newBase->isVirtual) {
+    // does 'newBase' correspond to an already-existing virtual base?
+    BaseClassSubobj *vbase = findVirtualSubobject(newBase->ct);
+    if (vbase) {
+      // yes it's already a virtual base; just point 'subobj'
+      // at the existing instance
+      subobj->parents.append(vbase);
+
+      // we're incorporating 'newBase's properties into 'vbase';
+      // naturally both should already be marked as virtual
+      xassert(vbase->isVirtual);
+
+      // grant access according to the least-restrictive link
+      if (newBase->access < vbase->access) {
+        vbase->access = newBase->access;    // make it less restrictive
+      }
+
+      // no need to recursively examine 'newBase' since the presence
+      // of 'vbase' in 'virtualBases' means we already incorporated
+      // its inheritance structure
+      return;
+    }
+  }
+
+  // represent newBase in the subobj hierarchy
+  BaseClassSubobj *newBaseObj = new BaseClassSubobj(*newBase);
+  subobj->parents.append(newBaseObj);
+
+  // if we just added a new virtual base, remember it
+  if (newBaseObj->isVirtual) {
+    virtualBases.append(newBaseObj);
+  }
+
+  // put all of newBase's base classes into newBaseObj
+  FOREACH_OBJLIST(BaseClass, newBase->ct->bases, iter) {
+    makeSubobjHierarchy(newBaseObj, iter.data());
+  }
+}
+
+
+// simple scan of 'virtualBases'
+BaseClassSubobj const *CompoundType::findVirtualSubobjectC
+  (CompoundType const *ct) const
+{
+  FOREACH_OBJLIST(BaseClassSubobj, virtualBases, iter) {
+    if (iter.data()->ct == ct) {
+      return iter.data();
+    }
+  }
+  return NULL;   // not found
+}
+
+
+// fundamentally, this takes advantage of the ownership scheme,
+// where nonvirtual bases form a tree, and the 'virtualBases' list
+// gives us additional trees of internally nonvirtual bases
+void CompoundType::clearSubobjVisited() const
+{
+  // clear the 'visited' flags in the nonvirtual bases
+  clearVisited_helper(&subobj);
+
+  // clear them in the virtual bases
+  FOREACH_OBJLIST(BaseClassSubobj, virtualBases, iter) {
+    clearVisited_helper(iter.data());
+  }
+}
+
+STATICDEF void CompoundType::clearVisited_helper
+  (BaseClassSubobj const *subobj)
+{
+  subobj->visited = false;
+
+  // recursively clear flags in the *nonvirtual* bases
+  SFOREACH_OBJLIST(BaseClassSubobj, subobj->parents, iter) {
+    if (!iter.data()->isVirtual) {
+      clearVisited_helper(iter.data());
+    }
+  }
+}
+
+
+// interpreting the subobject hierarchy recursively is sometimes a bit
+// of a pain, especially when the client doesn't care about the access
+// paths, so this allows a more natural iteration by collecting them
+// all into a list; this function provides a prototypical example of
+// how to interpret the structure recursively, when that is necessary
+void CompoundType::getSubobjects(SObjList<BaseClassSubobj const> &dest) const
+{
+  // reverse before also, in case there happens to be elements
+  // already on the list, so those won't change order
+  dest.reverse();
+
+  clearSubobjVisited();
+  getSubobjects_helper(dest, &subobj);
+
+  // reverse the list since it was constructed in reverse order
+  dest.reverse();
+}
+
+STATICDEF void CompoundType::getSubobjects_helper
+  (SObjList<BaseClassSubobj const> &dest, BaseClassSubobj const *subobj)
+{
+  if (subobj->visited) return;
+  subobj->visited = true;
+
+  dest.prepend(subobj);
+
+  SFOREACH_OBJLIST(BaseClassSubobj, subobj->parents, iter) {
+    getSubobjects_helper(dest, iter.data());
+  }
+}
+
+
+string CompoundType::renderSubobjHierarchy() const
+{
+  stringBuilder sb;
+  sb << "// subobject hierarchy for " << name << "\n"
+     << "digraph \"Subobjects\" {\n"
+     ;
+
+  SObjList<BaseClassSubobj const> objs;
+  getSubobjects(objs);
+
+  // look at all the subobjects
+  SFOREACH_OBJLIST(BaseClassSubobj const, objs, iter) {
+    BaseClassSubobj const *obj = iter.data();
+
+    sb << "  \"" << obj->canonName() << "\" [\n"
+       << "    label = \"" << obj->ct->name
+                  << "\\n" << ::toString(obj->access) << "\"\n"
+       << "  ]\n"
+       ;
+
+    // render 'obj's base class links
+    SFOREACH_OBJLIST(BaseClassSubobj, obj->parents, iter) {
+      BaseClassSubobj const *parent = iter.data();
+
+      sb << "  \"" << parent->canonName() << "\" -> \""
+                   << obj->canonName() << "\" [\n";
+      if (parent->isVirtual) {
+        sb << "    style = dashed\n";    // virtual inheritance: dashed link
+      }
+      sb << "  ]\n";
+    }
+  }
+
+  sb << "}\n\n";
+
+  return sb;
+}
+
+
+string toString(CompoundType::Keyword k)
+{
+  xassert((unsigned)k < (unsigned)CompoundType::NUM_KEYWORDS);
+  return string(typeIntrNames[k]);    // see cc_type.h
+}
+
+
+int CompoundType::countBaseClassSubobjects(CompoundType const *ct) const
+{
+  SObjList<BaseClassSubobj const> objs;
+  getSubobjects(objs);
+
+  int count = 0;
+  SFOREACH_OBJLIST(BaseClassSubobj const, objs, iter) {
+    if (iter.data()->ct == ct) {
+      count++;
+    }
+  }
+
+  return count;
+}
+
+
+// simple recursive computation
+void getBaseClasses(SObjSet<CompoundType*> &bases, CompoundType *ct)
+{
+  bases.add(ct);
+
+  FOREACH_OBJLIST(BaseClass, ct->bases, iter) {
+    getBaseClasses(bases, iter.data()->ct);
+  }
+}
+
+STATICDEF CompoundType *CompoundType::lub
+  (CompoundType *t1, CompoundType *t2, bool &wasAmbig)
+{
+  wasAmbig = false;
+
+  // might be a common case?
+  if (t1 == t2) {
+    return t1;
+  }
+
+  // compute the set of base classes for each class
+  SObjSet<CompoundType*> t1Bases, t2Bases;
+  getBaseClasses(t1Bases, t1);
+  getBaseClasses(t2Bases, t2);
+
+  // look for an element in the intersection that has nothing below it
+  // (hmm.. this will be quadratic due to linear-time 'hasBaseClass'...)
+  CompoundType *least = NULL;
+  {
+    for (SObjSetIter<CompoundType*> iter(t1Bases); !iter.isDone(); iter.adv()) {
+      if (!t2Bases.contains(iter.data())) continue;       // filter for intersection
+
+      if (!least ||
+          iter.data()->hasBaseClass(least)) {
+        // new least
+        least = iter.data();
+      }
+    }
+  }
+
+  if (!least) {
+    return NULL;        // empty intersection
+  }
+
+  // check that it's the unique least
+  for (SObjSetIter<CompoundType*> iter(t1Bases); !iter.isDone(); iter.adv()) {
+    if (!t2Bases.contains(iter.data())) continue;       // filter for intersection
+
+    if (least->hasBaseClass(iter.data())) {
+      // least is indeed less than (or equal to) this one
+    }
+    else {
+      // counterexample; 'least' is not in fact the least
+      wasAmbig = true;
+      return NULL;
+    }
+  }
+
+  // good to go
+  return least;
+}
+
+
+void CompoundType::finishedClassDefinition(StringRef specialName)
+{
+  // get inherited conversions
+  FOREACH_OBJLIST(BaseClass, bases, iter) {
+    conversionOperators.appendAll(iter.data()->ct->conversionOperators);
+  }
+
+  // remove duplicates (in/t0483.cc); if there is an ambiguity because
+  // of inheriting something multiple times, it should be detected when
+  // we go to actually *use* the conversion operator
+  conversionOperators.removeDuplicatesAsPointerMultiset();
+
+  // add those declared locally; they hide any that are inherited
+  Variable *localOps = rawLookupVariable(specialName);
+  if (!localOps) {
+    return;      // nothing declared locally
+  }
+
+  if (!localOps->overload) {
+    addLocalConversionOp(localOps);
+  }
+  else {
+    SFOREACH_OBJLIST_NC(Variable, localOps->overload->set, iter) {
+      addLocalConversionOp(iter.data());
+    }
+  }
+}
+
+void CompoundType::addLocalConversionOp(Variable *op)
+{
+  Type *opRet = op->type->asFunctionTypeC()->retType;
+
+  // remove any existing conversion operators that yield the same type
+  {
+    SObjListMutator<Variable> mut(conversionOperators);
+    while (!mut.isDone()) {
+      Type *mutRet = mut.data()->type->asFunctionTypeC()->retType;
+
+      if (mutRet->equals(opRet)) {
+        mut.remove();    // advances the iterator
+      }
+      else {
+        mut.adv();
+      }
+    }
+  }
+
+  // add 'op'
+  conversionOperators.append(op);
+}
+
+
+// return false if the presence of 'v' in a CompoundType
+// prevents that compound from being "aggregate"
+static bool isAggregate_one(Variable const *v)
+{
+  // typedef and static members are irrelevant
+  if (v->isType() || v->hasFlag(DF_STATIC)) {
+    return true;
+  }
+
+  if (!v->hasFlag(DF_IMPLICIT) &&
+      v->type->isFunctionType() &&
+      v->type->asFunctionTypeC()->isConstructor()) {
+    // user-defined (non-DF_IMPLICIT) constructor
+    return false;
+  }
+
+  if (v->hasFlag(DF_VIRTUAL)) {
+    // virtual function
+    return false;
+  }
+
+  if (v->getAccess() != AK_PUBLIC &&
+      !v->type->isFunctionType()) {
+    // non-public data
+    return false;
+  }
+
+  // does not prevent container from being "aggregate"
+  return true;
+}
+
+
+// conditions:
+//   - no user-defined constructors
+//   - no private or protected non-static data members
+//   - no base classes
+//   - no virtual functions
+bool CompoundType::isAggregate() const
+{
+  StringRefMap<Variable>::Iter iter(getVariableIter());
+  for (; !iter.isDone(); iter.adv()) {
+    Variable const *v = iter.value();
+
+    if (v->isOverloaded()) {
+      SFOREACH_OBJLIST(Variable, v->overload->set, iter2) {
+        if (!isAggregate_one(iter2.data())) {
+          return false;
+        }
+      }
+    }
+    else {
+      if (!isAggregate_one(v)) {
+        return false;
+      }
+    }
+  }
+
+  if (bases.isNotEmpty()) {
+    return false;
+  }
+
+  return true;
+}
+
+
+// ---------------- EnumType ------------------
+EnumType::~EnumType()
+{}
+
+
+string EnumType::toCString() const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+
+  if (typedefVar) {
+    // include full scoping info (debatable ...)
+    return stringc << "enum " << (typedefVar->fullyQualifiedName0());
+  }
+  else {
+    // NULL typedefVar should only happen for anonymous types
+    xassert(!name);
+    return stringc << "enum /*anonymous*/";
+  }
+}
+
+
+int EnumType::reprSize() const
+{
+  // this is the usual choice
+  return simpleTypeReprSize(ST_INT);
+}
+
+
+void EnumType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitAtomicType(this)) {
+    return;
+  }
+  vis.postvisitAtomicType(this);
+}
+
+
+EnumType::Value *EnumType::addValue(StringRef name, int value, Variable *decl)
+{
+  xassert(!valueIndex.isMapped(name));
+
+  Value *v = new Value(name, this, value, decl);
+  valueIndex.add(name, v);
+
+  // 7/22/04: At one point I was also maintaining a linked list of
+  // the Value objects.  Daniel pointed out this was quadratic b/c
+  // I was using 'append()'.  Since I never used the list anyway,
+  // I just dropped it in favor of the dictionary (only).
+
+  if (value < 0) {
+    hasNegativeValues = true;
+  }
+
+  return v;
+}
+
+
+EnumType::Value const *EnumType::getValue(StringRef name) const
+{
+  Value const *v;
+  if (valueIndex.queryC(name, v)) {
+    return v;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+// ---------------- EnumType::Value --------------
+EnumType::Value::Value(StringRef n, EnumType *t, int v, Variable *d)
+  : name(n), type(t), value(v), decl(d)
+{}
+
+EnumType::Value::~Value()
+{}
+
+
+// -------------------- TypePred ----------------------
+bool StatelessTypePred::operator() (Type const *t)
+{
+  return f(t);
+}
+
+
+// -------------------- BaseType ----------------------
+ALLOC_STATS_DEFINE(BaseType)
+
+bool BaseType::printAsML = false;
+
+
+BaseType::BaseType()
+{
+  ALLOC_STATS_IN_CTOR
+}
+
+BaseType::~BaseType()
+{
+  ALLOC_STATS_IN_DTOR
+}
+
+
+DOWNCAST_IMPL(BaseType, CVAtomicType)
+DOWNCAST_IMPL(BaseType, PointerType)
+DOWNCAST_IMPL(BaseType, ReferenceType)
+DOWNCAST_IMPL(BaseType, FunctionType)
+DOWNCAST_IMPL(BaseType, ArrayType)
+DOWNCAST_IMPL(BaseType, PointerToMemberType)
+
+
+bool BaseType::equals(BaseType const *obj, MatchFlags flags) const
+{
+  MType mtype;
+
+  // oy.. I think it's a fair assumption that the only direct subclass
+  // of BaseType is Type ...; in fact, I just made BaseType's ctor
+  // private to ensure this
+  return mtype.matchType(static_cast<Type const*>(this),
+                         static_cast<Type const*>(obj), flags);
+}
+
+unsigned BaseType::hashValue() const
+{
+  unsigned h = innerHashValue();
+
+  // 'h' now has quite a few bits of entropy, but they're mostly
+  // in the high bits.  push it through a PRNG to mix it better.
+  return lcprngTwoSteps_inline(h);
+}
+
+
+string cvToString(CVFlags cv)
+{
+  if (cv != CV_NONE) {
+    return stringc << " " << toString(cv);
+  }
+  else {
+    return string("");
+  }
+}
+
+
+void BaseType::gdb() const
+{
+  cout << toString() << endl;
+}
+
+string BaseType::toString() const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  if (printAsML) {
+    return toMLString();
+  }
+  else {
+    return toCString();
+  }
+}
+
+
+string BaseType::toCString() const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  if (isCVAtomicType()) {
+    // special case a single atomic type, so as to avoid
+    // printing an extra space
+    CVAtomicType const *cvatomic = asCVAtomicTypeC();
+    return stringc
+      << cvatomic->atomic->toCString()
+      << cvToString(cvatomic->cv);
+  }
+  else {
+    return stringc
+      << leftString()
+      << rightString();
+  }
+}
+
+string BaseType::toCString(char const *name) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  // print the inner parentheses if the name is omitted
+  bool innerParen = (name && name[0])? false : true;
+
+  #if 0    // wrong
+  // except, if this type is a pointer, then omit the parens anyway;
+  // we only need parens when the type is a function or array and
+  // the name is missing
+  if (isPointerType()) {
+    innerParen = false;
+  }
+  #endif // 0
+  stringBuilder s;
+  s << leftString(innerParen);
+  if (name) {
+    s << name;
+  }
+  else if (printAnonComment) {
+    s << "/*anon*/";
+  }
+  s << rightString(innerParen);
+  return s;
+}
+
+// this is only used by CVAtomicType.. all others override it
+string BaseType::rightString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  return "";
+}
+
+
+bool BaseType::anyCtorSatisfiesF(TypePredFunc f) const
+{
+  StatelessTypePred stp(f);
+  return anyCtorSatisfies(stp);
+}
+
+
+CVFlags BaseType::getCVFlags() const
+{
+  return CV_NONE;
+}
+
+
+bool BaseType::isSimpleType() const
+{
+  if (isCVAtomicType()) {
+    AtomicType const *at = asCVAtomicTypeC()->atomic;
+    return at->isSimpleType();
+  }
+  else {
+    return false;
+  }
+}
+
+SimpleType const *BaseType::asSimpleTypeC() const
+{
+  return asCVAtomicTypeC()->atomic->asSimpleTypeC();
+}
+
+bool BaseType::isSimple(SimpleTypeId id) const
+{
+  return isSimpleType() &&
+         asSimpleTypeC()->type == id;
+}
+
+bool BaseType::isSomeKindOfCharType() const
+{
+  return
+    isSimple(ST_CHAR)          ||
+    isSimple(ST_UNSIGNED_CHAR) ||
+    isSimple(ST_SIGNED_CHAR)   ||
+    isSimple(ST_WCHAR_T);
+}
+
+bool BaseType::isStringType() const
+{
+  return isArrayType() &&
+    (asArrayTypeC()->eltType->isSimpleCharType() ||
+     asArrayTypeC()->eltType->isSimpleWChar_tType());
+}
+
+bool BaseType::isIntegerType() const
+{
+  return isSimpleType() &&
+         ::isIntegerType(asSimpleTypeC()->type);
+}
+
+
+bool BaseType::isEnumType() const
+{
+  return isCVAtomicType() &&
+         asCVAtomicTypeC()->atomic->isEnumType();
+}
+
+
+bool BaseType::isDependent() const
+{
+  // 14.6.2.1: type variables (template parameters) are the base case
+  // for dependent types
+  return isSimple(ST_DEPENDENT) ||
+         isTypeVariable();
+}
+
+bool BaseType::isGeneralizedDependent() const
+{
+  if (isSimple(ST_DEPENDENT) ||
+      isTypeVariable() ||
+      isPseudoInstantiation() ||
+      isDependentQType()) {
+    return true;
+  }
+
+  // 10/09/04: (in/d0113.cc) I want to regard A<T>::B, where B is an
+  // inner class of template class A, as being dependent.  For that
+  // matter, A itself should be regarded as dependent.  So if 'ct'
+  // has template parameters (including inherited), say it is
+  // dependent.
+  //
+  // 2005-05-06: I removed the following because I think it is wrong.
+  // The name 'A' (if found in, say, the global scope) is not dependent,
+  // though 'A<T>' might be (if T is an uninst template param).  I think
+  // in/d0113.cc was just invalid, and I fixed it.
+  //
+  // 2005-08-12: Ok, I think I want to call it dependent *only* on the
+  // basis of whether there are *inherited* params, as in A<T>::B.
+  // A<T> itself would be a PseudoInstantiation (and therefore
+  // dependent), while just A would not be dependent, despite having
+  // (non-inherited) parameters.  (in/t0551.cc)
+  if (isCompoundType()) {
+    TemplateInfo *ti = asCompoundTypeC()->templateInfo();
+    if (ti && ti->hasInheritedParameters()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static bool cGD_helper(Type const *t)
+{
+  return t->isGeneralizedDependent();
+}
+
+// What is the intended difference in usage between
+// 'isGeneralizedDependent' and 'containsGeneralizedDependent'?
+// Mostly, the latter includes types that cannot be classes even when
+// template args are supplied, whereas the former includes only types
+// that *might* be classes when targs are supplied.  (TODO: write up
+// the entire design of dependent type representation)
+bool BaseType::containsGeneralizedDependent() const
+{
+  return anyCtorSatisfiesF(cGD_helper);
+}
+
+
+bool BaseType::isCompoundTypeOf(CompoundType::Keyword keyword) const
+{
+  if (isCVAtomicType()) {
+    CVAtomicType const *a = asCVAtomicTypeC();
+    return a->atomic->isCompoundType() &&
+           a->atomic->asCompoundTypeC()->keyword == keyword;
+  }
+  else {
+    return false;
+  }
+}
+
+NamedAtomicType *BaseType::ifNamedAtomicType()
+{
+  return isNamedAtomicType()? asNamedAtomicType() : NULL;
+}
+
+CompoundType *BaseType::ifCompoundType()
+{
+  return isCompoundType()? asCompoundType() : NULL;
+}
+
+NamedAtomicType const *BaseType::asNamedAtomicTypeC() const
+{
+  return asCVAtomicTypeC()->atomic->asNamedAtomicTypeC();
+}
+
+CompoundType const *BaseType::asCompoundTypeC() const
+{
+  return asCVAtomicTypeC()->atomic->asCompoundTypeC();
+}
+
+PseudoInstantiation const *BaseType::asPseudoInstantiationC() const
+{
+  return asCVAtomicTypeC()->atomic->asPseudoInstantiationC();
+}
+
+
+bool BaseType::isOwnerPtr() const
+{
+  return isPointer() && ((asPointerTypeC()->cv & CV_OWNER) != 0);
+}
+
+bool BaseType::isMethod() const
+{
+  return isFunctionType() &&
+         asFunctionTypeC()->isMethod();
+}
+
+bool BaseType::isReferenceToConst() const {
+  return isReferenceType() && asReferenceTypeC()->atType->isConst();
+}
+
+bool BaseType::isPointerOrArrayRValueType() const {
+  return asRvalC()->isPointerType() || asRvalC()->isArrayType();
+}
+
+// FIX: this is silly; it should be made into a virtual dispatch
+Type *BaseType::getAtType() const
+{
+  if (isPointerType()) {
+    return asPointerTypeC()->atType;
+  }
+  else if (isReferenceType()) {
+    return asReferenceTypeC()->atType;
+  }
+  else if (isArrayType()) {
+    return asArrayTypeC()->eltType;
+  }
+  else if (isPointerToMemberType()) {
+    return asPointerToMemberTypeC()->atType;
+  }
+  else {
+    xfailure("illegal call to getAtType");
+    return NULL;       // silence warning
+  }
+}
+
+BaseType const *BaseType::asRvalC() const
+{
+  if (isReference()) {
+    // note that due to the restriction about stacking reference
+    // types, unrolling more than once is never necessary
+    return asReferenceTypeC()->atType;
+  }
+  else {
+    return this;       // this possibility is one reason to not make 'asRval' return 'Type*' in the first place
+  }
+}
+
+
+bool BaseType::isCVAtomicType(AtomicType::Tag tag) const
+{
+  return isCVAtomicType() &&
+         asCVAtomicTypeC()->atomic->getTag() == tag;
+}
+
+
+TypeVariable const *BaseType::asTypeVariableC() const
+{
+  return asCVAtomicTypeC()->atomic->asTypeVariableC();
+}
+
+
+bool BaseType::isNamedAtomicType() const {
+  return isCVAtomicType() && asCVAtomicTypeC()->atomic->isNamedAtomicType();
+}
+
+
+bool typeIsError(Type const *t)
+{
+  return t->isError();
+}
+
+bool BaseType::containsErrors() const
+{
+  return anyCtorSatisfiesF(typeIsError);
+}
+
+
+bool typeHasTypeVariable(Type const *t)
+{
+  return t->isTypeVariable() ||
+         (t->isCompoundType() &&
+          t->asCompoundTypeC()->isTemplate(true /*considerInherited*/)) ||
+         t->isPseudoInstantiation();
+}
+
+bool BaseType::containsTypeVariables() const
+{
+  return anyCtorSatisfiesF(typeHasTypeVariable);
+}
+
+
+// TODO: sm: I think it's wrong to have both 'hasTypeVariable' and
+// 'hasVariable', since I think any use of the former actually wants
+// to be a use of the latter.
+
+
+// ------------------ ContainsVariablesPred ------------------
+class ContainsVariablesPred : public TypePred {
+public:      // data
+  MType *map;        // nullable serf
+
+private:     // funcs
+  bool isUnbound(StringRef name);
+
+public:      // funcs
+  ContainsVariablesPred(MType *m) : map(m) {}
+
+  virtual bool operator() (Type const *t);
+  bool atomicTypeHasVariable(AtomicType const *t);
+  bool nameContainsVariables(PQName const *name);
+};
+
+
+bool ContainsVariablesPred::isUnbound(StringRef name)
+{
+  return !map || !map->isBound(name);
+}
+
+
+bool ContainsVariablesPred::atomicTypeHasVariable(AtomicType const *t)
+{
+  if (t->isTypeVariable()) {
+    return isUnbound(t->asTypeVariableC()->name);
+  }
+
+  if (t->isPseudoInstantiation()) {
+    PseudoInstantiation const *pi = t->asPseudoInstantiationC();
+    return atomicTypeHasVariable(pi->primary) ||
+           containsVariables(pi->args, map);
+  }
+
+  if (t->isDependentQType()) {
+    DependentQType const *dqt = t->asDependentQTypeC();
+    return atomicTypeHasVariable(dqt->first) ||
+           nameContainsVariables(dqt->rest);
+  }
+
+  if (t->isCompoundType() &&
+      t->asCompoundTypeC()->isTemplate(true /*considerInherited*/)) {
+    return true;
+
+    // 2005-08-12: this was here, but I think it is wrong
+    //return containsVariables(t->asCompoundTypeC()->templateInfo()->arguments, map);
+  }
+
+  return false;
+}
+
+
+bool ContainsVariablesPred::nameContainsVariables(PQName const *name)
+{
+  ASTSWITCHC(PQName, name) {
+    ASTCASEC(PQ_template, t) {
+      return containsVariables(t->sargs, map);
+    }
+    ASTNEXTC(PQ_qualifier, q) {
+      return containsVariables(q->sargs, map) ||
+             nameContainsVariables(q->rest);
+    }
+    ASTDEFAULTC {
+      return false;
+    }
+    ASTENDCASEC
+  }
+}
+
+
+bool ContainsVariablesPred::operator() (Type const *t)
+{
+  if (t->isCVAtomicType()) {
+    return atomicTypeHasVariable(t->asCVAtomicTypeC()->atomic);
+  }
+  else if (t->isPointerToMemberType()) {
+    return atomicTypeHasVariable(t->asPointerToMemberTypeC()->inClassNAT);
+  }
+
+  return false;
+}
+
+
+bool BaseType::containsVariables(MType *map) const
+{
+  ContainsVariablesPred cvp(map);
+  return anyCtorSatisfies(cvp);
+}
+
+
+string toString(Type *t)
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  return t->toString();
+}
+
+
+// ----------------- CVAtomicType ----------------
+// map cv down to {0,1,2,3}
+inline unsigned cvHash(CVFlags cv)
+{
+  return cv >> CV_SHIFT_AMOUNT;
+}
+
+unsigned CVAtomicType::innerHashValue() const
+{
+  // underlying atomic is pointer-based equality
+  return (unsigned long)atomic +
+         cvHash(cv);
+         // T_ATOMIC is zero anyway
+}
+
+
+string CVAtomicType::leftString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder s;
+  s << atomic->toCString();
+  s << cvToString(cv);
+
+  // this is the only mandatory space in the entire syntax
+  // for declarations; it separates the type specifier from
+  // the declarator(s)
+  s << " ";
+
+  return s;
+}
+
+
+int CVAtomicType::reprSize() const
+{
+  return atomic->reprSize();
+}
+
+
+bool CVAtomicType::anyCtorSatisfies(TypePred &pred) const
+{
+  return pred(this);
+}
+
+
+CVFlags CVAtomicType::getCVFlags() const
+{
+  return cv;
+}
+
+
+void CVAtomicType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitType(this)) {
+    return;
+  }
+
+  atomic->traverse(vis);
+
+  vis.postvisitType(this);
+}
+
+
+// ------------------- PointerType ---------------
+PointerType::PointerType(CVFlags c, Type *a)
+  : cv(c), atType(a)
+{
+  // dsw: I had to put the 'if' here because the xml deserialization
+  // code makes objects with NULL arguments and then fills them in
+  // later
+  if (a) {
+    // it makes no sense to stack reference operators underneath
+    // other indirections (i.e. no ptr-to-ref, nor ref-to-ref)
+    xassert(!a->isReference());
+  }
+}
+
+
+enum {
+  // enough to leave room for a composed type to describe itself
+  // (essentially 5 bits)
+  HASH_KICK = 33,
+
+  // put the tag in the upper part of those 5 bits
+  TAG_KICK = 7
+};
+
+unsigned PointerType::innerHashValue() const
+{
+  // The essential strategy for composed types is to multiply the
+  // underlying type's hash by HASH_KICK, pushing the existing bits up
+  // (but with mixing), and then add our local info, including the
+  // tag.
+  //
+  // I don't claim to be an expert at designing hash functions.  There
+  // are probably better ones; if you think you know one, let me know.
+  // My plan is to watch the hash outputs produced during operator
+  // overload resolution, and tweak the function if I see an obvious
+  // avenue for improvement.
+
+  return atType->innerHashValue() * HASH_KICK +
+         cvHash(cv) +
+         T_POINTER * TAG_KICK;
+}
+
+
+string PointerType::leftString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder s;
+  s << atType->leftString(false /*innerParen*/);
+  if (atType->isFunctionType() ||
+      atType->isArrayType()) {
+    s << "(";
+  }
+  s << "*";
+  if (cv) {
+    // 1/03/03: added this space so "Foo * const arf" prints right (t0012.cc)
+    s << cvToString(cv) << " ";
+  }
+  return s;
+}
+
+string PointerType::rightString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder s;
+  if (atType->isFunctionType() ||
+      atType->isArrayType()) {
+    s << ")";
+  }
+  s << atType->rightString(false /*innerParen*/);
+  return s;
+}
+
+
+int PointerType::reprSize() const
+{
+  // a typical value .. (architecture-dependent)
+  return 4;
+}
+
+
+bool PointerType::anyCtorSatisfies(TypePred &pred) const
+{
+  return pred(this) ||
+         atType->anyCtorSatisfies(pred);
+}
+
+
+CVFlags PointerType::getCVFlags() const
+{
+  return cv;
+}
+
+
+void PointerType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitType(this)) {
+    return;
+  }
+
+  atType->traverse(vis);
+
+  vis.postvisitType(this);
+}
+
+
+// ------------------- ReferenceType ---------------
+ReferenceType::ReferenceType(Type *a)
+  : atType(a)
+{
+  // dsw: I had to put the 'if' here because the xml deserialization
+  // code makes objects with NULL arguments and then fills them in
+  // later
+  if (a) {
+    // it makes no sense to stack reference operators underneath
+    // other indirections (i.e. no ptr-to-ref, nor ref-to-ref)
+    xassert(!a->isReference());
+  }
+}
+
+
+unsigned ReferenceType::innerHashValue() const
+{
+  return atType->innerHashValue() * HASH_KICK +
+         T_REFERENCE * TAG_KICK;
+}
+
+
+string ReferenceType::leftString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder s;
+  s << atType->leftString(false /*innerParen*/);
+  if (atType->isFunctionType() ||
+      atType->isArrayType()) {
+    s << "(";
+  }
+  s << "&";
+  return s;
+}
+
+string ReferenceType::rightString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder s;
+  if (atType->isFunctionType() ||
+      atType->isArrayType()) {
+    s << ")";
+  }
+  s << atType->rightString(false /*innerParen*/);
+  return s;
+}
+
+int ReferenceType::reprSize() const
+{
+  return 4;
+}
+
+
+bool ReferenceType::anyCtorSatisfies(TypePred &pred) const
+{
+  return pred(this) ||
+         atType->anyCtorSatisfies(pred);
+}
+
+
+CVFlags ReferenceType::getCVFlags() const
+{
+  return CV_NONE;
+}
+
+
+void ReferenceType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitType(this)) {
+    return;
+  }
+
+  atType->traverse(vis);
+
+  vis.postvisitType(this);
+}
+
+
+// -------------------- FunctionType::ExnSpec --------------
+FunctionType::ExnSpec::ExnSpec(ExnSpec const &obj)
+{
+  // copy list contents
+  types = obj.types;
+}
+
+
+FunctionType::ExnSpec::~ExnSpec()
+{
+  types.removeAll();
+}
+
+
+bool FunctionType::ExnSpec::anyCtorSatisfies(TypePred &pred) const
+{
+  SFOREACH_OBJLIST(Type, types, iter) {
+    if (iter.data()->anyCtorSatisfies(pred)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// -------------------- FunctionType -----------------
+FunctionType::FunctionType(Type *r)
+  : flags(FF_NONE),
+    retType(r),
+    params(),
+    exnSpec(NULL)
+{}
+
+
+FunctionType::~FunctionType()
+{
+  if (exnSpec) {
+    delete exnSpec;
+  }
+}
+
+
+// sm: I moved 'isCopyConstructorFor' and 'isCopyAssignOpFor' out into
+// cc_tcheck.cc since the rules are fairly specific to the analysis
+// being performed there
+
+
+bool FunctionType::paramsHaveDefaultsPast(int startParam) const
+{
+  SObjListIter<Variable> iter(params);
+
+  // count off 'startParams' parameters that are not tested
+  while (!iter.isDone() && startParam>0) {
+    iter.adv();
+    startParam--;
+  }
+
+  // all remaining parameters must accept defaults
+  for (; !iter.isDone(); iter.adv()) {
+    if (!iter.data()->value) {
+      return false;     // doesn't have a default value
+    }
+  }
+
+  return true;          // all params after 'startParam' have defaults
+}
+
+
+unsigned FunctionType::innerHashValue() const
+{
+  // process return type similarly to how other constructed types
+  // handle their underlying type
+  unsigned val = retType->innerHashValue() * HASH_KICK +
+                 params.count() +
+                 T_FUNCTION * TAG_KICK;
+
+  // now factor in the parameter types
+  int ct = 1;
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    // similar to return value
+    unsigned p = iter.data()->type->innerHashValue() * HASH_KICK +
+                 (ct + T_FUNCTION) * TAG_KICK;
+
+    // multiply with existing hash, sort of like each parameter
+    // is another dimension and we're constructing a tuple in
+    // some space
+    val *= p;
+  }
+
+  // don't consider exnSpec or templateInfo; I don't think I'll be
+  // encountering situations where I want the hash to be sensitive to
+  // those
+
+  // the 'flags' information is mostly redundant with the parameter
+  // list, so don't bother folding that in
+
+  return val;
+}
+
+
+void FunctionType::addParam(Variable *param)
+{
+  xassert(param->hasFlag(DF_PARAMETER));
+  params.append(param);
+}
+
+void FunctionType::addReceiver(Variable *param)
+{
+  xassert(param->type->isReference());
+  xassert(param->hasFlag(DF_PARAMETER));
+  xassert(!isConstructor());    // ctors don't get a __receiver param
+  xassert(!isMethod());         // this is about to change below
+  params.prepend(param);
+  setFlag(FF_METHOD);
+}
+
+
+Variable const *FunctionType::getReceiverC() const
+{
+  xassert(isMethod());
+  Variable const *ret = params.firstC();
+  xassert(ret->getTypeC()->isReference());
+  return ret;
+}
+
+CVFlags FunctionType::getReceiverCV() const
+{
+  if (isMethod()) {
+    // expect 'this' to be of type 'SomeClass cv &', and
+    // dig down to get that 'cv'
+    return getReceiverC()->type->asReferenceType()->atType->asCVAtomicType()->cv;
+  }
+  else {
+    return CV_NONE;
+  }
+}
+
+CompoundType *FunctionType::getClassOfMember()
+{
+  return getReceiver()->type->asReferenceType()->atType->asCompoundType();
+}
+
+NamedAtomicType *FunctionType::getNATOfMember()
+{
+  return getReceiver()->type->asReferenceType()->atType->asNamedAtomicType();
+}
+
+
+string FunctionType::leftString(bool innerParen) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder sb;
+
+  // FIX: FUNC TEMPLATE LOSS
+  // template parameters
+//    if (templateInfo) {
+//      sb << templateInfo->paramsToCString() << " ";
+//    }
+
+  // return type and start of enclosing type's description
+  if (flags & (/*FF_CONVERSION |*/ FF_CTOR | FF_DTOR)) {
+    // don't print the return type, it's implicit
+
+    // 7/18/03: changed so we print ret type for FF_CONVERSION,
+    // since otherwise I can't tell what it converts to!
+  }
+  else {
+    sb << retType->leftString();
+  }
+
+  // NOTE: we do *not* propagate 'innerParen'!
+  if (innerParen) {
+    sb << "(";
+  }
+
+  return sb;
+}
+
+string FunctionType::rightString(bool innerParen) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  // I split this into two pieces because the Cqual++ concrete
+  // syntax puts $tainted into the middle of my rightString,
+  // since it's following the placement of 'const' and 'volatile'
+  return stringc
+    << rightStringUpToQualifiers(innerParen)
+    << rightStringQualifiers(getReceiverCV())
+    << rightStringAfterQualifiers();
+}
+
+string FunctionType::rightStringUpToQualifiers(bool innerParen) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  // finish enclosing type
+  stringBuilder sb;
+  if (innerParen) {
+    sb << ")";
+  }
+
+  // arguments
+  sb << "(";
+  int ct=0;
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    ct++;
+    if (isMethod() && ct==1) {
+      // don't actually print the first parameter;
+      // the 'm' stands for nonstatic member function
+      sb << "/""*m: " << iter.data()->type->toCString() << " *""/ ";
+      continue;
+    }
+    if (ct >= 3 || (!isMethod() && ct>=2)) {
+      sb << ", ";
+    }
+    sb << iter.data()->toCStringAsParameter();
+  }
+
+  if (acceptsVarargs()) {
+    if (ct++ > 0) {
+      sb << ", ";
+    }
+    sb << "...";
+  }
+
+  sb << ")";
+
+  return sb;
+}
+
+STATICDEF string FunctionType::rightStringQualifiers(CVFlags cv)
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  if (cv) {
+    return stringc << " " << ::toString(cv);
+  }
+  else {
+    return "";
+  }
+}
+
+string FunctionType::rightStringAfterQualifiers() const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder sb;
+
+  // exception specs
+  if (exnSpec) {
+    sb << " throw(";
+    int ct=0;
+    SFOREACH_OBJLIST(Type, exnSpec->types, iter) {
+      if (ct++ > 0) {
+        sb << ", ";
+      }
+      sb << iter.data()->toCString();
+    }
+    sb << ")";
+  }
+
+  // hook for verifier syntax
+  extraRightmostSyntax(sb);
+
+  // finish up the return type
+  sb << retType->rightString();
+
+  return sb;
+}
+
+void FunctionType::extraRightmostSyntax(stringBuilder &) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+}
+
+
+string FunctionType::toString_withCV(CVFlags cv) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  return stringc
+    << leftString(true /*innerParen*/)
+    << rightStringUpToQualifiers(true /*innerParen*/)
+    << rightStringQualifiers(cv)
+    << rightStringAfterQualifiers();
+}
+
+
+int FunctionType::reprSize() const
+{
+  // thinking here about how this works when we're summing
+  // the fields of a class with member functions ..
+  return 0;
+}
+
+
+bool parameterListCtorSatisfies(TypePred &pred,
+                                SObjList<Variable> const &params)
+{
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    if (iter.data()->type->anyCtorSatisfies(pred)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FunctionType::anyCtorSatisfies(TypePred &pred) const
+{
+  return pred(this) ||
+         retType->anyCtorSatisfies(pred) ||
+         parameterListCtorSatisfies(pred, params) ||
+         (exnSpec && exnSpec->anyCtorSatisfies(pred));
+  // FIX: FUNC TEMPLATE LOSS
+  //
+  // UPDATE: this is actually symmetric with the way that compound
+  // type templates are dealt with, which is to say we do not recurse
+  // on the parameters
+//      || (templateInfo && templateInfo->anyParamCtorSatisfies(pred));
+}
+
+
+void FunctionType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitType(this)) {
+    return;
+  }
+
+  retType->traverse(vis);
+
+  // dsw: I need to know when the params list starts and stops
+  if (vis.visitFunctionType_params(params)) {
+    SFOREACH_OBJLIST_NC(Variable, params, iter) {
+      // I am choosing not to traverse into any of the other fields of
+      // the parameters, including default args.  For the application I
+      // have in mind right now (matching definitions to declarations),
+      // I do not need or want anything other than the parameter type.
+      // So, if this code is later extended to traverse into default
+      // args, there should be a flag to control that, and it should
+      // default to off (or change the existing call sites).
+      //
+//        iter.data()->type->traverse(vis);
+      // dsw: we now traverse the variable directly; the above comment
+      // should probably be moved into Variable::traverse()
+      if (vis.visitFunctionType_params_item(iter.data())) {
+        iter.data()->traverse(vis);
+        vis.postvisitFunctionType_params_item(iter.data());
+      }
+    }
+    vis.postvisitFunctionType_params(params);
+  }
+
+  // similarly, I don't want traversal into exception specs right now
+  //
+  // dsw: if you ever put them in, we have to take them out of the xml
+  // rendering or they will get rendered twice; in
+  // XmlTypeWriter::visitType() see this case statement
+  //   case Type::T_FUNCTION:
+
+  vis.postvisitType(this);
+}
+
+
+// -------------------- ArrayType ------------------
+void ArrayType::checkWellFormedness() const
+{
+  xassert(eltType);
+  xassert(!eltType->isReference());
+}
+
+
+unsigned ArrayType::innerHashValue() const
+{
+  // similar to PointerType
+  return eltType->innerHashValue() * HASH_KICK +
+         size +
+         T_ARRAY * TAG_KICK;
+}
+
+
+string ArrayType::leftString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  return eltType->leftString();
+}
+
+string ArrayType::rightString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder sb;
+
+  if (hasSize()) {
+    sb << "[" << size << "]";
+  }
+  else {
+    sb << "[]";
+  }
+
+  sb << eltType->rightString();
+
+  return sb;
+}
+
+
+int ArrayType::reprSize() const
+{
+  if (!hasSize()) {
+    throw_XReprSize(size == DYN_SIZE /*isDynamic*/);
+  }
+
+  return eltType->reprSize() * size;
+}
+
+
+bool ArrayType::anyCtorSatisfies(TypePred &pred) const
+{
+  return pred(this) ||
+         eltType->anyCtorSatisfies(pred);
+}
+
+
+
+void ArrayType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitType(this)) {
+    return;
+  }
+
+  eltType->traverse(vis);
+
+  vis.postvisitType(this);
+}
+
+
+// ---------------- PointerToMemberType ---------------
+PointerToMemberType::PointerToMemberType(NamedAtomicType *inClassNAT0, CVFlags c, Type *a)
+  : inClassNAT(inClassNAT0), cv(c), atType(a)
+{
+  // 'inClassNAT' should always be a compound or something dependent
+  // on a type variable; basically, it should just not be an enum,
+  // given that it is a named atomic type
+  xassert(!inClassNAT->isEnumType());
+
+  // cannot have pointer to reference type
+  xassert(!a->isReference());
+
+  // there are some other semantic restrictions, but I let the
+  // type checker enforce them
+}
+
+
+CompoundType *PointerToMemberType::inClass() const {
+  if (inClassNAT->isCompoundType()) {
+    return inClassNAT->asCompoundType();
+  }
+  xfailure("Request for the inClass member of a PointerToMemberType "
+           "as if it were a CompoundType which it is not in this case.");
+}
+
+
+unsigned PointerToMemberType::innerHashValue() const
+{
+  return atType->innerHashValue() * HASH_KICK +
+         cvHash(cv) +
+         T_POINTERTOMEMBER * TAG_KICK +
+         (unsigned long)inClass();   // we'll see...
+}
+
+
+string PointerToMemberType::leftString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder s;
+  s << atType->leftString(false /*innerParen*/);
+  s << " ";
+  if (atType->isFunctionType() ||
+      atType->isArrayType()) {
+    s << "(";
+  }
+  s << inClassNAT->name << "::*";
+  s << cvToString(cv);
+  return s;
+}
+
+string PointerToMemberType::rightString(bool /*innerParen*/) const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder s;
+  if (atType->isFunctionType() ||
+      atType->isArrayType()) {
+    s << ")";
+  }
+  s << atType->rightString(false /*innerParen*/);
+  return s;
+}
+
+
+int PointerToMemberType::reprSize() const
+{
+  // a typical value .. (architecture-dependent)
+  return 4;
+}
+
+
+bool PointerToMemberType::anyCtorSatisfies(TypePred &pred) const
+{
+  return pred(this) ||
+         atType->anyCtorSatisfies(pred);
+}
+
+
+CVFlags PointerToMemberType::getCVFlags() const
+{
+  return cv;
+}
+
+
+void PointerToMemberType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitType(this)) {
+    return;
+  }
+
+  inClassNAT->traverse(vis);
+  atType->traverse(vis);
+
+  vis.postvisitType(this);
+}
+
+
+// ---------------------- toMLString ---------------------
+// print out a type as an ML-style string
+
+//  Atomic
+string SimpleType::toMLString() const
+{
+  return simpleTypeName(type);
+}
+
+string CompoundType::toMLString() const
+{
+  stringBuilder sb;
+
+//    bool hasParams = templateInfo && templateInfo->params.isNotEmpty();
+//    if (hasParams) {
+  TemplateInfo *tinfo = templateInfo();
+  if (tinfo) {
+    sb << tinfo->paramsToMLString();
+  }
+
+//    if (!templateInfo || hasParams) {
+    // only say 'class' if this is like a class definition, or
+    // if we're not a template, since template instantiations
+    // usually don't include the keyword 'class' (this isn't perfect..
+    // I think I need more context)
+  sb << keywordName(keyword) << "-";
+//    }
+
+  if (name) {
+    sb << "'" << name << "'";
+  } else {
+    sb << "*anonymous*";
+  }
+
+  // template arguments are now in the name
+  //if (templateInfo && templateInfo->specialArguments) {
+  //  sb << "<" << templateInfo->specialArgumentsRepr << ">";
+  //}
+
+  return sb;
+}
+
+string EnumType::toMLString() const
+{
+  stringBuilder sb;
+  sb << "enum-";
+  if (name) {
+    sb << "'" << name << "'";
+  } else {
+    sb << "*anonymous*";
+  }
+  return sb;
+}
+
+string TypeVariable::toMLString() const
+{
+  return stringc << "typevar-'" << string(name) << "'";
+}
+
+string PseudoInstantiation::toMLString() const
+{
+  return stringc << "psuedoinstantiation-'" << primary->name << "'"
+                 << sargsToString(args);      // sm: ?
+}
+
+//  Constructed
+
+// I don't like #if-s everywhere, and Steve Fink agrees with me.
+void BaseType::putSerialNo(stringBuilder &sb) const
+{
+  #if USE_SERIAL_NUMBERS
+    printSerialNo(sb, "t", serialNumber, "-");
+  #endif
+}
+
+string CVAtomicType::toMLString() const
+{
+  stringBuilder sb;
+  sb << cvToString(cv) << " ";
+  putSerialNo(sb);
+  sb << atomic->toMLString();
+  return sb;
+}
+
+string PointerType::toMLString() const
+{
+  stringBuilder sb;
+  if (cv) {
+    sb << cvToString(cv) << " ";
+  }
+  putSerialNo(sb);
+  sb << "ptr(" << atType->toMLString() << ")";
+  return sb;
+}
+
+string ReferenceType::toMLString() const
+{
+  stringBuilder sb;
+  putSerialNo(sb);
+  sb << "ref(" << atType->toMLString() << ")";
+  return sb;
+}
+
+string FunctionType::toMLString() const
+{
+  stringBuilder sb;
+  // FIX: FUNC TEMPLATE LOSS
+//    if (templateInfo) {
+//      sb << templateInfo->paramsToMLString();
+//    }
+  putSerialNo(sb);
+  if (flags & FF_CTOR) {
+    sb << "ctor-";
+  }
+  sb << "fun";
+
+  sb << "(";
+
+  sb << "retType: " << retType->toMLString();
+  // arg, you can't do this due to the way Scott handles retVar
+//    if (retVar) {
+//      sb << ", " << retVar->toMLString();
+//    }
+
+  int ct=0;
+//    bool firstTime = true;
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    Variable const *v = iter.data();
+    ct++;
+//      if (firstTime) {
+//        firstTime = false;
+//      } else {
+    sb << ", ";                 // retType is first
+//      }
+//      if (isMethod() && ct==1) {
+//        // print "this" param
+//        sb << "this: " << v->type->toMLString();
+//        continue;
+//      }
+    sb << v->toMLString();
+//      sb << "'" << v->name << "'->" << v->type->toMLString();
+  }
+  sb << ")";
+  return sb;
+}
+
+string ArrayType::toMLString() const
+{
+  stringBuilder sb;
+  putSerialNo(sb);
+  sb << "array(";
+  sb << "size:";
+  if (hasSize()) {
+    sb << size;
+  } else {
+    sb << "unspecified";
+  }
+  sb << ", ";
+  sb << eltType->toMLString();
+  sb << ")";
+  return sb;
+}
+
+string PointerToMemberType::toMLString() const
+{
+  stringBuilder sb;
+  if (cv) {
+    sb << cvToString(cv) << " ";
+  }
+  putSerialNo(sb);
+  sb << "ptm(";
+  sb << inClassNAT->name;
+  sb << ", " << atType->toMLString();
+  sb << ")";
+  return sb;
+}
+
+string TemplateParams::paramsToMLString() const
+{
+  stringBuilder sb;
+  sb << "template <";
+#if 0
+  int ct=0;
+  // FIX: incomplete
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    Variable const *p = iter.data();
+    if (ct++ > 0) {
+      sb << ", ";
+    }
+
+    // FIX: is there any difference here?
+    // NOTE: use var->toMLString()
+    if (p->type->isTypeVariable()) {
+//        sb << "var(name:" << p->name << ", " << v->type->toMLString() << ")";
+    }
+    else {
+      // non-type parameter
+//        sb << p->toStringAsParameter();
+    }
+  }
+#endif
+  sb << ">";
+  return sb;
+}
+
+
+// ---------------------- TypeFactory ---------------------
+CompoundType *TypeFactory::makeCompoundType
+  (CompoundType::Keyword keyword, StringRef name)
+{
+  return new CompoundType(keyword, name);
+}
+
+
+Type *TypeFactory::shallowCloneType(Type *baseType)
+{
+  switch (baseType->getTag()) {
+    default:
+      xfailure("bad tag");
+      break;
+
+    case Type::T_ATOMIC: {
+      CVAtomicType *atomic = baseType->asCVAtomicType();
+
+      // make a new CVAtomicType with the same AtomicType as 'baseType',
+      // but with the new flags
+      return makeCVAtomicType(atomic->atomic, atomic->cv);
+    }
+
+    case Type::T_POINTER: {
+      PointerType *ptr = baseType->asPointerType();
+      return makePointerType(ptr->cv, ptr->atType);
+    }
+
+    case Type::T_REFERENCE: {
+      ReferenceType *ref = baseType->asReferenceType();
+      return makeReferenceType(ref->atType);
+    }
+
+    case Type::T_FUNCTION: {
+      FunctionType *ft = baseType->asFunctionType();
+      FunctionType *ret = makeFunctionType(ft->retType);
+      ret->flags = ft->flags;
+      SFOREACH_OBJLIST_NC(Variable, ft->params, paramiter) {
+        ret->params.append(paramiter.data());
+      }
+      ret->exnSpec = ft->exnSpec;
+      return ret;
+    }
+
+    case Type::T_ARRAY: {
+      ArrayType *arr = baseType->asArrayType();
+      return makeArrayType(arr->eltType, arr->size);
+    }
+
+    case Type::T_POINTERTOMEMBER: {
+      PointerToMemberType *ptm = baseType->asPointerToMemberType();
+      return makePointerToMemberType(ptm->inClassNAT, ptm->cv, ptm->atType);
+    }
+  }
+}
+
+
+// the idea is we're trying to apply 'cv' to 'baseType'; for
+// example, we could have gotten baseType like
+//   typedef unsigned char byte;     // baseType == unsigned char
+// and want to apply const:
+//   byte const b;                   // cv = CV_CONST
+// yielding final type
+//   unsigned char const             // return value from this fn
+Type *TypeFactory::setQualifiers(SourceLoc loc, CVFlags cv, Type *baseType,
+                                 TypeSpecifier *)
+{
+  if (baseType->isError()) {
+    return baseType;
+  }
+
+  if (cv == baseType->getCVFlags()) {
+    // keep what we've got
+    return baseType;
+  }
+
+  Type *ret = NULL;
+
+  if (baseType->isCVAtomicType()) {
+    ret = shallowCloneType(baseType);
+    ret->asCVAtomicType()->cv = cv;
+  } else if (baseType->isPointerType()) {
+    ret = shallowCloneType(baseType);
+    ret->asPointerType()->cv = cv;
+  } else if (baseType->isPointerToMemberType()) {
+    ret = shallowCloneType(baseType);
+    ret->asPointerToMemberType()->cv = cv;
+  } else {
+    // anything else cannot have a cv applied to it anyway; the NULL
+    // will result in an error message in the client
+    ret = NULL;
+  }
+
+  return ret;
+}
+
+
+Type *TypeFactory::applyCVToType(SourceLoc loc, CVFlags cv, Type *baseType,
+                                 TypeSpecifier *syntax)
+{
+  if (baseType->isReferenceType()) {
+    // 8.3.2p1: this is fine; 'cv' is ignored
+    return baseType;
+  }
+
+  CVFlags now = baseType->getCVFlags();
+  if (wantsQualifiedTypeReuseOptimization() &&
+      now | cv == now) {
+    // no change, 'cv' already contained in the existing flags
+    return baseType;
+  }
+  else if (baseType->isArrayType()) {
+    // 8.3.4 para 1: apply cv to the element type
+    //
+    // Note: This clones the ArrayType object every time, if someone
+    // is adding const or volatile to an array (possible via typedef).
+    // This is probably a bug.
+    ArrayType *at = baseType->asArrayType();
+    return makeArrayType(applyCVToType(loc, cv, at->eltType, NULL /*syntax*/),
+                         at->size);
+  }
+  else {
+    // change to the union; setQualifiers will take care of catching
+    // inappropriate application (e.g. 'const' to a reference)
+    return setQualifiers(loc, now | cv, baseType, syntax);
+  }
+}
+
+
+bool TypeFactory::wantsQualifiedTypeReuseOptimization()
+{
+  return true;
+}
+
+
+Type *TypeFactory::syntaxPointerType(SourceLoc loc,
+  CVFlags cv, Type *type, D_pointer *)
+{
+  return makePointerType(cv, type);
+}
+
+Type *TypeFactory::syntaxReferenceType(SourceLoc loc,
+  Type *type, D_reference *)
+{
+  return makeReferenceType(type);
+}
+
+
+FunctionType *TypeFactory::syntaxFunctionType(SourceLoc loc,
+  Type *retType, D_func *syntax, TranslationUnit *tunit)
+{
+  return makeFunctionType(retType);
+}
+
+
+PointerToMemberType *TypeFactory::syntaxPointerToMemberType(SourceLoc loc,
+  NamedAtomicType *inClassNAT, CVFlags cv, Type *atType, D_ptrToMember *syntax)
+{
+  return makePointerToMemberType(inClassNAT, cv, atType);
+}
+
+
+Type *TypeFactory::makeTypeOf_receiver(SourceLoc loc,
+  NamedAtomicType *classType, CVFlags cv, D_func *syntax)
+{
+  CVAtomicType *at = makeCVAtomicType(classType, cv);
+  return makeReferenceType(at);
+}
+
+
+FunctionType *TypeFactory::makeSimilarFunctionType(SourceLoc loc,
+  Type *retType, FunctionType *similar)
+{
+  FunctionType *ret =
+    makeFunctionType(retType);
+  ret->flags = similar->flags & ~FF_METHOD;     // isMethod is like a parameter
+  if (similar->exnSpec) {
+    ret->exnSpec = new FunctionType::ExnSpec(*similar->exnSpec);
+  }
+  return ret;
+}
+
+
+CVAtomicType *TypeFactory::getSimpleType(SimpleTypeId st, CVFlags cv)
+{
+  xassert((unsigned)st < (unsigned)NUM_SIMPLE_TYPES);
+  return makeCVAtomicType(&SimpleType::fixed[st], cv);
+}
+
+
+ArrayType *TypeFactory::setArraySize(SourceLoc loc, ArrayType *type, int size)
+{
+  return makeArrayType(type->eltType, size);
+}
+
+
+// -------------------- BasicTypeFactory ----------------------
+// this is for when I split Type from Type_Q
+CVAtomicType BasicTypeFactory::unqualifiedSimple[NUM_SIMPLE_TYPES] = {
+  #define CVAT(id) \
+    CVAtomicType(&SimpleType::fixed[id], CV_NONE),
+  CVAT(ST_CHAR)
+  CVAT(ST_UNSIGNED_CHAR)
+  CVAT(ST_SIGNED_CHAR)
+  CVAT(ST_BOOL)
+  CVAT(ST_INT)
+  CVAT(ST_UNSIGNED_INT)
+  CVAT(ST_LONG_INT)
+  CVAT(ST_UNSIGNED_LONG_INT)
+  CVAT(ST_LONG_LONG)
+  CVAT(ST_UNSIGNED_LONG_LONG)
+  CVAT(ST_SHORT_INT)
+  CVAT(ST_UNSIGNED_SHORT_INT)
+  CVAT(ST_WCHAR_T)
+  CVAT(ST_FLOAT)
+  CVAT(ST_DOUBLE)
+  CVAT(ST_LONG_DOUBLE)
+  CVAT(ST_FLOAT_COMPLEX)
+  CVAT(ST_DOUBLE_COMPLEX)
+  CVAT(ST_LONG_DOUBLE_COMPLEX)
+  CVAT(ST_FLOAT_IMAGINARY)
+  CVAT(ST_DOUBLE_IMAGINARY)
+  CVAT(ST_LONG_DOUBLE_IMAGINARY)
+  CVAT(ST_VOID)
+
+  CVAT(ST_ELLIPSIS)
+  CVAT(ST_CDTOR)
+  CVAT(ST_ERROR)
+  CVAT(ST_DEPENDENT)
+  CVAT(ST_IMPLINT)
+  CVAT(ST_NOTFOUND)
+
+  CVAT(ST_PROMOTED_INTEGRAL)
+  CVAT(ST_PROMOTED_ARITHMETIC)
+  CVAT(ST_INTEGRAL)
+  CVAT(ST_ARITHMETIC)
+  CVAT(ST_ARITHMETIC_NON_BOOL)
+  CVAT(ST_ANY_OBJ_TYPE)
+  CVAT(ST_ANY_NON_VOID)
+  CVAT(ST_ANY_TYPE)
+
+  CVAT(ST_PRET_STRIP_REF)
+  CVAT(ST_PRET_PTM)
+  CVAT(ST_PRET_ARITH_CONV)
+  CVAT(ST_PRET_FIRST)
+  CVAT(ST_PRET_FIRST_PTR2REF)
+  CVAT(ST_PRET_SECOND)
+  CVAT(ST_PRET_SECOND_PTR2REF)
+  #undef CVAT
+};
+
+
+CVAtomicType *BasicTypeFactory::makeCVAtomicType(AtomicType *atomic, CVFlags cv)
+{
+  // dsw: we now need to avoid this altogether since in
+  // setQualifiers() I mutate the cv value on a type after doing the
+  // shallowClone(); NOTE: the #ifndef OINK is no longer needed as
+  // Oink no longer delegates to this method.
+//  #ifndef OINK
+//    // FIX: We need to avoid doing this in Oink
+//    if (cv==CV_NONE && atomic->isSimpleType()) {
+//      // since these are very common, and ordinary Types are immutable,
+//      // share them
+//      SimpleType *st = atomic->asSimpleType();
+//      xassert((unsigned)(st->type) < (unsigned)NUM_SIMPLE_TYPES);
+//      return &(unqualifiedSimple[st->type]);
+//    }
+//  #endif
+
+  return new CVAtomicType(atomic, cv);
+}
+
+
+PointerType *BasicTypeFactory::makePointerType(CVFlags cv, Type *atType)
+{
+  return new PointerType(cv, atType);
+}
+
+
+Type *BasicTypeFactory::makeReferenceType(Type *atType)
+{
+  return new ReferenceType(atType);
+}
+
+
+FunctionType *BasicTypeFactory::makeFunctionType(Type *retType)
+{
+  return new FunctionType(retType);
+}
+
+void BasicTypeFactory::doneParams(FunctionType *)
+{}
+
+
+ArrayType *BasicTypeFactory::makeArrayType(Type *eltType, int size)
+{
+  return new ArrayType(eltType, size);
+}
+
+
+PointerToMemberType *BasicTypeFactory::makePointerToMemberType
+  (NamedAtomicType *inClassNAT, CVFlags cv, Type *atType)
+{
+  return new PointerToMemberType(inClassNAT, cv, atType);
+}
+
+
+Variable *BasicTypeFactory::makeVariable(
+  SourceLoc L, StringRef n, Type *t, DeclFlags f)
+{
+  // I will turn this on from time to time as a way to check that
+  // Types are always capable of printing themselves.  It should never
+  // be checked in when in the "on" state.
+  #if 0
+    if (t) {
+      t->toString();
+    }
+  #endif // 0
+
+  // the TranslationUnit parameter is ignored by default; it is passed
+  // only for the possible benefit of an extension analysis
+  Variable *var = new Variable(L, n, t, f);
+  return var;
+}
+
+
+// -------------------- XReprSize -------------------
+XReprSize::XReprSize(bool d)
+  : xBase(stringc << "reprSize of a " << (d ? "dynamically-sized" : "sizeless")
+                  << " array"),
+    isDynamic(d)
+{}
+
+XReprSize::XReprSize(XReprSize const &obj)
+  : xBase(obj),
+    isDynamic(obj.isDynamic)
+{}
+
+XReprSize::~XReprSize()
+{}
+
+
+void throw_XReprSize(bool d)
+{
+  XReprSize x(d);
+  THROW(x);
+}
+
+
+// --------------- debugging ---------------
+char *type_toString(Type const *t)
+{
+  // defined in smbase/strutil.cc
+  return copyToStaticBuffer(t->toString().c_str());
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cc_type.h
===================================================================
--- vendor/elsa/current/elsa/cc_type.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cc_type.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1388 @@
+// cc_type.h            see license.txt for copyright and terms of use
+// compile-type representation of C++ types
+// see doc/cc_type.html
+// and Diagram 1 of doc/cpp_er.html
+
+// The original design intent was that type representation would be
+// completely independent of the Expression language, or anything
+// else from cc.ast.  That is, types should have meaning independent
+// of the language of values, or of the syntax used to describe them
+// in source code.
+//
+// However, the practicalities of parsing C++ have forced my hand in a
+// couple of places.  Those places are marked with the annotation
+// "(AST pointer)".  In all cases so far, I can forsee an intermediate
+// transformation which would remove (e.g. nullify) all the AST
+// pointers in the process of creating a "minimized" C++ subset.  In
+// particular, it should be possible to translate away everything
+// related to templates.
+//
+// *Please* do not add any additional AST pointers unless it is
+// really necessary.  Also please make sure all the types can
+// intelligbly print themselves *without* inspecting the AST pointers
+// (by storing a textual representation if necessary).
+
+#ifndef CC_TYPE_H
+#define CC_TYPE_H
+
+#include "str.h"          // string
+#include "objlist.h"      // ObjList
+#include "sobjlist.h"     // SObjList
+#include "astlist.h"      // ASTList
+#include "cc_flags.h"     // CVFlags, DeclFlags, SimpleTypeId
+#include "strtable.h"     // StringRef
+#include "strobjdict.h"   // StringObjDict
+#include "cc_scope.h"     // Scope
+#include "srcloc.h"       // SourceLoc
+#include "exc.h"          // xBase
+#include "serialno.h"     // INHERIT_SERIAL_BASE
+#include "mflags.h"       // MatchFlags
+
+class Variable;           // variable.h
+class Env;                // cc_env.h
+class TS_classSpec;       // cc.ast
+class Expression;         // cc.ast
+class TemplateArgument;   // cc.ast
+class D_pointer;          // cc.ast
+class D_reference;        // cc.ast
+class D_func;             // cc.ast
+class D_ptrToMember;      // cc.ast
+class TypeSpecifier;      // cc.ast
+class Declaration;        // cc.ast
+class TypeVariable;       // template.h
+class PseudoInstantiation;// template.h
+class DependentQType;     // template.h
+class MType;              // mtype.h
+class XmlReader;
+
+// fwd in this file
+class AtomicType;
+class SimpleType;
+class NamedAtomicType;
+class CompoundType;
+class BaseClass;
+class EnumType;
+class CVAtomicType;
+class PointerType;
+class ReferenceType;
+class FunctionType;
+class ArrayType;
+class PointerToMemberType;
+class Type;
+class TemplateInfo;
+class STemplateArgument;
+class TypeFactory;
+class BasicTypeFactory;
+class TypePred;
+
+
+// This is a debugging aid.
+extern bool global_mayUseTypeAndVarToCString;
+
+
+// --------------------- type visitor -----------------------
+// Visitor that digs down into template arguments, among other things.
+// Like the AST visitors, the 'visit' functions return true to
+// continue digging into subtrees, or false to prune the search.
+class TypeVisitor {
+public:
+  virtual ~TypeVisitor() {}     // silence warning
+
+  virtual bool visitType(Type *obj);
+  virtual void postvisitType(Type *obj);
+
+  virtual bool visitFunctionType_params(SObjList<Variable> &params);
+  virtual void postvisitFunctionType_params(SObjList<Variable> &params);
+  virtual bool visitFunctionType_params_item(Variable *param);
+  virtual void postvisitFunctionType_params_item(Variable *param);
+
+  virtual bool visitVariable(Variable *var);
+  virtual void postvisitVariable(Variable *var);
+
+  virtual bool visitAtomicType(AtomicType *obj);
+  virtual void postvisitAtomicType(AtomicType *obj);
+
+  // I don't know where to say this, so I'll say it here: there is no
+  // call in EnumType::traverse() that will take you here; visitors
+  // call it manually.  However, the existance of these methods allows
+  // you to organize your code in the same way as you would for the
+  // other classes.
+  //
+  // Also, please note that I cannot forward declare EnumType::Value,
+  // so unless I move this class until after class Enum, I have to
+  // make the argument type 'void*'!
+  virtual bool visitEnumType_Value(void /*EnumType::Value*/ *obj);
+  virtual void postvisitEnumType_Value(void /*EnumType::Value*/ *obj);
+
+  virtual bool visitScope(Scope *obj);
+  virtual void postvisitScope(Scope *obj);
+
+  virtual bool visitScope_variables(StringRefMap<Variable> &variables);
+  virtual void postvisitScope_variables(StringRefMap<Variable> &variables);
+  virtual bool visitScope_variables_entry(StringRef name, Variable *var);
+  virtual void postvisitScope_variables_entry(StringRef name, Variable *var);
+
+  virtual bool visitScope_typeTags(StringRefMap<Variable> &typeTags);
+  virtual void postvisitScope_typeTags(StringRefMap<Variable> &typeTags);
+  virtual bool visitScope_typeTags_entry(StringRef name, Variable *var);
+  virtual void postvisitScope_typeTags_entry(StringRef name, Variable *var);
+
+  virtual bool visitScope_templateParams(SObjList<Variable> &templateParams);
+  virtual void postvisitScope_templateParams(SObjList<Variable> &templateParams);
+  virtual bool visitScope_templateParams_item(Variable *var);
+  virtual void postvisitScope_templateParams_item(Variable *var);
+
+  virtual bool visitBaseClass(BaseClass *bc);
+  virtual void postvisitBaseClass(BaseClass *bc);
+
+  virtual bool visitBaseClassSubobj(BaseClassSubobj *bc);
+  virtual void postvisitBaseClassSubobj(BaseClassSubobj *bc);
+
+  virtual bool visitBaseClassSubobj_parents(SObjList<BaseClassSubobj> &parents);
+  virtual void postvisitBaseClassSubobj_parents(SObjList<BaseClassSubobj> &parents);
+  virtual bool visitBaseClassSubobj_parents_item(BaseClassSubobj *parent);
+  virtual void postvisitBaseClassSubobj_parents_item(BaseClassSubobj *parent);
+
+  virtual bool visitSTemplateArgument(STemplateArgument *obj);
+  virtual void postvisitSTemplateArgument(STemplateArgument *obj);
+
+  virtual bool visitPseudoInstantiation_args(ObjList<STemplateArgument> &args);
+  virtual void postvisitPseudoInstantiation_args(ObjList<STemplateArgument> &args);
+  virtual bool visitPseudoInstantiation_args_item(STemplateArgument *arg);
+  virtual void postvisitPseudoInstantiation_args_item(STemplateArgument *arg);
+
+  virtual bool visitDependentQTypePQTArgsList(ObjList<STemplateArgument> &list);
+  virtual void postvisitDependentQTypePQTArgsList(ObjList<STemplateArgument> &list);
+  virtual bool visitDependentQTypePQTArgsList_item(STemplateArgument *sta);
+  virtual void postvisitDependentQTypePQTArgsList_item(STemplateArgument *sta);
+
+  // note that this call is always a leaf in the traversal; the type
+  // visitor does *not* dig into Expressions (though of course you can
+  // write a 'visitExpression' method that does)
+  virtual bool visitExpression(Expression *obj);
+  virtual void postvisitExpression(Expression *obj);
+};
+
+
+// --------------------- atomic types --------------------------
+// interface to types that are atomic in the sense that no
+// modifiers can be stripped away; see cc_type.html
+class AtomicType {
+public:     // types
+  enum Tag {
+    // these are defined in cc_type.h
+    T_SIMPLE,                // int, char, float, etc.
+    T_COMPOUND,              // struct/class/union
+    T_ENUM,                  // enum
+
+    // these are defined in template.h
+    T_TYPEVAR,               // T
+    T_PSEUDOINSTANTIATION,   // C<T>
+    T_DEPENDENTQTYPE,        // C<T>::some_type
+
+    NUM_TAGS
+  };
+
+public:     // funcs
+  AtomicType();
+  virtual ~AtomicType();
+
+  virtual Tag getTag() const = 0;
+  bool isSimpleType() const   { return getTag() == T_SIMPLE; }
+  bool isCompoundType() const { return getTag() == T_COMPOUND; }
+  bool isEnumType() const     { return getTag() == T_ENUM; }
+  bool isTypeVariable() const { return getTag() == T_TYPEVAR; }
+  bool isPseudoInstantiation() const { return getTag() == T_PSEUDOINSTANTIATION; }
+  bool isDependentQType() const      { return getTag() == T_DEPENDENTQTYPE; }
+  virtual bool isNamedAtomicType() const;    // default impl returns false
+
+  // see smbase/macros.h
+  DOWNCAST_FN(SimpleType)
+  DOWNCAST_FN(NamedAtomicType)
+  DOWNCAST_FN(CompoundType)
+  DOWNCAST_FN(EnumType)
+  DOWNCAST_FN(TypeVariable)
+  DOWNCAST_FN(PseudoInstantiation)
+  DOWNCAST_FN(DependentQType)
+
+  // concrete types do not have holes
+  bool isConcrete() const
+    { return !isTypeVariable() && !isPseudoInstantiation(); }
+
+  // this is type equality, *not* coercibility -- e.g. if
+  // we say "extern type1 x" and then "extern type2 x" we
+  // will allow it only if type1==type2
+  bool equals(AtomicType const *obj) const;
+
+  // print the string according to 'Type::printAsML'
+  string toString() const;
+
+  // print in C notation
+  virtual string toCString() const = 0;
+
+  // print in "ML" notation (really just more verbose)
+  virtual string toMLString() const = 0;
+
+  // size this type's representation occupies in memory; this
+  // might throw XReprSize, see below
+  virtual int reprSize() const = 0;
+
+  // invoke 'vis.visitAtomicType(this)', and then traverse subtrees
+  virtual void traverse(TypeVisitor &vis) = 0;
+
+  // toString()+newline to cout
+  void gdb() const;
+
+  ALLOC_STATS_DECLARE
+};
+
+
+// represents one of C's built-in types;
+// there are exactly as many of these objects as there are built-in types
+class SimpleType : public AtomicType {
+public:     // data
+  SimpleTypeId const type;
+
+  // global read-only array for each built-in type
+  // (read-only is enforced by making all of SimpleType's members
+  // const, rather then the objects themselves, because doing the
+  // latter would clash AtomicType pointers not being const below)
+  static SimpleType fixed[NUM_SIMPLE_TYPES];
+
+public:     // funcs
+  SimpleType(SimpleTypeId t) : type(t) {}
+
+  // AtomicType interface
+  virtual Tag getTag() const { return T_SIMPLE; }
+  virtual string toCString() const;
+  virtual string toMLString() const;
+  virtual int reprSize() const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// elements common to structs and enums
+class NamedAtomicType : public AtomicType {
+public:     // data
+  StringRef name;          // (nullable) user-assigned name of this struct or enum
+  Variable *typedefVar;    // (nullable owner) implicit typedef variable; NULL if anonymous type
+  AccessKeyword access;    // accessibility of this type in its declaration context
+
+public:
+  NamedAtomicType(StringRef name);
+  ~NamedAtomicType();
+
+  virtual bool isNamedAtomicType() const;       // returns true
+};
+
+
+// represent a base class
+class BaseClass {
+public:
+  CompoundType *ct;          // (serf) the base class itself
+  AccessKeyword access;      // access mode of the inheritance
+  bool isVirtual;            // true for virtual inheritance
+
+public:
+  BaseClass(BaseClass const &obj)
+    : DMEMB(ct), DMEMB(access), DMEMB(isVirtual) {}
+  BaseClass(CompoundType *c, AccessKeyword a, bool v)
+    : ct(c), access(a), isVirtual(v) {}
+
+  // this isn't virtual because the caller always knows the
+  // dynamic type
+  void traverse(TypeVisitor &vis);
+};
+
+// represent an instance of a base class in a particular class'
+// inheritance hierarchy; it is these things that represent things
+// like diamond inheritance patterns; the terminology comes from
+// [cppstd 10.1 para 4]
+class BaseClassSubobj : public BaseClass {
+public:
+  // classes that this one inherits from; non-owning since the
+  // 'parents' links form a DAG, not a tree; in fact I regard
+  // this list as an owner of exactly those sub-objects whose
+  // inheritance is *not* virtual
+  SObjList<BaseClassSubobj> parents;
+
+  // for visit-once-only traversals
+  mutable bool visited;
+
+public:
+  BaseClassSubobj(CompoundType *c, AccessKeyword a, bool v)
+    : BaseClass(c, a, v)
+  {}
+  BaseClassSubobj(BaseClass const &base);
+  ~BaseClassSubobj();
+  // dsw: note: we use the implicit operator=() on this object
+
+  // name and virtual address to uniquely identify this object
+  string canonName() const;
+
+  void traverse(TypeVisitor &vis);
+};
+
+// represent a user-defined compound type; the members of the
+// compound are whatever has been entered in the Scope
+class CompoundType : public NamedAtomicType, public Scope {
+public:      // types
+  // NOTE: keep these consistent with TypeIntr (in file cc_flags.h)
+  enum Keyword { K_STRUCT, K_CLASS, K_UNION, NUM_KEYWORDS };
+
+public:      // data
+  bool forward : 1;               // true when it's only fwd-declared
+
+  // When true, this is a GNU transparent union.  I think adding
+  // a bool like this is inelegant, but oh well.
+  bool isTransparentUnion : 1;
+
+  Keyword keyword;            // keyword used to introduce the type
+
+  // nonstatic data members, in the order they appear within the body
+  // of the class definition; note that this is partially redundant
+  // with the Scope's 'variables' map, and hence should not be changed
+  // without also updating that map
+  SObjList<Variable> dataMembers;
+
+  // classes from which this one directly/syntactically inherits;
+  // 'const' so you have to use 'addBaseClass', but public to make
+  // traversal easy
+  const ObjList<BaseClass> bases;
+
+  // all the bases the class inherits from virtually, including for
+  // transitive reasons; collected virtual base class subobjects
+  ObjList<BaseClassSubobj> virtualBases;
+
+  // this is the root of the subobject hierarchy diagram which
+  // includes the transitive consequences of inheritance; NOTE: this
+  // entire hierarchy is just for the parents of this particular
+  // CompoundType and is isomorphic to but NOT shared with the
+  // subobject hierarchy of this CompoundType's parents; invariant:
+  // subobj.ct == this
+  BaseClassSubobj subobj;
+
+  // list of all conversion operators this class has, including
+  // those that have been inherited but not then hidden
+  SObjList<Variable> conversionOperators;
+
+  // list of friends; the friends are members of other scopes, but
+  // they can access protected/private members of this class, and
+  // argument-dependent lookups in this class can find them
+  //
+  // this is almost certainly *not* the best way to record this
+  // information if access control were to be implemented, but it
+  // does the job for the moment
+  SObjList<Variable> friends;
+
+  // if this class is a template instantiation, 'instName' is
+  // the class name plus a rendering of the arguments; otherwise
+  // it's the same as 'name'; this is for debugging
+  StringRef instName;
+
+  // AST node that describes this class; used for implementing
+  // templates (AST pointer)
+  // dsw: used for other purposes also
+  TS_classSpec *syntax;               // (nullable serf)
+
+  // template parameter scope that is consulted for lookups after
+  // this scope and its base classes; this changes over time as
+  // the class is added to and removed from the scope stack; it
+  // is NULL whenever it is not on the scope stack
+  Scope *parameterizingScope;         // (nullable serf)
+
+  // this is the type of the compound as bound to the
+  // injected-class-name; it is different than typedefVar->type
+  // for template classes, as the former is the template class
+  // itself while the latter is a PseudoInstantiation thereof
+  Type *selfType;                     // (nullable serf)
+
+private:     // funcs
+  void makeSubobjHierarchy(BaseClassSubobj *subobj, BaseClass const *newBase);
+
+  BaseClassSubobj const *findVirtualSubobjectC(CompoundType const *ct) const;
+  BaseClassSubobj *findVirtualSubobject(CompoundType *ct)
+    { return const_cast<BaseClassSubobj*>(findVirtualSubobjectC(ct)); }
+
+  static void clearVisited_helper(BaseClassSubobj const *subobj);
+
+  static void getSubobjects_helper
+    (SObjList<BaseClassSubobj const> &dest, BaseClassSubobj const *subobj);
+
+  void addLocalConversionOp(Variable *op);
+
+protected:   // funcs
+  // create an incomplete (forward-declared) compound
+  // experiment: force creation of these to go through the factory too
+  CompoundType(Keyword keyword, StringRef name);
+  friend class TypeFactory;
+  friend class XmlTypeReader;
+
+  // override no-op implementation in Scope
+  virtual void afterAddVariable(Variable *v);
+
+public:      // funcs
+  virtual ~CompoundType();
+
+  bool isComplete() const { return !forward; }
+
+  // true if this is a class that is incomplete because it requires
+  // template arguments to be supplied (i.e. not true for classes
+  // that come from templates, but all arguments have been supplied)
+  bool isTemplate(bool considerInherited = false) const;
+
+  // true if it is an instance (fully concrete type arguments) of some
+  // template
+  bool isInstantiation() const;
+
+  // manipulate 'templateInfo', which is now stored in the 'typedefVar'
+  TemplateInfo *templateInfo() const;
+  void setTemplateInfo(TemplateInfo *templInfo0);
+
+  // same as 'typedefVar' but with a bunch of assertions...
+  Variable *getTypedefVar() const;
+
+  // true if the class has RTTI/vtable
+  bool hasVirtualFns() const;
+
+  static char const *keywordName(Keyword k);
+
+  // AtomicType interface
+  virtual Tag getTag() const { return T_COMPOUND; }
+  virtual string toCString() const;
+  virtual string toMLString() const;
+  virtual int reprSize() const;
+  virtual void traverse(TypeVisitor &vis);
+
+  string toStringWithFields() const;
+  string keywordAndName() const { return toCString(); }
+
+  int numFields() const;
+
+  // returns NULL if doesn't exist
+  Variable *getNamedField(StringRef name, Env &env, LookupFlags f=LF_NONE)
+    { return lookupVariable(name, env, f); }
+
+  // alias for Scope::addVariable (should probably be deleted)
+  void addField(Variable *v);
+
+  // sm: for compatibility with existing code
+  SObjList<Variable> &getDataVariablesInOrder()
+    { return dataMembers; }
+
+  // return the ordinal position of the named nonstatic data field
+  // in this class, starting with 0; or, return -1 if the field does
+  // not exist (this is a query on 'dataMembers')
+  int getDataMemberPosition(StringRef name) const;
+
+  // return the offset in bytes of 'dataMember' in this struct;
+  // fail an assertion if it is not present (why does this function
+  // take a Variable* and the previous one a StringRef?  I'm not
+  // sure, I think Variable* is better, but don't want to mess with
+  // the other one right now)
+  int getDataMemberOffset(Variable *dataMember) const;
+
+  // add to 'bases'; incrementally maintains 'virtualBases'
+  virtual void addBaseClass(BaseClass * /*owner*/ newBase);
+
+  // true if this class inherits from 'ct', either directly or
+  // indirectly, and the inheritance is virtual
+  bool hasVirtualBase(CompoundType const *ct) const
+    { return !!findVirtualSubobjectC(ct); }
+
+  // set all the 'visited' fields to false in the subobject hierarchy
+  void clearSubobjVisited() const;
+
+  // collect all of the subobjects into a list; each subobject
+  // appears exactly once; NOTE: you may want to call
+  // Env::ensureClassBodyInstantiated before calling this, since
+  // an uninstantiated class won't have any subobjects yet
+  void getSubobjects(SObjList<BaseClassSubobj const> &dest) const;
+
+  // render the subobject hierarchy to a 'dot' graph
+  string renderSubobjHierarchy() const;
+
+  // how many times does 'ct' appear as a subobject?
+  // returns 1 if ct==this
+  int countBaseClassSubobjects(CompoundType const *ct) const;
+
+  bool hasUnambiguousBaseClass(CompoundType const *ct) const
+    { return countBaseClassSubobjects(ct)==1; }
+  bool hasBaseClass(CompoundType const *ct) const
+    { return countBaseClassSubobjects(ct)>=1; }
+  bool hasStrictBaseClass(CompoundType const *ct) const
+    { return this != ct && hasBaseClass(ct); }
+
+  // compute the least upper bound of two compounds in the inheritance
+  // network; 'wasAmbig==true' means that the intersection of the
+  // superclasses was not empty, but that set had no least element;
+  // return NULL if no LUB ("least" means most-derived)
+  static CompoundType *lub(CompoundType *t1, CompoundType *t2, bool &wasAmbig);
+
+  // call this when we're finished adding base classes and member
+  // fields; it builds 'conversionOperators'; 'specialName' is the
+  // name under which the conversion operators have been filed in
+  // the class scope
+  virtual void finishedClassDefinition(StringRef specialName);
+
+  // true if this is an "aggregate" (8.5.1p1)
+  bool isAggregate() const;
+};
+
+string toString(CompoundType::Keyword k);
+
+
+// represent an enumerated type
+class EnumType : public NamedAtomicType {
+public:     // types
+  // represent a single value in an enum
+  class Value {
+  public:
+    StringRef name;           // the thing whose name is being defined
+    EnumType *type;           // enum in which it was declared
+    int value;                // value it's assigned to
+
+    // similar to fields, I keep a record of where this came from
+    Variable *decl;           // (nullable serf)
+
+  public:
+    Value(StringRef n, EnumType *t, int v, Variable *d);
+    ~Value();
+  };
+
+public:     // data
+  StringObjDict<Value> valueIndex;    // values in this enumeration
+  int nextValue;                      // next value to assign to elements automatically
+  bool hasNegativeValues;             // true iff some 'value' is negative
+
+public:     // funcs
+  EnumType(StringRef n)
+    : NamedAtomicType(n), nextValue(0), hasNegativeValues(false) {}
+  ~EnumType();
+
+  // AtomicType interface
+  virtual Tag getTag() const { return T_ENUM; }
+  virtual string toCString() const;
+  virtual string toMLString() const;
+  virtual int reprSize() const;
+  virtual void traverse(TypeVisitor &vis);
+
+  Value *addValue(StringRef name, int value, /*nullable*/ Variable *d);
+  Value const *getValue(StringRef name) const;
+};
+
+
+// moved PseudoInstantiation into template.h
+
+
+// ---------------------- TypePred ----------------------------
+// This visitor predates TypeVisitor, and is a little different
+// because it does not dig into atomic types or template args.
+// It would be good to merge them at some point.
+
+// abstract superclass
+class TypePred {
+public:
+  virtual bool operator() (Type const *t) = 0;
+  virtual ~TypePred() {}     // gcc sux
+};
+
+// when you just want a stateless predicate
+typedef bool (*TypePredFunc)(Type const *t);
+
+class StatelessTypePred : public TypePred {
+  TypePredFunc const f;
+public:
+  StatelessTypePred(TypePredFunc f0) : f(f0) {}
+  virtual bool operator() (Type const *t);
+};
+
+
+// ------------------- constructed types -------------------------
+// generic constructed type; to allow client analyses to annotate the
+// description of types, this class is inherited by "Type", the class
+// that all of the rest of the parser regards as being a "type"
+//
+// note: clients should refer to Type, not BaseType
+class BaseType INHERIT_SERIAL_BASE {
+public:     // types
+  enum Tag {
+    // dsw: I want these to not be picked arbitrarily by the compiler,
+    // so I start it at something specific; I like 0 to be meaningless
+    // so that nothing meaningfull happens by default, a la pointers.
+    T_ATOMIC = 1,               // int const, class Foo, etc.
+    T_POINTER,                  // int *
+    T_REFERENCE,                // int &
+    T_FUNCTION,                 // int ()(int, float)
+    T_ARRAY,                    // int [3]
+    T_POINTERTOMEMBER,          // int C::*
+
+    T_LAST_TYPE_TAG,
+    // IMPORTANT: it is important that T_LAST_TYPE_TAG be the last one
+    // so I can make a disjoint set in Oink by starting my enum at
+    // T_LAST_TYPE_TAG+1.  Therefore if you add anything, add it
+    // before T_LAST_TYPE_TAG.
+  };
+
+public:     // data
+  // when true (the default is false), types are printed in ML-like
+  // notation instead of C notation by AtomicType::toString and
+  // Type::toString
+  static bool printAsML;
+
+private:    // disallowed
+  BaseType(BaseType&);
+
+private:    // funcs
+  // the constructor of BaseType is private so the only subclass
+  // is Type, an assumption relied upon in BaseType::equals
+  BaseType();
+  friend class Type;
+
+public:     // funcs
+  virtual ~BaseType();
+
+  virtual Tag getTag() const = 0;
+  bool isCVAtomicType() const { return getTag() == T_ATOMIC; }
+  bool isPointerType() const { return getTag() == T_POINTER; }
+  bool isReferenceType() const { return getTag() == T_REFERENCE; }
+  bool isFunctionType() const { return getTag() == T_FUNCTION; }
+  bool isArrayType() const { return getTag() == T_ARRAY; }
+  bool isPointerToMemberType() const { return getTag() == T_POINTERTOMEMBER; }
+
+  DOWNCAST_FN(CVAtomicType)
+  DOWNCAST_FN(PointerType)
+  DOWNCAST_FN(ReferenceType)
+  DOWNCAST_FN(FunctionType)
+  DOWNCAST_FN(ArrayType)
+  DOWNCAST_FN(PointerToMemberType)
+
+  // like above, this is (structural) equality, not coercibility;
+  // internally, this calls the innerEquals() method on the two
+  // objects, once their tags have been established to be equal
+  bool equals(BaseType const *obj, MatchFlags flags = MF_NONE) const;
+
+  // compute a hash value: equal types (EF_EXACT) have the same hash
+  // value, and unequal types are likely to have different values
+  unsigned hashValue() const;
+  virtual unsigned innerHashValue() const = 0;
+
+  // print the string according to 'printAsML'
+  string toString() const;
+
+  // print the type, with an optional name like it was a declaration
+  // for a variable of that type
+  string toCString() const;
+  string toCString(char const * /*nullable*/ name) const;
+  string toCString(rostring name) const { return toCString(name.c_str()); }
+
+  // NOTE: yes, toMLString() is virtual, whereas toCString() is not
+  virtual string toMLString() const = 0;
+  void putSerialNo(stringBuilder &sb) const;
+
+  // toString+newline to cout
+  void gdb() const;
+
+  // the left/right business is to allow us to print function
+  // and array types in C's syntax; if 'innerParen' is true then
+  // the topmost type constructor should print the inner set of
+  // paretheses
+  virtual string leftString(bool innerParen=true) const = 0;
+  virtual string rightString(bool innerParen=true) const;    // default: returns ""
+
+  // size of representation at run-time; for now uses nominal 32-bit
+  // values
+  virtual int reprSize() const = 0;
+
+  // filter on all constructed types that appear in the type,
+  // *including* parameter types; return true if any constructor
+  // satisfies 'pred' (note that recursive types always go through
+  // CompoundType, and this does not dig into the fields of
+  // CompoundTypes)
+  virtual bool anyCtorSatisfies(TypePred &pred) const=0;
+
+  // automatically wrap 'pred' in a StatelessTypePred;
+  // trailing 'F' in name means "function", so as to avoid
+  // overloading and overriding on the same name
+  bool anyCtorSatisfiesF(TypePredFunc f) const;
+
+  // return the cv flags that apply to this type, if any;
+  // default returns CV_NONE
+  virtual CVFlags getCVFlags() const;
+  bool isConst() const { return !!(getCVFlags() & CV_CONST); }
+
+  // invoke 'vis.visitType(this)', and then traverse subtrees
+  virtual void traverse(TypeVisitor &vis) = 0;
+
+  // some common queries
+  bool isSimpleType() const;
+  SimpleType const *asSimpleTypeC() const;
+  bool isSimple(SimpleTypeId id) const;
+  bool isSimpleCharType() const { return isSimple(ST_CHAR); }
+  bool isSimpleWChar_tType() const { return isSimple(ST_WCHAR_T); }
+  bool isSomeKindOfCharType() const;
+  bool isStringType() const;
+  bool isIntegerType() const;            // any of the simple integer types
+  bool isEnumType() const;
+  bool isUnionType() const { return isCompoundTypeOf(CompoundType::K_UNION); }
+  bool isStructType() const { return isCompoundTypeOf(CompoundType::K_STRUCT); }
+  bool isCompoundTypeOf(CompoundType::Keyword keyword) const;
+  bool isVoid() const { return isSimple(ST_VOID); }
+  bool isBool() const { return isSimple(ST_BOOL); }
+  bool isEllipsis() const { return isSimple(ST_ELLIPSIS); }
+  bool isError() const { return isSimple(ST_ERROR); }
+  bool isDependent() const;    // TODO: this should be ST_DEPENDENT only
+  bool isOwnerPtr() const;
+  bool isMethod() const;                       // function and method
+
+  // ST_DEPENDENT or TypeVariable or PseudoInstantiation or DependentQType
+  bool isGeneralizedDependent() const;
+  bool containsGeneralizedDependent() const;   // anywhere in Type tree
+
+  // (some of the following are redundant but I want them anyway, to
+  // continue with the pattern that isXXX is for language concepts and
+  // isXXXType is for implementation concepts)
+
+  // pointer/reference stuff
+  bool isPointer() const { return isPointerType(); }
+  bool isReference() const { return isReferenceType(); }
+  bool isReferenceToConst() const;
+  bool isLval() const { return isReference(); }// C terminology
+
+  // allow some degree of unified handling of PointerType and ReferenceType
+  bool isPtrOrRef() const { return isPointer() || isReference(); }
+  bool isPointerOrArrayRValueType() const;
+
+  // dsw: this is virtual because in Oink an int can act as a pointer
+  // so I need a way to do that
+  virtual Type *getAtType() const;
+
+  // note that Type overrides these to return Type instead of BaseType
+  BaseType const *asRvalC() const;             // if I am a reference, return referrent type
+  BaseType *asRval() { return const_cast<BaseType*>(asRvalC()); }
+
+  bool isCVAtomicType(AtomicType::Tag tag) const;
+  bool isTypeVariable() const { return isCVAtomicType(AtomicType::T_TYPEVAR); }
+  TypeVariable const *asTypeVariableC() const;
+  TypeVariable *asTypeVariable()
+    { return const_cast<TypeVariable*>(asTypeVariableC()); }
+
+  // downcast etc. to NamedAtomicType
+  bool isNamedAtomicType() const;
+  NamedAtomicType *ifNamedAtomicType();  // NULL or corresp. NamedAtomicType
+  NamedAtomicType const *asNamedAtomicTypeC() const;
+  NamedAtomicType *asNamedAtomicType() { return const_cast<NamedAtomicType*>(asNamedAtomicTypeC()); }
+
+  // similar for CompoundType
+  bool isCompoundType() const { return isCVAtomicType(AtomicType::T_COMPOUND); }
+  CompoundType *ifCompoundType();        // NULL or corresp. compound
+  CompoundType const *asCompoundTypeC() const; // fail assertion if not
+  CompoundType *asCompoundType() { return const_cast<CompoundType*>(asCompoundTypeC()); }
+
+  // etc. ...
+  bool isPseudoInstantiation() const { return isCVAtomicType(AtomicType::T_PSEUDOINSTANTIATION); }
+  PseudoInstantiation const *asPseudoInstantiationC() const;
+  PseudoInstantiation *asPseudoInstantiation() { return const_cast<PseudoInstantiation*>(asPseudoInstantiationC()); }
+
+  bool isDependentQType() const { return isCVAtomicType(AtomicType::T_DEPENDENTQTYPE); }
+
+  // something that behaves like a CompoundType in most respects
+  bool isLikeCompoundType() const
+    { return isCompoundType() || isPseudoInstantiation(); }
+
+  // this is true if any of the type *constructors* on this type
+  // refer to ST_ERROR; we don't dig down inside e.g. members of
+  // referred-to classes
+  bool containsErrors() const;
+
+  // similar for TypeVariable
+  bool containsTypeVariables() const;
+
+  // returns true if contains type or object variables (template
+  // parameters); recurses down into TemplateArguments
+  //
+  // if 'map' is not NULL, then we only count variables that
+  // are *not* bound in 'map'
+  bool containsVariables(MType *map = NULL) const;
+
+  ALLOC_STATS_DECLARE
+};
+
+string cvToString(CVFlags cv);
+
+#ifdef TYPE_CLASS_FILE
+  // pull in the definition of Type, which may have additional
+  // fields (etc.) added for the client analysis
+#define CC_TYPE_INCLUDE_CLASS_FILE_FLAG
+  #include TYPE_CLASS_FILE
+// this 'undef' is rather important
+#undef CC_TYPE_INCLUDE_CLASS_FILE
+#else
+  // please see cc_type.html, section 6, "BaseType and Type", for more
+  // information about this class
+  class Type : public BaseType {
+  protected:   // funcs
+    Type() {}
+
+  public:      // funcs
+    // do not leak the name "BaseType"
+    Type const *asRvalC() const
+      { return static_cast<Type const *>(BaseType::asRvalC()); }
+    Type *asRval()
+      { return static_cast<Type*>(BaseType::asRval()); }
+  };
+#endif // TYPE_CLASS_FILE
+
+// supports the use of 'Type*' in AST constructor argument lists
+string toString(Type *t);
+
+
+// essentially just a wrapper around an atomic type, but
+// also with optional const/volatile flags
+class CVAtomicType : public Type {
+public:     // data
+  AtomicType *atomic;          // (serf) underlying type
+  CVFlags cv;                  // const/volatile
+
+protected:
+  friend class BasicTypeFactory;
+  friend class XmlTypeReader;
+  CVAtomicType(AtomicType *a, CVFlags c)
+    : atomic(a), cv(c) {}
+
+  // need this to make a static array of them
+  CVAtomicType(CVAtomicType const &obj)
+    : atomic(obj.atomic), cv(obj.cv) {}
+
+public:
+  bool isConst() const { return !!(cv & CV_CONST); }
+  bool isVolatile() const { return !!(cv & CV_VOLATILE); }
+
+  // Type interface
+  virtual Tag getTag() const { return T_ATOMIC; }
+  unsigned innerHashValue() const;
+  virtual string toMLString() const;
+  virtual string leftString(bool innerParen=true) const;
+  virtual int reprSize() const;
+  virtual bool anyCtorSatisfies(TypePred &pred) const;
+  virtual CVFlags getCVFlags() const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// type of a pointer
+class PointerType : public Type {
+public:     // data
+  CVFlags cv;                  // const/volatile; refers to pointer *itself*
+  Type *atType;                // (serf) type of thing pointed-at
+
+protected:  // funcs
+  friend class BasicTypeFactory;
+  friend class XmlTypeReader;
+  PointerType(CVFlags c, Type *a);
+
+public:
+  bool isConst() const { return !!(cv & CV_CONST); }
+  bool isVolatile() const { return !!(cv & CV_VOLATILE); }
+
+  // Type interface
+  virtual Tag getTag() const { return T_POINTER; }
+  unsigned innerHashValue() const;
+  virtual string toMLString() const;
+  virtual string leftString(bool innerParen=true) const;
+  virtual string rightString(bool innerParen=true) const;
+  virtual int reprSize() const;
+  virtual bool anyCtorSatisfies(TypePred &pred) const;
+  virtual CVFlags getCVFlags() const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// type of a reference
+class ReferenceType : public Type {
+public:     // data
+  Type *atType;                // (serf) type of thing pointed-at
+
+protected:  // funcs
+  friend class BasicTypeFactory;
+  friend class XmlTypeReader;
+  ReferenceType(Type *a);
+
+public:
+  bool isConst() const { return false; }
+  bool isVolatile() const { return false; }
+
+  // Type interface
+  virtual Tag getTag() const { return T_REFERENCE; }
+  unsigned innerHashValue() const;
+  virtual string toMLString() const;
+  virtual string leftString(bool innerParen=true) const;
+  virtual string rightString(bool innerParen=true) const;
+  virtual int reprSize() const;
+  virtual bool anyCtorSatisfies(TypePred &pred) const;
+  virtual CVFlags getCVFlags() const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// some flags that can be associated with function types
+enum FunctionFlags {
+  FF_NONE          = 0x0000,  // nothing special
+  FF_METHOD        = 0x0001,  // function is a nonstatic method
+  FF_VARARGS       = 0x0002,  // accepts variable # of arguments
+  FF_CONVERSION    = 0x0004,  // conversion operator function
+  FF_CTOR          = 0x0008,  // constructor
+  FF_DTOR          = 0x0010,  // destructor
+  FF_BUILTINOP     = 0x0020,  // built-in operator function (cppstd 13.6)
+  FF_NO_PARAM_INFO = 0x0040,  // C parameter list "()" (C99 6.7.5.3 para 14)
+  FF_DEFAULT_ALLOC = 0x0080,  // is a default [de]alloc function from 3.7.3p2
+  FF_KANDR_DEFN    = 0x0100,  // derived from a K&R-style function definition
+  FF_ALL           = 0x01FF,  // all flags set to 1
+};
+ENUM_BITWISE_OPS(FunctionFlags, FF_ALL);
+
+
+// type of a function
+class FunctionType : public Type {
+public:     // types
+  // list of exception types that can be thrown
+  class ExnSpec {
+  public:
+    SObjList<Type> types;
+
+  public:
+    ExnSpec() {}
+    ExnSpec(ExnSpec const &obj);
+    ~ExnSpec();
+
+    bool anyCtorSatisfies(TypePred &pred) const;
+  };
+
+public:     // data
+  // various boolean properties
+  FunctionFlags flags;
+
+  // type of return value
+  Type *retType;                     // (serf)
+
+  // list of function parameters; if (flags & FF_METHOD) then the
+  // first parameter is '__receiver'
+  SObjList<Variable> params;
+
+  // allowable exceptions, if not NULL
+  ExnSpec *exnSpec;                  // (nullable owner)
+
+protected:  // funcs
+  friend class BasicTypeFactory;
+  friend class XmlTypeReader;
+
+  FunctionType(Type *retType);
+
+public:
+  virtual ~FunctionType();
+
+  // interpretations of flags
+  bool hasFlag(FunctionFlags f) const { return !!(flags & f); }
+  bool isMethod() const               { return hasFlag(FF_METHOD); }
+  bool acceptsVarargs() const         { return hasFlag(FF_VARARGS); }
+  bool isConversionOperator() const   { return hasFlag(FF_CONVERSION); }
+  bool isConstructor() const          { return hasFlag(FF_CTOR); }
+  bool isDestructor() const           { return hasFlag(FF_DTOR); }
+
+  void setFlag(FunctionFlags f)       { flags |= f; }
+  void clearFlag(FunctionFlags f)     { flags &= ~f; }
+
+  // if the '__receiver' parameter (if any) is ignored in both
+  // function types, am I equal to 'obj'?
+  bool equalOmittingReceiver(FunctionType const *obj) const
+    { return equals(obj, MF_STAT_EQ_NONSTAT | MF_IGNORE_IMPLICIT); }
+
+  // true if all parameters after 'startParam' (0 is first) have
+  // default values
+  bool paramsHaveDefaultsPast(int startParam) const;
+
+  // append a parameter to the (ordinary) parameters list
+  void addParam(Variable *param);
+
+  // add the implicit '__receiver' param; sets 'isMember()' to true
+  void addReceiver(Variable *param);
+
+  // Note: After calling 'addParam', etc., the client must call
+  // TypeFactory::doneParams so that the factory has a chance to
+  // do any final adjustments.
+
+  Variable const *getReceiverC() const;  // 'isMember' must be true
+  Variable *getReceiver() { return const_cast<Variable*>(getReceiverC()); }
+
+  CVFlags getReceiverCV() const;         // dig down; or CV_NONE if !isMember
+  CompoundType *getClassOfMember();      // 'isMember' must be true
+
+  // the above only works if the function is a member of a concrete
+  // class; if it's a member of a template class, this must be used
+  NamedAtomicType *getNATOfMember();
+
+  // more specialized printing, for Cqual++ syntax
+  static string rightStringQualifiers(CVFlags cv);
+  virtual string rightStringUpToQualifiers(bool innerParen) const;
+  virtual string rightStringAfterQualifiers() const;
+
+  // print the function type, but use these cv-flags as the
+  // receiver param cv-flags
+  string toString_withCV(CVFlags cv) const;
+
+  // a hook for the verifier's printer
+  virtual void extraRightmostSyntax(stringBuilder &sb) const;
+
+  // Type interface
+  virtual Tag getTag() const { return T_FUNCTION; }
+  unsigned innerHashValue() const;
+  virtual string toMLString() const;
+  virtual string leftString(bool innerParen=true) const;
+  virtual string rightString(bool innerParen=true) const;
+  virtual int reprSize() const;
+  virtual bool anyCtorSatisfies(TypePred &pred) const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// type of an array
+class ArrayType : public Type {
+public:       // types
+  enum {
+    NO_SIZE = -1,              // no size specified
+    DYN_SIZE = -2              // GNU extension: size is not a constant
+  };
+
+public:       // data
+  Type *eltType;               // (serf) type of the elements
+  int size;                    // specified size (>=0), or NO_SIZE or DYN_SIZE
+
+  // Note that whether a size of 0 is legal depends on the current
+  // language settings (cc_lang.h), so most code should adapt itself
+  // to that possibility.
+
+private:      // funcs
+  void checkWellFormedness() const;
+
+protected:
+  friend class BasicTypeFactory;
+  friend class XmlTypeReader;
+  ArrayType(Type *e, int s = NO_SIZE)
+    : eltType(e), size(s) { checkWellFormedness(); }
+  ArrayType(XmlReader&)           // a ctor for de-serialization
+    : eltType(NULL), size(NO_SIZE) {}
+
+public:
+  int getSize() const { return size; }
+  bool hasSize() const { return size >= 0; }
+
+  // Type interface
+  virtual Tag getTag() const { return T_ARRAY; }
+  unsigned innerHashValue() const;
+  virtual string toMLString() const;
+  virtual string leftString(bool innerParen=true) const;
+  virtual string rightString(bool innerParen=true) const;
+  virtual int reprSize() const;
+  virtual bool anyCtorSatisfies(TypePred &pred) const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// pointer to member
+class PointerToMemberType : public Type {
+public:
+  // Usually, this is a compound type, as ptr-to-members are
+  // w.r.t. some compound.  However, to support the 'compound'
+  // being a template parameter, we generalize slightly so that
+  // a TypeVariable can be the 'inClass'.
+  NamedAtomicType *inClassNAT;
+
+  CVFlags cv;                   // whether this pointer is const
+  Type *atType;                 // type of the member
+
+protected:
+  friend class BasicTypeFactory;
+  friend class XmlTypeReader;
+  PointerToMemberType(NamedAtomicType *inClassNAT0, CVFlags c, Type *a);
+  PointerToMemberType(XmlReader&) // a ctor for de-serialization
+    : inClassNAT(NULL), cv(CV_NONE), atType(NULL) {}
+
+public:
+  bool isConst() const { return !!(cv & CV_CONST); }
+
+  // use this in contexts where the 'inClass' is known to be
+  // a real compound (which is most contexts); this fails an
+  // assertion if it turns out to be a TypeVariable
+  CompoundType *inClass() const;
+
+  // Type interface
+  virtual Tag getTag() const { return T_POINTERTOMEMBER; }
+  unsigned innerHashValue() const;
+  virtual string toMLString() const;
+  virtual string leftString(bool innerParen=true) const;
+  virtual string rightString(bool innerParen=true) const;
+  virtual int reprSize() const;
+  virtual bool anyCtorSatisfies(TypePred &pred) const;
+  virtual CVFlags getCVFlags() const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// moved into template.h:
+//   class TypeVariable
+//   class TemplateParams
+//   class InheritedTemplateParams
+//   class TemplateInfo
+//   class STemplateArgument
+
+
+// ------------------- type factory -------------------
+// The type factory is used for constructing objects that represent
+// C++ types.  The reasons for using a factory instead of direct
+// construction include:
+//
+//   - Types have a complicated and unpredictable sharing structure,
+//     which makes recursive deallocation impossible.  The factory
+//     is thus given responsibility for deallocation of all objects
+//     created by that factory.  (Hmm.. currently there's no interface
+//     for relinquishing a reference back to the factory... doh.)
+//
+//   - Types are intended to be immutable, and thus referentially
+//     transparent.  This enables the optimization of "hash consing"
+//     where multiple requests for the same equivalent object yield
+//     the exact same object.  The factory is responsible for
+//     maintaining the data structures necessary for this, and for
+//     choosing whether to do it at all.
+//
+//   - It is often desirable to annotate Types, but the base Type
+//     hierarchy should be free from any particular annotations.
+//     The factory allows one to derive subclasses of Type to add
+//     such annotations, without modifying creation sites (since
+//     they use the factory).  Of course, an alternative is to use
+//     a hash table on the side, but that's sometimes inconvenient.
+
+// first, we have the abstract interface of a TypeFactory
+class TypeFactory {
+public:
+  virtual ~TypeFactory() {}      // silence stupid compiler warnings
+
+  // ---- constructors for the atomic types ----
+  // for now, only CompoundType is built this way, and I'm going to
+  // provide a default implementation in TypeFactory to avoid having
+  // to change the interface w.r.t. oink/qual
+  virtual CompoundType *makeCompoundType
+    (CompoundType::Keyword keyword, StringRef name);
+
+  // ---- constructors for the constructed types ----
+  virtual CVAtomicType *makeCVAtomicType(AtomicType *atomic, CVFlags cv)=0;
+
+  virtual PointerType *makePointerType(CVFlags cv, Type *atType)=0;
+
+  // this returns a Type* instead of a ReferenceType because I need to
+  // be able to return an error type
+  virtual Type *makeReferenceType(Type *atType)=0;
+
+  virtual FunctionType *makeFunctionType(Type *retType)=0;
+
+  // this must be called after 'makeFunctionType', once all of the
+  // parameters have been added
+  virtual void doneParams(FunctionType *ft)=0;
+
+  virtual ArrayType *makeArrayType(Type *eltType, int size)=0;
+
+  virtual PointerToMemberType *makePointerToMemberType
+    (NamedAtomicType *inClassNAT, CVFlags cv, Type *atType)=0;
+
+
+  // ---- create a type based on another one ----
+  // NOTE: all 'syntax' pointers are nullable, since there are contexts
+  // where I don't have an AST node to pass
+
+  // NOTE: The functions in this section do *not* modify their argument
+  // Types, rather they return a new object if the desired Type is different
+  // from the one passed-in.  (That is, they behave functionally.)
+
+  // do a shallow clone
+  virtual Type *shallowCloneType(Type *baseType);
+
+  // given a type, set its cv-qualifiers to 'cv'; return NULL if the
+  // base type cannot be so qualified; I pass the syntax from which
+  // the 'cv' flags were derived, when I have it, for the benefit of
+  // extension analyses
+  //
+  // NOTE: 'baseType' is *not* modified; a copy is returned if necessary
+  virtual Type *setQualifiers(SourceLoc loc, CVFlags cv, Type *baseType,
+                                TypeSpecifier * /*nullable*/ syntax);
+
+  // add 'cv' to existing qualifiers; default implementation just
+  // calls setQualifiers
+  virtual Type *applyCVToType(SourceLoc loc, CVFlags cv, Type *baseType,
+                              TypeSpecifier * /*nullable*/ syntax);
+
+  // Return true if this factory wants to reuse type objects in
+  // 'applyCVToType' when the new and existing qualifiers are the same.
+  // By default, returns true.
+  virtual bool wantsQualifiedTypeReuseOptimization();
+
+  // build a pointer type from a syntactic description; here I allow
+  // the factory to know the name of an AST node, but the default
+  // implementation will not use it, so it need not be linked in for
+  // this to make sense
+  virtual Type *syntaxPointerType(SourceLoc loc,
+    CVFlags cv, Type *underlying, D_pointer * /*nullable*/ syntax);
+  virtual Type *syntaxReferenceType(SourceLoc loc,
+    Type *underlying, D_reference * /*nullable*/ syntax);
+
+  // similar for a function type; the parameters will be added by
+  // the caller after this function returns
+  virtual FunctionType *syntaxFunctionType(SourceLoc loc,
+    Type *retType, D_func * /*nullable*/ syntax, TranslationUnit *tunit);
+
+  // and another for pointer-to-member
+  virtual PointerToMemberType *syntaxPointerToMemberType(SourceLoc loc,
+    NamedAtomicType *inClassNAT, CVFlags cv, Type *atType,
+    D_ptrToMember * /*nullable*/ syntax);
+
+  // given a class, build the type of the receiver object parameter
+  // 1/19/03: it should be a *reference* type
+  // 1/30/04: fixing name: it's the receiver, not 'this'
+  // 4/18/04: the 'classType' has been generalized because we
+  //          represent ptr-to-member-func using a FunctionType
+  //          with receiver parameter of type 'classType'
+  virtual Type *makeTypeOf_receiver(SourceLoc loc,
+    NamedAtomicType *classType, CVFlags cv, D_func * /*nullable*/ syntax);
+
+  // given a function type and a return type, make a new function type
+  // which is like it but has no parameters; i.e., copy all fields
+  // except 'params'; this does *not* call doneParams
+  virtual FunctionType *makeSimilarFunctionType(SourceLoc loc,
+    Type *retType, FunctionType *similar);
+
+  // ---- similar functions for Variable ----
+  // Why not make a separate factory?
+  //   - It's inconvenient to have two.
+  //   - Every application I can think of will want to define both
+  //     or neither.
+  //   - Variable is used by Type and vice-versa.. they could have
+  //     both been defined in cc_type.h
+  virtual Variable *makeVariable(SourceLoc L, StringRef n, Type *t, DeclFlags f)=0;
+
+
+  // ---- convenience functions ----
+  // these functions are implemented in TypeFactory directly, in
+  // terms of the interface above, so they're not virtual
+
+  // given an AtomicType, wrap it in a CVAtomicType
+  // with no const or volatile qualifiers
+  CVAtomicType *makeType(AtomicType *atomic)
+    { return makeCVAtomicType(atomic, CV_NONE); }
+
+  // make a ptr-to-'type' type; returns generic Type instead of
+  // PointerType because sometimes I return ST_ERROR
+  inline Type *makePtrType(Type *type)
+    { return type->isError()? type : makePointerType(CV_NONE, type); }
+
+  // map a simple type into its CVAtomicType representative
+  CVAtomicType *getSimpleType(SimpleTypeId st, CVFlags cv = CV_NONE);
+
+  // given an array type with no size, return one that is
+  // the same except its size is as specified
+  ArrayType *setArraySize(SourceLoc loc, ArrayType *type, int size);
+};
+
+
+// This is an implementation of the above interface which returns the
+// actual Type-derived objects defined, as opposed to objects of
+// further-derived classes.  On the extension topics mentioned above:
+//   - It does not deallocate Types at all (oh well...).
+//   - It does not (yet) implement hash-consing, except for CVAtomics
+//     of SimpleTypes.
+//   - No annotations are added; the objects returned have exactly
+//     the types declared below.
+class BasicTypeFactory : public TypeFactory {
+private:   // data
+  // global array of non-const, non-volatile built-ins; it's expected
+  // to be treated as read-only
+  static CVAtomicType unqualifiedSimple[NUM_SIMPLE_TYPES];
+
+public:    // funcs
+  // TypeFactory funcs
+  virtual CVAtomicType *makeCVAtomicType(AtomicType *atomic, CVFlags cv);
+  virtual PointerType *makePointerType(CVFlags cv, Type *atType);
+  virtual Type *makeReferenceType(Type *atType);
+  virtual FunctionType *makeFunctionType(Type *retType);
+  virtual void doneParams(FunctionType *ft);
+
+  virtual ArrayType *makeArrayType(Type *eltType, int size);
+  virtual PointerToMemberType *makePointerToMemberType
+    (NamedAtomicType *inClassNAT, CVFlags cv, Type *atType);
+
+  virtual Variable *makeVariable(SourceLoc L, StringRef n, Type *t, DeclFlags f);
+};
+
+
+// this one should be sound; gradually making it more available
+template <class T>
+inline SObjList<T> const & objToSObjListC(ObjList<T> const &list)
+{
+  return reinterpret_cast<SObjList<T> const &>(list);
+}
+
+
+// -------------------- XReprSize ---------------------
+// thrown when the reprSize() function cannot determine an
+// array size
+class XReprSize : public xBase {
+public:
+  // This is set to true when the reason for failing to determine a
+  // size is that a dynamically-sized array was involved (this is a
+  // gnu extension).
+  //
+  // TODO: The better solution is to store the size expression with
+  // the array, so I can compute a symbolic expression that evaluates
+  // to the array's size.  But that involves changing a lot of stuff.
+  bool isDynamic;
+
+public:
+  XReprSize(bool isDynamic = false);
+  XReprSize(XReprSize const &obj);
+  ~XReprSize();
+};
+
+void throw_XReprSize(bool isDynamic = false) NORETURN;
+
+
+// ------ for debugging ------
+// The idea here is you say "print type_toString(x)" in gdb, where 'x'
+// is a pointer to some type.  The pointer that is returned will be
+// printed as a string by gdb.
+//
+// update: it turns out the latest gdbs are capable of using the
+// toString method directly!  but I'll leave this here anyway.
+char *type_toString(Type const *t);
+
+
+// I should explain my intended relationship between references and
+// lvalues.  The C++ standard uses the term 'reference' to refer to
+// types (a compile-time concept), and 'lvalue' to refer to
+// expressions and values (a run-time concept).  Of course, a
+// reference type gives rise to an lvalue, and a (non-const) reference
+// must be bound to an lvalue, so there's a close relationship between
+// the two.  In constrast, the same document uses the term 'pointer'
+// when referring to both types and values.
+//
+// In the interest of reducing the number of distinct concepts, I use
+// "reference types" and "lvalues" interchangeably; non-references
+// refer to rvalues.  Generally, this works well.  However, one must
+// keep in mind that there is consequently a slight terminological
+// difference between my stuff and the C++ standard.  For example, in
+// the code
+//
+//   int a;
+//   f(a);
+//
+// the argument 'a' has type 'int' and is an lvalue according to the
+// standard, whereas cc_tcheck.cc just says it's an 'int &'.
+
+
+#endif // CC_TYPE_H

Added: vendor/elsa/current/elsa/ccparse.cc
===================================================================
--- vendor/elsa/current/elsa/ccparse.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/ccparse.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,236 @@
+// ccparse.cc            see license.txt for copyright and terms of use
+// code for ccparse.h
+
+#include "ccparse.h"      // this module
+#include "astvisit.h"     // ASTVisitorEx
+#include "trace.h"        // TRACE
+
+#include <iostream.h>     // cout
+
+
+// ----------------------- ParseEnv -----------------------
+char const *maybeNull(StringRef n)
+{
+  if (n) {
+    return n;
+  }
+  else {
+    return "(null)";
+  }
+}
+
+void ParseEnv::pushClassName(StringRef n)
+{
+  TRACE("className", "pushing " << maybeNull(n));
+  classNameStack.push(n);
+}
+
+void ParseEnv::popClassName()
+{
+  StringRef n = classNameStack.pop();
+  TRACE("className", "popping " << maybeNull(n));
+  PRETEND_USED(n);
+}
+
+
+SimpleTypeId ParseEnv::uberSimpleType(SourceLoc loc, UberModifiers m)
+{
+  m = (UberModifiers)(m & UM_TYPEKEYS);
+
+  // implement cppstd Table 7, p.109
+  switch (m) {
+    case UM_CHAR:                         return ST_CHAR;
+    case UM_UNSIGNED | UM_CHAR:           return ST_UNSIGNED_CHAR;
+    case UM_SIGNED | UM_CHAR:             return ST_SIGNED_CHAR;
+    case UM_BOOL:                         return ST_BOOL;
+    case UM_UNSIGNED:                     return ST_UNSIGNED_INT;
+    case UM_UNSIGNED | UM_INT:            return ST_UNSIGNED_INT;
+    case UM_SIGNED:                       return ST_INT;
+    case UM_SIGNED | UM_INT:              return ST_INT;
+    case UM_INT:                          return ST_INT;
+    case UM_UNSIGNED | UM_SHORT | UM_INT: return ST_UNSIGNED_SHORT_INT;
+    case UM_UNSIGNED | UM_SHORT:          return ST_UNSIGNED_SHORT_INT;
+    case UM_UNSIGNED | UM_LONG | UM_INT:  return ST_UNSIGNED_LONG_INT;
+    case UM_UNSIGNED | UM_LONG:           return ST_UNSIGNED_LONG_INT;
+    case UM_SIGNED | UM_LONG | UM_INT:    return ST_LONG_INT;
+    case UM_SIGNED | UM_LONG:             return ST_LONG_INT;
+    case UM_LONG | UM_INT:                return ST_LONG_INT;
+    case UM_LONG:                         return ST_LONG_INT;
+    case UM_SIGNED | UM_SHORT | UM_INT:   return ST_SHORT_INT;
+    case UM_SIGNED | UM_SHORT:            return ST_SHORT_INT;
+    case UM_SHORT | UM_INT:               return ST_SHORT_INT;
+    case UM_SHORT:                        return ST_SHORT_INT;
+    case UM_WCHAR_T:                      return ST_WCHAR_T;
+    case UM_FLOAT:                        return ST_FLOAT;
+    case UM_DOUBLE:                       return ST_DOUBLE;
+    case UM_LONG | UM_DOUBLE:             return ST_LONG_DOUBLE;
+    case UM_VOID:                         return ST_VOID;
+
+    // GNU extensions
+    case UM_UNSIGNED | UM_LONG_LONG | UM_INT:  return ST_UNSIGNED_LONG_LONG;
+    case UM_UNSIGNED | UM_LONG_LONG:           return ST_UNSIGNED_LONG_LONG;
+    case UM_SIGNED | UM_LONG_LONG | UM_INT:    return ST_LONG_LONG;
+    case UM_SIGNED | UM_LONG_LONG:             return ST_LONG_LONG;
+    case UM_LONG_LONG | UM_INT:                return ST_LONG_LONG;
+    case UM_LONG_LONG:                         return ST_LONG_LONG;
+    
+    // C99/GNU complex types
+    case UM_FLOAT | UM_COMPLEX:                return ST_FLOAT_COMPLEX;
+    case UM_DOUBLE | UM_COMPLEX:               return ST_DOUBLE_COMPLEX;
+    case UM_LONG | UM_DOUBLE | UM_COMPLEX:     return ST_LONG_DOUBLE_COMPLEX;
+
+    // C99 imaginary types
+    case UM_FLOAT | UM_IMAGINARY:              return ST_FLOAT_IMAGINARY;
+    case UM_DOUBLE | UM_IMAGINARY:             return ST_DOUBLE_IMAGINARY;
+    case UM_LONG | UM_DOUBLE | UM_IMAGINARY:   return ST_LONG_DOUBLE_IMAGINARY;
+
+    default:
+      error(loc, stringc << "malformed type: " << toString(m));
+      return ST_ERROR;
+  }
+}
+
+
+UberModifiers ParseEnv
+  ::uberCombine(SourceLoc loc, UberModifiers m1, UberModifiers m2)
+{
+  // check for long long (GNU extension)
+  if (m1 & m2 & UM_LONG) {
+    // were there already two 'long's?
+    if ((m1 | m2) & UM_LONG_LONG) {
+      error(loc, "too many `long's");
+    }
+
+    // make it look like only m1 had 'long long' and neither had 'long'
+    m1 = (UberModifiers)((m1 & ~UM_LONG) | UM_LONG_LONG);
+    m2 = (UberModifiers)(m2 & ~(UM_LONG | UM_LONG_LONG));
+  }
+
+  // any duplicate flags?
+  UberModifiers dups = (UberModifiers)(m1 & m2);
+  if (!lang.isCplusplus) {
+    // C99 6.7.3p4: const/volatile/restrict can be redundantly combined
+    dups = (UberModifiers)(dups & ~UM_CVFLAGS);
+  }
+  if (dups) {
+    if (dups == UM_INT && lang.allowRepeatedTypeSpecifierKeywords) {
+      // in/c/dC0024.c
+      diagnose3(lang.allowRepeatedTypeSpecifierKeywords, loc, 
+                "repeated 'int' type specifier (gcc bug allows it)");
+    }
+    else {
+      // C++ 7.1.5p1
+      error(loc, stringc << "duplicate modifier: " << toString(dups));
+    }
+  }
+
+  return (UberModifiers)(m1 | m2);
+}
+
+
+LocString * /*owner*/ ParseEnv::ls(SourceLoc loc, char const *name)
+{
+  return new LocString(loc, str(name));
+}
+
+
+void ParseEnv::error(SourceLoc loc, char const *msg)
+{
+  cout << toString(loc) << ": error: " << msg << endl;
+  errors++;
+}
+
+
+void ParseEnv::warning(SourceLoc loc, char const *msg)
+{
+  cout << toString(loc) << ": warning: " << msg << endl;
+  warnings++;
+}
+
+
+void ParseEnv::diagnose3(Bool3 b, SourceLoc loc, char const *msg)
+{
+  if (!b) {
+    error(loc, msg);
+  }
+  else if (b == B3_WARN) {
+    warning(loc, msg);
+  }
+}
+
+
+// ---------------------- AmbiguityCounter -----------------
+// check for ambiguities
+class AmbiguityCounter : public ASTVisitorEx {
+public:
+  int ambiguousNodes;    // count of nodes with non-NULL ambiguity links
+
+public:
+  AmbiguityCounter() : ambiguousNodes(0) {}
+
+  virtual void foundAmbiguous(void *obj, void **ambig, char const *kind);
+};
+
+
+void AmbiguityCounter::foundAmbiguous(void *obj, void **ambig, char const *kind)
+{
+  ambiguousNodes++;
+}
+
+
+template <class T>
+int numAmbiguousNodes_impl(T *t)
+{
+  AmbiguityCounter c;
+  t->traverse(c);
+  return c.ambiguousNodes;
+}
+
+
+int numAmbiguousNodes(TranslationUnit *unit)
+{ return numAmbiguousNodes_impl(unit); }
+
+int numAmbiguousNodes(Statement *stmt)
+{ return numAmbiguousNodes_impl(stmt); }
+
+int numAmbiguousNodes(Expression *e)
+{ return numAmbiguousNodes_impl(e); }
+
+int numAmbiguousNodes(ASTTypeId *t)
+{ return numAmbiguousNodes_impl(t); }
+
+
+#if 0   // not needed
+// --------------------- LocationSearcher ------------------
+LocationSearcher::LocationSearcher()
+  : loc(SL_UNKNOWN)
+{}
+
+
+#define DEFN(type)                                \
+  bool LocationSearcher::visit##type(type *obj)   \
+  {                                               \
+    if (loc == SL_UNKNOWN) {                      \
+      loc = obj->loc;                             \
+    }                                             \
+                                                  \
+    /* examine children if location not found */  \
+    return loc == SL_UNKNOWN;                     \
+  }
+
+DEFN(TopForm)
+DEFN(PQName)
+DEFN(TypeSpecifier)
+DEFN(Enumerator)
+DEFN(Member)
+DEFN(IDeclarator)
+DEFN(Statement)
+DEFN(Initializer)
+DEFN(TemplateParameter)
+
+#undef DEFN
+
+#endif // 0
+
+
+// EOF

Added: vendor/elsa/current/elsa/ccparse.h
===================================================================
--- vendor/elsa/current/elsa/ccparse.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/ccparse.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,114 @@
+// ccparse.h            see license.txt for copyright and terms of use
+// data structures used during parsing of C++ code
+
+#ifndef CCPARSE_H
+#define CCPARSE_H
+
+#include "strhash.h"       // StringHash
+#include "strtable.h"      // StringTable
+#include "objlist.h"       // ObjList
+#include "array.h"         // ArrayStack
+#include "cc_flags.h"      // UberModifiers, SimpleTypeId
+#include "cc_ast.h"        // C++ AST classes, needed for the action function signatures
+#include "srcloc.h"        // SourceLoc
+#include "cc_lang.h"       // CCLang, Bool3
+
+// parsing action state
+class ParseEnv {
+private:
+  ArrayStack<StringRef> classNameStack;   // stack of class names
+
+public:
+  StringTable &str;                       // string table
+  int errors;                             // parse errors
+  int warnings;                           // and warnings
+  StringRef strRefAttr;                   // "attr"
+  CCLang &lang;                           // language options
+
+public:
+  ParseEnv(StringTable &table, CCLang &aLang)
+    : classNameStack(),
+      str(table),
+      errors(0),
+      warnings(0),
+      strRefAttr(table.add("attr")),
+      lang(aLang)
+   {}
+  ~ParseEnv() {}
+
+  // manipulate the name of the class whose declaration we're inside;
+  // this is *not* the general class context, merely the innermost
+  // syntactically-occurring "class { ... }" declaration syntax, and
+  // it is used only to recognize declarations of constructors
+  void pushClassName(StringRef n);
+  void popClassName();
+  StringRef curClassName() const   { return classNameStack.top(); }
+
+  // manipulate UberModifiers
+  SimpleTypeId uberSimpleType(SourceLoc loc, UberModifiers m);
+  UberModifiers uberCombine(SourceLoc loc, UberModifiers m1, UberModifiers m2);
+
+  // generate a LocString suitable for use during parsing
+  LocString * /*owner*/ ls(SourceLoc loc, char const *name);
+
+  // report an error or warning
+  void error(SourceLoc loc, char const *msg);
+  void warning(SourceLoc loc, char const *msg);
+  
+  // depending on 'b', accept, accept with warning, or reject
+  void diagnose3(Bool3 b, SourceLoc loc, char const *msg);
+};
+
+
+// count ambiguous nodes; actually, this may double-count some nodes
+// because of sharing in the ambiguous forest--but it will
+// double-count exactly to the degree that debugPrint will
+// double-print, so they will agree in that regard
+int numAmbiguousNodes(TranslationUnit *unit);
+int numAmbiguousNodes(Statement *stmt);
+int numAmbiguousNodes(Expression *e);
+int numAmbiguousNodes(ASTTypeId *t);
+
+
+#if 0   // not needed anymore
+// fail if there are any ambiguous nodes
+void rejectAmbiguousNodes(TranslationUnit *unit);
+
+
+// search within an AST for a location
+class LocationSearcher : public ASTVisitor {
+public:
+  // location, or SL_UNKNOWN if not found yet
+  SourceLoc loc;
+
+public:
+  LocationSearcher();
+
+  // all nodes with locations
+  #define DECL(type) \
+    bool visit##type(type *obj) /*user ;*/
+  DECL(TopForm);
+  DECL(PQName);
+  DECL(TypeSpecifier);
+  DECL(Enumerator);
+  DECL(Member);
+  DECL(IDeclarator);
+  DECL(Statement);
+  DECL(Initializer);
+  DECL(TemplateParameter);
+  #undef DECL
+};
+
+// use the searcher to retrieve the location for an arbitrary
+// AST node (may return SL_UNKNOWN if it cannot find one)
+template <class T>
+SourceLoc getASTNodeLoc(T *obj)
+{
+  LocationSearcher searcher;
+  obj->traverse(searcher);
+  return searcher.loc;
+}
+#endif // 0
+
+
+#endif // CCPARSE_H

Added: vendor/elsa/current/elsa/cfg.ast
===================================================================
--- vendor/elsa/current/elsa/cfg.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cfg.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+// cfg.ast
+// AST extension to cc.ast for storing and computing a CFG
+
+// the methods declared here are defined in cfg.cc
+
+verbatim {
+  #define CFG_EXTENSION   // this extension module is active
+
+  #include "cfg.h"        // NextPtr
+}
+
+class Statement {
+  // control flow successor edge; interpretation depends on the exact
+  // kind of statement this is, however, so that's best left to
+  // 'getSuccessors()', and this is therefore protected
+  protected NextPtr next;
+  public friend class CFGEnv;     // allow CFGEnv to write 'next'
+  
+  // retrieve all successors of this node, given how we got to this
+  // node ('isContinue'), and put them into 'dest'; this can only
+  // be called after 'computeCFG' has finished; if this returns an
+  // empty set, it means that after the statement, the function returns
+  public void getSuccessors(NextPtrList &dest, bool isContinue);
+  public string successorsToString() const;
+  custom debugPrint {
+    ind(os, indent) << "succ=" << successorsToString() << endl;
+  }
+
+  // compute the CFG within this statement (e.g. a compound statement that
+  // is a function body)
+  public void computeCFG(CFGEnv &env);
+  pure_virtual void icfg(CFGEnv &env);    // TODO: make this private (must modify astgen)
+  
+  // switch has many outgoing edges, so it needs more than just 'next'
+  -> S_switch {
+       // pointers to all of the cases (& default) in this switch; when
+       // interpreted as a NextPtr, all 'continue' flags are false
+       private SObjList<Statement> cases;
+       public friend class CFGEnv;     // allow CFGEnv to write 'cases'
+       public friend class Statement;  // for Statement::getSuccessors
+     }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cfg.cc
===================================================================
--- vendor/elsa/current/elsa/cfg.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cfg.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,603 @@
+// cfg.cc
+// code for cfg.h and cfg.ast
+
+#include "cfg.h"           // this module
+#include "cc_ast.h"        // C++ AST, including cfg.ast's contributions
+#include "cc_ast_aux.h"    // class LoweredASTVisitor
+#include "sobjset.h"       // SObjSet
+
+#include <iostream.h>      // cout
+
+
+// -------------------------- NextPtr ----------------------
+string NextPtr::asString()
+{
+  return stringc << stmt()->kindLocString()
+                 << (cont()? "(c)" : "");
+}
+
+
+// ---------------------- CFGEnv --------------------
+CFGEnv::CFGEnv()
+  : pendingNexts(),
+    breaks(),
+    labels(),
+    gotos(),
+    switches(),
+    loops(),
+    errors(0)
+{
+  // make empty top frames
+  pushNexts();
+  pushBreaks();
+}
+
+CFGEnv::~CFGEnv()
+{}
+
+
+void CFGEnv::err(SourceLoc loc, char const *str)
+{
+  cout << toString(loc) << ": " << str << endl;
+}
+
+
+// -------- nexts -------
+void CFGEnv::pushNexts()
+{
+  pendingNexts.push(new SObjList<Statement>());
+}
+
+void CFGEnv::addPendingNext(Statement *source)
+{
+  pendingNexts.top()->prepend(source);
+}
+
+void CFGEnv::popNexts()
+{
+  SObjList<Statement> *top = pendingNexts.pop();
+  pendingNexts.top()->concat(*top);    // empties 'top'
+  delete top;
+}
+
+void CFGEnv::clearNexts()
+{
+  pendingNexts.top()->removeAll();
+}
+
+void CFGEnv::resolveNexts(NextPtr target)
+{
+  SMUTATE_EACH_OBJLIST(Statement, *(pendingNexts.top()), iter) {
+    iter.data()->next = target;
+  }
+  clearNexts();
+}
+
+
+// -------- breaks --------
+void CFGEnv::pushBreaks()
+{
+  breaks.push(new SObjList<S_break>());
+}
+
+void CFGEnv::addBreak(S_break *source)
+{
+  breaks.top()->prepend(source);     // O(n)
+}
+
+void CFGEnv::popBreaks()
+{
+  // all topmost breaks become pending nexts
+  SMUTATE_EACH_OBJLIST(S_break, *(breaks.top()), iter) {
+    addPendingNext(iter.data());
+  }
+  breaks.delPop();
+}
+
+
+// -------- labels --------
+void CFGEnv::addLabel(StringRef name, S_label *target)
+{
+  labels.add(name, target);
+}
+
+void CFGEnv::addPendingGoto(S_goto *source)
+{
+  // sm: I'm not sure what I was thinking when I had 'gotos' as
+  // a dictionary...
+  
+  gotos.push(source);
+}
+
+void CFGEnv::resolveGotos()
+{
+  // go over all the gotos and find their corresponding target
+  while (gotos.isNotEmpty()) {
+    S_goto *g = gotos.pop();
+    S_label *target = labels.get(g->target);
+    if (target) {
+      g->next = NextPtr(target, false);
+    }
+    else {
+      err(g->loc, stringc << "goto to undefined label: " << g->target);
+    }
+  }
+
+  // empty the label dictionary (goto set already empty)
+  labels.empty();
+}
+
+
+// -------- switches --------
+void CFGEnv::pushSwitch(S_switch *sw)
+{
+  switches.push(sw);
+}
+
+S_switch *CFGEnv::getCurrentSwitch()
+{
+  return switches.top();
+}
+
+void CFGEnv::popSwitch()
+{
+  switches.pop();
+}
+
+
+// --------- loops ----------
+void CFGEnv::pushLoop(Statement *loop)
+{
+  loops.push(loop);
+}
+
+Statement *CFGEnv::getCurrentLoop()
+{
+  return loops.top();
+}
+
+void CFGEnv::popLoop()
+{
+  loops.pop();
+}
+
+
+// -------- end --------
+void CFGEnv::verifyFunctionEnd()
+{
+  xassert(pendingNexts.count() == 1);
+  xassert(pendingNexts.top()->count() == 0);
+
+  xassert(breaks.count() == 1);
+  xassert(breaks.top()->count() == 0);
+
+  xassert(labels.getNumEntries() == 0);
+  xassert(gotos.isEmpty());
+
+  xassert(switches.count() == 0);
+  xassert(loops.count() == 0);
+}
+
+
+// ----------------------- Statement ---------------------
+void Statement::computeCFG(CFGEnv &env)
+{
+  if (isS_for()) {
+    // go immediately into 'init' so any pending 'next' pointers
+    // point directly at the initializer; effectively, this makes the
+    // system behave as if 'init' appeared syntactically just before
+    // the "for" loop
+    asS_for()->init->computeCFG(env);
+  }
+
+  // any pending 'next' pointers go here
+  env.resolveNexts(NextPtr(this /*target*/, false /*continue*/));
+
+  // my 'next' will go to whoever's (outer) tcheck is called next
+  env.addPendingNext(this /*source*/);
+
+  // do inner CFG computation
+  icfg(env);
+}
+
+
+void S_skip::icfg(CFGEnv &env)
+{}
+
+void S_label::icfg(CFGEnv &env)
+{
+  env.addLabel(name, this);
+  s->computeCFG(env);
+}
+
+
+void CFGEnv::connectEnclosingSwitch(Statement *stmt, char const *kind)
+{
+  S_switch *sw = getCurrentSwitch();
+  if (!sw) {
+    err(stmt->loc, stringc << kind << " can only appear in the context of a 'switch'");
+  }
+  else {
+    sw->cases.append(stmt);
+  }
+}
+
+void S_case::icfg(CFGEnv &env)
+{
+  env.connectEnclosingSwitch(this, "'case'");
+  s->computeCFG(env);
+}
+
+void S_default::icfg(CFGEnv &env)
+{
+  env.connectEnclosingSwitch(this, "'default'");
+  s->computeCFG(env);
+}
+
+
+void S_expr::icfg(CFGEnv &env)
+{
+  // this CFG does not model apparent flow of control present in
+  // things like short-circuit evaluation of boolean expressions
+}
+
+void S_compound::icfg(CFGEnv &env)
+{
+  FOREACH_ASTLIST_NC(Statement, stmts, iter) {
+    iter.data()->computeCFG(env);
+  }
+}
+
+void S_if::icfg(CFGEnv &env)
+{
+  thenBranch->computeCFG(env);
+
+  // any pending 'next's should not be resolved as pointing into
+  // the 'else' clause, but instead as pointing at whatever follows
+  // the entire 'if' statement
+  env.pushNexts();
+
+  elseBranch->computeCFG(env);
+
+  // merge current pending nexts with those saved above
+  env.popNexts();
+}
+
+void S_switch::icfg(CFGEnv &env)
+{
+  // existing 'break's must be postponed
+  env.pushBreaks();
+
+  // any occurrences of 'case' will be relative to this switch
+  env.pushSwitch(this);
+  branches->computeCFG(env);
+  env.popSwitch();
+
+  // any 'break's found will resolve to whatever comes next
+  env.popBreaks();
+}
+
+
+static void icfgLoop(CFGEnv &env, Statement *loop, Statement *body)
+{
+  // existing 'break's must be postponed
+  env.pushBreaks();
+
+  // any occurrences of 'continue' will be relative to this loop
+  env.pushLoop(loop);
+  body->computeCFG(env);
+  env.popLoop();
+
+  // the body continues back into this loop
+  env.resolveNexts(NextPtr(loop /*target*/, true /*continue*/));
+
+  // any previous 'break's will resolve to whatever comes next
+  env.popBreaks();
+
+  // I want the loop's 'next' to point to what comes after; right now
+  // it points at the body (if anywhere; see S_for), and this will
+  // change it
+  env.addPendingNext(loop /*source*/);
+}
+
+void S_while::icfg(CFGEnv &env)
+{
+  icfgLoop(env, this, body);
+}
+
+void S_doWhile::icfg(CFGEnv &env)
+{
+  icfgLoop(env, this, body);
+}
+
+void S_for::icfg(CFGEnv &env)
+{
+  icfgLoop(env, this, body);
+}
+
+
+void S_break::icfg(CFGEnv &env)
+{
+  // add myself to the list of active breaks
+  env.addBreak(this);
+}
+
+void S_continue::icfg(CFGEnv &env)
+{
+  Statement *loop = env.getCurrentLoop();
+  if (!loop) {
+    env.err(loc, "'continue' can only occur in the scope of a loop");
+  }
+  else {
+    // take myself off the list of pending nexts
+    env.clearNexts();
+
+    // point my next at the loop
+    next = NextPtr(loop, true /*continue*/);
+  }
+}
+
+void S_return::icfg(CFGEnv &env)
+{
+  // ensure my 'next' is null
+  env.clearNexts();
+  xassert(next.stmt() == NULL);
+}
+
+
+void S_goto::icfg(CFGEnv &env)
+{
+  env.addPendingGoto(this);
+}
+
+
+void S_decl::icfg(CFGEnv &env)
+{}
+
+
+void S_try::icfg(CFGEnv &env)
+{ 
+  // control flows into the body
+  body->computeCFG(env);
+  
+  // but, it could spontaneously arrive at any of the handlers..
+  // hmm.. that raises at least two issues:
+  //   - control can transfer away from any statement at any time,
+  //     because of a thrown exception; so all claims as to what
+  //     statement is "next" are conditional upon no exceptions
+  //   - I need a way to regard handlers as origins of the CFG, but
+  //     which can only be reached after the try block has entered,
+  //     and not after it has exited.. I have no idea how to do that
+  //     without being dramatically conservative (forget about the
+  //     time constraint, for example)
+  FAKELIST_FOREACH(Handler, handlers, h) {
+    // save any pending 'next's until after the handler
+    env.pushNexts();
+
+    // treat the handler as a CFG origin
+    h->body->computeCFG(env);
+
+    // merge resulting 'next's with those we saved
+    env.popNexts();
+  }
+
+  // now, we've merged the 'try' body 'next's with all of those from
+  // the handlers, and will point all of them at whatever poor,
+  // unsuspecting statement might come next
+}
+
+
+void S_asm::icfg(CFGEnv &env)
+{}
+
+void S_namespaceDecl::icfg(CFGEnv &env)
+{}
+
+
+// ------------------ Statement::getSuccessors ----------------
+// add it if it's not NULL
+static void addNextPtrIf(NextPtrList &arr, NextPtr p)
+{
+  if (p.stmt()) {
+    addNextPtr(arr, p);
+  }
+}
+
+// this function interprets the 'next' field, plus any other control
+// flow intrinsic to the statement, to find out which statements might
+// receive control flow after this one
+void Statement::getSuccessors(NextPtrList &dest, bool isContinue)
+{
+  ASTSWITCH(Statement, this) {
+    ASTCASE(S_if, i)
+      // the 'next' field is ignored since it always points at
+      // the 'then' branch anyway
+      addNextPtr(dest, NextPtr(i->thenBranch, false));
+      addNextPtr(dest, NextPtr(i->elseBranch, false));
+
+    ASTNEXT(S_switch, s)
+      SFOREACH_OBJLIST_NC(Statement, s->cases, iter) {
+        addNextPtr(dest, NextPtr(iter.data(), false));
+      }
+
+    ASTNEXT(S_while, w)
+      addNextPtrIf(dest, next);
+      addNextPtr(dest, NextPtr(w->body, false));
+
+    ASTNEXT(S_doWhile, d)
+      if (isContinue) {
+        // continue jumps to conditional, so it could exit the loop
+        addNextPtrIf(dest, next);
+      }
+      // either way, doing the body is an option
+      addNextPtr(dest, NextPtr(d->body, false));
+
+    ASTNEXT(S_for, f)
+      // though the semantics of choosing which expressions get
+      // evaluated are different depending on 'isContinue', the
+      // statement-level control flow options are the same
+      addNextPtrIf(dest, next);
+      addNextPtr(dest, NextPtr(f->body, false));
+
+    ASTDEFAULT
+      // for most statements, there is only one control flow option
+      addNextPtrIf(dest, next);
+
+    ASTENDCASE
+  }
+}
+
+
+static bool contains(NextPtrList &arr, NextPtr p)
+{
+  for (int i=0; i < arr.length(); i++) {
+    if (arr[i] == p) {
+      return true;
+    }
+  }
+  return false;   // not found
+}
+
+string Statement::successorsToString() const
+{
+  // getSuccessors() is not declared const because it returns pointers
+  // that are themselves not const.. but that capability won't be
+  // abused in this function, so I'll cast away constness so I can
+  // call that function
+  Statement *ths = const_cast<Statement*>(this);
+
+  NextPtrList succNoCont;
+  ths->getSuccessors(succNoCont, false);
+
+  NextPtrList succYesCont;
+  ths->getSuccessors(succYesCont, true);
+
+  stringBuilder sb;
+  sb << "{";
+
+  for (int i=0; i < succYesCont.length(); i++) {
+    NextPtr np = succYesCont[i];
+
+    // a leading "(c)" means the successor edge is only present when
+    // this node is reached via continue; a trailing "(c)" means that
+    // successor is itself a continue edge; the algorithm assumes
+    // that 'succYesCont' is a superset of 'succNoCont'
+    sb << (contains(succNoCont, np)? " " : " (c)")
+       << np.stmt()->lineColString()
+       << (np.cont()? "(c)" : "");
+  }
+
+  sb << " }";
+  return sb;
+}
+
+
+// ------------------- reversePostorder ---------------
+// DFS from 'node', having arrived at node with 'isContinue'
+// disposition; 'seen' is those nodes either currently being
+// considered somewhere in the call chain ("gray"), or else finished
+// entirely ("black"), and 'seenCont' is the same thing but for the
+// continue==true halves of the nodes
+static
+void rp_dfs(NextPtrList &order, NextPtr node,
+            SObjSet<Statement*> &seen, SObjSet<Statement*> &seenCont)
+{
+  // we're now considering 'node'; did we arrive via continue?
+  (node.cont()? seenCont : seen).add(node.stmt());     // C++ generalized lvalue!
+
+  // consider each of this node's successors
+  NextPtrList successors;
+  node.stmt()->getSuccessors(successors, node.cont());
+
+  for (int i=0; i < successors.length(); i++) {
+    NextPtr succ = successors[i];
+
+    if ((succ.cont()? seenCont : seen).contains(succ.stmt())) {
+      // we're already considering, or have already considered, this node;
+      // do nothing with it
+    }
+    else {
+      // visit this new child
+      rp_dfs(order, succ, seen, seenCont);
+    }
+  }
+
+  // since we're finished with this node, we append it to compute the
+  // postorder
+  order.push(node);
+}
+
+
+void reversePostorder(NextPtrList &order, Function *func)
+{
+  xassert(order.isEmpty());
+
+  // DFS from the function start, computing the spanning tree implicitly,
+  // and the postorder explicitly
+  SObjSet<Statement*> seen, seenCont;
+  rp_dfs(order, NextPtr(func->body, false /*isContinue*/), seen, seenCont);
+  
+  // reverse the list
+  int low=0, high=order.length()-1;
+  while (low < high) {
+    NextPtr temp = order[low];
+    order[low] = order[high];
+    order[high] = temp;
+    low++;
+    high--;
+  }
+}
+
+
+// --------------------- computeCFG -------------------
+// Intended to be used with LoweredASTVisitor
+class CFGVisitor : private ASTVisitor {
+public:
+  LoweredASTVisitor loweredVisitor; // use this as the argument for traverse()
+
+private:
+  CFGEnv &env;
+
+public:
+  CFGVisitor(CFGEnv &e)
+    : loweredVisitor(this)
+    , env(e)
+  {}
+  virtual ~CFGVisitor() {}
+
+  virtual bool visitFunction(Function *obj);
+};
+
+bool CFGVisitor::visitFunction(Function *obj)
+{
+  computeFunctionCFG(env, obj);
+
+  return true;     // visit children (it's possible to nest functions inside local classes)
+}
+
+void computeFunctionCFG(CFGEnv &env, Function *f)
+{
+  f->body->computeCFG(env);
+
+  env.resolveGotos();
+  env.resolveNexts(NextPtr(NULL /*target*/, false /*isContinue*/));
+
+  env.verifyFunctionEnd();
+}
+
+int computeUnitCFG(TranslationUnit *unit)
+{
+  CFGEnv env;
+  CFGVisitor vis(env);
+  unit->traverse(vis.loweredVisitor);
+
+  // plan for supporting GNU statement-expression: use the visitor to
+  // find the statement-expressions, and treat them as relatively
+  // isolated pieces (push & pop the environment) of the CFG, but
+  // still in the context of the function (for gotos, etc.)
+  
+  return env.errors;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/cfg.h
===================================================================
--- vendor/elsa/current/elsa/cfg.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cfg.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,154 @@
+// cfg.h
+// intraprocedural control flow graph over statements
+
+#ifndef CFG_H
+#define CFG_H
+
+#include "array.h"        // ArrayStack<NextPtr>
+#include "sobjlist.h"     // SObjList
+#include "objstack.h"     // ObjStack
+#include "sobjstack.h"    // SObjStack
+#include "strmap.h"       // StringRefMap
+#include "strtable.h"     // StringRef
+#include "srcloc.h"       // SourceLoc
+
+// can't just #include cc.ast.gen.h b/c that #includes this file
+class Statement;
+class S_break;
+class S_label;
+class S_goto;
+class S_switch;
+class Function;
+class TranslationUnit;
+
+
+// dsw: Design note: the graph that is built here is NOT the control
+// flow graph!  It is only information additional to what is inherent
+// in the AST that Statement::getSuccessors() needs to compute the
+// control flow graph when asked; See the comment at the top of
+// Statement::getSuccessors() in cfg.cc.  For example, an 'if'
+// statement (S_if) never has an edge added to the start of its 'else'
+// block because the fact that the 'else' (sometimes) follows the 'if'
+// is inherent in the meaning of the AST.
+
+// a 'next' pointer in the CFG, i.e. a pointer to a Statement
+class NextPtr {
+private:     // data
+  // encoding is a Statement*, OR'd with 1 if it's a "continue" edge;
+  // hopefully the compiler will be smart about representation and
+  // calling convention, as both will be semantically equivalent to
+  // how an ordinary 'long' is treated
+  long p;
+
+public:
+  // construction, assignment
+  NextPtr() : p(0) {}
+  NextPtr(Statement *next, bool isContinue)
+    : p((long)next | !!isContinue) {}
+  NextPtr(NextPtr const &obj) : p(obj.p) {}
+  NextPtr& operator= (NextPtr const &obj) { p = obj.p; return *this; }
+
+  // comparison
+  bool operator== (NextPtr const &obj) const { return p == obj.p; }
+  bool operator!= (NextPtr const &obj) const { return p != obj.p; }
+
+  // selection
+  Statement *stmt() { return (Statement*)(p & ~1L); }
+  bool cont() const { return (bool)(p & 1); }
+
+  // like next()->kindLocString(), with a "(c)" appended if it's the
+  // cont()==true half
+  string asString();
+};
+
+
+// represent lists with a growable array/stack
+typedef ArrayStack<NextPtr> NextPtrList;
+
+// add another pointer to a list
+inline void addNextPtr(NextPtrList &arr, NextPtr p)
+  { arr.push(p); }
+
+// iterate over such a thing
+#define FOREACH_NEXTPTR(list, itervar) \
+  for (ArrayStackIterNC<NextPtr> itervar(list); !itervar.isDone(); itervar.adv())
+
+
+// environment for constructing an intraprocedural CFG
+class CFGEnv {
+  NO_OBJECT_COPIES(CFGEnv);
+
+private:    // data
+  ObjStack< SObjList<Statement> > pendingNexts;
+
+  ObjStack< SObjList<S_break> > breaks;
+
+  StringRefMap<S_label> labels;         // goto targets
+  SObjStack<S_goto> gotos;              // goto sources (a set)
+
+  SObjStack<S_switch> switches;
+  SObjStack<Statement> loops;
+
+public:     // data
+  // count of errors found with e.g. goto/label correspondence
+  int errors;
+
+public:     // funcs
+  CFGEnv();
+  virtual ~CFGEnv();
+
+  // report an error
+  void err(SourceLoc loc, char const *str);
+
+  // manipulate a stack of lists of nodes whose 'next' link
+  // needs to be set
+  void pushNexts();          // push an empty top
+  void addPendingNext(Statement *source);
+  void popNexts();           // merge two topmost frames
+  void clearNexts();         // clear top
+  void resolveNexts(NextPtr target);
+
+  // manipulate a stack of lists of 'break' nodes whose 'next'
+  // link needs to be set
+  void pushBreaks();         // push empty top
+  void addBreak(S_break *source);
+  void popBreaks();          // resolve all at top, and pop frame
+
+  // manipulate lists of sources and targets of gotos
+  void addLabel(StringRef name, S_label *target);
+  void addPendingGoto(S_goto *source);
+  void resolveGotos();
+
+  // maintain a stack of nested switch statements
+  void pushSwitch(S_switch *sw);
+  S_switch *getCurrentSwitch();
+  void popSwitch();
+  void connectEnclosingSwitch(Statement *stmt, char const *kind);
+
+  // stack of nested loops
+  void pushLoop(Statement *loop);
+  Statement *getCurrentLoop();
+  void popLoop();
+
+  // check data structures for conditions which should hold between
+  // funcs (if they do not, then there's a bug in the CFG algorithm,
+  // not the user's code)
+  void verifyFunctionEnd();
+};
+
+
+// given a function node annotated with CFG edges, return a list of
+// all the CFG nodes, in reverse postorder w.r.t. some spanning tree
+// (useful for initializing worklists in dataflow algorithms)
+void reversePostorder(NextPtrList &order, Function *func);
+
+
+// compute CFGs for all functions in a translation unit; return the
+// number of CFG errors
+int computeUnitCFG(TranslationUnit *unit);
+
+// and for just one function, with an environment already made
+void computeFunctionCFG(CFGEnv &env, Function *f);
+
+
+#endif // CFG_H

Added: vendor/elsa/current/elsa/chop_out
===================================================================
--- vendor/elsa/current/elsa/chop_out	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/chop_out	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+#!/usr/bin/perl -w
+# -*-perl-*-
+use strict;
+
+# Chop out part of a file.
+
+# Daniel S. Wilkerson dsw at cs.berkeley.edu
+
+my $start = "---- START ----";  # NOTE: a filename can come after
+my $stop  = "---- STOP ----";
+
+# sm: I want to use this with some other delimiters
+if (@ARGV) {
+  $start = $ARGV[0];
+  $stop = $ARGV[1];
+}
+
+while(<STDIN>) {
+    last if /${start}/;
+}
+
+while(<STDIN>) {
+    last if /${stop}/;
+    print;
+}
+
+while(<STDIN>) {
+}


Property changes on: vendor/elsa/current/elsa/chop_out
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/cipart.lex
===================================================================
--- vendor/elsa/current/elsa/cipart.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/cipart.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,430 @@
+/* cipart.lex */
+/* interval partition generator for C/C++ */
+
+
+/* ------------ C prelude ------------ */
+%{
+#include "array.h"       // ArrayStack
+#include "str.h"         // stringc
+
+// this works around a problem with cygwin & fileno
+#define YY_NEVER_INTERACTIVE 1
+
+// current file offset
+int loc = 0;
+
+// current line number
+int lineNum = 1;
+
+// current line start
+int lineStart = 0;
+
+// last intraline boundary; -1 for none
+int boundary = -1;
+
+// stack of open braces
+ArrayStack<int> openBraces;
+
+// stack of lines starts where open braces occur
+ArrayStack<int> openBraceLines;
+
+// stack of open paren/brackets
+ArrayStack<int> openParens;
+
+// line-starts of open-braces that are now closed and so should
+// get a partition at the next end-of-line
+ArrayStack<int> pendingBracePair;
+                                
+// saved values of 'boundary' from outer levels of parentheses
+ArrayStack<int> savedBoundaries;
+
+// emit a partition
+void emit(int lo, int hi, char const *why);
+
+// handle a comment
+void comment();
+
+// handle a string literal
+void stringLit();
+
+// update location, moving past yytext
+void updLoc();
+
+// close any open intraline boundaries
+void finishBoundaries();
+%}
+
+
+/* ------------ flex options ----------- */
+/* no wrapping is needed; setting this means we don't have to link with libfl.a */
+%option noyywrap
+
+/* don't use the default-echo rules */
+%option nodefault
+
+/* I don't call unput */
+%option nounput
+
+/* the scanner is never interactive */
+%option never-interactive
+
+
+/* -------------- regexp defns ----------- */
+/* horizontal whitespace */
+WS          [ \t\f\v\r]
+
+/* normal string character: any but quote, newline, or backslash */
+STRCHAR       [^\"\n\\]
+
+/* (start of) an escape sequence */
+ESCAPE        ({BACKSL}{ANY})
+
+/* double quote */
+QUOTE         [\"]
+
+/* normal character literal character: any but single-quote, newline, or backslash */
+CCCHAR        [^\'\n\\]
+
+/* single quote */
+TICK          [\']
+
+/* backslash */
+BACKSL        "\\"
+
+/* newline */
+NL            "\n"
+
+/* any of 256 source characters */
+ANY           ({NOTNL}|{NL})
+
+/* end of line */
+EOL           {NL}
+
+/* anything but newline */
+NOTNL         .
+
+
+/* -------------- token rules ------------ */
+%%
+
+  /* newline: boundary unless inside parens */
+  /* this approximates the old 'delta' behavior of acting at line granularity */
+"\n" {
+  updLoc();
+  if (openParens.isEmpty()) {
+    finishBoundaries();
+    emit(lineStart, loc-1, (stringc << "line " << lineNum).c_str());
+    lineStart = loc;
+
+    while (pendingBracePair.isNotEmpty()) {
+      emit(pendingBracePair.pop(), loc-1, "brace pair");
+    }
+  }
+  lineNum++;
+}
+
+  /* braces: partition at start/end of containing lines */
+"{" {
+  finishBoundaries();
+  if (pendingBracePair.isNotEmpty()) {
+    // just let this open-brace cancel one of the close-braces
+    // on the same line 
+    int prev = pendingBracePair.pop();
+    openBraceLines.push(prev);
+    openBraces.push(prev /*approximate; will be fine*/);
+  }
+  else {
+    openBraceLines.push(lineStart);
+    openBraces.push(loc);
+  }
+  updLoc();
+}
+
+"}" {
+  finishBoundaries();
+
+  // where was the corresponding open-brace?
+  int openLineStart = openBraceLines.pop();
+  int openChar = openBraces.pop();
+
+  if (openLineStart != lineStart) {
+    // this is closing a brace pair started on another line, so
+    // schedule an emission when we reach the end of this line
+    pendingBracePair.push(openLineStart);
+  }
+  else {
+    // this pair was entirely within one line, so emit it as-is
+    emit(openChar, loc, "intraline brace pair");
+  }
+
+  updLoc();
+}
+
+  /* parens: partition just inside, and save boundary info */
+"("|"[" {
+  openParens.push(loc+1);      // just inside
+  savedBoundaries.push(boundary);
+  boundary = -1;
+  updLoc();
+}
+
+"]"|")" {
+  int openLoc = openParens.pop();
+
+  finishBoundaries();
+
+  // bound the contents inside the parens
+  emit(openLoc, loc-1, "contents of parens");
+
+  // restore old boundary info
+  boundary = savedBoundaries.pop();
+  updLoc();
+}
+
+
+  /* punctuation, operators: intraline boundary */
+"->"               |
+"::"               |
+"."                |
+"!"                |
+"~"                |
+"+"                |
+"-"                |
+"++"               |
+"--"               |
+"&"                |
+"*"                |
+".*"               |
+"->*"              |
+"/"                |
+"%"                |
+"<<"               |
+">>"               |
+"<"                |
+"<="               |
+">"                |
+">="               |
+"=="               |
+"!="               |
+"^"                |
+"|"                |
+"&&"               |
+"||"               |
+"?"                |
+":"                |
+"="                |
+"*="               |
+"/="               |
+"%="               |
+"+="               |
+"-="               |
+"&="               |
+"^="               |
+"|="               |
+"<<="              |
+">>="              |
+","                |
+"..."              |
+"<%"               |
+"%>"               |
+"<:"               |
+":>"               |
+"and"              |
+"bitor"            |
+"or"               |
+"xor"              |
+"compl"            |
+"bitand"           |
+"and_eq"           |
+"or_eq"            |
+"xor_eq"           |
+"not"              |
+"not_eq"           |
+".."               {
+  finishBoundaries();
+
+  // open a new boundary on the operator
+  boundary = loc;
+
+  updLoc();
+}
+
+
+  /* semicolon: close open boundaries, but don't start any
+   * (sort of line newline) */
+";" {
+  finishBoundaries();
+
+  updLoc();
+}
+
+
+  /* C++ comment */
+{WS}*"//".*    {
+  comment();
+}
+
+  /* C comment */
+"/""*"([^*]|"*"*[^*/])*"*"+"/"     {
+  comment();
+}
+
+  /* unterminated C comment */
+"/""*"([^*]|"*"*[^*/])*"*"*        {
+  comment();
+}
+
+
+  /* string literal */
+"L"?{QUOTE}({STRCHAR}|{ESCAPE})*{QUOTE} {
+  stringLit();
+}
+
+  /* string literal missing final quote */
+"L"?{QUOTE}({STRCHAR}|{ESCAPE})*{EOL}   {
+  stringLit();
+}
+
+  /* unterminated string literal at EOF */
+"L"?{QUOTE}({STRCHAR}|{ESCAPE})*{BACKSL}? {
+  stringLit();
+}
+
+
+  /* character literal */
+"L"?{TICK}({CCCHAR}|{ESCAPE})*{TICK}   {
+  stringLit();
+}
+
+  /* character literal missing final tick */
+"L"?{TICK}({CCCHAR}|{ESCAPE})*{EOL}    {
+  stringLit();
+}
+
+  /* unterminated character literal */
+"L"?{TICK}({CCCHAR}|{ESCAPE})*{BACKSL}?  {
+  stringLit();
+}
+
+
+  /* anything else: ignore */
+.  {
+  updLoc();
+}
+
+<<EOF>> {
+  yyterminate();
+}
+
+
+%%
+/* ----------------- C epilogue --------------- */
+
+#include "exc.h"         // xbase
+#include "autofile.h"    // AutoFILE
+
+// output file
+FILE *out;
+
+void emit(int lo, int hi, char const *why)
+{
+  if (lo <= hi) {
+    fprintf(out, "%d,%d; \t// %s\n", lo, hi, why);
+  }
+  else {
+    // happens for example when we have empty parens and try
+    // to identify their contents; just drop it
+  }
+}
+
+
+void comment()
+{
+  emit(loc, loc+yyleng-1, "comment");
+  updLoc();
+}
+
+
+// for string literals, regard all the text as optional except
+// the first character
+void stringLit()
+{
+  char *begin = yytext;
+  if (*begin == 'L') {
+    begin++;
+  }
+  begin++;                        // now 'begin' points to first non-quote char
+  begin++;                        // second non-quote char
+
+  char *end = yytext-yyleng-2;    // 'end' points to last non-quote char
+
+  if (end >= begin) {
+    // mark the chars between begin and end, inclusive
+    emit(loc + (begin-yytext), loc + (end-yytext), "string lit contents - 1");
+  }
+  
+  updLoc();
+}
+
+
+void updLoc()
+{
+  loc += yyleng;
+}
+
+
+void finishBoundaries()
+{
+  if (boundary != -1) {
+    // finish the intraline boundary
+    emit(boundary, loc-1, "intraline boundary");
+    boundary = -1;
+  }
+}
+
+
+void entry(int argc, char *argv[])
+{
+  xBase::logExceptions = false;
+
+  if (argc != 2) {
+    xbase(stringc << "usage: " << argv[0] << " foo.c\n"
+                  << "  writes foo.c.str");
+  }
+
+  string fname = argv[1];
+  AutoFILE fp(toCStr(fname), "r");
+  yyrestart(fp);
+
+  string outfname = stringc << fname << ".str";
+  AutoFILE outfp(toCStr(outfname), "w");
+  out = outfp;
+
+  fprintf(out, "// %s\n", outfname.c_str());
+  fprintf(out, "// generated automatically by %s from %s\n\n",
+               argv[0], fname.c_str());
+
+  try {
+    yylex();
+  }
+  catch (xBase &x) {
+    x.addContext(stringc << "lexing on line " << lineNum);
+    throw;
+  }
+}
+
+
+int main(int argc, char *argv[])
+{
+  try {
+    entry(argc, argv);
+    return 0;
+  }
+  catch (xBase &x) {
+    cout << x.why() << endl;
+    return 4;
+  }
+}
+
+
+  /* EOF */

Added: vendor/elsa/current/elsa/configure.pl
===================================================================
--- vendor/elsa/current/elsa/configure.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/configure.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,191 @@
+#!/usr/bin/perl -w
+# configure script for elsa
+
+use strict 'subs';
+
+# default location of smbase relative to this package
+$SMBASE = "../smbase";
+$req_smcv = 1.03;            # required sm_config version number
+$thisPackage = "elsa";
+
+# -------------- BEGIN common block ---------------
+# do an initial argument scan to find if smbase is somewhere else
+for (my $i=0; $i < @ARGV; $i++) {
+  my ($d) = ($ARGV[$i] =~ m/-*smbase=(.*)/);
+  if (defined($d)) {
+    $SMBASE = $d;
+  }
+}
+
+# try to load the sm_config module
+eval {
+  push @INC, ($SMBASE);
+  require sm_config;
+};
+if ($@) {
+  die("$@" .     # ends with newline, usually
+      "\n" .
+      "I looked for smbase in \"$SMBASE\".\n" .
+      "\n" .
+      "You can explicitly specify the location of smbase with the -smbase=<dir>\n" .
+      "command-line argument.\n");
+}
+
+# check version number
+$smcv = get_sm_config_version();
+if ($smcv < $req_smcv) {
+  die("This package requires version $req_smcv of sm_config, but found\n" .
+      "only version $smcv.\n");
+}
+# -------------- END common block ---------------
+
+# defaults
+ at LDFLAGS = ("-g -Wall");
+$AST = "../ast";
+$ELKHOUND = "../elkhound";
+$USE_GNU = "1";
+$USE_KANDR = "1";
+$GCOV_MODS = "";
+
+
+sub usage {
+  standardUsage();
+
+  print(<<"EOF");
+package options:
+  -prof              enable profiling
+  -gcov=<mods>       enable coverage testing for modules <mods>
+  -devel             add options useful while developing (-Werror)
+  -gnu=[0/1]         enable GNU extensions? [$USE_GNU]
+  -kandr=[0/1]       enable K&R extensions? [$USE_KANDR]
+  -ast=<dir>:        specify where the ast system is [$AST]
+  -elkhound=<dir>:   specify where the elkhound system is [$ELKHOUND]
+  -useSerialNumbers: give serial numbers to some objects for debugging
+EOF
+}
+
+
+# -------------- BEGIN common block 2 -------------
+# global variables holding information about the current command-line
+# option being processed
+$option = "";
+$value = "";
+
+# process command-line arguments
+foreach $optionAndValue (@ARGV) {
+  # ignore leading '-' characters, and split at first '=' (if any)
+  ($option, $value) =
+    ($optionAndValue =~ m/^-*([^-][^=]*)=?(.*)$/);
+                      #      option     = value
+
+  my $arg = $option;
+
+  if (handleStandardOption()) {
+    # handled by sm_config.pm
+  }
+  # -------------- END common block 2 -------------
+
+  elsif ($arg eq "prof") {
+    push @CCFLAGS, "-pg";
+    push @LDFLAGS, "-pg";
+  }
+
+  elsif ($arg eq "gcov") {
+    $GCOV_MODS = getOptArg();
+  }
+
+  elsif ($arg eq "devel") {
+    push @CCFLAGS, "-Werror";
+  }
+
+  elsif ($arg eq "ast") {
+    $AST = getOptArg();
+  }
+  elsif ($arg eq "elkhound") {
+    $ELKHOUND = getOptArg();
+  }
+
+  elsif ($arg eq "gnu") {
+    $USE_GNU = getBoolArg();
+  }
+  elsif ($arg eq "kandr") {
+    $USE_KANDR = getBoolArg();
+  }
+
+  elsif ($arg eq "useSerialNumbers") {
+    push @CCFLAGS, "-DUSE_SERIAL_NUMBERS=1";
+  }
+
+  else {
+    die "unknown option: $arg\n";
+  }
+}
+
+finishedOptionProcessing();
+
+
+# ------------------ check for needed components ----------------
+test_smbase_presence();
+
+test_CXX_compiler();
+
+# ast
+if (! -f "$AST/asthelp.h") {
+  die "I cannot find asthelp.h in `$AST'.\n" .
+      "The ast system is required for elsa.\n" .
+      "If it's in a different location, use the -ast=<dir> option.\n";
+}
+
+# elkhound
+if (! -f "$ELKHOUND/glr.h") {
+  die "I cannot find glr.h in `$ELKHOUND'.\n" .
+      "The elkhound system is required for elsa.\n" .
+      "If it's in a different location, use the -elkhound=<dir> option.\n";
+}
+
+$PERL = get_PERL_variable();
+
+
+# ------------------ config.summary -----------------
+$summary = getStandardConfigSummary();
+
+$summary .= <<"OUTER_EOF";
+cat <<EOF
+  LDFLAGS:     @LDFLAGS
+  SMBASE:      $SMBASE
+  AST:         $AST
+  ELKHOUND:    $ELKHOUND
+  USE_GNU:     $USE_GNU
+  USE_KANDR:   $USE_KANDR
+EOF
+OUTER_EOF
+
+if ($GCOV_MODS) {
+  $summary .= "echo \"  GCOV_MODS:   $GCOV_MODS\"\n";
+}
+
+writeConfigSummary($summary);
+
+
+# ------------------- config.status ------------------
+writeConfigStatus("LDFLAGS" => "@LDFLAGS",
+                  "SMBASE" => "$SMBASE",
+                  "AST" => "$AST",
+                  "ELKHOUND" => "$ELKHOUND",
+                  "PERL" => "$PERL",
+                  "USE_GNU" => "$USE_GNU",
+                  "USE_KANDR" => "$USE_KANDR",
+                  "GCOV_MODS" => "$GCOV_MODS");
+
+
+# ----------------- final actions -----------------
+# run the output file generator
+run("./config.status");
+
+print("\nYou can now run make, usually called 'make' or 'gmake'.\n");
+
+exit(0);
+
+
+# silence warnings
+pretendUsed($thisPackage);


Property changes on: vendor/elsa/current/elsa/configure.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/const_eval.cc
===================================================================
--- vendor/elsa/current/elsa/const_eval.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/const_eval.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,826 @@
+// const_eval.cc
+// code for const_eval.h
+
+#include "const_eval.h"     // this module
+#include "cc_ast.h"         // C++ AST
+#include "cc_env.h"         // Env
+#include "stdconv.h"        // applyIntegralPromotions, etc.
+
+
+// ----------------------- CValue ------------------------
+STATICDEF CValue::Kind CValue::classify(SimpleTypeId t)
+{
+  switch (t) {
+    case ST_CHAR:
+    case ST_SIGNED_CHAR:
+    case ST_SHORT_INT:
+    case ST_WCHAR_T:
+    case ST_INT:
+    case ST_LONG_INT:
+    case ST_LONG_LONG:
+      return K_SIGNED;
+
+    case ST_BOOL:
+    case ST_UNSIGNED_CHAR:
+    case ST_UNSIGNED_SHORT_INT:
+    case ST_UNSIGNED_INT:
+    case ST_UNSIGNED_LONG_INT:
+    case ST_UNSIGNED_LONG_LONG:
+      return K_UNSIGNED;
+
+    case ST_FLOAT:
+    case ST_DOUBLE:
+    case ST_LONG_DOUBLE:
+      return K_FLOAT;
+
+    case ST_DEPENDENT:
+      return K_DEPENDENT;
+
+    default:
+      return K_ERROR;
+  }
+}
+
+
+void CValue::dup(CValue const &obj)
+{
+  type = obj.type;
+  switch (classify(type)) {
+    case K_SIGNED:    si = obj.si;     break;
+    case K_UNSIGNED:  ui = obj.ui;     break;
+    case K_FLOAT:     f = obj.f;       break;
+    case K_ERROR:     why = obj.why;   break;
+    case K_DEPENDENT:                  break;
+  }
+}
+
+
+bool CValue::isZero() const
+{
+  switch (kind()) {
+    default: // silence warning
+    case K_SIGNED:    return si == 0;
+    case K_UNSIGNED:  return ui == 0;
+    case K_FLOAT:     return f == 0.0;
+  }
+}
+
+
+bool CValue::isIntegral() const
+{
+  Kind k = kind();
+  return k==K_SIGNED || k==K_UNSIGNED;
+}
+
+int CValue::getIntegralValue() const
+{
+  xassert(isIntegral());
+  if (kind() == K_SIGNED) {
+    return si;
+  }
+  else {
+    return (int)ui;
+  }
+}
+
+
+void CValue::setSigned(SimpleTypeId t, long v)
+{
+  type = t;
+  xassert(isSigned());
+  si = v;
+}
+
+
+void CValue::setUnsigned(SimpleTypeId t, unsigned long v)
+{
+  type = t;
+  xassert(isUnsigned());
+  ui = v;
+}
+
+
+void CValue::setFloat(SimpleTypeId t, float v)
+{
+  type = t;
+  xassert(isFloat());
+  f = v;
+}
+
+
+void CValue::setError(rostring w)
+{
+  type = ST_ERROR;
+  why = new string(w);
+}
+
+
+void CValue::setDependent()
+{
+  type = ST_DEPENDENT;
+  si = 0;
+}
+
+
+void CValue::performIntegralPromotions()
+{
+  convertToType(applyIntegralPromotions(type));
+}
+
+void CValue::convertToType(SimpleTypeId newType)
+{
+  Kind oldKind = classify(type);
+  Kind newKind = classify(newType);
+  if (newKind != oldKind) {
+    // neither source nor dest should be sticky
+    xassert(oldKind != K_ERROR && oldKind != K_DEPENDENT &&
+            newKind != K_ERROR && newKind != K_DEPENDENT);
+
+    xassert((unsigned)oldKind < 8u);    // for my representation trick
+
+    // sort of like ML-style case analysis on a pair of values
+    switch (newKind*8 + oldKind) {
+      default:
+        xfailure("unexpected type conversion scenario in const-eval");
+        break;                   // silence warning
+
+      case K_SIGNED*8 + K_UNSIGNED:
+        si = (long)ui;           // convert unsigned to signed
+        break;
+
+      case K_SIGNED*8 + K_FLOAT:
+        si = (long)f;
+        break;
+
+      case K_UNSIGNED*8 + K_SIGNED:
+        ui = (unsigned long)si;
+        break;
+
+      case K_UNSIGNED*8 + K_FLOAT:
+        ui = (unsigned long)f;
+        break;
+
+      case K_FLOAT*8 + K_SIGNED:
+        f = (float)si;
+        break;
+
+      case K_FLOAT*8 + K_UNSIGNED:
+        f = (float)ui;
+        break;
+    }
+  }
+
+  type = newType;
+
+  // truncate the value based on the final type
+  int reprSize = simpleTypeReprSize(type);
+  if (reprSize >= 4) {
+    // do no truncation
+  }
+  else {
+    int maxValue = (1 << 8*reprSize) - 1;
+    switch (kind()) {
+      case K_SIGNED:     if (si > maxValue) { si=maxValue; }  break;
+      case K_UNSIGNED:   if (ui > (unsigned)maxValue) { ui=(unsigned)maxValue; }  break;
+      default: break;   // ignore
+    }
+  }
+}
+
+
+void CValue::applyUnary(UnaryOp op)
+{
+  if (isSticky()) { return; }
+
+  switch (op) {
+    default: xfailure("bad code");
+
+    case UNY_PLUS:
+      // 5.3.1p6
+      performIntegralPromotions();
+      break;
+
+    case UNY_MINUS:
+      // 5.3.1p7
+      performIntegralPromotions();
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:    si = -si;   break;
+        case K_UNSIGNED:  ui = -ui;   break;
+        case K_FLOAT:     f = -f;     break;
+      }
+      break;
+
+    case UNY_NOT:
+      // 5.3.1p8
+      ui = isZero()? 1u : 0u;
+      type = ST_BOOL;
+      break;
+
+    case UNY_BITNOT:
+      // 5.3.1p9
+      performIntegralPromotions();
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:    si = ~si;   break;
+        case K_UNSIGNED:  ui = ~ui;   break;
+        case K_FLOAT:     setError("cannot apply ~ to float types"); break;
+      }
+  }
+}
+
+
+void CValue::applyUsualArithmeticConversions(CValue &other)
+{
+  SimpleTypeId finalType = usualArithmeticConversions(type, other.type);
+  this->convertToType(finalType);
+  other.convertToType(finalType);
+}
+
+
+void CValue::addOffset(int offset)
+{
+  if (isSigned()) {
+    si += offset;
+  }
+  else if (isUnsigned()) {
+    ui += (unsigned long)offset;
+  }
+  else if (isFloat()) {
+    f += (float)offset;     // questionable...
+  }
+  else {
+    // other cases: leave as-is
+  }
+}
+
+
+void CValue::applyBinary(BinaryOp op, CValue other)
+{
+  if (isSticky()) { return; }
+  
+  if (other.isSticky()) {
+    *this = other;
+    return;
+  }
+
+  switch (op) {
+    default:
+      setError(stringc << "cannot const-eval binary operator `" 
+                       << toString(op) << "'");
+      return;
+
+    // ---- 5.6 ----
+    case BIN_MULT:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     si = si * other.si;    break;
+        case K_UNSIGNED:   ui = ui * other.ui;    break;
+        case K_FLOAT:      f = f * other.f;       break;
+      }
+      break;
+
+    case BIN_DIV:
+      applyUsualArithmeticConversions(other);
+      if (other.isZero()) {
+        setError("division by zero");
+        return;
+      }
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     si = si / other.si;    break;
+        case K_UNSIGNED:   ui = ui / other.ui;    break;
+        case K_FLOAT:      f = f / other.f;       break;
+      }
+      break;
+
+    case BIN_MOD:
+      applyUsualArithmeticConversions(other);
+      if (other.isZero()) {
+        setError("mod by zero");
+        return;
+      }
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     si = si % other.si;    break;
+        case K_UNSIGNED:   ui = ui % other.ui;    break;
+        case K_FLOAT:      setError("mod applied to floating-point args"); return;
+      }
+      break;
+
+    // ---- 5.7 ----
+    case BIN_PLUS:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     si = si + other.si;    break;
+        case K_UNSIGNED:   ui = ui + other.ui;    break;
+        case K_FLOAT:      f = f + other.f;       break;
+      }
+      break;
+
+    case BIN_MINUS:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     si = si - other.si;    break;
+        case K_UNSIGNED:   ui = ui - other.ui;    break;
+        case K_FLOAT:      f = f - other.f;       break;
+      }
+      break;
+
+    // ---- gcc <? and >? ----
+    // guessing that <? and >? behave approximately like '+' in
+    // terms of the types
+    case BIN_MINIMUM:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case CValue::K_SIGNED:     si = ((si < other.si) ? si : other.si);   break;
+        case CValue::K_UNSIGNED:   ui = ((ui < other.ui) ? ui : other.ui);   break;
+        case CValue::K_FLOAT:      f = ((f < other.f) ? f : other.f);        break;
+      }
+      break;
+
+    case BIN_MAXIMUM:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case CValue::K_SIGNED:     si = ((si > other.si) ? si : other.si);   break;
+        case CValue::K_UNSIGNED:   ui = ((ui > other.ui) ? ui : other.ui);   break;
+        case CValue::K_FLOAT:      f = ((f > other.f) ? f : other.f);        break;
+      }
+      break;
+
+    // ---- 5.8 ----
+    case BIN_LSHIFT:
+    case BIN_RSHIFT: {
+      this->performIntegralPromotions();
+      other.performIntegralPromotions();
+
+      if (kind() == K_FLOAT || other.kind() == K_FLOAT) {
+        setError("cannot shift with float types");
+        return;
+      }
+
+      // get shift amount
+      int shamt = 0;
+      switch (other.kind()) {
+        default: // silence warning
+        case K_SIGNED:     shamt = other.si;    break;
+        case K_UNSIGNED:   shamt = other.ui;    break;
+      }
+
+      // apply it
+      if (op == BIN_LSHIFT) {
+        switch (kind()) {
+          default: // silence warning
+          case K_SIGNED:     si <<= shamt;    break;
+          case K_UNSIGNED:   ui <<= shamt;    break;
+        }
+      }
+      else {
+        switch (kind()) {
+          default: // silence warning
+          case K_SIGNED:     si >>= shamt;    break;
+          case K_UNSIGNED:   ui >>= shamt;    break;
+        }
+      }
+      break;
+    }
+
+    // ---- 5.9 ----
+    case BIN_LESS:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     ui = si < other.si;    break;
+        case K_UNSIGNED:   ui = ui < other.ui;    break;
+        case K_FLOAT:      ui = f < other.f;       break;
+      }
+      type = ST_BOOL;
+      break;
+
+    case BIN_GREATER:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     ui = si > other.si;    break;
+        case K_UNSIGNED:   ui = ui > other.ui;    break;
+        case K_FLOAT:      ui = f > other.f;       break;
+      }
+      type = ST_BOOL;
+      break;
+
+    case BIN_LESSEQ:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     ui = si <= other.si;    break;
+        case K_UNSIGNED:   ui = ui <= other.ui;    break;
+        case K_FLOAT:      ui = f <= other.f;       break;
+      }
+      type = ST_BOOL;
+      break;
+
+    case BIN_GREATEREQ:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     ui = si >= other.si;    break;
+        case K_UNSIGNED:   ui = ui >= other.ui;    break;
+        case K_FLOAT:      ui = f >= other.f;       break;
+      }
+      type = ST_BOOL;
+      break;
+
+    // ---- 5.10 ----
+    case BIN_EQUAL:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     ui = si == other.si;    break;
+        case K_UNSIGNED:   ui = ui == other.ui;    break;
+        case K_FLOAT:      ui = f == other.f;       break;
+      }
+      type = ST_BOOL;
+      break;
+
+    case BIN_NOTEQUAL:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     ui = si != other.si;    break;
+        case K_UNSIGNED:   ui = ui != other.ui;    break;
+        case K_FLOAT:      ui = f != other.f;       break;
+      }
+      type = ST_BOOL;
+      break;
+
+    // ---- 5.11 ----
+    case BIN_BITAND:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     si = si & other.si;    break;
+        case K_UNSIGNED:   ui = ui & other.ui;    break;
+        case K_FLOAT:      setError("cannot apply bitand to float types"); break;
+      }
+      break;
+
+    // ---- 5.12 ----
+    case BIN_BITXOR:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     si = si ^ other.si;    break;
+        case K_UNSIGNED:   ui = ui ^ other.ui;    break;
+        case K_FLOAT:      setError("cannot apply bitxor to float types"); break;
+      }
+      break;
+
+    // ---- 5.13 ----
+    case BIN_BITOR:
+      applyUsualArithmeticConversions(other);
+      switch (kind()) {
+        default: // silence warning
+        case K_SIGNED:     si = si | other.si;    break;
+        case K_UNSIGNED:   ui = ui | other.ui;    break;
+        case K_FLOAT:      setError("cannot apply bitor to float types"); break;
+      }
+      break;
+
+    // ---- 5.14 ----
+    case BIN_AND:
+      // Note: short-circuit behavior is handled by the caller of
+      // this function; by the time we get here, both args have
+      // already been evaluated
+      this->convertToType(ST_BOOL);
+      other.convertToType(ST_BOOL);
+      ui = ui && other.ui;
+      break;
+
+    // ---- 5.15 ----
+    case BIN_OR:
+      this->convertToType(ST_BOOL);
+      other.convertToType(ST_BOOL);
+      ui = ui || other.ui;
+      break;
+  }
+}
+
+
+string CValue::asString() const
+{
+  switch (kind()) {
+    case K_SIGNED:      return stringc << toString(type) << ": " << si;
+    case K_UNSIGNED:    return stringc << toString(type) << ": " << ui;
+    case K_FLOAT:       return stringc << toString(type) << ": " << f;
+    case K_ERROR:       return stringc << "error: " << *why;
+    default:    // silence warning
+    case K_DEPENDENT:   return "dependent";
+  }
+}
+
+
+// ----------------------- ConstEval ------------------------
+ConstEval::ConstEval(Variable *d)
+  : dependentVar(d)
+{}
+
+ConstEval::~ConstEval()
+{}
+
+
+// external interface
+CValue Expression::constEval(ConstEval &env) const
+{
+  #if 1       // production
+    return iconstEval(env);
+  #else       // debugging
+    #warning debugging code is enabled
+    CValue ret = iconstEval(env);
+    cout << "const-eval of `" << exprToString() << "' is " << ret.asString() << endl;
+    return ret;
+  #endif
+}
+
+
+CValue Expression::iconstEval(ConstEval &env) const
+{
+  if (ambiguity) {
+    // 2005-05-26: This used to be cause for an assertion failure, but
+    // what can happen (in/c/dC0018.c) is that a user-error here or
+    // higher up causes the tcheck to prune, thereby leaving an
+    // ambiguity link.  What I will do is make this a user-error
+    // condition also, under the premise that (due to disambiguation
+    // selecting a different interpretation) the user will never see
+    // it; but by adding the error, I ensure this interpretation will
+    // not part of a successful parse.
+    return CValue("ambiguous expr being const-eval'd (user should not see this)");
+  }
+
+  if (type->isError()) {
+    // don't try to const-eval an expression that failed
+    // to typecheck
+    return CValue("failed to tcheck");
+  }
+
+  ASTSWITCHC(Expression, this) {
+    // Handle this idiom for finding a member offset:
+    // &((struct scsi_cmnd *)0)->b.q
+    ASTCASEC(E_addrOf, eaddr)
+      return eaddr->expr->constEvalAddr(env);
+
+    ASTNEXTC(E_boolLit, b)
+      CValue ret;
+      ret.setBool(b->b);
+      return ret;
+
+    ASTNEXTC(E_intLit, i)
+      CValue ret;
+      SimpleTypeId id = type->asSimpleTypeC()->type;
+      switch (CValue::classify(id)) {
+        default: xfailure("unexpected intlit type");
+        case CValue::K_SIGNED:     ret.setSigned(id, (long)i->i);              break;
+        case CValue::K_UNSIGNED:   ret.setUnsigned(id, (unsigned long)i->i);   break;
+      }
+      return ret;
+
+    ASTNEXTC(E_floatLit, f)
+      CValue ret;
+      SimpleTypeId id = type->asSimpleTypeC()->type;
+      ret.setFloat(id, (float)f->d);
+      return ret;
+
+    ASTNEXTC(E_charLit, c)
+      CValue ret;
+      SimpleTypeId id = type->asSimpleTypeC()->type;
+      switch (CValue::classify(id)) {
+        default: xfailure("unexpected charlit type");
+        case CValue::K_SIGNED:     ret.setSigned(id, (long)c->c);              break;
+        case CValue::K_UNSIGNED:   ret.setUnsigned(id, (unsigned long)c->c);   break;
+      }
+      return ret;
+
+    ASTNEXTC(E_variable, v)
+      return env.evaluateVariable(v->var);
+
+    ASTNEXTC(E_constructor, c)
+      if (type->isIntegerType()) {
+        // allow it; should only be 1 arg, and that will be value
+        return c->args->first()->constEval(env);
+      }
+      else {
+        return CValue("can only const-eval E_constructors for integer types");
+      }
+
+    ASTNEXTC(E_sizeof, s)
+      // 5.3.3p6: result is of type 'size_t'; most systems (including my
+      // elsa/include/stddef.h header) make that the same as 'unsigned';
+      // in any case, it must be an unsigned integer type (c99, 7.17p2)
+      CValue ret;
+      ret.setUnsigned(ST_UNSIGNED_INT, s->size);
+      return ret;
+
+    ASTNEXTC(E_unary, u)
+      CValue ret = u->expr->constEval(env);
+      ret.applyUnary(u->op);
+      return ret;
+
+    ASTNEXTC(E_binary, b)
+      if (b->op == BIN_COMMA) {
+        // avoid trying to eval the LHS
+        return b->e2->constEval(env);
+      }
+
+      CValue v1 = b->e1->constEval(env);
+      if (b->op == BIN_AND && v1.isZero()) {
+        CValue ret;
+        ret.setBool(false);   // short-circuit: propagate false
+        return ret;
+      }
+      if (b->op == BIN_OR && !v1.isZero()) {
+        CValue ret;
+        ret.setBool(true);    // short-circuit: propagate false
+        return ret;
+      }
+
+      CValue v2 = b->e2->constEval(env);
+
+      v1.applyBinary(b->op, v2);
+      return v1;
+
+    ASTNEXTC(E_cast, c)
+      return constEvalCast(env, c->ctype, c->expr);
+      
+    ASTNEXTC(E_keywordCast, c)
+      if (c->key == CK_DYNAMIC) {
+        return CValue("cannot const-eval a keyword_cast");
+      }
+      else {
+        // assume the other three work like C casts
+        return constEvalCast(env, c->ctype, c->expr);
+      }
+
+    ASTNEXTC(E_cond, c)
+      CValue v = c->cond->constEval(env);
+      if (v.isSticky()) {
+        return v;
+      }
+
+      if (!v.isZero()) {
+        return c->th->constEval(env);
+      }
+      else {
+        return c->el->constEval(env);
+      }
+
+    ASTNEXTC(E_sizeofType, s)
+      if (s->atype->getType()->isGeneralizedDependent()) {
+        return CValue(ST_DEPENDENT);
+      }
+      CValue ret;
+      ret.setUnsigned(ST_UNSIGNED_INT, s->size);
+      return ret;
+
+    ASTNEXTC(E_grouping, e)
+      return e->expr->constEval(env);
+
+    ASTDEFAULTC
+      return extConstEval(env);
+
+    ASTENDCASEC
+  }
+}
+
+// The intent of this function is to provide a hook where extensions
+// can handle the 'constEval' message for their own AST syntactic
+// forms, by overriding this function.  The non-extension nodes use
+// the switch statement above, which is more compact.
+CValue Expression::extConstEval(ConstEval &env) const
+{
+  return CValue(stringc << kindName() << " is not constEval'able");
+}
+
+
+CValue ConstEval::evaluateVariable(Variable *var)
+{
+  if (var->isEnumerator()) {
+    CValue ret;
+    ret.setSigned(ST_INT, var->getEnumeratorValue());
+    return ret;
+  }
+
+  if (var->type->isCVAtomicType() &&
+      (var->type->asCVAtomicTypeC()->cv & CV_CONST) &&
+      var->value) {
+    // const variable
+    return var->value->constEval(*this);
+  }
+
+  if (var->type->isGeneralizedDependent() &&
+      var->value) {
+    return CValue(ST_DEPENDENT);
+  }
+
+  if (var->isTemplateParam()) {
+    return CValue(ST_DEPENDENT);
+  }
+
+  if (var == dependentVar) {
+    // value-dependent expression
+    return CValue(ST_DEPENDENT);
+  }
+
+  return CValue(stringc
+    << "can't const-eval non-const variable `" << var->name << "'");
+}
+
+
+// TODO: This function is basically a stub; it does not compute
+// the right result in almost any circumstance.
+CValue Expression::constEvalAddr(ConstEval &env) const
+{
+  // FIX: I'm sure there are cases missing from this
+  ASTSWITCHC(Expression, this) {
+    // These two are dereferences, so they recurse back to constEval().
+    ASTCASEC(E_deref, e)
+      return e->ptr->constEval(env);
+
+    ASTNEXTC(E_arrow, e)
+      return e->obj->constEval(env);
+
+    ASTNEXTC(E_fieldAcc, e) {
+      // 2006-06-03: Trying to make this work for in/c/k0014.c.
+      CValue val = e->obj->constEvalAddr(env);
+      CompoundType *ct = e->obj->type->asRval()->ifCompoundType();
+      if (!ct) {
+        // probably something weird like a template
+      }
+      else {
+        val.addOffset(ct->getDataMemberOffset(e->field));
+      }
+      return val;
+    }
+
+    // These just recurse on constEvalAddr().
+    ASTNEXTC(E_cast, e)
+      return e->expr->constEvalAddr(env);
+
+    ASTNEXTC(E_keywordCast, e)
+      // FIX: haven't really thought about these carefully
+      switch (e->key) {
+        default:
+          xfailure("bad CastKeyword");
+
+        case CK_DYNAMIC:
+          return CValue("can't const-eval dynamic_cast");
+
+        case CK_STATIC:
+        case CK_REINTERPRET:
+        case CK_CONST:
+          return e->expr->constEvalAddr(env);
+      }
+      break;
+
+    ASTNEXTC(E_grouping, e)
+      return e->expr->constEvalAddr(env);
+
+    ASTDEFAULTC
+      return CValue("unhandled case in constEvalAddr");
+
+    ASTENDCASEC
+  }
+}
+
+
+CValue Expression::constEvalCast(ConstEval &env, ASTTypeId const *ctype,
+                                 Expression const *expr) const
+{
+  CValue ret = expr->constEval(env);
+  if (ret.isSticky()) {
+    return ret;
+  }
+
+  Type *t = ctype->getType();
+  if (t->isSimpleType()) {
+    ret.convertToType(t->asSimpleTypeC()->type);
+  }
+  else if (t->isEnumType() ||
+           t->isPointer()) {        // for Linux kernel
+    ret.convertToType(ST_INT);
+  }
+  else {
+    // TODO: this is probably not the right rule..
+    return CValue(stringc
+      << "in constant expression, can only cast to arithmetic or pointer types, not `"
+      << t->toString() << "'");
+  }
+
+  return ret;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/const_eval.h
===================================================================
--- vendor/elsa/current/elsa/const_eval.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/const_eval.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,131 @@
+// const_eval.h
+// evaluate Expression AST nodes to a constant, if possible
+
+#ifndef CONST_EVAL_H
+#define CONST_EVAL_H
+
+#include "str.h"         // string
+#include "cc_flags.h"    // SimpleTypeId
+#include "xassert.h"     // xassert
+
+class Variable;          // variable.h
+
+
+// represent a value during constant evaluation; in essence, the
+// constant evaluator is an interpreter for a small fragment of the
+// expression language, and CValue is the type of data manipulated by
+// that interpreter
+class CValue {
+public:      // data
+  // This is the type of the value, as one of the C built-in types, or
+  // ST_ERROR for a non-const-evaluatable expression, or ST_DEPENDENT
+  // for an expression whose value depends on a template parameter.
+  SimpleTypeId type;
+
+  // kind of CValue; determines which element of the union below
+  // is valid; basically a partition of SimpleTypeId
+  enum Kind {
+    K_SIGNED,                // signed integer value
+    K_UNSIGNED,              // unsigned integer value
+    K_FLOAT,                 // floating-point value (even for ST_DOUBLE)
+    K_ERROR,                 // ST_ERROR
+    K_DEPENDENT              // ST_DEPENDENT
+  };
+
+  union {
+    long si;                 // K_SIGNED
+    unsigned long ui;        // K_UNSIGNED
+    float f;                 // K_FLOAT
+    string *why;             // K_ERROR
+  };
+
+private:
+  void dup(CValue const &obj);
+
+public:      // funcs
+  explicit CValue(SimpleTypeId t = ST_INT)
+    { type=t; si=0; }
+  explicit CValue(rostring why)
+    { setError(why); }
+
+  CValue(CValue const &obj)
+    { dup(obj); }
+
+  CValue& operator= (CValue const &obj)
+    { dup(obj); return *this; }
+
+  // map SimpleTypeId to CValue::Kind
+  static Kind classify(SimpleTypeId t);
+
+  Kind kind() const          { return classify(type); }
+  bool isSigned() const      { return kind() == K_SIGNED; }
+  bool isUnsigned() const    { return kind() == K_UNSIGNED; }
+  bool isFloat() const       { return kind() == K_FLOAT; }
+  bool isError() const       { return kind() == K_ERROR; }
+  bool isDependent() const   { return kind() == K_DEPENDENT; }
+
+  // true when the value cannot further be changed by arithmetic
+  bool isSticky() const      { return isError() || isDependent(); }
+
+  long getSignedValue() const    { xassert(isSigned()); return si; }
+  long getUnsignedValue() const  { xassert(isUnsigned()); return ui; }
+  float getFloatValue() const    { xassert(isFloat()); return f; }
+  string *getWhy() const         { xassert(isError()); return why; }
+
+  bool isZero() const;
+  bool isIntegral() const;
+  int getIntegralValue() const;
+
+  void setSigned(SimpleTypeId t, long v);
+  void setUnsigned(SimpleTypeId t, unsigned long v);
+  void setFloat(SimpleTypeId t, float v);
+  void setError(rostring why);
+  void setDependent();
+
+  void setBool(bool b)
+    { setUnsigned(ST_BOOL, (unsigned)b); }
+
+  // *this = <op> *this;
+  void applyUnary(UnaryOp op);
+
+  // *this = *this <op> other;
+  void applyBinary(BinaryOp op, CValue other);
+  
+  // convert this value to 'newType', carrying along the value
+  void convertToType(SimpleTypeId newType);
+
+  // promote and convert
+  void performIntegralPromotions();
+
+  // convert *this and 'other' to a common type
+  void applyUsualArithmeticConversions(CValue &other);
+
+  // add 'offset' to the current value
+  void addOffset(int offset);
+
+  // debugging
+  string asString() const;
+};
+
+
+// this is a container for the evaluation state; the actual
+// evaluation methods are associated with the AST nodes,
+// and declared in cc_tcheck.ast
+//
+// 2005-03-30: It's become almost an empty container since I
+// added the 'CValue' concept.  So be it.
+class ConstEval {
+public:      // data
+  // needed to tell when an expression is value-dependent...
+  Variable * /*nullable*/ dependentVar;
+
+public:
+  ConstEval(Variable * /*nullable*/ dependentVar);
+  ~ConstEval();
+  
+  // evaluation of a Variable is exposed so that it can be
+  // used with a Variable not wrapped in an E_variable
+  CValue evaluateVariable(Variable *var);
+};
+
+#endif // CONST_EVAL_H

Added: vendor/elsa/current/elsa/crlf.txt
===================================================================
--- vendor/elsa/current/elsa/crlf.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/crlf.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+

Added: vendor/elsa/current/elsa/doc/ambiguous_ast.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/ambiguous_ast.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/anon-structs.txt
===================================================================
--- vendor/elsa/current/elsa/doc/anon-structs.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/anon-structs.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+2005-04-16 12:12
+
+in/k0046a.cc is an example of an anonymous struct:
+
+  union U1 {
+      struct {
+          int foo1;
+          int foo2;
+      };
+  };
+
+My reading of the standard is that this is invalid.
+
+I did some googling, and found:
+
+  http://cpptips.hyperformix.com/cpptips/anon_union_struct
+    -> says same as above, namely that anon structs do not work
+    
+  http://docs.sun.com/source/816-2460/Language_Extensions.html
+    -> documents Sun C++ extension that allows anon structs in unions
+    
+  http://www.alegsa.com.ar/Visitas/i38/Union%20with%20anonymous%20struct.php
+    -> some discussion of anon structs and an alternative to them
+    
+  http://gcc.gnu.org/ml/gcc-patches/1999-11n/msg00128.html
+    -> patch to gcc to improve pre-existing support for anon structs
+    
+  http://gcc.gnu.org/ml/gcc-bugs/1999-08n/msg00914.html
+    -> mentions patches that add anon struct support
+    
+  http://gcc.gnu.org/ml/gcc-help/2004-04/msg00002.html
+    -> says gcc-3.3.3 will allow only with -fms-extensions; this of course
+       suggests that this is an MSVC feature that got ported
+       
+  http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10225
+    -> discusses -fms-extensions and the fact that a linux driver uses it
+
+  http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13286
+    -> dup of 10225, "microsoft extension"
+    
+Bottom line: this bug/extension originated with microsoft and/or
+DEC/Sun, and is now implemented in gcc and icc (though some versions
+of gcc require a special flag to enable), an apparently has semantics
+similar anon unions; I will implement in Elsa with warning, with flag
+in CCLang to disable.

Added: vendor/elsa/current/elsa/doc/ast_build.dot
===================================================================
--- vendor/elsa/current/elsa/doc/ast_build.dot	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/ast_build.dot	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// ast_build.dot
+// information flow for building the Elsa AST
+
+digraph "Elsa AST Build Process" {
+
+  "cc.ast" -> "astgen";
+  "cc_tcheck.ast" -> "astgen";
+  "cc_print.ast" -> "astgen";
+  "cc_elaborate.ast" -> "astgen";
+  "gnu.ast" -> "astgen";
+  "cfg.ast" -> "astgen";
+
+  "astgen" [
+    shape = rectangle
+  ];
+
+  "astgen" -> "cc.ast.gen.h";
+  "astgen" -> "cc.ast.gen.cc";
+}

Added: vendor/elsa/current/elsa/doc/ast_build.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/ast_build.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/atomic_types.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/atomic_types.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/block_diagram.fig
===================================================================
--- vendor/elsa/current/elsa/doc/block_diagram.fig	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/block_diagram.fig	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,61 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 6150 3750 7050 4275
+4 1 0 50 0 0 16 0.0000 4 225 495 6600 3975 Type\001
+4 1 0 50 0 0 16 0.0000 4 165 810 6600 4260 Checker\001
+-6
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 1800 3600 3000 3600 3000 4500 1800 4500 1800 3600
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 3900 3600 5100 3600 5100 4500 3900 4500 3900 3600
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 6000 3600 7200 3600 7200 4500 6000 4500 6000 3600
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 1200 4050 1800 4050
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 3000 4050 3900 4050
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 5100 4050 6000 4050
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 7200 4050 8100 4050
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 1350 3150 1350 3900
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 3450 3150 3450 3900
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 5550 3450 5550 3900
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 7650 3450 7650 3900
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 8100 3600 9600 3600 9600 4500 8100 4500 8100 3600
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 9600 4050 10200 4050
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 10050 3150 10050 3900
+4 1 0 50 0 0 16 0.0000 4 165 615 4500 4125 Parser\001
+4 1 0 50 0 0 16 0.0000 4 165 570 2400 4125 Lexer\001
+4 0 0 50 0 0 16 0.0000 4 225 1275 1200 2700 Preprocessed\001
+4 0 0 50 0 0 16 0.0000 4 165 1245 1200 2985 Source Code\001
+4 0 0 50 0 0 16 0.0000 4 165 615 3300 2700 Token\001
+4 0 0 50 0 0 16 0.0000 4 165 705 3300 2985 Stream\001
+4 0 0 50 0 0 16 0.0000 4 225 825 5400 2700 Possibly\001
+4 0 0 50 0 0 16 0.0000 4 225 1140 5400 2985 Ambiguous\001
+4 0 0 50 0 0 16 0.0000 4 165 465 5400 3270 AST\001
+4 0 0 50 0 0 16 0.0000 4 165 1020 7500 2700 Annotated\001
+4 0 0 50 0 0 16 0.0000 4 225 1365 7500 2985 Unambiguous\001
+4 0 0 50 0 0 16 0.0000 4 165 465 7500 3270 AST\001
+4 1 0 50 0 0 16 0.0000 4 165 1155 8850 4125 Elaboration\001
+4 0 0 50 0 0 16 0.0000 4 165 1065 9600 2700 Elaborated\001
+4 0 0 50 0 0 16 0.0000 4 165 465 9600 2985 AST\001

Added: vendor/elsa/current/elsa/doc/block_diagram.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/block_diagram.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/cc.ast.html
===================================================================
--- vendor/elsa/current/elsa/doc/cc.ast.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/cc.ast.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,250 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>cc.ast</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+</HEAD>
+
+<body>
+
+<center><h2>
+cc.ast: The Abstract Syntax Tree description
+</h2></center>
+
+<p>
+This page documents <a href="../cc.ast">cc.ast</a>, the most
+important file in <a href="../index.html">Elsa</a>.  Mainly
+I document here the big ideas or the tricky points; cc.ast itself
+should be consulted for the details, and you should probably be
+looking at that file as you read this page (classes are documented
+in the same order as they appear in cc.ast).
+
+<p>
+Note that some of the AST classes, but not all, have source location
+information (SourceLoc; <a href="../../smbase/srcloc.h">smbase/srcloc.h</a>).
+Generally I've just put location info wherever I've happened to need it;
+there's no clear strategy.  Now that SourceLoc is just one word (it
+used to be three), I might put it everywhere.
+
+<h3>ASTVisitor</h3>
+
+<p>
+One way to walk over the AST is to write a set of mutually-recursive
+functions that manually traverse the AST edges.  This works well for
+analyses that are sensitive to context, and/or use results from
+subtrees in nontrivial ways.  The type checker
+(<a href="../cc_tcheck.ast">cc_tcheck.ast</a>,
+<a href="../cc_tcheck.cc">cc_tcheck.cc</a>) is such an analysis.
+
+<p>
+An alternative, which is less work if the analysis is mostly
+insensitive to context and/or does not need to inspect all of the
+nodes in the AST, is to use ASTVisitor.  One simply implements the
+ASTVisitor interface (defined in cc.ast.gen.h once that file has been
+generated), and invokes the <tt>traverse</tt> method on the root of
+the AST subtree of interest.  For example, this code would print all
+of the function names (without qualifiers) in the AST:
+
+<pre>
+  class FuncPrinter : public ASTVisitor {
+  public:
+    virtual bool visitFunction(Function *f) {
+      cout &lt;&lt; f-&gt;nameAndParams-&gt;getDeclaratorId()-&gt;getName() &lt;&lt; "\n";
+    }
+  };
+
+  void printFuncNames(TranslationUnit *unit)
+  {
+    FuncPrinter fp;
+    unit-&gt;traverse(fp);
+  }
+</pre>
+
+<h3>TranslationUnit, TopForm</h3>
+
+<p>
+The entire AST is a list of TopForms, collected into a TranslationUnit.
+A TopForm is something that appears at toplevel, or at toplevel in a 
+namespace.
+
+<h3>Function, MemberInit</h3>
+
+<p>
+All function definitions, whether at toplevel or inside class bodies,
+get a Function AST node.  The function's name and parameters are
+encoded in the <tt>nameAndParams</tt> Declarator.  Also included
+are constructor member initializers, and constructor exception
+handlers, if any.
+
+<h3>Declaration</h3>
+
+<p>
+A Declaration is a TypeSpecifier and then some Declarators, plus
+some optional keywords (DeclFlags) like <tt>static</tt> or
+<tt>extern</tt>.
+
+<h3>ASTTypeId</h3>
+
+<p>
+An ASTTypeId is like a Declaration, but there's only one Declarator
+and no DeclFlags.  It's used for function parameters and for
+the types that appear in the cast syntax.
+
+<h3>PQName</h3>
+
+<p>
+A PQName, a possibly-qualified name, is usually just a string
+(actually a StringRef, a pointer into the StringTable; see
+<a href="../../ast/strtable.h">ast/strtable.h</a>).  However, it
+might also have qualifiers, those names that can appear before
+the "<tt>::</tt>" symbol.  To complicate matters further, sometimes
+the names have template arguments, and sometimes the names refer
+to <tt>operator</tt>s.
+
+<h3>TypeSpecifier, BaseClassSpec, Enumerator</h3>
+
+<p>
+TypeSpecifiers are the first part of Declarations.  They mainly
+correspond to AtomicTypes in the terminology of
+<a href="cc_type.html">cc_type</a>: built-in types, enums, structs,
+classes, and unions.  However, via typedefs (TS_name), they can
+actually refer to constructed types (like pointers) also.
+
+<h3>MemberList, Member</h3>
+
+<p>
+Members are elements in a class definition.  Typical members
+are data members or method prototypes (MR_decl), or inline
+definitions of methods (MR_func).  MR_publish is obscure,
+corresponding to an "access declaration" [cppstd Section 11.3].
+
+<a name="declarator">
+<h3>Declarator, IDeclarator, ExceptionSpec</h3>
+</a>
+
+<p>
+The C/C++ syntax for declarators is probably the strangest part
+of the language to someone new to parsing it.  Declarators are
+the things that come after TypeSpecifiers in Declarations:
+<pre>
+  int                  *       x      ,    *     *     y     ;
+   |
+  TypeSpecifier     &lt;-- Declarator -&gt;    &lt;-- Declarator --&gt;
+
+  &lt;---------------------- Declaration -----------------------&gt;
+</pre>
+
+But they also have a recursive structure, represented in my
+AST as IDeclarators:
+<pre>
+  int       *          *                 y       ;
+                                         |
+                                      D_name
+                       &lt;---- D_pointer ----&gt;
+            &lt;--------- D_pointer ----------&gt;
+
+
+  int    * *      (    *           func    ) (int, int)  ;
+                                     |
+                                  D_name
+                       &lt;-- D_pointer --&gt;
+                  &lt;----- D_grouping -------&gt;
+                  &lt;-------------- D_func -------------&gt;
+           &lt;------------- D_pointer ------------------&gt;
+         &lt;------------- D_pointer --------------------&gt;
+</pre>
+
+<p>
+Now, what really makes them screwy is that they're inside out!  Taking
+the last example above, <tt>func</tt> is being declared to be a
+pointer to a function which returns a pointer to pointer to an
+integer--you read it from right to left.  The type checker
+(<a href="../cc_tcheck.cc">cc_tcheck.cc</a>) sorts the types out into
+a more usable representation
+(<a href="cc_type.html">cc_type</a>), but they start as above.
+
+<p>
+(By the way: declarators are inside-out not because Kernighan
+and Ritchie are evil or stupid, but because they wanted the syntax of
+declarations to mirror the syntax of expressions, to try to make the
+language easier to learn.  When I first learned C, I thought it
+made perfect sense.  Only now as a PhD student in computer science
+do I find it confusing.  <tt>:)</tt>&nbsp;  )
+
+<h3>OperatorName</h3>
+
+<p>
+OperatorName just stores the various <tt>operator</tt>-induced
+names.  The getOperatorName then flattens them down to a string
+anyway.  The tricky one is ON_conversion, which can't be
+canonically flattened, so this has to be special-cased in code
+that consumes OperatorNames.
+
+<h3>Statement, Condition, Handler</h3>
+
+<p>
+Statement represents statements; it's pretty straightforward.
+Condition is the thing between the parentheses in conditionals.
+Handler is what comes after <tt>try</tt>.
+
+<h3>Expression, ExpressionListOpt</h3>
+
+<p>
+Expression represents expressions.  Again, straightforward.
+
+<p>
+Notice that E_stringLit may contain a continuation.  That's
+how string literal concatenation is implemented: in the parser.
+This is done because the lexer does no interpretation of any
+kind of literal, but concatenation semantics would require that it
+do so (e.g. "\xA" "B" is equivalent to "\x0AB", two characters,
+not "\xAB", one character).
+
+<p>
+One possibly surprising choice is not to fold E_this into E_variable.
+The reason E_this is split off is that "this" is a pointer to the
+receiver object (called "__receiver"), which already is represented by
+a Variable in the parameter list.  If "this" were parsed as an
+E_variable then its 'var' field would have to point at some
+<em>other</em> Variable (so the type makes sense), but then we'd have
+two Variables for the same concept (receiver), which would be extra
+disconnect for analyses to overcome.  Therefore E_this lets us treat
+"this" the same as "&amp;__receiver".
+
+<h3>Initializer</h3>
+
+<p>
+Initializers are what come after IDeclarators in Declarations;
+they're the "3" in "int x = 3;".  They can be nested, as
+IN_compound.
+
+<p>
+GNU/C99 designated initializers are implemented in the GNU
+extension, <a href="../gnu.ast">gnu.ast</a>.  The build process
+that comes with Elsa will include the GNU extension if you
+pass "<tt>-gnu</tt>" to <tt>./configure</tt>.
+
+<h3>TemplateDeclaration, TemplateParameter, TemplateArgument</h3>
+
+<p>
+Representation of templates in the AST is straightforward.
+Elsa does not (yet?) expand or instantiate templates, however.
+
+<p>
+2005-03-02: The above is no longer true.  See
+<a href="design.html">design.html</a> for more info.
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+
+</HTML>
+
+
+

Added: vendor/elsa/current/elsa/doc/cc_type.html
===================================================================
--- vendor/elsa/current/elsa/doc/cc_type.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/cc_type.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,347 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>cc_type</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+</HEAD>
+
+<body>
+
+<center><h2>
+cc_type: Type Representation
+</h2></center>
+
+<p>
+This page documents <a href="../cc_type.h">cc_type.h</a> and
+<a href="../cc_type.cc">cc_type.cc</a>, the files which make up the type
+representation module in <a href="../index.html">Elsa</a>.  You
+should look at cc_type.h as you read this file.
+
+<p>
+Note that Diagram 1 of
+<a href="cpp_er.html">C++ Entities and Relationships</a> puts the concepts
+on this page in context with the rest of the language, in particular the
+lookup infrastructure.
+
+<h2>1. Introduction</h2>
+
+<p>
+The broad intent of cc_type is to represent types in a way that's easy
+to understand and manipulate.  The abstract syntax of C/C++ type
+declarations is very much <em>not</em> amenable to either, because it
+shares type specifiers among declarators in a declaration, and because
+declarators are inside-out (see the description of <a
+href="cc.ast.html#declarator">Declarator in cc.ast.html</a>).  The
+type checker has the responsibility of interpreting the C/C++ syntax,
+and constructing corresponding Type objects so that subsequent
+analyses don't have to deal with the actual syntax.
+
+<p>
+Another goal of the type representation is general independence from
+syntax.  Ideally, cc_type would not refer to cc.ast at all, but
+I haven't quite been able to achieve that.  Nevertheless, it remains
+a goal to minimize the knowledge cc_type has about cc.ast.  Types
+are concepts that exist independently from any particular syntax used
+to describe them, and I want the module dependencies to reflect that
+basic fact to the extent possible.
+
+<p>
+One major decision I made for this module was to translate typedefs
+away entirely.  This means I don't have a node for some kind of
+arbitrary "named type", which would have to be "unwrapped" every
+place a type is inspected.  The potential disadvantage is that I
+won't use the programmer's names when referring to types in error
+messages, but there's an easy solution to that too: every constructed
+type could have a field saying what name, if any, the programmer had
+been using as an alias for this type.  That's not implemented, but I'm
+confident it would eliminate any advantage to retaining typedefs.
+(Update: It has recently been implemented, see Type::typedefAliases.)
+
+<p>
+Types are divided into two major classes: atomic types and constructed
+types.  Atomic types (my terminology) are types atop which type
+constructors (like "*" or "[]") might be applied, but which themselves
+do not have any constructors, so cannot be further "deconstructed"
+(for example, by template pattern matching).
+They consist of built-in types like "int", enums, structs, classes and
+unions.  I regard the aggregation of structs/classes/unions to form
+an atomic wrapper around their members, in part because two (e.g.) struct
+types are equal only if they arise from the exact same declaration; there 
+is no structural equality for structs.  Each kind of atomic type
+is explained in Section 2.
+
+<p>
+Constructed types, by constrast, are whatever is built on top of
+atomic types by applying type constructors such as "*".  
+These types <em>can</em> be deconstructed by template unification
+<pre>
+  template &lt;class T&gt;
+  void foo(T *p) { ... }      // could pull "int" out of "int *"
+</pre>
+and typedefs can be used to build them in pieces
+<pre>
+  typedef int myint;
+  myint const *p;             // builds "int const"
+</pre>
+(again, in contrast to the AtomicTypes).
+Each type constructor is explained in Section 3.
+
+<p>
+If you're really bothered by the apparent contradiction that
+CompoundType is an AtomicType, think of the "struct { ... }"
+syntax as wrapping the members in an opaque container, thus
+forming an indivisble unit (i.e. an "atom").  This is of 
+course exactly what happens from the compiler's point of
+view, and the basis for the terminology.  Quoting from
+Dennis Ritchie's
+<a href="http://cm.bell-labs.com/cm/cs/who/dmr/chist.html">The
+Development of the C Language</a>, section "Embryonic C":
+<blockquote>
+  The central notion I captured from Algol was a type structure based
+  on atomic types (including structures), composed into arrays,
+  pointers (references), and functions (procedures).
+</blockquote>
+
+
+<h2>2. Atomic Types</h2>
+
+<center><img src="atomic_types.png" alt="Atomic Type Hierarchy"></center>
+
+<p>
+<b>AtomicType</b> is the root of the atomic type hierarchy.  It just
+contains methods to figure out what kind of type it actually is.
+
+<p>
+<b>SimpleType</b> is represents simple types built-in to C/C++, like
+"int".  <a href="../cc_flags.h">cc_flags.h</a> contains the definition of
+SimpleTypeId.  Note that there is no attempt to break down primitive
+types along dimensions like "signed" or "long", since the set of types
+is not orthogonal w.r.t. those dimensions (e.g. there is no "signed
+float" or "long char").  If an analysis wants (e.g.) an "isSigned"
+function, it should provide it itself, and make the associated
+decisions about what "isSigned(ST_FLOAT)" returns.
+
+<p>
+There are some SimpleTypeId codes that do not correspond to
+primitive C/C++ types, but are used instead by the front-end for
+various intermediate communication purposes.  For example, ST_ERROR
+represents the type of an expression that contained an error, and
+is used to try to reduce the amount of error cascading.  There
+are also some ids used to help implement section 13.6 of the C++
+standard.  Analyses generally won't have to concern themselves
+with such oddball values, since they shouldn't be visible outside
+the type checker implementation.
+
+<p>
+<b>CompoundType</b> is certainly the most complex of all the type classes.
+It represents a class, struct, or union.  Storage of class members is
+done by inheriting a Scope (<a href="../cc_scope.h">cc_scope.h</a>).
+Thus, CompoundType itself is mostly concerned with representing
+the inheritance hierarchy.
+
+<p>
+To get the name lookup semantics right, we must be able to tell when
+names are ambiguous and also know the inheritance path used to arrive
+at any base.  This is complicated by the presence of virtual
+inheritance.  Each class contains its own, independent representation
+of its particular inheritance DAG; this representation is a graph of
+<b>BaseClassSubobj</b> objects.  A base class subobject corresponds
+one-to-one to some particular (contiguous) range of byte offsets in
+the final object's layout.
+
+<p>
+CompoundType knows how to print out its DAG to
+<a href="http://www.research.att.com/sw/tools/graphviz/">Dot</a> format;
+see CompoundType::renderSubobjHierarchy.
+For example, <a href="../in/std/3.4.5.cc">in/std/3.4.5.cc</a> yields
+<a href="../gendoc/3.4.5.png">3.4.5.png</a>.
+
+<p>
+<b>EnumType</b> represents an enum.  It has a list of enumerator
+values, which are also added to the Env 
+(<a href="../cc_env.h">cc_env.h</a>) during type checking.
+
+
+<h2>3. Constructed Types</h2>
+
+<center><img src="constructed_types.png" alt="Constructed Type Hierarchy"></center>
+
+<p>
+<b>Type</b> is the root of the constructed type hierarchy.  Like
+<b>AtomicType</b>, it has methods to find out which kind
+of type a particular object is (roll-my-own RTTI).  It also has
+a variety of query methods (like isVoid()), and entry points for
+printing types.
+
+<p>
+<b>CVAtomicType</b> is always the leaf of a constructed type.
+It just wraps an AtomicType, but possibly with <tt>const</tt>
+or <tt>volatile</tt> qualifiers.
+
+<p>
+<b>PointerType</b> represents a pointer type,
+possibly qualified with <tt>const</tt> or <tt>volatile</tt>.
+
+<p>
+<b>ReferenceType</b> represents a reference type.  It has
+no qualifiers.  Note that in the original design, PointerType
+was used for <em>both</em> pointers and references, so you
+might find the occasional comment incorrectly referring to
+that state of affairs.  However, you can still treat pointers
+and references uniformly if you want, by using 
+<tt>isPtrOrRef()</tt>, <tt>getCVFlags()</tt>, and
+<tt>getAtType()</tt>.
+
+<p>
+<b>FunctionType</b> represents a function type.  The parameters
+are represented as a list of Variable
+(<a href="../variable.h">variable.h</a>) objects.  Nonstatic
+member functions have the <tt>isMember</tt> flag set, in which
+case their first parameter is called "this" and has type
+"C <i>cv</i> &", where "C" is the name of the class of which the
+function is a member, and <i>cv</i> is optional const/volatile flags.
+FunctionType also has a flag to indicate if it accepts a
+variable number of arguments, and a way (ExnSpec) to represent
+exception specifications.
+
+<p>
+Finally, function templates have a list of template parameters.  As I
+think about it, it's kind of strange to imagine a function
+<em>type</em> being templatized, so maybe I should have put that list
+someplace else (Variable?).  On the other hand, maybe it will work to
+treat templates as having polymorphic types.  Until the template
+implementation matures, it's not clear what the best strategy is.
+
+<p>
+4/19/04: The above description is out of date; the template
+parameters have indeed been moved into Variable.  However the
+template design remains in a state of flux so I'm waiting for
+it to settle before thoroughly documenting it.
+
+<p>
+<b>ArrayType</b> represents an array type.  Types with no
+size specified have size <tt>NO_SIZE</tt>.
+
+<p>
+<b>PointerToMemberType</b> represents a C++ pointer-to-member.
+It says which class' member it thinks it points at, the type
+of the referred-to thing, and some optional const/volatile
+qualifiers.  This is used for both pointers to both member
+functions and member data.
+
+<p>
+Note that creating a Pointer to a Function that happens to have
+<tt>isMember</tt> be true is not the same thing as a PointerToMember
+to a Function (without <tt>isMember</tt>).  The former is a concept
+that I think would be useful, but does not exist in C++.  The latter
+is C++'s pointer-to-member (to a function), and has the "heterogeneous
+array" semantics.
+
+<h2>4. Templates</h2>
+
+<p>
+The template design is still somewhat incomplete.  I'd like to
+have a pass that can fully instantiate templates, and so some
+of this is looking forward to the existence of such a pass.
+
+<p>
+<b>TypeVariable</b> is used for template functions and classes
+to stand for a type which is unknown because it's a parameter
+to the template.  It should point at its corresponding
+Variable, rather than just having a StringRef name...
+
+<p>
+<b>TemplateParams</b> is a list of template parameters.  I
+pulled this out into its own class for reasons I now don't 
+remember...
+
+<p>
+<b>ClassTemplateInfo</b> is intended to contain information about
+template instantiations.  It's not used right now.
+
+
+<h2>5. TypeFactory</h2>
+    
+<p>
+When the type checker 
+(<a href="../cc_tcheck.cc">cc_tcheck.cc</a>)
+constructs types, it actually does so via the
+<b>TypeFactory</b> interface.  This is to make it possible for someone
+to build annotations on top of my Types, instead of going in and
+mucking about in cc_type.h.  It has several core functions that
+must be defined by a derived class, and a variety of other functions
+with default implementations when such an implementation is "obvious"
+in terms of the core functions.
+
+<p>
+The present form of TypeFactory is driven by the existence of one
+project that has such an annotation system.  As new analyses arise
+that may need to customize the way types are built, I'll add new entry
+points to TypeFactory and modify cc_tcheck.cc to use them.
+
+<p>
+I consider the presence of the SourceLoc parameter in most of the
+TypeFactory functions to be a wart on the design.  I don't even know
+what that location should be, if the type is constructed outside
+the context of interpreting a type denotation in the AST.  The base
+Elsa front end itself always ignores that value, and passes
+<tt>SL_UNKNOWN</tt> whenever there isn't a location handy.  I'd
+like to eventually revisit the decisions that led to the presence
+of those parameters.
+
+<p>
+<b>BasicTypeFactory</b> is an implementation of TypeFactory that
+just builds the types defined in cc_type.h in the obvious way.
+
+
+<a name="basetype"></a>
+<h2>6. BaseType and Type</h2>
+
+<p>
+While the <b>TypeFactory</b> mechanism makes it easy to annotate the leaf
+types, like FunctionType and PointerType, it doesn't offer a way
+to effectively annotate Type itself, because that class is in the
+middle of the inheritance hierarchy.
+
+<p>
+So, Type is actually split into two classes, <b>BaseType</b> and <b>Type</b>.
+Type inherits from BaseType, and by default, adds almost nothing
+to BaseType.  However, clients of Elsa are allowed to
+replace Type's definition with one that includes additional
+annotations.
+
+<p>
+To replace Type's definition, make a header file that contains the
+new class definition (make a copy of the existing Type definition as a
+starting point).  Then arrange for the preprocessor symbol
+<code>TYPE_CLASS_FILE</code> to be set to the name (in quotes) of
+the file containing the new definition.
+
+<p>
+The key requirement of class Type is that it must <em>not</em> allow the
+name "BaseType" to leak out into its interface.  I do not want
+to have to deal with more than one name for "generic type" in
+analyses like the type checker.  Some care is required to achieve
+this, as I don't want to make the inheritance private (since that
+would necessitate repeating all of BaseType's member declarations).
+<!--
+This requirement is the reason that Type, and not BaseType, has
+the declaration of <code>anyCtorSatisfies()</code>.  Were it in BaseType,
+then <code>TypePred</code> would expose the BaseType name.
+-->
+
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="valid-html401.png"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+
+</HTML>
+
+
+

Added: vendor/elsa/current/elsa/doc/class_templates.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/class_templates.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/coloncolon.txt
===================================================================
--- vendor/elsa/current/elsa/doc/coloncolon.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/coloncolon.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,91 @@
+The TYPENAME ::NAME Problem
+---------------------------
+
+2005-08-14
+
+This document explains the precedence and associativity of "::" in
+cc.gr, and the use of explicit precedence("::") annotations.
+
+The scope qualification operator "::" is syntactically ambiguous,
+because it can be used as either unary (::a) or binary (a::b), and
+C++ syntax allows identifiers to be juxtaposed in the declaration
+syntax (e.g. "a b;" declaring 'b' of type 'a').  For example,
+the syntax
+
+  A :: B :: C :: D :: E;
+
+could be parsed as a declaration four different ways, since any of
+the four "::" could be interpreted as being just after the dividing
+point (and hence a unary qualifier).
+
+(You might object that you don't declare qualified names; but you do
+in a 'friend' declaration, out-of-line member definitions, and in a
+few other places, so the parser basically has to assume qualified
+declarators can occur anywhere.  The type checker then deals with the
+ruling out the bad cases.)
+
+I cannot find any place in the standard that justifies this, but
+every C++ compiler I've experimented with regards "::" as binding
+very tightly, such that any occurrence of an identifier followed
+by "::" is always interpreted as an attempt to use the binary "::",
+even when the identifier is not a class or namespace (in/t0565.cc).
+
+Previously, my solution was to use the keep() function to discard
+parsing alternatives that juxtaposed an identifier with unary "::".
+However, this is too late to prevent a multi-yield problem with
+ElaboratedOrSpecifier (in/t0564.cc), and for performance reasons I do
+not want to allow multi-yield there.
+
+So, the new solution is to use precedence and associativity.  I give
+"::" right associativity.  Then, for all all rules involved in
+constructing qualified names (especially sibling rules of rules that
+include the "::" terminal in their RHS), I make sure all rules have
+the precedence of "::" (with an explicit precedence specification
+where necessary).
+
+The usual way this works is, given a nominal scenario:
+
+  (1) PQName -> Identifier            precedence("::")
+  (2) PQName -> Identifier "::" PQName
+
+after the parser sees an identifier, and the lookahead symbol is
+"::", the parser must choose between reducing by rule (1) or
+shifting the "::" in hopes of eventually reducing by rule (2).  As
+these rules will have the same precedence, the right-associativity
+of "::" means to shift, which is the intended resolution.
+
+(I also give "::" high precedence, in hopes of reducing the
+chances of unintended impacts of this change.  It should not cause
+any problems since, indeed, no operator can bind more tightly.)
+
+There are a few places where rules that have siblings containing
+"::" are not explicitly annotated with precedence("::"):
+
+  - IdExpression: not needed, it's above the S/R
+  - ColonColonOpt: not needed, always followed by "new"
+  - NameAfterDot and friends: I think you can't juxtapose after
+    a dot, so the S/R conflict should not arise.
+  - PQTypeName: above S/R (but PQTypeName_ncc is not, and in fact
+    is the rule that was a problem for ElaboratedOrSpecifier)
+  - PQDtorName: similar reasoning as NameAfterDot
+
+Though I'm not 100% sure about the above reasoning, I think that
+leaving out questionable annotations is less risky than adding
+them.
+
+
+----------
+2005-08-16
+
+I just now discovered that the prec/assoc specification of "::"
+interacts badly with prec/assoc in verifier/annot.gr.  Perhaps
+the solution is to use forbid_next instead of prec/assoc, perhaps
+annot.gr should be changed.  For now I've just hacked it by
+using smbase/codepatch.pl to remove the prec/assoc of "::", as
+the verifier isn't concerned with parsing C++ right now.
+
+This is a perfect example of the potential danger of prec/assoc
+in a modular parser generator, as the spec in cc.gr broke the
+extension in annot.gr.  It would be interesting to consider trying
+to develop a scheme for static conflict resolution that had
+predictable effects across extension modules...

Added: vendor/elsa/current/elsa/doc/complex.txt
===================================================================
--- vendor/elsa/current/elsa/doc/complex.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/complex.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+2005-05-27 20:06
+
+Complex types in Elsa
+---------------------
+
+To parse complex types in Elsa, we regard _Complex and _Imaginary
+(and also __complex__) as new type keywords.  They are assembled
+as UberModifiers and become SimpleTypeIds when uberCombined.
+
+Alongside ST_FLOAT and friends, we have SimpleTypes like
+ST_FLOAT_COMPLEX and ST_DOUBLE_IMAGINARY.  These are the types
+given to variables and expressions of complex/imaginary type.
+
+(see cc_flags, cc_type, gnu_ext.tok, gnu.lex)
+
+
+The GNU component selectors __real__ and __imag__ are parsed as
+field accesses, e.g.:
+
+  __real__ c          -->     c.__real__
+  __imag__ c          -->     c.__imag__
+
+In fact, if someone writes "c.__real__", Elsa will handle it
+exactly the same as "__real__ c".
+
+(see cc_env.h, gnu.gr)
+
+
+When the result is typechecked, the E_fieldAcc::field member is
+set to point at one of six predefined fields standing for the
+components of the three complex types.  (Note that there are no
+predefined complex structures, just the fields.)
+
+When an arithmetic operation involving complex/imaginary types
+is checked, the result type is computed according to rules like
+imag+imag=imag and real*imag=imag.  The computation is, for now,
+not well tested and might have a variety of bugs.  If an analysis
+is depending on accurate computation of complex/imaginary type
+expressions, this code will have to be more carefully examined.
+
+(see gnu.ast, gnu.cc)

Added: vendor/elsa/current/elsa/doc/constructed_types.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/constructed_types.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/contributors.html
===================================================================
--- vendor/elsa/current/elsa/doc/contributors.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/contributors.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elsa Contributors</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+</HEAD>
+
+<body>
+
+<p>
+<a href="http://www.cs.berkeley.edu/~smcpeak">Scott McPeak</a> ("sm"): 
+Original author, maintainer.
+
+<p>
+<a href="http://www.cs.berkeley.edu/~dsw">Daniel Wilkerson</a> ("dsw"):
+Template instantiation, c/dtor elaboration, pretty printer,
+implicit members, testing and bugfixes (among other things).
+
+<br>
+Nominal maintainer of:
+<ul>
+<li><a href="../matchtype.h">matchtype</a>
+<li><a href="../cc_elaborate.h">cc_elaborate</a>
+<li><a href="../template.h">template</a> (shared)
+<li><a href="../cc_print.h">cc_print</a>
+</ul>
+
+<p>
+Wes Weimer
+
+<p>
+Ben Liblit
+
+<p>
+Jeff Foster: OSX fixes
+
+<p>
+Jim Nichols: cygwin fixes
+
+
+</body>
+</html>

Added: vendor/elsa/current/elsa/doc/convertibility.txt
===================================================================
--- vendor/elsa/current/elsa/doc/convertibility.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/convertibility.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,623 @@
+Date: 8/10/03
+Author: Scott McPeak
+
+
+             Convertibility and Operator Overloading
+
+
+--- Introduction ---
+
+This is a characterization of (standard) convertibility relation (C++
+standard, section 4), and its role in operator overload analysis. 
+The first part builds a partial order on types, R, to describe
+convertibility.  The second part uses R to assist in the
+implementation of operator overload resolution.
+
+(I refrain from saying "subtyping" here because in C++ subtyping is
+context-dependent; convertibility is a particular form of subtyping.)
+
+What we want is a (reflexive) partial order:
+  - reflexive         R(a,a)
+  - transitive        R(a,b) & R(b,c) => R(a,c)
+  - anti-symmetric    R(a,b) => not R(b,a)
+
+In this context, R(a,b) means a is convertible to b.
+
+The reason we want a partial order is it will help simplify the
+analysis.  Among other things, transitivity is useful when trying to
+select a "best" candidate from an infinite set, and anti-symmetry
+avoids ambiguity through circularity (more on this below).
+
+In what follows, I make reference to the C++ standard:
+  International Organization for Standardization.
+  ISO/IEC 14882:1998: Programming languages -- C++.
+  International Organization for Standardization, Geneva,
+  Switzerland, September 1998.
+
+
+--- Atomic Types ---
+
+The atomic types are:
+  - simple types
+    - char, unsigned char, signed char, wchar_t
+    - bool
+    - short int, unsigned short int
+    - int, unsigned int
+    - long int, unsigned long int
+    - long long int, unsigned long long int (GNU, C99)
+    - float, double, long double
+    - void
+  - bitfields
+  - enums
+  - classes (by which I mean class, struct, or union)
+
+First, unify all the arithmetic types into a single representative,
+AR.  AR includes chars, bool, ints, floats, and bitfields.  All the
+things inside AR are inter-convertible, so would defy convertibility
+being a partial order.  Note that I do *not* unify them when under
+a pointer constructor, e.g. int* != float*.
+
+Nothing is convertible to or from void.  But in this context, nothing
+has type void anyway, so it doesn't much matter.
+
+Every enum type is convertible to AR, and to itself.  Nothing is
+convertible to the enum besides itself.
+
+Every class type is convertible only to and from itself.
+
+Thus, the partial order on atomic types looks like this:
+
+           AR
+        /  |      \        class1 class2 ... classN   void
+   enum1 enum2 ... enumN
+
+(Note that inheritance isn't relevant until we start talking about
+pointers or references.)
+
+
+--- Constructed Types ---
+
+The constructed types are:
+  - pointer
+  - function
+  - array
+  - pointer to member
+  - reference
+
+While there is a standard conversion from function types to
+pointer to function types, we can eliminate that conversion from
+consideration by:
+  - normalizing all parameters to accept pointers to function
+    rather than function
+  - noting that conversion operators cannot yield functions
+    (12.3.2 paragraph 4)
+
+Therefore, we can regard each function type as only convertible
+to and from itself.
+
+Similarly, array types can be normalized out of parameters, and
+cannot be returned from conversion operators, and so are isolated.
+
+
+--- Pointers ---
+
+Two things factor into pointer convertibility: inheritance, and
+cv-qualification.
+
+Inheritance lets C* convert to P* when C is a child of P.  (It does
+not matter whether P is private or ambiguous; those concerns come
+after all decisions regarding convertibility and overloading.)
+
+cv-qualification lets const and volatile be added anywhere with
+a pointer type, provided that the *resulting* type has 'const'
+at all levels above the lowest changed qualifier.  For example,
+
+  int *                      ->  int const *
+  int volatile *             ->  int volatile *
+  int **                     ->  int const * const volatile *
+  int **                     ->  int volatile * const *
+  int ****                   ->  int volatile * const * const * const *
+
+but not
+
+  int **                     ->  int const **
+
+These two combine, but inheritance only works when there is exactly
+one level of pointer. For example
+
+  C *                        -> P const *
+  C const *                  -> P const volatile *
+
+but not
+
+  C **                       -> P **
+
+or even
+
+  C **                       -> P const * const *
+
+even though this last example would not violate soundness of the type
+system, were it allowed in the language and given the obvious
+semantics.  (Perhaps a design oversight, or maybe just an intentional
+simplification of an already complex language.)
+
+The order induced by the conversion is straightforward.  For one-level
+pointers, it is the product of the inheritance order and the cv
+subset lattice:
+
+  R(A cv *, B cv' *) iff
+    A inherits from B and
+    cv is a subset of cv'
+
+For two- or more level pointers, it's the union of all cartesian products
+of the cv subset lattice, plus the restriction ($) about adding const
+above changed qualifiers:
+
+  R(T cv1 * cv2 * ... cvN *, T cv1' * cv2' * ... cvN' *) iff
+    cv1 is a subset of cv1' and
+    cv2 is a subset of cv2' and
+      ...
+    cvN is a subset of cvN'
+  and
+    for all I in 1..N,                           ($)
+      if cvI != cvI', then
+        for all J in I+1..N,
+          cvJ' contains const
+
+Ignoring the restriction ($), we have the union of products of partial
+orders, and the sets of objects they relate are disjoint, so the
+result is also a partial order.  The effect of ($) is to make the
+relation smaller, but it won't break transitivity anywhere (it
+monotonically adds const), and reflexivity and anti-symmetry are
+obviously preserved.
+
+Finally (4.10 para 2), for any T, R(T cv *, void cv *) (i.e., any
+pointer can be converted to a void pointer).  This doesn't
+compromise the partial order; it's a one-way trip to void-land.
+
+Also note that pointers cannot convert to or from any of the atomic
+types.  (TODO: What about convertibility from the null literal?  I
+probably need to treat that like a class with conversions to int and
+T* (for any T), though Elsa at the moment does not.  Hmm...)
+
+
+--- Pointers to members ---
+
+Pointers to members behave very much like pointers, except the
+order induced by inheritance is opposite what it is for pointers:
+T P::* (pointer to member of P with type T) can convert to T C::*,
+when C is a child of P.
+
+The interaction with the cv-lattice is analogous to the pointer
+case.  Furthermore, types constructed from a mix of pointer and
+pointer to member also have this analagous behavior.  For example,
+
+  int C::*                   ->  int const C::*
+  int C::* D::*              ->  int const C::* const D::*
+  int C::* *                 ->  int volatile C::* const *
+  int * C::* * D::*          ->  int volatile * const C::* const * const D::*
+
+For one level pointer to member, we have the order:
+
+  R(T cv A::*, T cv' B::*) iff
+    B inherits from A and            // reversed from pointer case
+    cv is a subset of cv'
+
+and for multi-level and mixed we have:
+
+  R(T cv1 P1 cv2 P2 ... cvN PN, T cv1' P1 cv2' P2 ... * cvN' PN) iff
+    cv1 is a subset of cv1' and
+    cv2 is a subset of cv2' and
+      ...
+    cvN is a subset of cvN'
+  and
+    Every Pi is either * (ordinary pointer) or C::* (pointer to
+    member) for some class C (not necessarily the same class for
+    every i).
+
+(This order includes the order described above for multi-level
+ordinary pointers.)
+
+Again, it's clear that we have a partial order.
+
+
+--- References ---
+
+References act like ordinary pointers.  The order on references is
+obtained from the order on pointers by substituting the word
+"reference" for "pointer" when "pointer" is the topmost type
+constructor.  For example:
+
+  int &                      ->  int const &
+  int volatile &             ->  int volatile &
+  int *&                     ->  int const * const &
+  int *&                     ->  int volatile * const &
+  int ***&                   ->  int volatile * const * const * const &
+  C &                        ->  P const &
+
+There's no conversion to 'void &', however.
+
+(TODO: I'm not 100% sure about this, but it's what my implementation
+does for now.)
+
+
+--- Order on conversions ---
+
+Now, the above partial order on types is a key component to the
+analysis, but is not enough.  The rules for overload resolution do not
+talk about comparing *types*, but rather comparing *conversions*
+between types.
+
+For example, consider 13.3.3.2, paragraph 3 (excerpt):
+
+  "Standard conversion sequence S1 is a better conversion sequence than
+  S2 if ...  S1 and S2 differ only in their qualification conversion and
+  yield similar types T1 and T2 (4.4), respectively, and the
+  cv-qualification signature of type T1 is a proper subset of the
+  cv-qualification signature of T2".
+
+What we need is an order on conversions that takes advantage of
+the order on types.  Luckily, the relation S appears to be equal
+to the order given in 13.3.3.2, paragraphs 3 and 4:
+
+  S("A->B", "A->C") iff R(B,C)                   ($$)
+
+That is, "A->B" (the standard conversion from A to B) is better than
+"A->C" if and only if B is convertible to C (using the convertibility
+relation R defined above, where the atomic types are unified, etc.).
+For the excerpt quoted, the order is the same: that induced by the cv
+subset lattice.  (Technical point: I want S to be nonreflexive, so
+I really mean the nonreflexive version of R.)
+
+Now, proving this for all types A, B and C requires a detailed
+analysis of the specific rules provided in 13.3.3.2.  I think it's
+right, but I'm not completely sure.  I haven't so far been able to
+adequately formalize those rules in a way that would allow a formal
+proof (not that I've tried much).  In any case, it's close enough that
+I'm confident if a discrepancy is found, it won't be difficult to hack
+around it in the implementation.
+
+Update: Here's one counterexample: If the hierarchy is
+
+         A
+        /
+       B
+      /
+     C
+
+then the conversion "B* -> A*" is better than "C* -> A*" (13.3.3.2
+para 4), but (A*,A*) is not in the nonreflexive R.  This doesn't
+appear to compromise the analysis, but I'm not sure how to build the
+argument.
+
+
+--- Application to operator overload resolution ---
+
+Where this analysis becomes useful is when we try to implement
+operator overload resolution.  The difficulty arises from section
+13.6, which says (paragraph 14, for example):
+
+  "For every T, where T is a pointer to object type, there exist
+  candidate operator functions of the form
+  
+    ptrdiff_t  operator- (T, T);"
+    
+Two things make this difficult.  First, this is an infinite set
+of candidate functions; we can't straightforwardly materialize all
+of the candidates and hand them to overload resolution.  
+
+Second, the types of the arguments are *correlated*; in fact, they
+have to be equal.  If they were not correlated (as in e.g. 13.6
+paragraph 12), then we could simply analyze the arguments separately:
+ambiguity in either argument would imply ambiguity for the entire
+analysis.  But for operator-, it is in fact possible to have (naive)
+ambiguity in *both* arguments but still an unambiguous call:
+
+  struct A {
+    operator int* ();
+    operator float* ();
+  };
+  
+  struct B {
+    operator float* ();
+    operator char* ();
+  };
+  
+  int f()
+  {
+    A a;
+    B b;
+    return a-b;     // overloaded operator call
+  };
+
+Both arguments can convert to "pointer to object type", but only one
+such type (float*) can be converted-to by both arguments.  So the
+candidate
+
+  ptrdiff_t  operator- (float*,float*);
+  
+is the unambiguous best candidate, and the call site has implicit
+calls to A::operator float*() and B::operator float*().
+
+These examples can get more complicated, where the winning candidate
+instantiates the pattern function with a type that does not explicitly
+appear anywhere in the program.  For example:
+
+  struct C {
+    operator int const **();
+  };
+  
+  struct D {
+    operator int volatile **();
+  };
+  
+  int g()
+  {
+    C c;
+    D d;
+    return c-d;     // overloaded operator call
+  }
+
+The winning candidate is
+
+  ptrdiff_t  operator- (int const volatile * const *,
+                        int const volatile * const *);
+                        
+even though that parameter type doesn't appear in the program.  In
+fact, current versions of GCC (through 3.3 at least) mistakenly
+believe the expression above is illegal, because GCC only tries (a
+subset of) types that do appear in the program.
+
+So what's the answer?  Well, consider any pair of types to which both
+arguments can convert (directly).  If the ultimate resolution picks
+those two conversions, what would the instantiation of the operator
+function be? 
+
+Suppose the first argument to operator- has a conversion to U, and the
+second has a conversion to V.  We need a type T such that both U and V
+can convert to T (existence).  We also need (for uniqueness) that for
+any T' not equal to T, such that U and V can convert to T':
+
+  U->T' is not better than U->T, and
+  V->T' is not better than V->T, and
+  either
+    U->T is better than U->T', or
+    V->T is better than V->T' (or both are better)
+
+(These rules paraphrase the relevant parts of 13.3.3 paragraph 1.)
+Applying equation ($$) above, rewrite this as
+
+  not R(T',T), and
+  not R(T',T), and
+  either
+    R(T,T') or
+    R(T,T')
+
+Applying antisymmetry and simplifying, we have
+
+  R(T,T')
+
+Ok!  Now this is a familiar algebraic question: do U and V have a
+least upper bound (LUB) w.r.t. the partial order R?  By definition,
+the LUB(U,V) is the T that satisfies the existence and uniqueness
+requirements above.  Consequently, it is the only possible
+instantiation of T that could yield a winning candidate function, if
+the arguments are converted to U and V.
+
+Based on the characterization of R given above, computing the LUB is
+fairly easy.  For single-level pointers, we need the LUB in the class
+hierarchy, which is straightforward to compute.  For single-level
+pointers to members, we need the greatest lower bound (GLB); but see
+the note about this at the end.  Then in all cases, we simply union
+the cv flags (only down to the first non-pointer,
+non-pointer-to-member type constructor), adding const at all levels
+above the deepest difference.  That is, the LUB in R is essentially
+the product of the underlying LUBs, just as the order itself is the
+product of underlying orders.
+
+But not all pairs of types have a LUB.  First, there might not be
+any types to which both can convert; 'int*' and 'int' are such
+a pair.  In that case, the pair cannot possibly be the pair selected
+for the winning candidate; the set of viable candidates to which
+that conversion pair corresponds is empty.
+
+Second, there may not be a least element for the set of types to which
+U and V can convert.  For example, if classes C1 and C2 both inherit
+from P1 and P2, but P1 and P2 are not related by inheritance, then
+'C1*' and 'C2*' can both convert to 'P1*' and 'P2*', but these latter
+two types are not comparable under R.
+
+When the upper bound set is not empty, but there is no least element,
+resolution among the set of candidates generated by the pattern is
+guaranteed to be ambiguous.  To see why, select any two elements T and
+T' from the upper bound set, for which T and T' do not convert (such a
+pair must exist; the upper bound set is finite).  There will be
+candidates
+
+  ptrdiff_t  operator-(T, T);
+  ptrdiff_t  operator-(T', T');
+
+and to compare the candidates, we'll have to compare conversions
+
+  U->T with U->T' and/or
+  V->T with V->T'
+
+but by ($$), this won't be possible.  (Just do the original reduction
+to R(T,T') backwards.)
+
+Furthermore, no other pairs of conversions (U',V') can yield a
+candidate that can beat either of these candidates, because they will
+use different user-defined conversion functions, and hence be
+incomparable as implicit conversion sequences (13.3.3.2, para 3,
+final bullet).
+
+(Note that the reason we *can* choose among user-defined conversion
+functions when instantiating for a particular pair is that it's the
+situation covered by 13.3.3 para 1, final bullet.  But once we're
+looking across pairs, that provision no longer applies.)
+
+However, though there cannot be a clear winner from among the pattern
+(built-in) candidates if the LUB is ambiguous, there might be a
+non-built-in (i.e. user-defined) candidate that is better than any of
+the built-in candidates, so the algorithm must take that into account.
+
+
+--- An algorithm for candidate instantiation ---
+
+Thus, to summarize, the algorithm for generating a finite set of
+built-in operator candidates, when the infinite set has correlated
+types, is:
+
+  - consider every pair (U,V) of types to which the arguments can
+    convert
+    - compute the LUB(U,V) w.r.t. the order R
+    - if the LUB exists, instantiate the pattern with it
+    - if the UB set is empty, do nothing with that pair
+    - if the UB set is nonempty, generate a fake candidate, both
+      of whose arguments are converted by the ambiguous conversion
+      sequence (13.3.3.1 para 10); this effectively summarizes
+      the built-in candidate set
+
+Then, run the usual overload resolution algorithm on this finite
+candidate set (plus member and non-member user-defined candidates; see
+13.3.1.2 paragraph 3).  If the fake candidate is chosen, report an
+ambiguity.  Otherwise, if a winner arises, it is certain that that
+winner is better than any of the pattern candidates, even those that
+were not instantiated, because of (among other things) the
+transitivity of R.
+
+Two comments are in order regarding instantiation.  First, if the
+LUB(U,V) = LUB(U',V') for distinct pairs (U,V) and (U',V'), do not
+instantiate the pattern twice with the same type.  The standard is
+clear about there being only one candidate with a given signature;
+we're computing an instantiation sub*set*, not a multiset.
+
+Second, a given LUB type might not fit the requirements of the
+pattern.  Taking the operator- example, it says T has "pointer to
+object type".  That means (1.8 para 1) that T is not a pointer to
+function type, nor pointer to void.  This can be implemented simply by
+filtering types before instantiating, because those types are at the
+top of the hierarchy; they represent the best type from a (small) set
+of upper bound types, none of which are admissable to the pattern.
+(The admissability rules always respect R, in the sense that if T is
+not admissable, than neither is any T' for which R(T,T').)
+
+
+--- Performance, etc. ---
+
+The algorithm given above requires O(n*m) LUB computations, where n
+and m are the number of types to which the arguments can (directly)
+convert.  That is, it can be at least quadratic in the size of the
+program.
+
+In practice, memoization is a very good way to ensure this does not
+become a problem.  Even if a program contains classes with many
+conversion functions, the program is very likely to use the same
+(pairs of) classes over and over in expressions.
+
+But the question remains: could this algorithm be improved to use
+fewer LUB calls?  I don't know.  I certainly don't see how, but also
+don't see an argument (such as a constructive adversary) to say that
+it could not be done.  
+
+Another interesting question: GCC's (current) algorithm appears to be
+linear, but it is also wrong.  Does that matter?  Do users need or
+want the correct analysis?  Might there be hidden ambiguities or other
+problems due to the incomplete analysis?  Or is this a good practical
+corner to cut?  I have relatively little experience with programs that
+make heavy use of conversion operators, so I just don't know.
+
+
+--- GLB in the class hierarchy ---
+
+The greatest lower bound (GLB) is a bit of a pain to compute, for two
+reasons.  First, this is the only place that the GLB is relevant to
+type checking in C++, so the necessary map (parent -> children)
+doesn't already exist in the type checker implementation.  Adding this
+map is not hard, but care should be taken to ensure this map isn't
+mistaken for the whole-program version: any one translation unit need
+not contain all classes.
+
+Second, because classes may be added at any time, GLB queries cannot
+be memoized in the obvious way.  The query memoization infrastructure
+needs to be able to partly invalidate its old results when new classes
+are added.  (This is essentially a single-translation-unit version of
+the problem identified in the previous paragraph: the GLB changes as
+you see more code.)
+
+Finally, I think the need for GLB is evidence of a language design
+mistake.  Consider this example that requires the GLB:
+
+  struct A { int x; };         //      A   B        .
+  struct B { int y; };         //       \ /         .
+  struct C : A,B { int z; };   //        C          .
+
+  // use some operator functions so that the compiler's
+  // static-semantic decisions have run-time consequences
+  struct PTMA {
+    operator int A::* ();      // return pointer to member of A
+  };
+  struct PTMB {
+    operator int B::* ();      // return pointer to member of B
+  };
+
+  bool f()
+  {
+    PTMA a;
+    PTMB b;
+
+    // equivalent to:
+    //   return  a.operator A::*()  ==  b.operator B::*();
+    // where the two arguments are converted to int C::* for comparison,
+    // i.e. the chosen candidate operator function is
+    //   bool operator== (int C::*, int C::*);
+    return a==b;
+  }
+
+In the first place, note that the equality could never be true when
+the original classes are not related by inheritance.  But then suppose
+that we follow this code (in the same translation unit) with:
+
+  //      A  B        .
+  //      |\/|        .
+  //      |/\|        .
+  //      C  D        .
+  struct D : A,B { int w; };
+
+  bool g()
+  {
+    PTMA a;
+    PTMB b;
+
+    // error!  cannot decide whether to convert the arguments to
+    // int C::* or int D::*; that is, these candidates conflict:
+    //   bool operator== (int C::*, int C::*);
+    //   bool operator== (int D::*, int D::*);
+    return a==b;
+  }
+
+Now, function g() is no more bizarre than f() was--its comparison is
+also guaranteed to be false--and yet the compiler must reject it.  The
+programmer is forced to be aware of the *entire* class hierarchy visible
+at each program point where the GLB might come into play, and not just
+those classes (and their superclasses) that the programmer is actually
+using.
+
+It's not clear to me what the best language fix is.  I think that
+pointer-to-member (with its current semantics) should not be in the
+language at all (it's the one feature I would remove if I could).  But
+given its presence, I don't see a quick fix to (e.g.) 13.6.  To attack
+the problem directly, e.g. "you don't need GLB" or "you don't need to
+instantiate the pattern with types outside such-and-such finite set",
+could easily make things worse.  To require that pointer-to-member
+conversions down the hierarchy be done with (e.g.) an explicit cast
+would go against the philosophy of minimal annotation for natural
+subtyping.  It's a dark, angry corner of the language, and it does
+not want to behave.
+
+Side note: In Elsa, I don't implement the GLB analysis.  If the
+classes in a single-level pointer-to-member pair aren't equal, I
+reject the pair (the pair does not lead to an instantiation).  I pity
+the fool whose code this breaks.  I'd be surprised if such code even
+exists, outside C++ test suites.
+

Added: vendor/elsa/current/elsa/doc/cpp_er.html
===================================================================
--- vendor/elsa/current/elsa/doc/cpp_er.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/cpp_er.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1178 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+<head>
+  <title>C++ Entities and Relationships</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175%; font-weight: bold }
+    P.remark { font-size: 125%; color: red }
+    SPAN.todo { font-weight: bold }
+    SPAN.program { font-family: monospace }
+    SPAN.variable { font-family: monospace }
+    a.toc:link { text-decoration: none }
+    a.toc:visited { text-decoration: none }
+  </style>
+</head>
+<body>
+
+<p>
+<a href="../index.html">Up</a>
+
+<center>
+<p class="title">C++ Entities and Relationships</p>
+</center>
+
+<p>
+This page contains data model diagrams useful for understanding the
+C++ language.  They show the various concepts in C++ static
+(compile-time) semantics, and their interrelationships. 
+
+<p>
+One use of these data models is to help understand the C++ Standard
+document.  It collects together the essential notions in the language,
+what components they have, how they are related, etc.  The data model
+is intended to be sufficiently complete that it could serve as the
+basis for a formal definition of the static semantics.
+
+<p>
+Another use is to understand the Elsa implementation.  Not surprisingly,
+many concepts in the data models correspond to prominent classes in
+the Elsa implementation.  However, the correspondence is not exact;
+in some cases, there are deviations due to known bugs in Elsa, while in
+others Elsa simply uses an implementation technique that may obscure
+a given concept.  Nevertheless, the intent is that Elsa should use a
+data model that could (in principle) be mapped back and forth to the
+model presented here.
+
+<p>
+That the names used in these diagrams do not correspond exactly with
+either the terminology in the standard (which is often unnecessarily
+vague) nor that used in Elsa (which makes fewer distinctions, for
+example among kinds of Variables).  However, there is an overall
+attempt at terminological consistency.
+
+
+<h1>Notation</h1>
+
+<p>
+The following diagrams use a notation that it is a mixture of
+traditional Entity-Relationship diagrams and UML, with some of my
+own ideas thrown in:
+<ul>
+
+<li>Entities are shown in boxes.  A dashed box indicates an entity that
+    with attributes and/or relationships that are elided from the
+    diagram.
+
+<li>Attributes are in ellipses.  Dashed ellipses similarly indicate
+    elided detail.
+
+<li>Relationships are thin lines with arrowheads connecting entities.
+    Either or both ends of a relationship may be named; the opposite
+    end of a named end has an arrowhead.  When an endpoint is named,
+    an annotation on the name indicates a <em>cardinality</em>, which
+    is the number times that a single instance of the entity may
+    participate in the relationship:
+    <ul>
+    <li>Name with no annotation: cardinality is one.
+    <li>Name with "?" annotation: zero or one.
+    <li>Name with "*" annotation: any number, including zero.
+    <li>Name with "[]" annotation: relation tuples are <em>ordered</em>,
+        forming a <em>sequence</em>; cardinality is anything.
+    <li>Unnamed: cardinality is anything.
+    </ul>
+
+<li>Attributes can be given "?", "*" and "[]" annotations, with similar
+    meanings as for relationships.  In fact, attribute notation is used
+    interchangeably with relationship notation where convenient.
+
+<li>Specialization (often conceptualized as inheritance) is indicated
+    by thick lines connecting entities, with triangular split points.
+    A solid triangle indicates <em>total</em> specialization (meaning
+    the superclass is abstract) while an open triangle indicates
+    <em>partial</em> specialization.  Color is used to emphasize
+    important specialization hierarchies.
+    <ul>
+    <li>What is the difference between a partial specialization and
+        an optional ("?") attribute or relationship?  The former cannot
+        change during the entity's lifetime, while the latter can.
+    </ul>
+</ul>
+
+
+<h1>Diagram 1: Scopes, Variables and Types</h1>
+
+<p>
+The following diagram
+(xfig sources: <a href="er.fig">er.fig</a>,
+postscript: <a href="er.ps">er.ps</a>)
+shows the essential static semantic concepts, such as scopes,
+variables and types.  It omits templates, and it omits executable
+AST fragments like statements and expressions.
+
+<p>
+<center><img src="er.png" alt="C++ Static Semantics ER diagram"></center>
+
+<p>
+This diagram has four primary dimensions:
+<ul>
+<li>Scope (green): Places searched during lookup.
+<li>Variable (blue): Things found by lookup.
+<li>Type (red): Types built up from type constructors.
+<li>AtomicType (magenta): Fundamental units of type identity.
+</ul>
+
+<h2>Name</h2>
+
+<p>
+Names [3p4] denote Variables.  As explained in [3p7], there are three
+kinds of Names: identifiers, operators, and conversions.  Names are
+<em>extensional</em>: two Names are the same if they have the same
+attributes and named relationships, and they are immutable once
+created.
+
+<h3>Identifier</h3>
+
+<p>
+An Identifier is a Name consisting of a nonempty sequence of source
+characters.
+
+<h3>OperatorName</h3>
+
+<p>
+An OperatorName is a Name consisting of the keyword <tt>operator</tt>
+followed by one of the overloadable operators [13.5p1].
+
+<h3>ConversionName</h3>
+
+<p>
+A ConversionName is a Name consisting of the keyword <tt>operator</tt>
+followed by a Type [12.3.2].
+
+<h2>Scope</h2>
+
+<p>
+A Scope ("declarative region") [3.3] is a set of Variables.  Name
+lookup [3.4] searches for a Name amongst a certain sequence of Scopes,
+yielding the set of Variables that have the given Name.  There are
+rules [3.3p4, 3.3.7p2] that restrict the set of Variables that may have the
+same Name and Scope; the data model itself does not enforce them.
+
+<p>
+The Standard's notion of the "potential scope of a variable" is
+induced by the timing of the sequence of updates to Scopes
+corresponding to processing declarations.  I have chosen not to
+include an explicit notion of time or point of declaration in this
+data model, but I may reconsider.
+
+<p>
+(Currently missing from data model: function scopes, which contain
+the labels for <tt>goto</tt> statements.)
+
+<h3>Namespace</h3>
+
+<p>
+A Namespace [3.3.5, 7.3] is a scope outside any class or function.
+They include the GlobalScope.  Namespaces can be connected by
+UsingDirectives [7.3.4].
+
+<h3>BlockScope</h3>
+
+<p>
+A BlockScope ("local scope") [3.3.2] contains local variables in
+a function.  FunctionDefinitions include a BlockScope that spans
+their body.
+
+<h3>PrototypeScope</h3>
+
+<p>
+A PrototypeScope [3.3.3] contains the parameters of a function
+declarator that is not the declarator of a function definition.
+
+<h3>ClassType (as a Scope)</h3>
+
+<p>
+A ClassType [9] includes the scope [3.3.6] that contains the
+class members.  It is described further in another entry below.
+
+
+<h2>Variable</h2>
+
+<p>
+A Variable (a mixture of Standard concepts "entity" [3p3] and
+"declaration" [3p5]) is something that can be found by lookup.  Every
+Variable is a member of exactly one Scope.
+
+<p>
+A Variable's name is both optional and mutable.  It is optional
+because function and template parameters may be declared without names
+[8.3.5p8, 14.1p1].  It is mutable because subsequent declarations may
+add or change a parameter name.  Variables without names are not
+subject to the rules of [3.3p4, 3.3.7p2] that restrict same-named
+Variables in a Scope.
+
+<p>
+Note that this is <em>not</em> the same as the Standard term "variable" [3p4].
+It is simply a convenient appelation for an important concept.
+
+<h3>StorageClass</h3>
+
+<p>
+The "storage" member of Variable is a subset of StorageClass, which 
+has (exactly) the following members:
+<ul>
+<li><tt>auto</tt>
+<li><tt>register</tt>
+<li><tt>static</tt>
+<li><tt>extern</tt>
+</ul>
+
+<p>
+This is not the same as the Standard storage-class-specifier [7.1.1],
+as that contains <tt>mutable</tt>, whereas I have instead introduced
+the MutableNonstaticDataMember specialization.
+
+<h3>NamespaceAlias</h3>
+
+<p>
+A NamespaceAlias [7.3.2] provides an alternate name for a Namespace.
+
+<h3>Function</h3>
+
+<p>
+A Function (Variable) is a unique name for a FunctionDefinition,
+which is a fragment of executable AST.  A Function may or may not
+have a definition, and that aspect may change during processing of
+a translation unit.
+
+<h3>Enumerator</h3>
+
+<p>
+An Enumerator [7.2] is one of the elements of an Enumeration.
+
+<h3>UsingAlias</h3>
+
+<p>
+A UsingAlias is introduced by a using-declaration [7.3.3].  When a
+lookup finds a UsingAlias, it transparently follows the "target"
+field.
+
+<h3>DataVariable</h3>
+
+<p>
+A DataVariable denotes a piece of named run-time data.  It
+can have any type other than a FunctionType (or <tt>void</tt>).
+DataVariables are partitioned:
+<ul>
+<li>LocalVariable: Appears in a BlockScope, denotes a variable
+    local to a function.  LocalVariables may have an initializer
+    Expression; this is relevant to static semantics only if
+    the variable is also <tt>const</tt> [5.19].
+<li>GlobalVariable: Appears in a Namespace, denotes a variable
+    visible to all functions (modulo namespace visibility).
+<li>FunctionParameter: Appears in a BlockScope (for FunctionDefinitions) or
+    a PrototypeScope, denotes a function parameter.
+    (TODO: Hmmm.  How are ProtoypeScopes related
+    to FunctionTypes and FunctionDefinitions?)       
+    A FunctionParameter may have a default value expression [8.3.6].
+<li>DataMember: Appears in a ClassType scope, denotes a data member
+    of a class (or struct or union).  These are further subdivided
+    into static and nonstatic members, the former of which may have
+    an initializer.
+<li>HandlerParam: Appears in a BlockScope, denotes the variable
+    bound to an exception object in an exception handler [15.3].
+</ul>
+
+<h2>ClassMember</h2>
+
+<p>
+A ClassMember is any Variable other than an Enumerator that is a
+member of a ClassType Scope.  Such Variables have an "access"
+attribute that is <tt>public</tt>, <tt>protected</tt> or
+<tt>private</tt>.  The access attribute of an Enumerator in
+a ClassType Scope can be determined by examining its type.
+
+<h3>ImplicitlyDeclaredMemberFunction</h3>
+
+<p>
+An ImplicitlyDeclaredMemberFunction is a constructor, destructor
+or copy assignment operator that is implicitly declared [12p1].
+
+
+<h2>TypeName</h2>
+
+<p>
+A TypeName names a type for purposes of lookup.  
+
+<h3>Typedef</h3>
+
+<p>
+A Typedef [7.1.3] is a type name in a scope, introduced via
+the <tt>typedef</tt> keyword.
+
+<h3>InjectedClassName</h3>
+
+<p>
+An InjectedClassName [9p2] is an alias for a ClassType within the
+scope of that ClassType.
+
+<h3>NamedAtomicType</h3>
+
+<p>
+A NamedAtomicType is both a TypeName and an AtomicType.  That is,
+it can be found by lookup, and it can be used to form constructed
+("compound") types and be cv-qualified.
+
+<h3>ClassType</h3>
+
+<p>
+A ClassType is a <tt>class</tt> or <tt>struct</tt> or <tt>union</tt>;
+the "keyword" field distinguishes these.  It has a sequence of base
+classes, each of which has an "access" specifier and may be virtual.
+It may also have a ClassDefinition, which is an AST fragment.  The
+presence of a ClassDefinition distinguishes forward declarations
+[3.4.4, 7.1.5.3, 9.2p2], and is also useful for implementing templates.
+
+<p>
+A ClassType has a set of constructors and a destructor.  They are
+found by direct examination of the ClassType, not by lookup, because
+they do not have names [12.1p1, 12.4(?)].  The data model allows both
+to be missing to accomodate the analysis of the class itself, which
+does not know in advance how to make them.
+
+<p>
+Currently, ClassType is called "CompoundType" in Elsa.
+
+<h3>Enumeration</h3>
+
+<p>
+An Enumeration [7.2] is a type consisting of a set of named constants,
+called enumerators.
+
+<h2>Type</h2>
+
+<p>
+A Type [3.9, 8.3] is an entity or concept that is used within the
+static semantics to approximate the dynamic semantics.  In the
+data model here, "Type" denotes those types constructed by applying
+type constructors and/or cv-qualifiers [3.9.2, 8.3] to other Types or
+AtomicTypes.  Types are extensional: two Types are equivalent if they
+have the same structure (attributes and relationships), and they
+are immutable once created.
+
+<h3>FunctionType</h3>
+
+<p>
+A FunctionType [8.3.5] is the type of a function.  It has a return
+type, parameters, and an optional exception specification.  Parameter
+types are equivalent if they have the same cv-unqualified type; that
+is, the name and the top-level cv-qualification of parameter types are
+not significant for type equivalence.
+
+<p>
+Even though the syntax of function declarators includes an exception
+specification, such specifications are only allowed when part of the
+certain declarations [15.4p1].
+
+<h3>MethodType</h3>
+
+<p>
+The type of a nonstatic member function, what I call a method, is a
+FunctionType that has a receiver parameter.  The receiver is always a
+reference to a (possibly cv-qualified) class type; the
+cv-qualification of the receiver records the cv-qualification of the
+member function declarator [8.3.5p4].
+
+<h3>DataType</h3>
+
+<p>
+An DataType is a Type that is not a FunctionType.  Note that the
+related Standard term "object type" [3.9p9] does not include
+references or <tt>void</tt>.
+
+<h3>CVAtomicType</h3>
+
+<p>
+A CVAtomicType is a leaf in a Type tree.  It refers to an AtomicType,
+and possibly cv-qualifies [3.9.3] it.
+
+<h3>IndirectionType</h3>
+
+<p>
+IndirectionType is the common ancestor for the types that are 
+constructed primarily from one other type.
+
+<h3>PointerType</h3>
+
+<p>
+A PointerType [8.3.1] is the type of a pointer to some other type,
+possibly with cv-qualification.  The cv-qualifiers apply to the
+pointer itself, not the referent (the type pointed to).
+
+<h3>PointerToMemberType</h3>
+
+<p>
+A PointerToMemberType [8.3.3] is the type of a pointer to a
+nonstatic class member.  In addition to cv-qualifiers, it names
+the class of which the referent is a member.
+
+<h3>ReferenceType</h3>
+
+<p>
+A ReferenceType [8.3.2] is the type of a reference to some other
+type.  It cannot be cv-qualified.
+
+<h3>ArrayType</h3>
+
+<p>
+An ArrayType [8.3.4] is the type of an array.  It does not
+(necessarily) have a known size.
+
+<h3>SizedArrayType</h3>
+
+<p>
+A SizedArrayType is the type of an array with known size.
+
+<h2>AtomicType</h2>
+
+<p>
+An AtomicType is a type which is not built from type constructors.
+Their identity is <em>physical</em>, not structural: two AtomicTypes
+can be different even when they have the same attributes and
+relationships.
+
+<h3>NamedAtomicType (as an AtomicType)</h3>
+
+<p>
+NamedAtomicType was already discussed above.  However, in this context
+it is worth explaining that even though class types are in some sense
+built by applying a "type constructor", this data model and the C++
+language regard the <tt>class { ... }</tt> syntax as creating a new type, 
+<em>not</em> equivalent to another type built with the same syntax.
+
+<h3>FundamentalType</h3>
+
+<p>
+A FundamentalType [3.9.1] is one of the following:
+<ul>
+<li><tt>char</tt>
+<li><tt>signed char</tt>
+<li><tt>unsigned char</tt>
+<li><tt>bool</tt>
+<li><tt>signed int</tt>
+<li><tt>unsigned int</tt>
+<li><tt>signed long int</tt>
+<li><tt>unsigned long int</tt>
+<li><tt>signed short int</tt>
+<li><tt>unsigned short int</tt>
+<li><tt>wchar_t</tt>
+<li><tt>float</tt>
+<li><tt>double</tt>
+<li><tt>long double</tt>
+<li><tt>void</tt>
+</ul>
+
+<p>
+Note that the data model does not imply any orthogonality between
+modifiers like <tt>signed</tt> and "basic" types like <tt>int</tt>.
+
+<p>
+The FundamentalTypes are further subdivided into categories [3.9.1]
+not reflected here.
+
+
+<h1>Diagram 2: Templates</h1>
+
+<p>
+This diagram
+(xfig sources: <a href="template_er.fig">template_er.fig</a>,
+postscript: <a href="template_er.ps">template_er.ps</a>)
+is an extension of the previous diagram, showing all the
+new and extended concepts needed to represent templates.
+
+<p>
+<center><img src="template_er.png" alt="C++ Templates diagram"></center>
+
+<p>
+One point of terminology: whereas the Standard refers to "template
+parameters" (etc.), I refer to "meta-parameters".  I use the term
+"template" only for templates themselves, and use the prefix "meta-"
+(or "Meta") for the parameters and values involved in defining and
+using templates.
+
+<p>
+This diagram has five primary dimensions.  (They are all colored black because
+assigning color seemed unnecessary, due to minimal overlap, and difficult
+to keep compatible with the first diagram.)
+<ul>
+<li>MetaParameter vs. MetaValue: MetaParameters are holes, and MetaValues
+    fill the holes.
+<li>MetaParameter vs. MetaBinding: An unbound parameter is a hole, while
+    a bound parameter represents a filled hole.
+<li>Kinds of meta-entities: Meta-entities can be types or non-types, which
+    further subdivide into ground types, templates, integers and (variable)
+    names.  This axis is present only implicitly via products (see below).
+<li>Template vs. Specialization: A template is an entity with holes.
+    A specialization is a version of a template with the holes filled.
+<li>Kinds of templates: There are three kinds of templates in C++: classes,
+    functions and static data members.  This axis is only implicit.
+</ul>
+
+<p>
+This diagram makes use of what I call <em>non-orthogonal inheritance
+products</em>.  This means that a set of entities is derived by
+multiplying two inheritance hierarchies together, but then giving
+attributes and relationships to the product tuples independent of
+their factors.  For example, an IntegerMetaParameter has an
+"AtomicType", attribute/relationship, but this is not common to
+MetaParameters nor IntegerMetaEntities.
+
+<p>
+Though non-orthogonal product tuples are individually named, their
+derivation as product tuples is still available (though implicit), and
+this is used to define the concept of <em>corresponding
+relationships</em>, shown with dashed arrows.  For example, every
+NameMetaParameter has an optional "val" relationship with a
+NameMetaValue.  There are corresponding "val" relationships for the
+other kinds of MetaValues.  These relationships are consistent with
+respect to the meta-entity-kind axis, so it is well-defined to
+introduce a "val" relationship between MetaParameters and MetaValues:
+given a MetaParameter, find out which kind it is, and retrieve its
+"val", which must be a MetaValue.  This makes it possible to
+generically refer to the default value (when present) of a
+MetaParameter as being a MetaValue, while at the same time having the
+"val" relationships be well-typed w.r.t. the meta-entity-kind axis.  A
+similar technique is used for the specializations/template
+relationship.
+
+<p>
+The diagram has essentially two parts.  The central part, comprising
+the five major dimensions above, is the data model required to
+represent templates and specializations themselves.  Then, sprinkled
+around the edges, is the second part which consists of miscellanous
+extensions and refinements of Diagram 1 necessary to integrate template
+concepts into the core data model.
+
+<p>
+Terminology:
+<ul>
+<li>"Abstract": an entity with unbound MetaParameters.
+<li>"Concrete": an entity with no unbound MetaParameters.
+    <br>
+    Note: The Standard uses the terms "dependent" and "non-dependent"
+    for these concepts, as in, "dependent upon template parameters"
+    [14.6.2].  I find this terminology a bit unwieldy, and possibly
+    confusing with the traditional concept of a "dependent type" in
+    type theory, so I use abstract/concrete instead.
+</ul>
+
+<h2>MetaParameter</h2>
+
+<p>
+A MetaParameter is a parameter of a template [14.1].  By supplying a
+MetaValue for the MetaParameter, the template can be instantiated
+to produce a concrete entity.  Note that it is not a full
+<em>meta-variable</em>; its value cannot be changed once set [14.1p6].
+
+<p>
+A MetaParameter has an optional default value.  As explained above,
+the kind of MetaValue is dependent on the kind of MetaParameter,
+according to a parallel decomposition of each along the
+meta-entity-kind axis.
+
+<h3>MetaBinding</h3>
+
+<p>
+A MetaParameter is a parameter, while a MetaBinding is a binding of a
+MetaParameter to a MetaValue.  Unlike a MetaParameter, the "val"
+relationship of a MetaBinding is not optional, because it carries the
+binding.  Furthermore, the MetaValue to which it is bound must be
+concrete; either a concrete Type, or one of the three
+ConcreteMetaValues.  (Neither of these constraints is depicted
+graphically.)
+
+<h3>TypeNameMetaParameter</h3>
+
+<p>
+The type branch of the MetaParameter hierarchy [14.1p3] is represented
+by the TypeNameMetaParameter.  It is a descendant of NamedAtomicType,
+and as such can be looked up as a type, and used to build constructed
+types.
+
+<h3>TypeMetaParameter</h3>
+
+<p>
+A TypeMetaParameter, such as the ubiquitous "<tt>&lt;class
+T&gt;</tt>", is a parameter that can be bound to concrete Type.
+(Despite the idiomatic use of the <tt>class</tt> keyword to introduce
+such parameters, they need not be bound to ClassTypes.)
+
+<h3>TemplateMetaParameter</h3>
+
+<p>
+A TemplateMetaParameter is syntactically introduced with something like
+<pre>
+  template &lt;template &lt;class S&gt; class T&gt; /*...*/
+</pre>
+and known in the Standard as a "template template parameter".  It can
+be bound to a ClassTemplate, enabling one template to use multiple
+specializations of another (class) template.  
+
+<p>
+Note that it is not possible to pass a template function or a template
+data member as the argument to a TemplateMetaParameter, though the
+effect could be simulated by creating an appropriate wrapper
+ClassTemplate.
+
+<h3>NontypeMetaParameter</h3>
+
+<p>
+A NontypeMetaParameter is a descendant of Variable, and can be used
+like an object variable.
+
+<h3>IntegerMetaParameter</h3>
+
+<p>
+An IntegerMetaParameter may be bound to an integer value [14.3.2p1].
+It has an AtomicType, but only integral types [3.9p7] and Enumerations
+are permitted [14.1p4].  This data model does not record the
+cv-qualification on the type of an IntegerMetaParameter because they
+are irrelevant [14.1p5].
+
+<h3>NameMetaParameter</h3>
+
+<p>
+A NameMetaParameter may be bound to a Function, GlobalVariable or
+DataMember [14.3.2p1].  It has an IndirectionType, which must be
+a PointerType, PointerToMemberType or ReferenceType [14.1p4].
+
+<h2>MetaValue</h2>
+
+<p>
+A MetaValue is something that can fill a hole of a MetaParameter.
+Syntactically, they are denoted with template arguments [14.3].
+They are decomposed along the meta-entity-kind axis, just like
+MetaParameters, though the diagram omits the names TypeNameMetaValue
+and NontypeMetaValue for reasons of space.
+
+<h3>TypeMetaValue</h3>
+
+<p>
+A TypeMetaValue is a Type.  It may be concrete or abstract, depending
+on the Type.
+
+<h3>TemplateMetaValue</h3>
+
+<p>
+A TemplateMetaValue is either a ConcreteTemplateMetaValue, which is
+a specific ClassTemplate, or an AbstractTemplateMetaValue, which is
+a reference to a TemplateMetaParameter.  AbstractTemplateMetaValues
+only occur as the default values of TemplateMetaParameters.
+
+<h3>IntegerMetaValue</h3>
+
+<p>
+An IntegerMetaValue is either a ConcreteIntegerMetaValue, which is
+an integer, or an AbstractIntegerMetaValue, which is an Expression
+that refers to MetaParameters.
+
+<h3>NameMetaValue</h3>
+
+<p>
+A NameMetaValue is either a ConcreteNameMetaValue, which is a
+specific concrete Variable, or is an AbstractNameMetaValue, which
+is a reference to a NameMetaParameter.  AbstractNameMetaValues
+only occur as the default values of NameMetaParameters.
+
+<p>
+The name of a template function may be passed as a syntactic template
+argument, but overload resolution will select a specific
+specialization for the binding [14.3.2p5b4,5].
+
+
+<h2>Template</h2>
+
+<p>
+A Template is an entity with named holes (parameters) that can be
+filled by supplying values.  Templates are distinct from (say)
+ordinary parameterized functions in that template parameters are are
+filled at compile time (only).
+
+<p>
+A Template is associated with a set of Specializations, instances
+of that template.
+
+<p>
+Note that members of ClassTemplates are not necessarily called
+Templates in this data model, even if they have holes due to the
+parameters of the class.  Only member templates (where the
+"<tt>template &lt;/*...*/&gt;</tt>" syntax is repeated inside the
+class body) are both ClassMembers and Templates.
+
+<p>
+Note further, however, that currently (2005-08-19) Elsa takes
+the opposite approach, regarding every member of a class template
+as being a template in its own right.  I now regard this design
+decision as a mistake, and hope to eventually rewrite that part
+of Elsa using the data model shown here.
+
+<h3>MetaParameterList</h3>
+
+<p>
+A Template is/has a MetaParameterList, a sequence of parameters.
+
+<h2>Specialization</h2>
+
+<p>
+A Specialization is a Template with the holes filled with MetaValue
+arguments.  The arguments are stored in a sequence that corresponds to
+the parameter sequence.  Except in the case of a
+ClassTemplatePartialSpecialization, a Specialization's arguments are
+always concrete.
+
+<p>
+A Specialization may be either <em>implicit</em> or <em>explicit</em>.
+An implicit specialization (also called an "instantiation") is
+generated automatically by the compiler by filling the holes of the
+Template definition with the supplied arguments.  An explicit
+specialization is supplied by the programmer, and effectively overrides
+implicit instantiation for a specific argument sequence.  
+
+<p>
+Note that the "explicit" attribute is a <em>mutable</em> boolean
+field.  This is because it is possible for the program to refer to a
+specialization prior to declaring it as an explicit specialization, as
+long as the compiler has no need to implicitly instantiate it in the
+meantime [14.7.3p6].  Thus, the static semantics and this data model
+allow for a specialization to be initially assumed implicit, but later
+determined to be explicit.
+
+
+<h2>ClassTemplate</h2>
+
+<p>
+A ClassTemplate is a Template of a ClassType.  It also <em>is</em>
+a ClassType: it can be looked up as a type (in which case template
+arguments would then have to be supplied), has members, etc.
+
+<h3>ClassTemplateSpecialization</h3>
+
+<p>
+A ClassTemplateSpecialization is a Specialization of a ClassTemplate.
+
+<h3>ClassTemplatePartialSpecialization</h3>
+
+<p>
+A ClassTemplatePartialSpecialization [14.5.4] is a Specialization of
+a ClassTemplate, whose template arguments ("args[]") are not all concrete.
+The holes in its arguments are declared in its MetaParameterList; i.e.,
+it is itself a ClassTemplate.
+
+<p>
+[TODO: This schema is missing the state needed to keep track of the
+instantiation of <em>members</em> of class templates.]
+
+
+<h2>FunctionTemplate</h2>
+
+<p>
+A FunctionTemplate is a Template of a Function.
+
+<h3>FunctionTemplateSpecialization</h3>
+
+<p>
+A FunctionTemplateSpecialization is a Specialization of a FunctionTemplate.
+
+<p>
+Note that, unlike for ClassTemplates, a Function cannot be both a
+FunctionTemplate and a FunctionTemplateSpecialization (there is no
+such thing as a function template partial specialization).
+
+
+<h2>Abstract NamedAtomicTypes</h2>
+
+<p>
+Abstract types are supported by several extensions of NamedAtomicType.
+
+<h3>TypeNameMetaParameter (as a NamedAtomicType)</h3>
+
+<p>
+Discussed above, a TypeNameMetaParameter is the leaf of any 
+abstract type.  Note that a TypeNameMetaParameter need not be
+abstract (it could be a TypeNameMetaBinding).
+
+<h3>AbstractTemplateId</h3>
+
+<p>
+An AbstractTemplateId is a template-id (template name plus arguments)
+where either the template or the arguments are abstract.  The template
+is indicated as a NamedAtomicType, but it must always be either a
+ClassTemplate or a TemplateMetaParameter.  For example:
+<pre>
+  template &lt;class T&gt;
+  struct A;
+  
+  template &lt;class T&gt;
+  struct B {
+    A&lt;T&gt; a;
+  };
+</pre>
+The B::a member has type <tt>A&lt;T&gt;</tt>, but (in the context of
+the template B) <TT>T</TT> is abstract, so <tt>A&lt;T&gt;</tt> is too.
+
+<p>
+Here is an example with an abstract template portion of an AbstractTemplateId:
+<pre>
+  template &lt;template &lt;class S&gt; class T, class U&gt;
+  struct A {
+    T&lt;U&gt; t;
+  };
+</pre>
+Here, A::t has type <tt>T&lt;U&gt;</tt>, in which both <TT>T</TT> and
+<TT>U</TT> are abstract.
+
+<p>
+In Elsa, this is called a "PseudoInstantiation".
+
+<h3>AbstractQualifiedType</h3>
+
+<p>
+An AbstractQualifiedType arises when a qualified name [3.4.3, 5.1p7]
+is used, but the qualifier is an abstract type name.  The "first" part (the
+abstract qualifier) is indicated as a NamedAtomicType, but must be
+a TypeMetaParameter or an AbstractTemplateId.  The "rest" part is
+a PossiblyQualifiedName, which is a sequence of identifiers and
+template-ids (to be shown on the as-yet-nonexistent Diagram 3).
+
+<p>
+Example:
+<pre>
+  template &lt;class T&gt;
+  struct A {
+    typename T::SomeType s;
+  };
+</pre>
+The type of A::s is <tt>T::SomeType</tt>, which is abstract because
+<TT>T</TT> is.
+
+<p>
+In Elsa, this is called a "DependentQualifiedType" or "DQT".
+
+
+<h2>AbstractSizedArrayType</h2>
+
+<p>
+An AbstractSizedArrayType is an ArrayType whose size is specified by
+an abstract Expression.  This is a necessary concept to permit matching
+declarations with definitions in some cases, for example (variant
+of <a href="../in/t0435.cc">../in/t0435.cc</a>):
+<pre>
+  template &lt;int n&gt;
+  struct A {
+    int foo(int (*p)[n]);
+    int foo(int (*p)[n+1]);
+  };
+
+  template &lt;int n&gt;
+  int A&lt;n&gt;::foo(int (*p)[n]) { /*...*/ }
+
+  template &lt;int n&gt;
+  int A&lt;n&gt;::foo(int (*p)[n+1]) { /*...*/ }
+</pre>
+Here, the array size expressions must be recorded in the data model
+to enable the declarations of <tt>A::foo</tt> to be matched with
+their definitions.
+
+
+<h2>MetaEntity Scopes</h2>
+
+<p>
+Two extensions of Scope are used for template support.
+
+<h3>MetaParameterScope</h3>
+
+<p>
+MetaParameters are stored in a MetaParameterScope.  When this scope
+is searched by lookup, MetaParameters can be found.
+
+<h3>MetaBindingScope</h3>
+
+<p>
+When an implicit specialization is instantiated, the static semantics
+require analyzing the specialization in light of its arguments.  The
+arguments are bound in a MetaBindingScope for this purpose.
+
+<p>
+(At the moment I cannot justify distinguishing a MetaParameterScope from
+a MetaBindingScope, but I know that Elsa needs to be able to tell them
+apart somewhere, so I'm reasonably confident that they do in fact need to be
+distinguished.)
+
+
+<h2>AbstractEnumerator</h2>
+
+<p>
+An AbstractEnumerator is like an Enumerator, but the precise value
+is unknown because its initializing expression is abstract.  It is
+a refinement of the Enumerator entity presented in Diagram 1.
+
+<p>
+It is not clear whether it is adequate to simply record that its value
+is abstract, as done here, or if it must actually carry the
+expression.  The testcase <a href="../in/t0578.cc">../in/t0578.cc</a>
+would be valid if AbstractEnumerators carried their value, and invalid
+otherwise.  Both ICC and GCC reject it, so at least the data model
+here is consistent their their interpretation.  If the Standard had a
+clear data model, such as the one presented in these diagrams, such a
+question would have a clear answer.
+
+
+<h2>OutOfLineTemplateMemberDefinition (abbreviated: OOLTMDefn)</h2>
+
+<p>
+A ClassMember of a ClassTemplate may have an out-of-line definition.
+If so, it has an OutOfLineTemplateMemberDefinition, which
+carries a sequence of MetaParameterLists.  These parameter lists
+override the nominal parameter names coming from the enclosing
+template class(es).  For example, in the following syntax:
+<pre>
+  template &lt;class S1&gt;
+  struct A {
+    template &lt;class T2&gt;
+    struct B {
+      int f();
+    };
+  };
+
+  template &lt;class S2&gt;
+  template &lt;class T2&gt;
+  int A&lt;S2&gt;::B&lt;T2&gt;::f() { /*...*/ }
+</pre>
+the ClassMember for A::B::f will have enclosing parameter lists
+<tt>&lt;S2&gt;</tt> and <tt>&lt;T2&gt;</tt>.  The definition of
+A::B::f may refer to the parameters in its enclosing parameter lists
+(S2 and T2), but not to the parameters in the enclosing
+TemplateClasses (S and T).
+
+<p>
+The order of the enclosingParams[] sequence is significant.  The first
+parameter list corresponds to the outermost enclosing template class,
+then proceeding towards the next innermost in sequence, until the last
+parameter list corresponds to the innermost enclosing template class.
+In other words, the enclosingParams[] sequence order is the same as
+the order in which they appear syntactically [14.7.3p17(?)].
+
+
+<h1>Diagram 3: C++ Abstract Syntax</h1>
+
+<p>
+This is work in progress, so no pretty pictures yet.
+
+<pre>
+  TranslationUnit: 
+    decls: Declaration[]
+    
+  Declaration
+    - BlockDeclaration
+    | - SimpleDeclaration
+    | |   declSpecifier
+    | |   initDecl[]
+    | - AsmDefinition
+    | |   string
+    | - NamespaceAliasDefinition
+    | |   src: Identifier
+    | |   tgt: PQName
+    | - UsingDeclaration
+    | |   t?
+    | |   PQName
+    | - UsingDirective
+    |     PQName
+    - FunctionDefinition
+    |   declSpecifier
+    |   declarator
+    |   ctorInit[]
+    |   handlers[]
+    - TemplateDeclaration
+    |   e?
+    |   params[+]
+    |   d: Declaration
+    - ExplicitInstantiation
+    |   d: Declaration
+    - ExplicitSpecialization
+    |   d: Declaration
+    - LinkageSpecification
+    | | string
+    | - LSSeq
+    | |   decls[]
+    | - LSOne
+    |     decl: Declaration
+    - NamespaceDefinition
+        n: Id?
+        decls[]
+        
+  InitDeclarator
+    declarator
+    init?
+    
+  Initializer
+    - IN_expr
+    |   expr
+    - IN_compound
+    |   initializer[]
+    - IN_ctor
+        args: Expression[+]
+        
+  DeclSpecifier(Seq)
+    declflag*
+    typeSpec
+    
+  DeclFlag
+    - StorageClass
+      - auto
+      - register
+      - static
+      - extern
+      - mutable
+    - FunctionSpecifier
+      - inline
+      - virtual
+      - explicit
+    - typedef
+    - friend
+    - CVFlag
+      - const
+      - volatile
+      
+  TypeSpecifier
+    - TS_name
+    |   t?
+    |   PQName
+    - TS_classSpec
+    |   keyword
+    |   PQName?
+    |   BaseClause[]
+    |   Member[]
+    - TS_enumSpec
+    |   Id?
+    |   EnumeratorDefn[]
+    - TS_elaborated
+    |   keyword
+    |   PQName
+    - TS_fundamental
+        FundamentalType
+        
+  Declarator           &lt;----+
+    - D_name                |
+    |   PQName?             |
+    - D_indirect            |
+      | base: Declarator ---+
+      - D_pointer
+      |   cv
+      - D_reference
+      - D_ptm
+      |   cv
+      |   class: PQName
+      - D_func
+      |   cv
+      |   params: ParameterDeclaration[]
+      |   exnSpec?
+      - D_array
+          size: Expression
+
+  PQName     &lt;----+
+    - QName       |
+    | | rest -----+
+    | - QN_global
+    | - QN_nested
+    |     qual -------+
+    - PQ_nameId   &lt;---+
+    | | n: Id
+    | - PQ_name
+    | - PQ_template
+    |     args: TemplateArg[]
+    - PQ_operator
+    |   op
+    - PQ_conversion
+    |   t: Type
+    - PQ_dtor
+        c: PQ_nameId
+</pre>
+
+
+<hr>
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="valid-html401.png"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+<p>
+<a href="../index.html">Up</a>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+<center>This space left intentionally blank.</center>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+
+
+
+
+
+</body>
+</html>

Added: vendor/elsa/current/elsa/doc/declarator.fig
===================================================================
--- vendor/elsa/current/elsa/doc/declarator.fig	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/declarator.fig	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,163 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 5250.000 2118.750 6300 1500 5250 900 4200 1500
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 4762.500 2212.500 4650 2250 4800 2325 4800 2100
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 4762.500 4012.500 4650 4050 4800 4125 4800 3900
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 3487.500 3750.000 3600 3600 3300 3750 3600 3900
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 0 1 0 3150.000 6900.000 2700 6300 3150 6150 3600 6300
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 3150.000 6000.000 2700 6600 3150 6750 3600 6600
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 0 1 0 3150.000 2400.000 2700 1800 3150 1650 3600 1800
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 3150.000 1500.000 2700 2100 3150 2250 3600 2100
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 0 1 0 4200.000 5662.500 6300 6900 4200 8100 2100 6900
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 4762.500 6712.500 4650 6750 4800 6825 4800 6600
+	2 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 0 -1 0.000 0 0 1 0 4162.500 6993.750 4350 6900 4200 7200 3975 6900
+	2 1 1.00 60.00 120.00
+5 1 1 1 0 7 50 0 -1 4.000 0 0 1 0 3150.000 6442.500 2550 6150 3150 5775 3750 6150
+	2 1 1.00 60.00 120.00
+5 1 1 1 0 7 50 0 -1 4.000 0 0 1 0 5250.000 6442.500 4650 6150 5250 5775 5850 6150
+	2 1 1.00 60.00 120.00
+5 1 1 1 0 7 50 0 -1 4.000 0 0 1 0 3150.000 1942.500 2550 1650 3150 1275 3750 1650
+	2 1 1.00 60.00 120.00
+6 5850 1725 6750 2100
+4 1 0 50 0 0 12 0.0000 4 135 810 6300 1875 Declarator\001
+4 1 0 50 0 0 12 0.0000 4 135 300 6300 2100 End\001
+-6
+6 1500 6000 2700 6900
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 2100 6450 600 450 1500 6000 2700 6900
+4 1 0 50 0 0 12 0.0000 4 135 780 2100 6525 Parameter\001
+-6
+6 3750 6225 4650 6600
+4 1 0 50 0 0 12 0.0000 4 135 780 4200 6375 Parameter\001
+4 1 0 50 0 0 12 0.0000 4 135 810 4200 6600 Declarator\001
+-6
+6 5700 3300 6900 4200
+6 5850 3450 6750 4050
+4 1 0 50 0 0 12 0.0000 4 180 645 6300 3600 Grouped\001
+4 1 0 50 0 0 12 0.0000 4 135 810 6300 3825 Declarator\001
+4 1 0 50 0 0 12 0.0000 4 135 300 6300 4050 End\001
+-6
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 6300 3750 600 450 5700 3300 6900 4200
+-6
+6 2625 4500 3300 4950
+4 0 0 50 0 0 12 0.0000 4 180 675 2625 4650 leftparen\001
+4 0 0 50 0 0 12 0.0000 4 180 360 2625 4875 push\001
+-6
+6 3000 7275 5400 7725
+4 1 0 50 0 0 12 0.0000 4 180 675 4200 7425 leftparen\001
+4 1 0 50 0 0 12 0.0000 4 180 2295 4200 7650 push ParameterDeclaratorEnd\001
+-6
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 2100 1950 600 450 1500 1500 2700 2400
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 4200 1950 600 450 3600 1500 4800 2400
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 6300 1950 600 450 5700 1500 6900 2400
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 8400 1950 600 450 7800 1500 9000 2400
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 4200 3750 600 450 3600 3300 4800 4200
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 4200 6450 600 450 3600 6000 4800 6900
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 6300 6450 600 450 5700 6000 6900 6900
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 4800 1950 5700 1950
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 6900 1950 7800 1950
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 4200 2400 4200 3300
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 4800 3750 5700 3750
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 6300 3300 6300 2850
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 4800 6450 5700 6450
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4
+	2 1 1.00 60.00 120.00
+	 6300 4200 6300 4500 1800 5100 1800 6000
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 5
+	2 1 1.00 60.00 120.00
+	 6750 2250 7800 2700 7800 4500 2100 5250 2100 6000
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4
+	2 1 1.00 60.00 120.00
+	 6300 6000 6300 4875 2400 5400 2400 6000
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+	2 1 1.00 60.00 120.00
+	 6900 6450 7800 6300 7800 5400
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+	2 1 1.00 60.00 120.00
+	 6750 1650 7200 900 7800 900
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+	2 1 1.00 60.00 120.00
+	 6750 6750 7200 7500 7800 7500
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 8250 1050 8250 1350
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+	2 1 1.00 60.00 120.00
+	 8250 750 8250 450 7800 450
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+	2 1 1.00 60.00 120.00
+	 8550 7350 8550 6900
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+	2 1 1.00 60.00 120.00
+	 8550 7725 8550 8100 7800 8100
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 3
+	2 1 1.00 60.00 120.00
+	 6900 2100 8400 2700 8400 3300
+4 1 0 50 0 0 12 0.0000 4 135 885 2100 2025 Declaration\001
+4 1 0 50 0 0 12 0.0000 4 135 810 4200 2025 Declarator\001
+4 1 0 50 0 0 12 0.0000 4 135 885 8400 1875 Declaration\001
+4 1 0 50 0 0 12 0.0000 4 135 300 8400 2100 End\001
+4 1 0 50 0 0 12 0.0000 4 90 540 5175 825 comma\001
+4 1 0 50 0 0 12 0.0000 4 180 645 4200 3675 Grouped\001
+4 1 0 50 0 0 12 0.0000 4 135 810 4200 3900 Declarator\001
+4 0 0 50 0 0 12 0.0000 4 180 675 4275 2775 leftparen\001
+4 0 0 50 0 0 12 0.0000 4 180 1515 4275 3000 push DeclaratorEnd\001
+4 0 0 50 0 0 12 0.0000 4 75 240 5025 2400 "*"\001
+4 0 0 50 0 0 12 0.0000 4 75 240 5025 4200 "*"\001
+4 2 0 50 0 0 12 0.0000 4 180 675 3150 3600 leftparen\001
+4 2 0 50 0 0 12 0.0000 4 180 2160 3150 3825 push GroupedDeclaratorEnd\001
+4 0 0 50 0 0 12 0.0000 4 180 765 6450 2925 rightparen\001
+4 0 0 50 0 0 12 0.0000 4 135 270 6450 3150 pop\001
+4 1 0 50 0 0 12 0.0000 4 135 810 6300 6525 Declarator\001
+4 1 0 50 0 0 12 0.0000 4 135 300 6300 6750 End\001
+4 1 0 50 0 0 12 0.0000 4 135 780 6300 6300 Parameter\001
+4 1 0 50 0 0 12 0.0000 4 150 780 3150 6975 type name\001
+4 1 0 50 0 0 12 0.0000 4 135 195 3150 6075 int\001
+4 1 0 50 0 0 12 0.0000 4 150 780 3150 2475 type name\001
+4 1 0 50 0 0 12 0.0000 4 135 195 3150 1575 int\001
+4 1 0 50 0 0 12 0.0000 4 90 540 4200 8325 comma\001
+4 1 0 50 0 0 12 0.0000 4 135 675 5250 1875 identifier\001
+4 1 0 50 0 0 12 0.0000 4 135 765 7350 1875 semicolon\001
+4 1 0 50 0 0 12 0.0000 4 135 675 5250 3675 identifier\001
+4 1 0 50 0 0 12 0.0000 4 135 675 5250 6375 identifier\001
+4 0 0 50 0 0 12 0.0000 4 75 240 5025 6900 "*"\001
+4 0 0 50 0 0 12 0.0000 4 180 765 7950 5850 rightparen\001
+4 0 0 50 0 0 12 0.0000 4 135 270 7950 6075 pop\001
+4 0 0 50 0 0 12 0.0000 4 180 495 7200 825 equals\001
+4 0 0 50 0 0 12 0.0000 4 135 705 7875 975 initializer\001
+4 0 0 50 0 0 12 0.0000 4 180 495 7200 7725 equals\001
+4 0 0 50 0 0 12 0.0000 4 180 1275 7875 7575 default argument\001
+4 0 0 50 0 0 12 0.0000 4 180 675 8550 2850 leftparen\001
+4 1 0 50 0 0 12 0.0000 4 135 585 8400 3525 ctor init\001
+4 1 0 50 0 0 12 0.0000 4 180 660 8400 3750 (Note 4)\001
+4 1 0 50 0 0 12 0.0000 4 180 675 3150 5700 epsilon 2\001
+4 1 0 50 0 0 12 0.0000 4 180 675 3150 1200 epsilon 1\001
+4 1 0 50 0 0 12 0.0000 4 180 675 5250 5700 epsilon 3\001

Added: vendor/elsa/current/elsa/doc/declarator.html
===================================================================
--- vendor/elsa/current/elsa/doc/declarator.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/declarator.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,238 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Declarator Parsing in Elsa</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+  </style>
+</HEAD>
+
+<body>
+
+<h1>Declarator Parsing in Elsa</h1>
+
+<p>
+One of the trickier aspects of parsing C and C++ is parsing the
+declarator structure.  In <a href="cc.ast.html#declarator">cc.ast.html</a>, I showed
+a diagram of how a somewhat complicated declarator is to be decomposed;
+but there is no suggestion there of <em>how</em> that decomposition is
+accomplished.  The mechanism of said decomposition, namely parsing a
+declarator, is the subject of this document.
+
+<h2>The Core Parsing Automaton</h2>
+
+<p>
+The parsing algorithm can be succinctly described by the following
+pushdown automaton:<br>
+<center>
+<img src="declarator.png" alt="Declarator Automaton Diagram">
+</center>
+
+<p>
+Quick pushdown automaton refresher: A pushdown automaton is like a finite
+automaton, transitioning from state to state as it consumes input.  In addition,
+it has the option of <em>pushing</em> a state onto its pushdown stack while
+making a transition, or <em>popping</em> a state off the stack instead of
+making a fixed transition.  In the diagram above, every transition on
+"leftparen" is accompanied by pushing a state (if I don't say which state,
+it means push the state you just came from), and every action on "rightparen"
+is to pop a state (and go there).  As demonstrated by this example, a
+pushdown automaton is more powerful than a finite automaton in that it can
+deal with arbitrarily nested constructs.
+
+<p>
+Ignoring the dashed arrows (which are discussed below), this automaton is 
+completely deterministic:
+in every state, for every next token, there is either zero or one
+possible transitions (zero transitions corresponds to a syntax error).
+This deterministic automaton is the core of the declarator parser
+mechanism.
+
+<p>
+Note that the automaton only includes the pointer type constructor "*"
+and function type constructor "()".  I have left out references ("&"),
+arrays ("[]"), and pointer to member ("<i>class</i>::*") for
+simplicity.  I have also left out the possibility of a parameter list
+being empty; adding it is a matter of splitting "Parameter" into
+"FirstParameter" (rightparen enabled) and "NextParameter" (reached by
+comma; rightparen not enabled), but I decided it's more clutter than
+it's worth here.
+
+<p>
+From here, I will consider in turn three complications that Elsa must
+deal with.
+
+<h2>Complication 1: Omitted Parameter Names</h2>
+
+<p>
+Parameters do not have to be given names; it is sufficient to give
+their types, for example:
+<pre>
+  int strcmp(char*, char*);
+</pre>
+
+<p>
+The effect on the automaton is to introduce an "epsilon transition",
+that is a transition that does not consume any input.  In particular,
+it introduces the transition from "Parameter Declarator" (PD) to
+"Parameter Declarator End" (PDE), labeled "epsilon 3".  Equivalently, all
+of the outgoing transitions for PDE are available in PD.
+
+<p>
+However, this creates a non-determinism: both PD and PDE have an
+outgoing transition on leftparen, and they do <em>not</em> go to the
+same place.  This choice, between "(" as a grouping punctuator and
+"(" as the function type constructor, is resolved in the C++ standard
+(section 8.2 paragraph 7, plus some deduction) by looking at the
+token <em>after</em> the "(" in question.  If it is a type keyword, or
+an identifier that names a type (in the current scope), or a rightparen, then the
+function type constructor interpretation is preferred.  Otherwise,
+the grouping punctuator interpretation is used.  Example:
+<pre>
+  int f(  int (int)  );      // 'f' accepts (a pointer to) a function
+
+  typedef int x;
+  int f(  int (x)  );        // same type as above
+
+  int g(  int (y)  );        // 'g' accepts an integer
+  
+  int h(  int ()  );         // 'h' accepts a function
+</pre>
+
+<h2>Complication 2: Constructor Initializers</h2>
+
+<p>
+In C++, objects can be initialized by invoking a constructor ("ctor"):
+<pre>
+  class A {
+  public:
+    A(int, float);
+  };
+
+  A a(3, 4.5);       // initialization by ctor call
+</pre>
+
+<p>
+In the automaton, this possibility adds an transition on "leftparen" from 
+"Declarator End" (DE) to the parsing of an argument list (not shown); the
+arc is labeled "ctor init (Note 4)" (CI).
+
+<p>
+Unfortunately, there is already a transition on "leftparen" in that
+state, to "Parameter" (P).  How do we decide whether to go to P or CI?
+The C++ standard (section 8.2 paragraph 1) says that if a construct
+"could possibly be a declaration" then it is a declaration.  What this
+(apparently) means is that we prefer the P interpretation, as that
+entails parsing a parameter <em>declaration</em>, instead of the CI
+interpretation.  But exactly what circumstances are covered by the
+phrase "could possibly be"?  How much checking should be done before
+deciding whether something could be a P; must we go all the way to
+type checking?
+
+<p>
+Now, in fact, Elsa <em>does</em> go all the way to type checking,
+though that's an artifact of what is convenient in Elsa, not a
+determination of what is perfect behavior (see below).  For this
+document, I want to have a simple, local rule.  As best I can tell,
+the determining factor is again the token after the "(": if it is a
+type keyword or an identifier that names a type, choose P, otherwise
+choose CI.
+
+<h2>Complication 3: Implicit Int</h2>
+
+<p>
+In old-style Kernighan and Ritchie (K&amp;R) C, declarations were allowed
+to omit specifying the type of a declared variable, and the type would
+implicitly be "int".  C++ does not allow this, but Elsa (in certain
+configurations) nevertheless allows this rule.  In the automaton
+diagram, this adds the epsilon transitions labeled "epsilon 1" and
+"epsilon 2".
+
+<p>
+Transition "epsilon 1" is easy to handle.  It adds no nondeterminisms.
+
+<p>
+Transition "epsilon 2" is more interesting.  It creates a nondeterminism
+for an identifier that names a type, since P can transition to PD or
+to PDE (using the implicit int for the latter).  However this is a
+familiar ambiguity for implicit int, and is resolved in the usual way:
+prefer the "type name" interpretation.
+
+<p>
+Interestingly, gcc (which is for the moment my only reference for
+what K&amp;R is) does <em>not</em> accept arbitrary use of implicit int
+for parameters.  Instead, it only allows it when the "register" keyword
+is used.  Thus, "epsilon 2" is really only available when that keyword
+appears first (the automaton does not include such keywords, for
+simplicity).  Elsa doesn't enforce this.
+
+
+<h2>Implementation in a Grammar</h2>
+
+<p>
+Now, the fact is that Elsa does not use a directly-written pushdown
+automaton to parse declarators, but a grammar instead.  Morever, that
+grammar was designed before the automaton was conceived (the grammar
+is based on the grammar in the C++ standard).  So what role does the
+automaton play?
+
+<p>
+Bascially, I use the automaton as a conceptual tool, to let me analyze
+tricky example syntax to figure out the "right" behavior.  Then, I
+modify the grammar and/or type checker to get the behavior I want.
+
+<p>
+It's somewhat ironic that my specification is the low-level automaton,
+and my implementation is the high-level grammar.  However, this is due
+to the fact that C's declarator parsing rules were developed along
+with other low-level implementations, so those rules are easier to
+formulate as low-level rules.  Fortunately, this is the only part of
+the language that has this specification inversion property; for all
+other parts, the high-level grammar spec is much preferable to an
+automaton.
+
+
+<h2>Elsa vs. Perfect Behavior</h2>
+
+<p>
+As hinted above, Elsa resolves ambiguities during type checking,
+rather than during parsing.  This is because Elsa does not use
+the "lexer hack" feedback technique, and hence does not have
+enough information at parse time to do ambiguity resolution.
+
+<p>
+The particular strategy employed is typically to type check both
+alternatives of a given ambigutiy, and keep the one that checks
+without any errors.  In the case of the declarator ambiguity, Elsa
+checks the declarator possibility first, and keeps it if it
+succeeds, regardless of what might happen to the other alternative.
+
+<p>
+This strategy works well when the input is assumed to be valid C++.
+However, there is a risk that Elsa will accept code that is not
+valid C++, if:
+<ul>
+<li>the "correct" syntactic interpretation turns out to have a
+    type checking error,
+<li>but the "incorrect" interpretation does not have any errors,
+    and hence is selected by Elsa.
+</ul>
+For the moment, we don't have any examples of this behavior.  If such
+behavior were observed, it would be relatively easy to modify the
+parser to detect the relevant syntax, and flag it as erroneous
+(thus defeating the second bullet).
+
+
+<p>
+  <a href="http://validator.w3.org/check?uri=referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+</HTML>

Added: vendor/elsa/current/elsa/doc/declarator.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/declarator.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/design.html
===================================================================
--- vendor/elsa/current/elsa/doc/design.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/design.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1713 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+<head>
+  <title>Elsa Design</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175%; font-weight: bold }
+    P.remark { font-size: 125%; color: red }
+    SPAN.todo { font-weight: bold }
+    SPAN.program { font-family: monospace }
+    SPAN.variable { font-family: monospace }
+    a.toc:link { text-decoration: none }
+    a.toc:visited { text-decoration: none }
+  </style>
+</head>
+<body>
+
+<center>
+<p class="title">Elsa Design</p>
+<p>By Daniel Wilkerson and Scott McPeak
+</center>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<h1>Introduction</h1>
+
+<p>This file is an attempt to articulate the design of
+<a href="../index.html">Elsa</a>
+to someone who would like to work on it.
+
+<p>Elsa attempts to parse C and C++:
+<ul>
+
+<li>C++ is defined by the C++03 spec, more officially known as "ISO/IEC
+14882:2003: Programming languages -- C++."  You will see it referred to
+as "cppstd" in comments throughout the code.  There are also references
+to the older C++98 standard.  The standard can be
+purchased from <a href="http://www.ansi.org/">ANSI</a> (among other
+places), and drafts
+of the standard can be found on
+<a href="http://www.csci.csusb.edu/dick/c++std/">Dick Botting's page</a>.
+
+<li>C is defined by the C89 and C99 specs, 
+"ISO/IEC 9899:1990 Programming languages -- C" and 
+"ISO/IEC 9899:1999 Programming languages -- C", respectively.
+
+<li>Elsa also supports the older C syntax described in
+    Kernighan and Ritchie's
+    <a href="http://cm.bell-labs.com/cm/cs/cbook/">"The C Programming Language"</a>
+    ("K&amp;R").
+
+<li>GCC has numerous extensions to C and C++, mostly documented in the
+    <a href="http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/">GCC Manual</a>; Elsa
+    parses most of these.
+
+</ul>
+
+<p>Note that Elsa does not try to reject all invalid programs.  The
+checking that Elsa does is primarily for the purpose of ensuring that
+its interpretation of the code is correct.  For example, Elsa
+<em>does</em> check that argument types match parameter types (which
+helps to catch bugs in Elsa's type computation logic, and is required
+to determine where user-defined conversions take place), but <em>does
+not</em> enforce the access control rules ("public", "private", etc.)
+of C++.  Ideally, Elsa eventually will check such things, but it is
+not a priority for the forseeable future.
+
+<p>Elsa is extensible; that is, one may add additional syntactic
+features to the language being parsed, <em>without</em> directly
+modifying the files that define the base language.  This
+"base-and-extension design pattern" occurs frequently in the design of
+Elsa; for example, it is used to support for C99 and GNU extensions to C++.
+The intent is to allow users to modify Elsa almost arbitrarily, but still be
+able to keep up with the Elsa release cycle.
+
+<p>There are several stages to the processing of an input file:<br>
+<center><img src="block_diagram.png" alt="Elsa Block Diagram"></center>
+<!-- BEGIN CONTENTS -->
+<!-- automatically generated by insert-html-toc; do not edit the TOC directly -->
+<ul>
+  <li><a class="toc" href="#lexing">1. Lexing</a>
+  <ul>
+    <li><a class="toc" href="#lexer_build">1.1 Lexer Build Process</a>
+    <li><a class="toc" href="#lexer_design">1.2 Lexer Design</a>
+  </ul>
+  <li><a class="toc" href="#parsing">2. Parsing</a>
+  <ul>
+    <li><a class="toc" href="#parser_build">2.1 Parser Build Process</a>
+    <li><a class="toc" href="#ast_build">2.2 AST Build Process</a>
+    <li><a class="toc" href="#parser_actions">2.3 Parser Actions</a>
+  </ul>
+  <li><a class="toc" href="#typechecking">3. Type Checking</a>
+  <ul>
+    <li><a class="toc" href="#disambiguation">3.1 AST disambiguation</a>
+    <li><a class="toc" href="#lookup">3.2 Variable lookup</a>
+    <ul>
+      <li><a class="toc" href="#lookup_variables">3.2.1 Variables</a>
+      <li><a class="toc" href="#overload_resolution">3.2.2 Overload Resolution</a>
+    </ul>
+    <li><a class="toc" href="#type_annotation">3.3 Type Annotation</a>
+    <li><a class="toc" href="#implicit_conversions">3.4 Insertion of Implicit Conversions</a>
+    <li><a class="toc" href="#templates">3.5 Templates</a>
+    <ul>
+      <li><a class="toc" href="#template_representation">3.5.1 Template Representation</a>
+      <li><a class="toc" href="#template_instantiation">3.5.2 Template Instantiation</a>
+      <li><a class="toc" href="#dependent_names">3.5.3 Dependent Types and Names</a>
+    </ul>
+  </ul>
+  <li><a class="toc" href="#elaboration_cdtors">4. Elaboration of constructors and destructors</a>
+  <li><a class="toc" href="#post_processing">5. Post-processing</a>
+  <li><a class="toc" href="#extension">6. Extension Mechanisms</a>
+  <ul>
+    <li><a class="toc" href="#ext_lexer">6.1 Lexer Extensions</a>
+    <li><a class="toc" href="#ext_parser">6.2 Parser Extensions</a>
+    <li><a class="toc" href="#ext_tcheck">6.3 Type Checker Extensions</a>
+    <li><a class="toc" href="#ext_elaboration">6.4 Elaboration Extensions</a>
+    <li><a class="toc" href="#ext_post">6.5 Post-processing Extensions</a>
+  </ul>
+  <li><a class="toc" href="#correctness">7. Correctness Assurance Techniques</a>
+  <ul>
+    <li><a class="toc" href="#testing">7.1 Testing</a>
+    <ul>
+      <li><a class="toc" href="#regrtest">7.1.1 regrtest</a>
+      <li><a class="toc" href="#minimization">7.1.2 Minimization</a>
+      <li><a class="toc" href="#builtin_functions">7.1.3 Built-in Testing Functions</a>
+      <li><a class="toc" href="#large_packages">7.1.4 Running Elsa on large software packages</a>
+    </ul>
+    <li><a class="toc" href="#debugging">7.2 Debugging</a>
+    <ul>
+      <li><a class="toc" href="#tracing_flags">7.2.1 Tracing Flags</a>
+      <li><a class="toc" href="#data_print">7.2.2 Data structure print routines</a>
+    </ul>
+    <li><a class="toc" href="#documentation">7.3 Documentation</a>
+    <ul>
+      <li><a class="toc" href="#doc_external">7.3.1 External Documentation</a>
+      <li><a class="toc" href="#doc_internal">7.3.2 Internal Documentation</a>
+      <li><a class="toc" href="#doc_doxygen">7.3.3 Why I don't use Documentation Generators</a>
+    </ul>
+    <li><a class="toc" href="#assertions">7.4 Assertions</a>
+    <li><a class="toc" href="#invalid_input">7.5 Invalid C++</a>
+  </ul>
+</ul>
+<!-- END CONTENTS -->
+
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<a name="lexing"></a>
+<h1>1. Lexing</h1>
+
+<p>Lexing (a.k.a. scanning) is the process of partitioning a flat sequence
+of characters into a sequence of <em>tokens</em>.  In addition to being a
+partition, the tokens represent <em>classifications</em> of the partitions:
+the character sequence "123" might be called an "integer literal", and the
+sequence "abc" an "identifier".  The Lexer discards comments and whitespace
+(rather than passing them on to the parser).
+
+<a name="lexer_build"></a>
+<h2>1.1 Lexer Build Process</h2>
+
+<p>As mentioned above, much of the Elsa design involves extension mechanisms,
+and the Lexer is no exception.  A base description is combined with one or
+more extension descriptions to arrive at the full lexical language:
+
+<p><center><img src="lexer_build.png" alt="Elsa Lexer Build Process"></center>
+
+<p>
+Above, solid lines indicate direct flow, and dashed lines indicate where
+one file is <tt>#included</tt> by another (i.e. both directly flow into
+a program further down but not shown).  Files are shown in ellipses and
+programs are shown in rectangles.
+
+<p><a href="../cc.lex">cc.lex</a> is the base lexer description.  It
+is written in the <a href="http://www.gnu.org/software/flex/manual/html_chapter/flex_toc.html">Flex</a>
+language.  <a href="../gnu.lex">gnu.lex</a> is an extension lexer description;
+it contains definitions for GNU and C99-specific lexical elements.  These two
+descriptions are combined with <a href="../merge-lexer-exts.pl">merge-lexer-exts.pl</a>
+to produce <a href="../lexer.lex">lexer.lex</a>.
+lexer.lex is subsequently read by Flex to generate
+<a href="../lexer.yy.cc">lexer.yy.cc</a>, a C++ module that does the
+actual scanning.
+
+<p><b>Build process invariant:</b> Any time a script or tool produces a
+text file, the build process marks it read-only.  This makes it harder to
+accidentally edit a file that is automatically generated.  Thus, all the
+files in the diagram above that are the output of a rectangle are marked
+read-only.
+
+<p>Unlike <a href="http://www.gnu.org/software/bison/manual/html_node/index.html">Bison</a>,
+<a href="../../elkhound/index.html">Elkhound</a>
+does not automatically choose the mapping from lexer token codes
+(like "4") to conceptual lexical elements (like "integer literal").  So the
+Elsa build process uses a script called
+<a href="../make-token-files">make-token-files</a> to assign the mapping.
+It uses the token descriptions supplied by
+<a href="../cc_tokens.tok">cc_tokens.tok</a> and
+<a href="../gnu_ext.tok">gnu_ext.tok</a>.
+
+
+<a name="lexer_design"></a>
+<h2>1.2 Lexer Design</h2>
+
+<p>
+<a href="../lexer.lex">lexer.lex</a> specifies how to partition the input
+characters into tokens.  Most of the actions are straightforward.  One
+tricky point is the notion of "separating tokens" and "nonseparation tokens",
+which is explained at the top of <a href="../lexer.cc">lexer.cc</a>.
+Another is that "<tt>#line</tt>" directives are handled by recording them
+with the <a href="../../smbase/hashline.h">hashline</a> module, which
+can then be used to map a raw input source location to a the location designed
+by the <tt>#line</tt> directives.
+
+<p>
+The <a href="../baselexer.h">baselexer</a> module is responsible for
+coordinating the activity of a Flex lexer and an Elkhound parser.  It
+inherits from LexerInterface (<a
+href="../../elkhound/lexerint.h">lexerint.h</a>), which defines three
+fields (<span class="variable">type</span>, <span
+class="variable">sval</span>, and <span class="variable">loc</span>) that the Elkhound
+parser reads.  BaseLexer updates these fields during lexing according
+to what the lexer actions do.
+
+<p>
+BaseLexer is extended by the <a href="../lexer.h">lexer</a> module,
+which defines the Lexer class, which contains the methods that the
+lexer actions invoke.
+
+<p>
+If you would like to see the results of just lexing an input file, the
+<span class="program">tlexer</span> program (<a href="../tlexer.cc">tlexer.cc</a>) will
+read in a preprocessed C/C++ source file and print out the sequence of
+tokens that would be yielded to the parser.
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<a name="parsing"></a>
+<h1>2. Parsing</h1>
+
+<p>
+Parsing is the process of converting a token stream into an Abstract
+Syntax Tree (AST).  In Elsa, the AST produced by the parser is not
+necessarily a tree at all, but a Directed Acyclic Graph (DAG) in
+general, because of ambiguities.  However, we still call it an AST.
+
+
+<a name="parser_build"></a>
+<h2>2.1 Parser Build Process</h2>
+
+<p>
+The parser is written in a mixture of <a
+href="../../elkhound/index.html">Elkhound</a> and C++; the Elkhound
+language defines how terminals, nonterminals and productions are
+defined, while the reduction actions associated with the productions
+are written in C++.  The parser description is a combination of three
+files:
+<ul>
+<li><a href="../cc_tokens.ids">cc_tokens.ids</a>: assigns token codes
+    (automatically produced, as described above)
+<li><a href="../cc.gr">cc.gr</a>: base C++ grammar
+<li><a href="../gnu.gr">gnu.gr</a>: extensions for gcc and C99
+</ul>
+
+<p>
+<center><img src="parser_build.png" alt="Elsa Parser Build Process"></center>
+
+<p>
+There are three output files from Elkhound:
+<ul>
+<li><a href="../cc.gr.gen.h">cc.gr.gen.h</a>: declares the CCParse class,
+    which has the parser entry point, among other things
+<li><a href="../cc.gr.gen.cc">cc.gr.gen.cc</a>: contains definitions of
+    CCParse methods, including all of the reduction actions
+<li><a href="../cc.gr.gen.out">cc.gr.gen.out</a>: exhaustive description of
+    the parsing DFA; mostly of use when debugging shift/reduce conflicts
+    (not necessary with Elkhound, but sometimes can improve performance)
+</ul>
+
+
+<a name="ast_build"></a>
+<h2>2.2 AST Build Process</h2>
+
+<p>
+The AST is described by a language that is input to the
+<a href="../../ast/index.html">astgen</a> tool.  The description is
+comprised of several files:
+<ul>
+<li><a href="../cc.ast">cc.ast</a>: base C++ language AST
+<li><a href="../cc_tcheck.ast">cc_tcheck.ast</a>: declares AST node methods
+    and annotation fields for use by the type checker
+<li><a href="../cc_print.ast">cc_print.ast</a>: methods for pretty printing
+<li><a href="../cc_elaborate.ast">cc_elaborate.ast</a>: elaboration methods
+<li><a href="../gnu.ast">gnu.ast</a>: gcc and C99 extensions to the language AST
+<li><a href="../cfg.ast">cfg.ast</a>: methods for computing a control flow graph
+    at the statement granularity (<a href="../cfg.h">cfg</a> module)
+</ul>
+
+<p>
+<center><img src="ast_build.png" alt="Elsa AST Build Process"></center>
+
+<p>
+The output files are:
+<ul>
+<li><a href="../cc.ast.gen.h">cc.ast.gen.h</a>: contains C++ class declarations
+    for all of the AST nodes
+<li><a href="../cc.ast.gen.cc">cc.ast.gen.cc</a>: definitions of the methods of
+    the AST node classes
+</ul>
+
+
+<a name="parser_actions"></a>
+<h2>2.3 Parser Actions</h2>
+
+<p>
+Most of the parser actions are straightfoward: combine the AST elements
+that comprise the production right-hand side (RHS) into a single AST
+element that represents the left-hand side (LHS).
+
+<p>
+Two issues are explained at the top of <a href="../cc.gr">cc.gr</a> are
+the various source of names, and handling of destructive actions.
+
+<p>
+Most instances of syntactic ambiguity are handled by using the <span
+class="variable">ambiguity</span> fields of certain AST nodes to
+explicitly represent the different alternatives.  The type checker
+then has the responsibility for picking one alternative.  For example,
+the ambiguous syntax "<tt>return (x)(y);</tt>" would be represented as
+shown in the following diagram, where the cast interpretation
+"<tt>return (x)y;</tt>" is shown in green, and the function call
+interpretation "<tt>return x(y);</tt>" is shown in purple.  Note that
+the nodes for "<tt>x</tt>" and "<tt>y</tt>" are shared by both
+interpretations.
+
+<center><img src="ambiguous_ast.png" alt="Ambiguous AST Example"></center>
+
+<p>
+A few instances of ambiguity are handled at parse time, rather than
+deferring to the type checker as in the diagram above.  This is done
+by writing <span class="variable">keep</span> functions that cancel a
+reduction if it can be determined that the syntax giving rise to the
+reduction has another (better) interpretation.  For example, there is
+an ambiguity in template parameters because "&lt;class T&gt;" could be
+a type parameter called "T", or it could be a non-type parameter of
+(existing) type "class T" but with no parameter name.  As the Standard
+specifies that this is always a type parameter, the reduction for
+non-type parameters cancels itself if the type is like "class T" (see
+the <tt>TemplateParameter -&gt; ParameterDeclaration</tt> reduction
+and the associated <span class="variable">keep</span> function
+in <a href="../cc.gr">cc.gr</a>).
+
+<p>The tracing flag "printAST" to <span class="program">ccparse</span>
+will print the (possibly ambiguous) AST as it exists before type
+checking.
+
+<p>The tracing flag "parseTree" will print the full parse tree.  The
+parse tree shows the structure of reduction action calls by replacing
+every reduction action with one that builds a generic parse tree node
+out of its subtrees.  This is useful for debugging ambiguities, since
+it shows exactly what happens in the parser, without interference from
+the actual reduction actions.
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<a name="typechecking"></a>
+<h1>3. Type Checking</h1>
+
+<p>The type checker (<a href="../cc_tcheck.cc">cc_tcheck.cc</a>) does
+five major jobs:
+<ul>
+  <li><a class="toc" href="#disambiguation">3.1 AST disambiguation</a>
+  <li><a class="toc" href="#lookup">3.2 Variable lookup</a>
+  <li><a class="toc" href="#type_annotation">3.3 Type Annotation</a>
+  <li><a class="toc" href="#implicit_conversions">3.4 Insertion of Implicit Conversions</a>
+  <li><a class="toc" href="#templates">3.5 Templates</a>
+</ul>
+
+<p>The fundamental data structure on which the type checker does its
+work is the AST, documented in <a href="cc.ast.html">cc.ast.html</a>.
+
+<p>The tracing flag "printTypedAST" will print the AST after type
+checking.
+
+<a name="disambiguation"></a>
+<h2>3.1 AST disambiguation</h2>
+
+<p>
+AST disambiguation means choosing a single interpretation for AST
+nodes that have more than one (i.e. a non-NULL <span
+class="variable">ambiguity</span> field).  Then, the surrounding AST
+nodes are modified to reflect the chosen choice and forget about the
+others.  The tracing flag "disamb" will report disambiguation
+activity.
+
+<p>
+Most disambiguation is done by the generic ambiguity resolver,
+in <a href="../generic_amb.h">generic_amb.h</a>.  The
+<span class="variable">resolveAmbiguity</span> function simply
+invokes the type checker recursively on each alternative by
+invoking the <span class="variable">mid_tcheck</span> method.
+If exactly one alternative successfully type-checks (i.e. does not
+report any errors), then that alternative is selected.  The
+<span class="variable">ambiguity</span> link for the selected
+node is nullified, and the selected node returned so the caller
+can update its AST pointer accordingly.  It is an error if more
+or less than one alternative type-checks.
+
+<p>
+As recursive type checking can sometimes involve doing computations
+unrelated to the disambiguation, such as template instantiation,
+at certain points the type checker uses the
+<span class="variable">InstantiationContextIsolator</span> class
+(<a href="../cc_env.h">cc_env.h</a>) to isolate those computations.
+They will only be done once (regardless of how many times they
+occur in ambiguous alternatives), and any errors generated are
+<em>not</em> considered by the ambiguity resolver.
+
+<p>
+Not every ambiguous situation will be resolved by the generic
+resolver.  In particular, there is a very common ambiguity between
+<span class="variable">E_funCall</span> and <span
+class="variable">E_constructor</span>, since the parser can almost
+never tell when the "<tt>f</tt>" in "<tt>f(1,2,3)</tt>" is a type or a
+function.  If the generic procedure were used, this would lead to
+exponential type checking time for expressions like
+"<tt>f1(f2(f3(...(fN())...)))</tt>".  Since this disambiguation choice
+depends only on the function/type and not the arguments, <span
+class="variable">Expression::tcheck</span> explicitly checks for this
+case and then just checks the first component by invoking the <span
+class="variable">inner1_tcheck</span> method.  Once the selection is
+made, <span class="variable">inner2_tcheck</span> is invoked to finish
+checking th argument list.
+
+<p>
+There are a few other ad-hoc disambiguation strategies here and 
+there, such as for deciding between statements and declarations, and
+resolving uses of implicit int (when K&amp;R support is enabled).
+
+
+<a name="lookup"></a>
+<h2>3.2 Variable lookup</h2>
+
+<p>
+Declared entities are represented by Variable objects
+(<a href="../variable.h">variable.h</a>).  In general, lookup is
+the process of mapping a name (which is a string of characters)
+and a context (scopes, etc.) to a Variable.  AST nodes that
+contain names subject to lookup, such as
+<span class="variable">E_variable</span> or 
+<span class="variable">E_fieldAcc</span>, contain
+a <span class="variable">var</span> field.  The
+<span class="variable">var</span> field is initially NULL, and
+the type checker sets it to some non-NULL value once it figures
+out which Variable the name refers to.
+
+<p>
+Though the C++ standard in principle gives all of the rules for
+exactly how lookup should be performed, in practice it can be
+difficult to map those rules into an implementation.  The auxilliary
+document <a href="lookup.txt">lookup.txt</a> explains how the
+rules in the standard are implemented in Elsa.
+
+<a name="lookup_variables"></a>
+<h3>3.2.1 Variables</h3>
+
+<p>
+There are many kinds of entities represented by Variables, as shown in
+the following diagram.  The rectangles and arrows represent a kind of 
+inheritance hierarchy; e.g., a Class is one of the type-denoting
+Variables (note that this is only conceptual inheritance; in the
+implementation, there is just one class called Variable).  The ellipses
+are data fields attached to Variables.
+
+<center><img src="variables.png" alt="Kinds of Variables"></center>
+
+<p>
+On the left half of the diagram are names corresponding to types, and
+on the right half are non-type entities.  Types are introduced by a
+<tt>typedef</tt> or by a class declaration.  Non-types are introduced
+by a variable declaration, or a function prototype or definition.  A
+few oddballs, such as enumerators and namespaces, round out the set.
+The neighborhoods of the class and function template boxes are
+expanded in a later diagram, below.
+
+<p>                                            
+Every Variable has a name (but it might be NULL), a type (only NULL
+for namespaces), and some flags.  The name is how the entity is found
+by lookup.  The type is either the denoted type (for type entities) or
+the type of the variable (for non-types).  The flags say what kind of
+entity a given Variable is; by interrogating the flags, one can
+determine (for any given Variable object) to which box in the diagram
+it belongs.
+
+<p>
+It may seem odd that so many kinds of entities are represented with
+the same Variable class.  The reason is that all of these entities are
+<em>looked up</em> in the same way, and all of these entities' names
+hide each other (when scopes are nested), so the Variable is the
+fundamental element of a Scope (<a
+href="../cc_scope.h">cc_scope.h</a>).  The word "name" in quotes
+suggests this connection, as all of these entities correspond to what
+the C++ Standard simply calls a "name".
+
+<a name="overload_resolution"></a>
+<h3>3.2.2 Overload Resolution</h3>
+
+<p>
+In C++, function names and operators can be <em>overloaded</em>,
+meaning there is more than one entity with a given name.  The name is
+mapped to an entity by considering the context in which it is used:
+for a function call, the argument types determine the overloaded
+entity; when taking the address of a function, the type of the
+variable receiving the address determines which entity has its address
+taken; etc.
+
+<p>
+Elsa represents overload sets by having a single representative
+Variable contain a linked list, the contents of which are the overload
+set (including the representative itself).  Initially, typechecking an <span
+class="variable">E_variable</span> or <span
+class="variable">E_fieldAcc</span> that refers to an overloaded name
+will set the node's <span class="variable">var</span> field to point
+at the set representative.  Later, it uses the
+call site arguments to pick the correct entity.  Then, the
+<span class="variable">E_variable</span> or
+<span class="variable">E_fieldAcc</span> node's
+<span class="variable">var</span> field is modified so that it
+points directly at the chosen element.  
+
+<p>
+At the moment, there is no way to distinguish between a Variable
+object denoting an overloaded set, and a Variable object denoting just
+the specific entity that happens to be the set representative, so this
+distinction must be inferred by context (i.e. before overload
+resolution has occurred, or after it).  This design might be changed
+at some point.
+
+<p>
+When Elsa finds that an operator is overloaded, it again uses the
+arguments to select the proper operator.  If the selected operator
+is a built-in operator, the (say) <span class="variable">E_binary</span>
+node is left alone.  But if a user-defined operator is chosen, then
+the node is changed into an <span class="variable">E_funCall</span> to
+reflect that, semantically, a function call occurs at that point.
+One way to observe this change is to pretty-print the AST (see
+<a href="#prettyprint">pretty printing</a>).
+
+
+<a name="type_annotation"></a>
+<h2>3.3 Type Annotation</h2>
+
+<p>
+Expressions (and a few other nodes) have a type associated with them.
+The type checker computes this type, and stores it in the
+<span class="variable">type</span> field of the node.
+
+<p>
+Types themselves have internal structure, which is explained in
+<a href="cc_type.html">cc_type.html</a>.
+
+
+<a name="implicit_conversions"></a>
+<h2>3.4 Insertion of Implicit Conversions</h2>
+
+<p>
+When an object is (say) passed as an argument to a function, depending
+on the types of the argument and parameter, an <em>implicit
+conversion</em> may be required to make the argument compatible with
+the parameter.  This determination is made by the <a
+href="../implconv.h">implconv</a> module.  Among the kinds of implicit
+conversions there are <em>user-defined conversions</em>, conversions
+accomplished by calling a user-defined function.  When Elsa finds that
+user-defined conversion is required, it modifies the AST to reflect
+the use of the conversion function, as if it had been written
+explicitly.
+
+<p>
+<b>Bug</b>: While Elsa currently (2005-05-29) does all the necessary
+computation to determine if a user-defined conversion is needed, in
+some cases it fails to rewrite the AST accordingly.  This will be
+fixed at some point (hopefully soon).
+
+
+<a name="templates"></a>
+<h2>3.5 Templates</h2>
+
+<p>
+Elsa does template instantiation for three reasons.  First,
+instantiation of template class declarations is required in order to
+disambiguate the AST, since a template class member can be either
+a type or a variable name, and that affects how a use of that name
+is parsed.  
+      
+<p>
+Second, instantiation is required to do annotation such as for
+expression types, since the type of an expression involving a member
+of a template class is dependent on that template class's definition.
+
+<p>
+Finally, instantiation of function templates (including members of
+class templates) lets analyses ignore the template (polymorphic)
+definitions and concentrate on the (monomorphic) instantiations, which
+are usually easier to analyze.
+
+<a name="template_representation"></a>
+<h3>3.5.1 Template Representation</h3>
+
+<p>
+Function templates are represented with a Variable (<a
+href="../variable.h">variable.h</a>) to stand for the function
+template, and an associated TemplateInfo (<a
+href="../template.h">template.h</a>) structure to remember the
+template parameters (including default arguments), and any
+instantiations that have been created.
+
+<p>
+The TemplateInfo class acts as an extension of the Variable class;
+every TemplateInfo is associated with a unique Variable.  It would
+have been possible to make TemplateInfo actually inherit from
+Variable, and at some point the design may be changed to do just that.
+
+<p>
+In the following diagram, rectangles represent (separate) objects that
+exist at run-time, and arrows represent pointers among those objects.
+An ellipse overlapping several arrows represents a list of pointers.
+
+<center><img src="function_templates.png" alt="Function Template Representation"></center>
+
+<p>
+Class templates are also represented by a Variable/TemplateInfo
+pair.  The wrinkle is that template classes can have
+<em>partial specializations</em>, user-provided classes for use
+when the template arguments match some given pattern (for example, a generic
+<tt>Vector</tt> template might have a partial specialization for
+<tt>Vector&lt;T*&gt;</tt> that uses a more efficient representation):
+
+<center><img src="class_templates.png" alt="Class Template Representation"></center>
+
+<a name="template_instantiation"></a>
+<h3>3.5.2 Template Instantiation</h3>
+
+<p>
+Function templates are instantiated as soon as a definition and a use
+(the use supplying the template arguments) have been seen.  This is
+done by calling <span
+class="variable">Env::instantiateFunctionTemplate</span>
+(<a href="../template.cc">template.cc</a>), which
+returns a Variable/TemplateInfo pair that represents the
+instantiation.  If the instantiation has already been made, the
+existing one is returned.  If not, the template definition AST is
+<em>cloned</em> (deeply copied), the template parameters are bound to
+their arguments, and the entire definition re-type-checked.
+
+<p>
+Class templates are instantiated as soon as a use is seen; a program
+is ill-formed if a definition has not been seen by the time of first
+use.  Instantiation is done by calling
+<span class="variable">Env::instantiateClassTemplate</span>
+(<a href="../template.cc">template.cc</a>).  As above, if the
+instantiation already exists, it is re-used; otherwise the template
+definition is cloned and re-type-checked.
+
+<p>
+Function members of class templates are <em>not</em> instantiated
+until a use of the member is seen.  For members whose definition appears
+"inline" in the class body, the 
+<span class="variable">MR_func::f</span> field points at the
+<em>uninstantiated</em> template body.  The body will be cloned
+and type-checked only when it is instantiated.  One consequence of this
+design is that analyses (usually) need to avoid looking at such uninstantiated
+members; one way to do this is by using 
+<span class="variable">ASTTemplVisitor</span> 
+(<a href="../cc_ast_aux.h">cc_ast_aux</a>) to do the traversal, as it
+automatically skips such methods.
+
+<a name="dependent_names"></a>
+<h3>3.5.3 Dependent Types and Names</h3>
+
+<p>
+The C++ Standard has fairly elaborate rules for deciding when a type
+or a name in a template definition is <em>dependent</em> on the
+template parameters.  Furthermore, it specifies that names and types
+that are <em>not</em> dependent <em>must</em> be looked up in the
+context of the original template definition, <em>not</em> the
+instantiation context (as is the case for dependent names).
+
+<p>
+To implement this (and to disambiguate template definition ASTs), Elsa
+type-checks function template definitions in advance of any instantiation.
+A dependent type is represented by the
+<span class="variable">ST_DEPENDENT</span> pseudo-type
+(see <span class="variable">enum SimpleTypeId</span> in
+<a href="../cc_flags.h">cc_flags.h</a>).
+
+<p>
+Furthermore, while type checking the template definition, if a name
+lookup is determined to not be dependent, the
+<span class="variable">nondependentVar</span> field is set to the
+same thing as the
+<span class="variable">var</span> field (both are fields of AST nodes
+that have names subject to lookup).  Later, when an instantiation
+is created, the <span class="variable">nondependentVar</span>
+value is preserved by cloning, and used instead of doing a new lookup,
+if it is not NULL.
+
+<p>
+When a class template instantiation is requested but one or more
+arguments is dependent, a
+<span class="variable">PseudoInstantiation</span> type
+(<a href="../template.h">template.h</a>) is created.  This is more
+precise than simply yielding
+<span class="variable">ST_DEPENDENT</span>, and that precision is
+necessary in some cases, and much cleaner than doing a full
+"instantiation" with incomplete information.
+
+<p>
+Similarly, when type checking a template definition, the template
+type parameters are bound to (unique) instances of
+<span class="variable">TypeVariable</span>
+(<a href="../template.h">template.h</a>) objects.
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<a name="elaboration_cdtors"></a>
+<h1>4. Elaboration of constructors and destructors</h1>
+
+Constructors and destructors: 
+<ul>
+
+<li> A struct/class with no ctor gets a no arg ctor that calls the no
+arg ctor of its members and superclasses.
+
+<li> A struct/class with no copy ctor gets a one arg copy ctor that
+calls the copy ctor for its members and superclasses.
+
+<li> A struct/class with no copy assignment operator gets a one arg
+copy assignment operator that calls the copy assignment operator for
+its members and superclasses.
+
+<li> A struct/class with no dtor gets a dtor that calls the dtor for
+its members and superclasses.
+
+</ul>
+
+<span class="todo">Add more info about this stage.</span>
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<a name="post_processing"></a>
+<h1>5. Post-processing</h1>
+
+<p>Elsa will perform various forms of post-processing on request.
+
+<p>Tracing flag "printHierarchies" will print inheritance
+hierarchies in Dot format. Interesting in that virtual inheritance is
+represented properly; for example <a href="in/std/3.4.5.cc">in/std/3.4.5.cc</a>
+yields <a href="gendoc/3.4.5.png">3.4.5.png</a>.
+
+<a name="prettyprint"></a>
+<p>Tracing flag "prettyPrint" will print out the AST as C++.  One use
+of this feature is to do some analysis on the source code, then print it
+out with analysis results intermixed as annotations that can then be
+fed to another analysis tool.  <b>Bug:</b> (2005-05-29) Not all C++ 
+constructs are correctly printed yet.
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<a name="extension"></a>
+<h1>6. Extension Mechanisms</h1>
+
+<p>
+Each phase of Elsa has some degree of support for extensions, as
+documented in this section.
+
+<p>
+First, let me distinguish <em>compile-time</em> extensions
+from <em>run-time</em> extensions.  Compile-time extensions let a
+programmer add new features to a program without having to modify that
+program's original source code; but the program must be recompiled
+(possibly with an altered build process) to incorporate those
+extensions.  In contrast, run-time extensions can be added by an
+end-user without recompilation; browser plugins are an example.
+
+<p>
+While Elsa does have a few run-time extension mechanisms such as the
+TypeFactory, the majority are compile-time mechanisms.  The rationale
+is that I can support a much wider range of extensions that way, and
+given that Elsa is more or less intended to be research infrastructure,
+there is no compelling reason for run-time extensibility.
+Note that the <a href="http://opencxx.sourceforge.net/">OpenC++</a>
+parser <em>is</em> designed for run-time extensibility.
+
+<p>
+In the limit, one need not explicitly design for compile-time
+extensibility at all, since programmers could simply write their
+extensions as patch files, and let <tt>patch</tt> incorporate them.
+However, this would be far from ideal, since patch files are fragile
+in the face of changes to the underlying source, and the toolchain
+(compiler error messages, source-level debuggers) would be unaware of
+them.  So the general Elsa strategy is to design ways that programmers
+can write extensions with the following properties:
+<ul>
+<li>Self-contained.  An extension should mostly make sense
+    in isolation.  (Contrast with a context diff, which contains pieces
+    of the code into which the changes are inserted.)
+<li>Robust.  If the artifact that is being extended is changed, the
+    extension should continue to work (within reason).
+<li>Toolchain-aware.  When an extension causes a compiler error message,
+    or a debugger steps into code added by an extension, the tool should
+    refer to the extension source itself, rather than an intermediate
+    file generated by combining the original with extensions.
+<li>Powerful.  Extensions should have the power to effect almost any
+    change to the original, such that programmers never need to make
+    direct changes to the original.
+<li>Separate.  The base Elsa system should not need to be aware of any
+    particular extension.  (Contrast with sprinkling Elsa with #ifdefs
+    for every extension, which otherwise meets the above criteria.)
+</ul>
+
+<p>
+Unfortunately, not every extension mechanism used in Elsa has all of these
+properties.  I will point out which properties hold below.
+
+<a name="ext_lexer"></a>
+<h2>6.1 Lexer Extensions</h2>
+
+<p>
+New token types can be added by creating a <tt>.tok</tt> file and
+arranging to feed it to the
+<a href="../make-token-files"><tt>make-token-files</tt></a> script.
+The effect of this is simply to define names and aliases for tokens,
+such that the lexer and parser can refer to them coherently.
+Flaws: not toolchain-aware.
+(Example: <a href="../gnu_ext.tok"><tt>gnu_ext.tok</tt></a>)
+
+<p>
+New lexical rules can be added by creating a <tt>.lex</tt> file
+and arranging to feed it to the
+<a href="../merge-lexer-exts.pl"><tt>merge-lexer-exts.pl</tt></a>
+script.  This script textually inserts the extension into a combined
+flex input file, with extensions coming before the original rules
+so as to be able to override them.  Flaws: not toolchain-aware,
+cannot delete origial rules (can leave spurious warnings).
+(Example: <a href="../gnu.lex"><tt>gnu.lex</tt></a>)
+
+<a name="ext_parser"></a>
+<h2>6.2 Parser Extensions</h2>
+
+<p>
+New syntactic constructs can be added by creating a <tt>.gr</tt> file
+and passing it on the <tt>elkhound</tt> command line.  The new grammar
+consists of the union of the productions from the original and the
+extension(s).  This is the cleanest of all the extension mechanisms,
+having all of the desired extension properties listed above.
+(Example: <a href="../gnu.gr"><tt>gnu.gr</tt></a>)
+
+<p>
+When new syntactic constructs are introduced, they typically need new
+AST nodes to represent them.  New AST nodes can be added by creating a
+<tt>.ast</tt> file and passing it on the <tt>astgen</tt> command line.
+The effective AST spec is the union of the base and all extensions.
+Flaws: <tt>astgen</tt> should emit #line directives that point into
+the respective <tt>.ast</tt> files (this is not a flaw with extension
+per se, but <tt>astgen</tt> in general).
+(Example: <a href="../gnu.ast"><tt>gnu.ast</tt></a>)
+
+<a name="ext_tcheck"></a>
+<h2>6.3 Type Checker Extensions</h2>
+
+<p>
+New Type classes can be added by creating new subclasses of AtomicType
+and Type (<a href="../cc_type.h"><tt>cc_type.h</tt></a>), and implementing 
+the appropriate virtual methods.  Operations on the new types can be defined 
+by creating a subclass of Env (<a href="../cc_env.h"><tt>cc_env.h</tt></a>)
+and overriding some of its methods.  Flaws: not very powerful; you can
+only change behaviors for which hooks are already provided.
+
+<p>
+Type checking for new AST nodes can be added simply by adding a new
+C++ source file that implements the <tt>tcheck</tt> methods for the
+new nodes.  Flaws: hard to do context-dependent behaviors.
+(Example: <a href="../gnu.cc"><tt>gnu.cc</tt></a>)
+
+<p>
+New fields and methods can be added to the Type superclass by replacing
+the definition of Type by defining the <tt>TYPE_CLASS_FILE</tt> macro.
+See <a href="cc_type.html#basetype">cc_type.html, Section 6</a> for 
+more information.  Flaws: can only change the Type class, not others.
+
+<p>
+Finally, the plan is to add a generic source code patcher that
+operates at a higher level and is more robust than <tt>patch</tt>.
+This would let users do things like rename functions, insert snippets
+of code into functions, add members to classes, etc.  However, that
+mechanism is still quite experimental and so not yet shipped with
+Elsa.  Flaws: vaporware.
+
+<a name="ext_elaboration"></a>
+<h2>6.4 Elaboration Extensions</h2>
+
+<p>
+Elaboration is done by the ElabVisitor class
+(<a href="../cc_elaborate.h"><tt>cc_elaborate.h</tt></a>), which
+could be extended with the usual inherit-and-override C++ idiom.
+See the next section for more information about visitors.
+
+<a name="ext_post"></a>
+<h2>6.5 Post-processing Extensions</h2>
+
+<p>
+Within Elsa, the intent is that users write new post-processing
+analyses and plug them in by simply copying and modifying
+<a href="../main.cc"><tt>main.cc</tt></a>.  This gives users
+maximal control over how an Elsa-based analysis interacts with
+the outside world.  Flaws: ad-hoc.
+
+<p>
+Alternatively, the <a href="http://www.cs.berkeley.edu/~dsw/oink.html">Oink</a>
+framework (based on Elsa) provides a more systematic architecture
+for integrating post-processing analyses, both with Elsa and with
+each other.  Flaws: analysis must fit into the framework.
+
+<p>
+For implementing an analysis, programmers are of course free to simply
+write a custom traversal similar to the type checker
+(<a href="../cc_tcheck.cc"><tt>cc_tcheck.cc</tt></a>).  However,
+for many analyses it is convenient to extend the ASTVisitor, a class
+created automatically by <tt>astgen</tt>.  A simple example is the
+NameChecker in <a href="../main.cc"><tt>main.cc</tt></a>, which does
+some simple processing at each Expression node.  Note that your visitor
+can traverse the full AST by inheriting from ASTVisitor, or traverse
+only the "lowered" AST (e.g., skipping templates and only looking at
+the instantiations) by inheriting from LoweredASTVisitor
+(<a href="../cc_ast_aux.h"><tt>cc_ast_aux.h</tt></a>).
+Flaws: visitors are simple, but make context dependence difficult
+to achieve.
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<a name="correctness"></a>
+<h1>7. Correctness Assurance Techniques</h1>
+
+<p>
+This section explains what policies and procedures are in place to try
+to ensure that Elsa is "correct", in the sense that it accepts valid
+C++ input code and produces an annotated, elaborated AST that
+accurately reflects the syntax and semantics of that code.
+
+<p>
+(I do not call this section "Quality Assurance" because I am talking
+about procedures followed by developers, rather than the processes
+and measurement techniques that might be used after the fact.)
+
+<p>
+Most of what is outlined here is standard practice, and the potential
+scope of "correctness assurance" is huge, so I'll try to confine this
+to things directly relevant to Elsa.
+
+<a name="testing"></a>
+<h2>7.1 Testing</h2>
+
+<!--
+testing
+
+  - regrtest
+    - general procedures
+    - every bug yields a new or enhanced testcase
+  - ERROR lines
+  - minimization
+  - special built-in testing functions
+  - running Elsa on large software packages
+-->
+
+<p>
+"Testing" is the process of searching for evidence of a defect.  The
+input to testing is a program, and the output is a testcase (for Elsa,
+a C++ input file) such that running the program with that testcase
+causes the program to demonstrably misbehave.
+
+<a name="regrtest"></a>
+<h3>7.1.1 regrtest</h3>
+
+<p>
+The central artifact of the Elsa testing effort is the
+<a href="../regrtest"><tt>regrtest</tt></a> ("regression test")
+script.  This script runs Elsa (via the <tt>ccparse</tt> driver
+program) on hundreds of input files, checking that it accepts the
+valid inputs and rejects the invalid ones.  In some cases there
+are known bugs in Elsa; corresponding inputs are marked with
+"failparse" (or similar), and <tt>regrtest</tt> expects Elsa to
+fail those tests.  It should be run before every commit.
+
+<p>
+Invalid inputs are handled by adding lines of the form
+<pre>
+  //ERROR(n): some-invalid-syntax
+</pre>
+to an otherwise valid input file, where <it>n</it> is a small
+integer like 1 or 2.  The <a href="../multitest.pl"><tt>multitest.pl</tt></a>
+script will run <tt>ccparse</tt> once on the valid input, then
+uncomment the ERROR lines and confirm that Elsa now rejects the
+input.  Note that the script requires that Elsa not segfault
+or abort (e.g., by failing an assertion); it must <em>cleanly</em>
+reject the invalid input.
+
+<p>
+Ideally, a <tt>regrtest</tt> testcase should have these properties:
+<ul>
+<li>Small: It should not take Elsa a long time to process the
+    testcase, because the total running time of <tt>regrtest</tt>
+    should be kept reasonably small, so that it remains convenient
+    to use.
+<li>Identifiable: Each testcase should be testing some specific
+    language feature or combination of features.  By inspecting
+    the testcase (including comments) it should be possible to
+    identify what is being tested.  This makes it easier to
+    debug Elsa when a particular test starts failing.  (It is fine
+    if a single testcase file tests many things, as long as each 
+    thing is itself identifiable.)
+<li>Unique: There should not be another testcase that tests the
+    exact same set of features.  Or if there is, the dominating test
+    should be testing them in a more complex setting, and come
+    <em>after</em> the dominated testcase in <tt>regrtest</tt> so
+    that the simple test has a chance to fail first.  This
+    helps to debug failing tests, and to keep the running time
+    of <tt>regrtest</tt> down.
+</ul>
+
+<p>
+Of course, these are not absolute rules, but they help to explain
+why we don't, say, put the entire preprocessed Mozilla codebase
+into <tt>regrtest</tt>.
+
+<p>
+Somewhat contradicting the above, at the end of <tt>regrtest</tt>
+there are several "big" tests.  These are included both as a sanity
+check to make sure Elsa can parse a few big things, and as a
+performance test.  However, if a bug in Elsa is revealed by one
+of these big tests, a minimized testcase should be added as well
+so that we are not unduly relying upon them.
+
+<p>
+Moreover, the general procedure is that no Elsa bug should be
+fixed without first adding a minimized testcase or extending
+an existing testcase.  This has several benefits:
+<ul>
+<li>It helps to clarify the nature of the problematic syntax.
+<li>It makes it much faster to test proposed fixes.
+<li>It ensures the bug won't be reintroduced at some point in the
+    future (this is the true meaning of "regression" tests).
+</ul>
+
+<a name="minimization"></a>
+<h3>7.1.2 Minimization</h3>
+
+<p>
+The Elsa developers rely heavily on the technique of <em>minimization</em>,
+which takes as input a testcase demonstrating an Elsa bug and produces as
+output a testcase that demonstrates the same bug but is as small as possible.
+This makes debugging easier and faster, and produces better testcases for
+inclusion in <tt>regrtest</tt>.
+
+<p>
+Typically, minimization is done with respect to two nominally opposing
+criteria:
+<ul>
+<li>The testcase should be <em>good</em>.  For example, gcc accepts it.
+    (Note that gcc-3 is a much better measure of goodness than gcc-2 for
+    this purpose.)
+<li>Elsa reports the testcase as <em>bad</em>.  For example, Elsa incorrectly
+    reports an error, or fails an assertion.
+</ul>
+
+<p>
+We have considerable support for automating the minimization process.
+The <a href="http://delta.tigris.org">Delta</a> tool will minimize an
+input with respect to arbitrary criteria, and the 
+<a href="../test-for-error"><tt>test-for-error</tt></a> script provides
+the good/bad criteria above.  The two are combined in the
+<a href="../run-delta-loop"><tt>run-delta-loop</tt></a> script.  These
+scripts may need to be modified to suit your particular use,
+or of course you can write your own.
+
+<p>
+Despite the automation, delta typically does not yield inputs that are
+adequately minimal.  Usually, I let delta make a first pass, then I
+simplify the testcase a bit (by hand) in ways that delta does not know
+how, let delta run again, then finish up by hand.  The goal here is to
+make it as easy as possible to <em>comprehend</em> the
+meaning/semantics of the testcase, so that the person trying to debug
+Elsa when that testcase fails has it as easy as possible.
+
+<p>
+There are several particular techniques that I have found useful when
+doing by-hand minimization after delta has done some work:
+<ul>
+<li>Remove unused corresponding parameters and arguments.
+<li>Use search+replace to eliminate typedefs.
+<li>Delete empty base classes (delta will often empty the class, but
+    cannot remove the reference in the base class list).
+<li>Simplify elements of the statement and expression language, for
+    example replacing "<tt>if (x) { foo(); }</tt>" with just "<tt>foo();</tt>".
+<li>If template instantiation is involved, use the "-tr template" tracing
+    flag to find out what is the <em>last</em> template instantiation
+    attempted before the failure.  Then, just put an explicit instantiation
+    request for that instantiation at the bottom of the file.  This often
+    lets me remove large amounts of code that just served to eventually
+    trigger a particular instantiation.
+</ul>
+
+<a name="builtin_functions"></a>
+<h3>7.1.3 Built-in Testing Functions</h3>
+
+<p>
+If all that Elsa were trying to do was recognize valid C++ and reject
+invalid C++, then the above techniques would be adequate.  However,
+Elsa is also trying to compute an internal representation of the input
+that accurately conveys its semantics.  For example, it computes the
+type of every expression in the program.  What if that type computation
+is incorrect?  It is sometimes possible to leverage a particular incorrect
+type computation such that it leads to spurious rejection, but doing so
+is ad-hoc and sometimes difficult.
+
+<p>
+Another approach would be to dump out the internal representation for
+a given source file and then compare that to a "known good" version of
+that dump.  The problem with this approach is it is fragile: if the
+dump format happens to change, all the known-good dumps have to either
+be modified by hand, or discarded and regenerated (possibly accidentally
+saving wrong output in the process, if there is an unnoticed bug).
+
+<p>
+The Elsa solution to the problem of testing internal computations is to
+<em>expose</em> them in the source syntax.  For example, to test that
+an expression's type is computed as expected, one can write
+(<a href="../in/t0228.cc"><tt>in/t0228.cc</tt></a>):
+<pre>
+  __checkType(sName, arr);
+</pre>
+and Elsa will test whether the types it gets for <tt>sName</tt> and
+<tt>arr</tt> are identical, and fail if they are not.
+
+<p>
+As a more interesting example, one can write
+(<a href="../in/t0117.cc"><tt>in/t0117.cc</tt></a>):
+<pre>
+  __getStandardConversion((Derived *)0, (Base const *)0, SC_PTR_CONV|SC_QUAL_CONV);
+</pre>
+and Elsa will attempt to convert <tt>Derived*</tt> to <tt>Base const *</tt>,
+and check that the conversion is a "pointer conversion" and a
+"qualification conversion" (terms defined in the C++ standard).
+
+<p>
+This approach ensures we can write robust tests for any feature, even those
+not directly connected to accepting or rejecting the input.
+The set of all such special functions is defined in the
+<tt>internalTestingHooks()</tt> function in
+<a href="../cc_tcheck.cc"><tt>cc_tcheck.cc</tt></a>.
+
+<a name="large_packages"></a>
+<h3>7.1.4 Running Elsa on large software packages</h3>
+
+<p>
+Typically, Elsa users want to use Elsa to parse some specific piece
+of software.  This requires some method for hooking into the build
+process to obtain all of the preprocessed input files.
+
+<p>
+One very simple method is to use the
+<a href="../test-parse-buildlog"><tt>test-parse-buildlog</tt></a>
+script.  Just build the package normally (say, with gcc), saving
+all of the output from <tt>make</tt> to a file.  Then this script
+will read that file and use it to generate the preprocessed source
+files one at a time, feeding each to <tt>ccparse</tt>.  This works
+pretty well if the goal is to ensure that Elsa can parse a given
+codebase.
+
+<p>
+However, it is not perfectly reliable (what if <tt>make</tt> is not
+echoing all of its commands, or if the package does not use
+<tt>make</tt> at all?), and it does not know how the translation units
+are assembled to form libraries and executables.  For that, we use the
+<a href="http://build-interceptor.tigris.org/">build interceptor</a>
+system.  This replaces the system compiler with a script that
+squirrels away the invocation history, which can then be reconstructed
+to get an accurate picture of how the project as a whole fits
+together.  (Note that build interception is something that a number of
+research groups have recently done.  You may want to google for some
+alternatives.)
+
+<p>
+When building a large package, keep in mind that a significant fraction
+of the preprocessed source will come from the headers of whatever
+compiler is used to do the preprocessing, and the choice of which
+headers to use can affect both Elsa's ability to parse the code and
+your analysis' ability to reason about the results.  There are a number
+of approaches:
+<ul>
+<li>Use the headers normally used to build the package, such as gcc-3
+    headers.  The disadvantage is they may be more complex than the
+    package really needs, unduly complicating parsing and analysis.
+<li>Use headers from an older compiler, such as gcc-2.  Most packages
+    will work with the older compiler, and those headers are much simpler.
+<li>Use a custom set of cut-down headers.  Elsa includes a few such
+    headers in the <a href="../include"><tt>elsa/include</tt></a>
+    directory, and those may serve as a useful starting point.
+<li>Do something completely independent, using something like
+    <a href="http://www.stlport.org/">STLport</a>.
+</ul>
+
+
+<a name="debugging"></a>
+<h2>7.2 Debugging</h2>
+
+<!--
+debugging
+
+  - tracing flags
+    - a good set of flags to start with
+  - toString(), gdb()
+-->
+
+<p>
+Debugging is the process of mapping from evidence of a defect back to
+the defect itself, such as an erroneous line of code.  Elsa has
+some features specifically designed to assist during debugging.
+
+<a name="tracing_flags"></a>
+<h3>7.2.1 Tracing Flags</h3>
+
+<p>
+A generalization of <tt>printf</tt>-debugging, tracing flags let
+the user control exactly what kind of information is printed, by
+associating each debugging output command with a flag that must
+be enabled for that output to be seen.  This is all implemented
+by the
+<a href="../../smbase/trace.html"><tt>trace</tt></a>
+module in 
+<a href="../../smbase/index.html">smbase</a>.
+
+<p>
+Though there are many tracing flags (grep for <tt>trace</tt> in the source
+to find some), there is a set of flags that have become my standard
+set of flags to use when debugging a minimized input file:
+<ul>
+
+<li><tt>error</tt>:
+    Print every error message that is added to the list of errors
+    in Env (<a href="../cc_env.h"><tt>cc_env.h</tt></a>).  This is useful
+    for seeing when a particular message is added.  Note that some
+    errors are added but never displayed, as part of disambiguation activity.
+
+<li><tt>overload</tt>:
+    Print details on the process of each overload resolution, such as
+    the argument types, candidate functions, argument conversions, etc.
+
+<li><tt>dependent</tt>:
+    Show information about non-dependent lookups in templates.
+
+<li><tt>template</tt>:
+    Show basic template-processing information, in particular the
+    instantiation activity.
+
+<li><tt>templateXfer</tt>:
+    This shows activities related to one of the most complex parts of
+    template instantiation, the transferring of template-ness from
+    members of templates to members of instantiations.
+
+<li><tt>topform</tt>:
+    Print a header for each toplevel form.  This helps to coordinate
+    the debugging output with the input syntax.
+
+<li><tt>matchtype</tt>:
+    Print the arguments and result of each call into the type matcher,
+    which is central to template argument deduction and template
+    declaration matching.
+
+<li><tt>templateParams</tt>:
+    Print activity related to adding and removing template parameters
+    to and from the scope stack, including the scope delegation
+    mechanism (a dirty hack).
+
+</ul>
+
+<p>
+To get these enabled automatically, I use a <tt>.gdbinit</tt> with
+the following contents (<tt>tmp2.cc</tt> is the filename I typically use for
+the testcase I'm currently working on):
+<pre>
+  file ccparse
+  set args -tr error,overload,dependent,template,templateXfer,topform,matchtype,templateParams tmp2.cc
+  set print static-members off
+  break main
+  break breaker
+  run
+</pre>
+
+<p>
+<b>Note:</b> Because they are rather expensive, none of the tracing
+flags do anything unless Elsa has been <tt>./configure</tt>d with the
+<tt>-debug</tt> switch.
+
+<a name="data_print"></a>
+<h3>7.2.2 Data structure print routines</h3>
+
+<p>
+While running Elsa in a debugger, it is often convenient to be able to
+print values of variables.  Of course, if the variable is a primitive
+type, then
+<pre>
+  (gdb) print x
+</pre>
+will suffice.  If <tt>x</tt> is not a primitive, then there is probably
+a routine that can be invoked to print it, typically one of the following
+forms:
+<pre>
+  (gdb) print toString(x)
+  (gdb) print x->toString()
+  (gdb) print x->asString()
+  (gdb) print x->gdb()
+</pre>
+There is some rationale for the inconsistency, but I don't feel like
+getting into all that here.  You will probably have to look at the
+declaration of the associated type to find out which to use.
+
+<a name="documentation"></a>
+<h2>7.3 Documentation</h2>
+
+<!--
+documentation
+
+  - external module docs
+  - in the code
+    - data member descriptions
+    - function descriptions
+    - paragraph style of coding
+    - references to the standard
+    - references to specific test cases
+  - why no doxygen
+-->
+
+<a name="doc_external"></a>
+<h3>7.3.1 External Documentation</h3>
+
+<p>
+The intent of the external documentation is to serve as something
+of a roadmap to Elsa, to inform programmers of where things are
+implemented and the assumptions behind those implementations.
+By "external", I mean "not in the source code".
+
+<p>
+Each of the four major components of Elsa
+(<a href="../../smbase/index.html">smbase</a>,
+<a href="../../ast/index.html">ast</a>,
+<a href="../../elkhound/index.html">elkhound</a> and
+<a href="../index.html">elsa</a>)
+has a page documenting it and containing a brief description
+of its modules.  They also have dependency diagrams to express
+some module interrelationships.
+
+<p>
+Further, some modules have their own documentation pages,
+such as <a href="cc_type.html">cc_type.html</a> and
+<a href="cc.ast.html">cc.ast.html</a>.  These pages explain
+high-level aspects of the module's design and interaction with
+other modules.  They are also linked from the index.html page
+of the component.
+
+<p>
+Finally, there are some documents (e.g., <a href="lookup.txt">lookup.txt</a>)
+that cut across modules, describing some or other C++ language
+feature and its implementation in Elsa.
+
+<a name="doc_internal"></a>
+<h3>7.3.2 Internal Documentation</h3>
+
+<p>
+The source code contains a great deal of documentation in the form of
+comments.  The comments are invaluable for quickly comprehending
+pieces of code.  I'd rather lose the code than the comments.
+
+<p>
+The following paragraphs explain some of the commenting style used
+(and to be used) in Elsa.  Perhaps I should make a separate style guide...
+
+<p>
+<b>Every data member of every class has a comment.</b>  There are no
+exceptions.  The data members are a shared API among all the code that
+can see them.  It is essential that the meaning and purpose of each
+data member be clearly stated next to its declaration.  Example:
+<pre>
+  // nesting level of disambiguation passes; 0 means not disambiguating;
+  // this is used for certain kinds of error reporting and suppression
+  int disambiguationNestingLevel;
+</pre>
+
+<p>
+<b>Most functions have a descriptive comment.</b>  The comment can be
+associated with the declaration or the definition, depending on whether
+most call sites are from outside or inside the module.  A function's
+comment should indicate the meaning of parameters and return values,
+and indicate the context in which it is called if that is relevant.
+Example:
+<pre>
+  // Remove all scopes that are inside 'bound' from 'scopes' and put them
+  // into 'dest' instead, in reverse order (to make it easy to undo).
+  void Env::removeScopesInside(ObjList&lt;Scope&gt; &amp;dest, Scope *bound)
+  { /*...*/ }
+</pre>
+
+<p>
+<b>Group statements into paragraphs.</b>  Long sequences of imperative
+code should be organized into small blocks ("paragraphs") of related functionality,
+with a comment at the start saying the intent of that block, and blocks
+separated by blank lines.  Example:
+<pre>
+  // connect tab A to slot B
+  Tab *a = assembly.getTabA();
+  Slot *b = widgetFoo.leftSlot;
+  a-&gt;insertInto(b);
+
+  // now fold it in half
+  Polygon p = assembly.bisection();
+  xassert(p.closed());
+  FoldManager::singleton()-&gt;fold(assembly, p);
+
+  // and queue for boxing
+  boxQueue.enqueue(assembly);
+</pre>
+
+<p>
+<b>Do not duplicate comments</b> for the same reason you do not
+duplicate code.  If you must copy code, and it contains a comment,
+delete the comment in the copy, possibly replacing it with something
+like "as above".
+
+<p>
+<b>Make liberal references to the standard.</b>  Pointers into the
+standard are very useful, for fairly obvious reasons.  On the other
+hand, do not quote large pieces of it, as that merely clutters the
+code.
+
+<p>
+<b>Make liberal references to the regression testcases.</b>  Most
+of the time, if a bug is fixed, a comment near the fix should mention
+the name of a testcase that demonstrates the bug.  This helps to
+understand the code, since it provides a concrete example, and it
+makes testing related modifications easier because you know to test
+against the named testcases first.
+
+<a name="doc_doxygen"></a>
+<h3>7.3.3 Why I don't use Documentation Generators</h3>
+
+<p>
+Given the above discussion of documentation, it is reasonable to
+ask why I do not advocate the use of "documentation generators"
+such as <a href="http://www.stack.nl/~dimitri/doxygen/">doxygen</a>.
+The main reason is I prefer not to have extra layers between
+the artifact I edit and the artifact I read.  Extra layers mean more
+work to map across them, and they make it less likely that the
+documentation will be consulted and updated.
+
+<p>
+For documenting detailed behavior of the code, having the
+documentation right in the code means it is immediately available,
+and easy to update.  For those times when I want to use special
+formatting or hyperlinks, I write a comment pointing at one of the
+separate HTML documents and put the formatting there.
+
+<p>
+For documenting archtecture-level behavior, a separate HTML file like
+this document works well.  I wouldn't want this to be a great big
+doxygen comment.  Nor do I want to use any of the latex-to-HTML
+translators, again for the reason of not wanting to introduce layers.
+I expect most people would read documentation like this in their
+web browser, not on paper, so producing postscript is not much benefit.
+
+<p>
+Finally, I feel that documentation generators can often be a
+distracting influence, as programmers can begin to act as if
+all that is needed to adequately document their code is to provide
+(say) doxygen attributes X, Y and Z; when in fact, the essence of
+good documentation is <em>communication</em> and <em>substance</em>,
+not form.  
+
+
+<a name="assertions"></a>
+<h2>7.4 Assertions</h2>
+
+<!--
+assertions
+
+  - rationale: ensure bugs have small witnesses
+  - xassert, xassertdb
+  - put a comment if the rationale for an assertion is not obvious
+-->
+
+<p>
+I am a believer in assertions.  Their primary value is as part
+of the specification of the program, providing a formal language
+for codifying programmer assumptions.
+
+<p>
+Additionally, the run-time checking implied by an assertion serves to
+aid testing and debugging by helping to ensure that <em>bugs have
+small witnesses</em>.  That is, given a particular bug in the program,
+the size of the input testcase required to demonstrate that bug is
+smaller when the program contains good assertions, and larger when it
+does not, because a failed assertion is an early manifestation of the
+defect.  By reducing the size of the input required to witness a bug,
+a given level of testing effort will find more bugs, and make the
+program consequently more reliable.
+
+<p>
+When an assertion is added to the code, if it is not obvious from
+inspection of the surrounding code why the condition should be true,
+add a comment explaining it.  Someday your assertion <em>will</em>
+fail, and when it does, you want to help the person who will have
+to figure out what has gone wrong and that the impact of that is.
+Example:
+<pre>
+  xassert(secondLast->qualifier);   // grammar should ensure this
+</pre>
+
+<p>
+Within elsa, there are three main assertion-related functions,
+defined in <a href="../../smbase/xassert.h">xassert.h</a>:
+<ul>
+<li><tt>xassert(cond)</tt>: Each time it is encountered, <tt>cond</tt> is
+evaluated.  If <tt>cond</tt> is false, the <tt>x_assert</tt> assertion
+(<a href="../../smbase/exc.h">exc.h</a>) is thrown.  Normally, this
+exception is only caught by <tt>main()</tt>, so it is similar to the
+C library's <tt>assert</tt>, which calls <tt>abort()</tt>.  However,
+in Elsa's <tt>ccparse</tt> driver program, a exception handler prints out
+the current location stack before aborting, often giving a clue as to
+what has caused the failure.
+
+<li><tt>xassertdb(cond)</tt>: This is like <tt>xassert</tt>, except it
+is compiled away if <TT>NDEBUG</TT> is defined.  It is used for checks
+that may significantly affect performance.
+
+<li><tt>xfailure(msg)</tt>: This is always throws <tt>x_assert</tt>,
+with the given message.  It is often used in code paths that are
+believed to not be reachable.
+</ul>
+
+
+<a name="invalid_input"></a>
+<h2>7.5 Invalid C++</h2>
+
+<!--
+attempts to reject invalid code
+
+  - role in finding Elsa bugs faster
+  - replicating other compilers' bugs
+-->
+
+<p>
+As mentioned at the top of this document, Elsa does not try to reject
+every invalid C++ program.  We tacitly assume that the programs Elsa
+is asked to parse are <em>already</em> accepted by some C++ compiler,
+which hopefully enforces the language.  However, enforcing some of the
+language's rules can help to expose bugs.
+
+<p>
+Anecdote: For a long time, Elsa would only try to convert argument
+types to parameter types if the function being invoked was overloaded.
+Checking the conversions is of course necessary to do overload
+resolution, but if the function is not overloaded then I figured it
+wasn't necessary.  But the effect of this was that bugs in the type
+computation logic would only be revealed in circumstances where overloading
+was involved, meaning the testcases were complicated.  When I went ahead
+and implemented checking for all function calls, at first there were a
+bunch of bugs that were revealed and had to be fixed, but from then on
+type computation bugs tended to have very simple witnesses, making it
+fairly easy to fix them.  Lesson learned.
+
+<p>
+But to the extent Elsa does try to enforce the rules of the language,
+there is another problem: sometimes it properly rejects inputs that
+another compiler mistakenly accepts!  In that case we may need to add
+a flag to CCLang (<a href="../cc_lang.h">cc_lang.h</a>) to emulate 
+the bug.
+
+<p>
+However, we don't want to commit to emulating every bug in every
+compiler.  Currently, our main goal is being able to parse code
+compiled with gcc on Linux, so we will support a bug if:
+<ul>
+<li>the bug is present in the latest 3.x version of gcc, and
+<li>the bug is also present in the latest Intel C++ compiler ("icc") or
+    there is a lot of code in the wild that relies on the bug
+</ul>
+or, if
+<ul>
+<li>it's a gcc-2 bug and the gcc-2 headers need it
+</ul>
+
+<p>
+Rationale: If the bug is not present in gcc-3.x, then presumably the
+author of the code needing the bug is already under pressure to
+fix it since the all the major Linux distributions are using gcc-3.
+If the bug is not emulated by icc, and code needing it is rare, then we
+can file a bug report directly with the package author, explaining that the
+code is invalid and using icc to support that claim (icc is freely
+available and reasonably popular).  Finally, we want to give users the
+option of preprocessing their code with the gcc-2 headers (because
+they are so much simpler), so we want to accept the code in those
+headers.
+
+<p>
+For the case of bugs in the gcc-2 headers, rather than implement
+full gcc-2 compatibility, I've just been adding little hacks that
+look at the names of the identifiers involved before relaxing the
+rules.  This way I minimize the degradation of the language
+enforcement, while still accepting the code in those specific headers.
+
+
+
+
+
+
+
+
+
+
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="valid-html401.png"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<!-- the following exists to make sure the document has lots of space
+     at the end, so that clicking on a link that points into the document
+     will always put the referred-to section at the top of the browser
+     window; without this, sections near the end don't work -->
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+<center>this space left intentionally blank</center>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+&nbsp;<br>
+
+
+
+</body>
+</html>

Added: vendor/elsa/current/elsa/doc/er.fig
===================================================================
--- vendor/elsa/current/elsa/doc/er.fig	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/er.fig	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,526 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+0 32 #008a94
+0 33 #733cc6
+0 34 #63799c
+5 1 0 1 -1 7 50 0 -1 0.000 0 1 1 0 3300.000 1125.000 3000 900 3300 1500 3600 900
+	1 1 1.00 60.00 120.00
+6 1200 9300 2400 9600
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 1800 9450 600 150 1200 9450 2400 9450
+4 1 -1 50 0 0 12 0.0000 4 180 795 1800 9525 type: Type\001
+-6
+6 3900 7500 5700 7800
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 4800 7650 900 150 3900 7500 5700 7800
+4 1 -1 50 0 0 12 0.0000 4 180 1170 4800 7725 type: DataType\001
+-6
+6 3900 4050 5100 4350
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 4500 4200 600 150 3900 4200 5100 4200
+4 1 -1 50 0 0 12 0.0000 4 135 690 4500 4275 value: int\001
+-6
+6 3900 4350 5700 4650
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 4800 4500 900 150 3900 4350 5700 4650
+4 1 -1 50 0 0 12 0.0000 4 180 1380 4800 4575 type: Enumeration\001
+-6
+6 12000 2700 12600 3000
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 12300 2850 300 150 12000 2700 12600 3000
+4 1 -1 50 0 0 12 0.0000 4 90 180 12300 2925 cv\001
+-6
+6 600 2100 1800 2400
+2 2 0 1 12 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 600 2100 1800 2100 1800 2400 600 2400 600 2100
+4 1 0 50 0 0 12 0.0000 4 180 465 1200 2325 Scope\001
+-6
+6 2700 3600 3900 3900
+2 2 0 1 12 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 2700 3600 3900 3600 3900 3900 2700 3900 2700 3600
+4 1 0 50 0 0 12 0.0000 4 180 900 3300 3825 BlockScope\001
+-6
+6 7800 1500 9000 1800
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 7800 1500 9000 1500 9000 1800 7800 1800 7800 1500
+4 1 0 50 0 0 12 0.0000 4 180 1035 8400 1725 FunctionType\001
+-6
+6 7200 2400 9000 2700
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 8100 2550 900 150 7200 2400 9000 2700
+4 1 -1 50 0 0 12 0.0000 4 135 1200 8100 2625 recv: Reference\001
+-6
+6 600 4500 1800 4800
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 600 4500 1800 4500 1800 4800 600 4800 600 4500
+4 1 0 50 0 0 12 0.0000 4 135 645 1200 4725 Variable\001
+-6
+6 8325 8400 10800 8700
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 9000 8400 10800 8400 10800 8700 9000 8700 9000 8400
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 9000 8475 8850 8550 9000 8625
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 8400 8550 8850 8550
+4 1 -1 50 0 0 12 0.0000 4 135 1290 9900 8625 MemberFunction\001
+-6
+6 8325 9000 10800 9300
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 9000 9000 10800 9000 10800 9300 9000 9300 9000 9000
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 9000 9075 8850 9150 9000 9225
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 8400 9150 8850 9150
+4 1 -1 50 0 0 12 0.0000 4 180 1455 9900 9225 MemberTypeName\001
+-6
+6 6900 4200 7500 4500
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 7200 4350 300 150 6900 4200 7500 4500
+4 1 -1 50 0 0 12 0.0000 4 90 180 7200 4425 cv\001
+-6
+6 9000 4200 9600 4500
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 9300 4350 300 150 9000 4200 9600 4500
+4 1 -1 50 0 0 12 0.0000 4 90 180 9300 4425 cv\001
+-6
+6 4500 6000 5700 6300
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 5100 6150 600 150 4500 6150 5700 6150
+4 1 -1 50 0 0 12 0.0000 4 180 795 5100 6225 type: Type\001
+-6
+6 6300 1800 7500 2100
+1 2 1 1 -1 7 50 0 -1 4.000 1 0.0000 6900 1950 600 150 6300 1950 7500 1950
+4 1 -1 50 0 0 12 0.0000 4 180 720 6900 2025 exnSpec?\001
+-6
+6 5100 1500 7500 1800
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 6300 1650 1200 150 5100 1500 7500 1800
+4 1 -1 50 0 0 12 0.0000 4 180 1620 6300 1725 params: FuncParam[]\001
+-6
+6 6300 1200 7500 1500
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 6900 1350 600 150 6300 1200 7500 1500
+4 1 -1 50 0 0 12 0.0000 4 180 675 6900 1425 ret: Type\001
+-6
+6 4500 6900 5700 7200
+2 2 1 1 -1 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 4500 6900 5700 6900 5700 7200 4500 7200 4500 6900
+4 1 -1 50 0 0 12 0.0000 4 135 810 5100 7125 ClassDefn\001
+-6
+6 5700 7200 8100 8100
+6 6900 7200 8100 7500
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 6900 7200 8100 7200 8100 7500 6900 7500 6900 7200
+4 1 0 50 0 0 12 0.0000 4 135 825 7500 7425 BaseClass\001
+-6
+6 5700 7200 6900 7500
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 6300 7350 600 150 5700 7200 6900 7500
+4 1 -1 50 0 0 12 0.0000 4 90 540 6300 7425 access\001
+-6
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 7425 7800 7500 7650 7575 7800
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 7500 7500 7500 7650
+2 2 0 1 -1 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 6900 7800 8100 7800 8100 8100 6900 8100 6900 7800
+4 1 -1 50 0 0 12 0.0000 4 135 765 7500 8025 VirtualBC\001
+-6
+6 11400 7800 12600 8100
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 11400 7800 12600 7800 12600 8100 11400 8100 11400 7800
+4 1 -1 50 0 0 12 0.0000 4 180 840 12000 8025 ImplicitMF\001
+-6
+6 11400 7500 12600 7800
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 11400 7500 12600 7500 12600 7800 11400 7800 11400 7500
+4 1 -1 50 0 0 12 0.0000 4 135 795 12000 7725 VirtualMF\001
+-6
+6 8700 7500 9900 7800
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 8700 7500 9900 7500 9900 7800 8700 7800 8700 7500
+4 1 -1 50 0 0 12 0.0000 4 135 900 9300 7725 Constructor\001
+-6
+6 8700 7950 9900 8250
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 8700 7950 9900 7950 9900 8250 8700 8250 8700 7950
+4 1 -1 50 0 0 12 0.0000 4 180 915 9300 8175 ExplicitCtor\001
+-6
+1 2 1 1 -1 7 50 0 -1 4.000 1 0.0000 4650 8550 150 150 4500 8550 4800 8550
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 2550 8550 150 150 2400 8400 2700 8700
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 2550 8850 150 150 2400 8700 2700 9000
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 12000 4950 600 150 11400 4800 12600 5100
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 12000 9300 600 150 11400 9150 12600 9450
+1 2 0 1 -1 7 50 0 -1 0.000 1 0.0000 7050 6450 450 150 6600 6300 7500 6600
+1 2 1 1 -1 7 50 0 -1 4.000 1 0.0000 6450 8700 150 150 6300 8700 6600 8700
+1 2 1 1 -1 7 50 0 -1 4.000 1 0.0000 4650 9150 150 150 4500 9150 4800 9150
+1 2 0 1 -1 -1 50 0 -1 3.000 1 0.0000 750 3900 150 600 600 3300 900 4500
+1 2 0 1 -1 -1 50 0 -1 3.000 1 0.0000 3300 2850 600 150 2700 2700 3900 3000
+1 2 1 1 -1 7 50 0 -1 3.000 1 0.0000 4650 8250 150 150 4500 8250 4800 8250
+2 2 0 1 32 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 2700 600 3900 600 3900 900 2700 900 2700 600
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 10200 1500 11400 1500 11400 1800 10200 1800 10200 1500
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 9000 600 10200 600 10200 900 9000 900 9000 600
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 2700 1800 4500 1800 4500 2100 2700 2100 2700 1800
+2 1 0 2 12 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 2700 825 2400 825 2400 6750 6600 6750
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 2700 750 2100 750 2100 7650 2700 7650
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2100 1950 2700 1950
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 3825 1800 3825 900
+2 2 0 1 32 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 4500 600 5700 600 5700 900 4500 900 4500 600
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 3000 7800 3000 9450 3300 9450
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 9600 3000 9600 2100 11700 2100 11700 2400
+2 1 0 2 -1 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 900 8100 900 9150 1200 9150
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 1200 8400 2400 8400 2400 8700 1200 8700 1200 8400
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 1200 8700 2400 8700 2400 9000 1200 9000 1200 8700
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 1200 9000 2400 9000 2400 9300 1200 9300 1200 9000
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 600 7800 1800 7800 1800 8100 600 8100 600 7800
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 1200 4800 1200 7800
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 1 2
+	1 1 1.00 60.00 120.00
+	1 1 1.00 60.00 120.00
+	 1200 2400 1200 4500
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 2700 2400 3900 2400 3900 2700 2700 2700 2700 2400
+2 1 0 2 12 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 3900 3750 4650 3750 4650 3450
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2700 2550 2100 2550
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2700 4350 2100 4350
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 5100 5700 5100 5400 9000 5400 9000 5700
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2100 4950 6300 4950
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 7800 2100 9000 2100 9000 2400 7800 2400 7800 2100
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 9900 3900 11100 3900 11100 4200 9900 4200 9900 3900
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 11400 3900 12600 3900 12600 4200 11400 4200 11400 3900
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 10500 3900 10500 3600
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 9150 3000 9150 900
+2 1 0 2 12 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 1800 2250 2400 2250
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2100 4650 1800 4650
+2 3 0 2 12 12 50 0 20 0.000 0 0 -1 0 0 4
+	 2400 2175 2250 2250 2400 2325 2400 2175
+2 3 0 2 10 10 50 0 20 0.000 0 0 -1 0 0 4
+	 2100 4575 1950 4650 2100 4725 2100 4575
+2 1 0 2 32 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 4500 675 4350 750 4500 825
+2 1 0 2 12 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 4575 3300 4650 3450 4725 3300
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 9600 900 9600 1050
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 8700 3000 10500 3000 10500 3300 8700 3300 8700 3000
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 9600 3300 9600 3450
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 8400 1800 8400 1950
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 8325 2100 8400 1950 8475 2100
+2 3 0 2 18 18 50 0 20 0.000 0 0 -1 0 0 4
+	 9525 1200 9600 1050 9675 1200 9525 1200
+2 3 0 2 18 18 50 0 20 0.000 0 0 -1 0 0 4
+	 10725 2100 10800 1950 10875 2100 10725 2100
+2 3 0 2 18 18 50 0 20 0.000 0 0 -1 0 0 4
+	 9525 3600 9600 3450 9675 3600 9525 3600
+2 3 0 2 10 10 50 0 20 0.000 0 0 -1 0 0 4
+	 2925 8250 3000 8100 3075 8250 2925 8250
+2 3 0 2 0 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 825 8550 900 8400 975 8550 825 8550
+2 1 0 2 -1 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 900 8550 1200 8550
+2 1 0 2 -1 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 900 8850 1200 8850
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 8400 1500 8400 1200 10800 1200 10800 1500
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 10800 1800 10800 1950
+2 1 0 2 32 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 3900 750 4350 750
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 3000 8250 3300 8250
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 3000 8550 3300 8550
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 3000 8850 3300 8850
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 3000 9150 3300 9150
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 10800 2400 12600 2400 12600 2700 10800 2700 10800 2400
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 2700 4200 3900 4200 3900 4500 2700 4500 2700 4200
+2 2 0 1 12 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 2700 5100 4500 5100 4500 5400 2700 5400 2700 5100
+2 1 0 2 12 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2700 5250 2400 5250
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 2700 7500 3900 7500 3900 7800 2700 7800 2700 7500
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 3300 8400 4500 8400 4500 8700 3300 8700 3300 8400
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 3300 8700 4500 8700 4500 9000 3300 9000 3300 8700
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 3300 9000 4500 9000 4500 9300 3300 9300 3300 9000
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 3300 9300 4500 9300 4500 9600 3300 9600 3300 9300
+2 2 1 1 -1 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 4200 3000 6000 3000 6000 3300 4200 3300 4200 3000
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 3300 8100 4500 8100 4500 8400 3300 8400 3300 8100
+2 1 0 2 18 18 50 0 -1 0.000 0 0 -1 0 0 4
+	 6900 3900 6900 3600 12000 3600 12000 3900
+2 1 0 2 12 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2700 3750 2400 3750
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 60.00 120.00
+	 2700 7125 1500 7125 1500 4800
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 9000 8775 8850 8850 9000 8925
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 8400 8850 8850 8850
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 9000 8700 10800 8700 10800 9000 9000 9000 9000 8700
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 10800 8550 11100 8550 11100 9450 10800 9450
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 11100 8850 10800 8850
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 11100 9150 10800 9150
+2 3 0 2 10 10 50 0 20 0.000 0 0 -1 0 0 4
+	 11100 8925 11250 9000 11100 9075 11100 8925
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 11400 9000 11100 9000
+2 2 0 1 33 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 9600 6600 10800 6600 10800 6900 9600 6900 9600 6600
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 6300 4800 7500 4800 7500 5100 6300 5100 6300 4800
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 6900 5100 6900 5700
+2 3 0 2 10 10 50 0 20 0.000 0 0 -1 0 0 4
+	 6825 5400 6900 5250 6975 5400 6825 5400
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 6300 3900 7500 3900 7500 4200 6300 4200 6300 3900
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 8700 3900 8700 3600
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 7800 3900 9600 3900 9600 4200 7800 4200 7800 3900
+2 2 0 1 33 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 8400 5700 10200 5700 10200 6000 8400 6000 8400 5700
+2 1 0 2 33 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 8700 6600 8700 6300 9900 6300 9900 6600
+2 1 0 2 33 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 9300 6000 9300 6300
+2 3 0 2 33 33 50 0 20 0.000 0 0 -1 0 0 4
+	 9225 6300 9300 6150 9375 6300 9225 6300
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 2700 6900 3900 6900 3900 7200 2700 7200 2700 6900
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2700 7050 2100 7050
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 8100 4200 8100 6600
+2 2 0 1 22 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 9600 4800 10800 4800 10800 5100 9600 5100 9600 4800
+2 1 0 2 22 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 10200 5400 10200 5100
+2 3 0 2 22 22 50 0 20 0.000 0 0 -1 0 0 4
+	 10125 5400 10200 5250 10275 5400 10125 5400
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 60.00 120.00
+	 11250 2700 11250 4350 10800 4800
+2 2 0 1 18 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 11400 4500 12600 4500 12600 4800 11400 4800 11400 4500
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 11925 4500 12000 4350 12075 4500
+2 1 0 2 18 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 12000 4200 12000 4350
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 4500 5700 5700 5700 5700 6000 4500 6000 4500 5700
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 6000 5700 7800 5700 7800 6000 6000 6000 6000 5700
+2 1 1 1 -1 7 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 7650 6000 7650 6600
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 60.00 120.00
+	 3900 2475 7050 2475 7950 1800
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 60.00 120.00
+	 3900 2625 4650 2625 4650 3000
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 11925 8850 12000 8700 12075 8850
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 12000 8550 12000 8700
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 7800 1650 7500 1650
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 7800 1575 7500 1350
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 7800 1725 7500 1950
+2 2 0 1 22 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 10800 5700 12600 5700 12600 6000 10800 6000 10800 5700
+2 1 0 2 22 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 9600 5700 9600 5400 11700 5400 11700 5700
+2 1 0 2 22 -1 50 0 -1 0.000 0 0 -1 0 0 3
+	 11100 6000 11100 7050 11400 7050
+2 2 0 1 22 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 11400 6300 12600 6300 12600 6600 11400 6600 11400 6300
+2 2 0 1 22 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 11400 6900 12600 6900 12600 7200 11400 7200 11400 6900
+2 1 0 2 22 -1 50 0 -1 0.000 0 0 -1 0 0 2
+	 11100 6450 11400 6450
+2 3 0 2 22 22 50 0 20 0.000 0 0 -1 0 0 4
+	 11025 6450 11100 6300 11175 6450 11025 6450
+2 1 2 2 22 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 11400 6600 11400 6900
+2 1 2 2 22 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 12600 6600 12600 6900
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 9900 6900 9900 7200
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 11400 8850 12600 8850 12600 9150 11400 9150 11400 8850
+2 1 0 1 -1 -1 50 0 -1 3.000 0 0 -1 1 0 3
+	1 1 1.00 60.00 120.00
+	 6600 6900 6450 7050 5700 7050
+2 2 0 1 34 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 6600 6600 9000 6600 9000 6900 6600 6900 6600 6600
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 7350 6900 7350 7200
+2 1 0 1 -1 7 50 0 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 7650 7200 7650 6900
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 11400 7875 11250 7950 11400 8025
+2 1 0 1 -1 -1 50 0 -1 3.000 0 0 -1 1 0 3
+	1 1 1.00 60.00 120.00
+	 8250 6900 8250 8175 9000 8400
+2 1 0 1 -1 -1 50 0 -1 3.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 8925 6900 8925 7500
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 10650 8400 10650 7950 11250 7950
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 4500 8850 4950 8850
+2 3 0 2 10 10 50 0 20 0.000 0 0 -1 0 0 4
+	 5100 8775 4950 8850 5100 8925 5100 8775
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 5100 8850 6300 8850 6300 9150 5100 9150 5100 8850
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 5100 8550 6300 8550 6300 8850 5100 8850 5100 8550
+2 2 0 1 10 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 5100 9300 6300 9300 6300 9600 5100 9600 5100 9300
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 5625 9300 5700 9150 5775 9300
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 11400 7575 11250 7650 11400 7725
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 10425 8400 10425 7650 11250 7650
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 9900 7575 10050 7650 9900 7725
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 10200 8400 10200 7650 10050 7650
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 9225 7950 9300 7800 9375 7950
+4 1 0 50 0 0 12 0.0000 4 180 900 3300 825 Namespace\001
+4 1 0 50 0 0 12 0.0000 4 180 750 10800 1725 DataType\001
+4 1 0 50 0 0 12 0.0000 4 180 375 9600 825 Type\001
+4 1 -1 50 0 0 12 0.0000 4 180 540 3300 1350 using*!\001
+4 0 -1 50 0 0 12 0.0000 4 150 450 3900 1725 target\001
+4 1 0 50 0 0 12 0.0000 4 180 960 5100 825 GlobalScope\001
+4 1 0 50 0 0 12 0.0000 4 135 1080 3900 9525 HandlerParam\001
+4 1 0 50 0 0 12 0.0000 4 135 780 3900 8625 GlobalVar\001
+4 1 0 50 0 0 12 0.0000 4 135 705 3900 8325 LocalVar\001
+4 1 0 50 0 0 12 0.0000 4 135 690 1800 8625 Identifier\001
+4 1 0 50 0 0 12 0.0000 4 180 675 1800 8925 Operator\001
+4 1 0 50 0 0 12 0.0000 4 135 855 1800 9225 Conversion\001
+4 1 0 50 0 0 12 0.0000 4 135 450 1200 8025 Name\001
+4 0 -1 50 0 0 12 0.0000 4 135 585 1275 2625 memb*!\001
+4 0 -1 50 0 0 12 0.0000 4 135 450 1275 4425 scope\001
+4 1 0 50 0 0 12 0.0000 4 135 660 3300 2625 Function\001
+4 1 -1 50 0 0 12 0.0000 4 135 1035 5100 3225 FunctionDefn\001
+4 1 0 50 0 0 12 0.0000 4 180 960 8400 2325 MethodType\001
+4 1 0 50 0 0 12 0.0000 4 135 780 10500 4125 Reference\001
+4 1 0 50 0 0 12 0.0000 4 180 435 12000 4125 Array\001
+4 1 0 50 0 0 12 0.0000 4 180 1185 9600 3225 IndirectionType\001
+4 0 -1 50 0 0 12 0.0000 4 135 510 11325 2925 atomic\001
+4 2 -1 50 0 0 12 0.0000 4 135 600 9075 2925 referent\001
+4 1 -1 50 0 0 12 0.0000 4 135 165 4650 8325 i?!\001
+4 1 -1 50 0 0 12 0.0000 4 135 165 4650 8625 i?!\001
+4 1 -1 50 0 0 18 0.0000 4 195 2400 7350 825 C++ Static Semantics\001
+4 1 0 50 0 0 12 0.0000 4 135 135 2550 8625 id\001
+4 1 0 50 0 0 12 0.0000 4 135 180 2550 8925 op\001
+4 1 0 50 0 0 12 0.0000 4 180 1185 11700 2625 CVAtomicType\001
+4 1 0 50 0 0 12 0.0000 4 135 885 3300 4425 Enumerator\001
+4 1 0 50 0 0 12 0.0000 4 180 1200 3600 5325 PrototypeScope\001
+4 1 0 50 0 0 12 0.0000 4 135 1020 3300 7725 DataVariable\001
+4 1 -1 50 0 0 12 0.0000 4 180 1515 7350 1050 (without templates)\001
+4 2 -1 50 0 0 12 0.0000 4 135 525 1125 5025 name?!\001
+4 1 0 50 0 0 12 0.0000 4 180 1485 9900 8925 MemberUsingAlias\001
+4 1 0 50 0 0 12 0.0000 4 135 960 10200 6825 Enumeration\001
+4 1 0 50 0 0 12 0.0000 4 180 825 6900 5025 TypeName\001
+4 1 -1 50 0 0 12 0.0000 4 180 1470 9300 5925 NamedAtomicType\001
+4 1 0 50 0 0 12 0.0000 4 135 540 6900 4125 Pointer\001
+4 1 0 50 0 0 12 0.0000 4 135 1365 8700 4125 PointerToMember\001
+4 1 0 50 0 0 12 0.0000 4 180 855 3300 7125 UsingAlias\001
+4 2 0 50 0 0 12 0.0000 4 150 450 2625 7275 target\001
+4 0 -1 50 0 0 12 0.0000 4 135 405 8175 4425 class\001
+4 1 0 50 0 0 12 0.0000 4 180 930 10200 5025 AtomicType\001
+4 1 -1 50 0 0 12 0.0000 4 135 600 12000 5025 size: int\001
+4 1 -1 50 0 0 12 0.0000 4 180 855 12000 4725 SizedArray\001
+4 1 0 50 0 0 12 0.0000 4 180 615 5100 5925 Typedef\001
+4 1 -1 50 0 0 12 0.0000 4 180 1500 6900 5925 InjectedClassName\001
+4 2 -1 50 0 0 12 0.0000 4 180 930 7575 6225 self = scope\001
+4 1 -1 50 0 0 12 0.0000 4 150 330 4200 2400 type\001
+4 0 -1 50 0 0 12 0.0000 4 135 450 4725 2775 defn?!\001
+4 1 0 50 0 0 12 0.0000 4 180 1350 11700 5925 FundamentalType\001
+4 1 -1 50 0 0 12 0.0000 4 135 330 12000 6525 char\001
+4 1 -1 50 0 0 12 0.0000 4 135 315 12000 7125 void\001
+4 1 -1 50 0 0 12 0.0000 4 15 135 12000 6825 ...\001
+4 0 -1 50 0 0 12 0.0000 4 135 1035 9975 7125 enumerators*\001
+4 1 0 50 0 0 12 0.0000 4 180 1305 3600 2025 NamespaceAlias\001
+4 1 -1 50 0 0 12 0.0000 4 135 1065 12000 9075 ClassMember\001
+4 1 -1 50 0 0 12 0.0000 4 90 540 12000 9375 access\001
+4 1 0 50 0 0 12 0.0000 4 180 810 7800 6825 ClassType\001
+4 1 -1 50 0 0 12 0.0000 4 180 645 7050 6525 keyword\001
+4 1 -1 50 0 0 12 0.0000 4 180 1035 10200 7425 (Enumerator)\001
+4 2 -1 50 0 0 12 0.0000 4 135 450 6450 6975 defn?!\001
+4 0 0 50 0 0 12 0.0000 4 135 360 7725 7125 base\001
+4 2 -1 50 0 0 12 0.0000 4 180 570 7275 7125 bases[]\001
+4 1 -1 50 0 0 12 0.0000 4 180 795 12000 8475 (Variable)\001
+4 0 -1 50 0 0 12 0.0000 4 135 420 8325 7125 dtor?!\001
+4 0 -1 50 0 0 12 0.0000 4 135 435 9000 7125 ctor*!\001
+4 2 -1 50 0 0 12 0.0000 4 180 810 8325 8625 (Function)\001
+4 2 -1 50 0 0 12 0.0000 4 180 1005 8325 8925 (UsingAlias)\001
+4 2 -1 50 0 0 12 0.0000 4 180 975 8325 9225 (TypeName)\001
+4 2 -1 50 0 0 12 0.0000 4 180 1155 10725 9525 (DataMember)\001
+4 1 0 50 0 0 12 0.0000 4 135 855 3900 9225 FuncParam\001
+4 1 0 50 0 0 12 0.0000 4 135 1005 3900 8925 DataMember\001
+4 1 0 50 0 0 12 0.0000 4 135 1050 5700 9075 NonstaticDM\001
+4 1 0 50 0 0 12 0.0000 4 135 750 5700 8775 StaticDM\001
+4 1 -1 50 0 0 12 0.0000 4 135 165 6450 8775 i?!\001
+4 1 -1 50 0 0 12 0.0000 4 135 210 4650 9225 d?!\001
+4 1 0 50 0 0 12 0.0000 4 135 1065 5700 9525 MutableNDM\001
+4 1 -1 50 0 0 12 1.5708 4 180 705 825 3900 storage*!\001
+4 1 -1 50 0 0 12 0.0000 4 135 480 3300 2925 inline?\001

Added: vendor/elsa/current/elsa/doc/er.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/er.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/er.ps
===================================================================
--- vendor/elsa/current/elsa/doc/er.ps	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/er.ps	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1158 @@
+%!PS-Adobe-2.0
+%%Title: er.ps
+%%Creator: /usr/X11R6/bin/fig2dev Version 3.2 Patchlevel 4
+%%CreationDate: Sat Aug 27 00:17:32 2005
+%%For: scott at seamonkey (,,,)
+%%Orientation: Landscape
+%%Pages: 1
+%%BoundingBox: 0 0 612 792
+%%DocumentPaperSizes: letter
+%%BeginSetup
+[{
+%BeginFeature: *PageRegion Letter
+<</PageSize [612 792]>> setpagedevice
+%EndFeature
+} stopped cleartomark
+%%EndSetup
+%%Magnification: 1.0000
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+/col32 {0.000 0.539 0.578 srgb} bind def
+/col33 {0.449 0.234 0.773 srgb} bind def
+/col34 {0.387 0.473 0.609 srgb} bind def
+
+end
+save
+newpath 0 792 moveto 0 0 lineto 612 0 lineto 612 792 lineto closepath clip newpath
+0.0 0.0 translate
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+  bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+  4 -2 roll mul srgb} bind def
+ /DrawEllipse {
+	/endangle exch def
+	/startangle exch def
+	/yrad exch def
+	/xrad exch def
+	/y exch def
+	/x exch def
+	/savematrix mtrx currentmatrix def
+	x y tr xrad yrad sc 0 0 1 startangle endangle arc
+	closepath
+	savematrix setmatrix
+	} def
+
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+$F2psBegin
+10 setmiterlimit
+0 slj 0 slc
+ 0.06000 0.06000 sc
+%%Page: 1 1
+%%BeginPageSetup
+ 90 rotate
+1 -1 scale
+%%EndPageSetup
+%
+% Fig objects follow
+%
+% 
+% here starts figure with depth 50
+% Ellipse
+7.500 slw
+n 1800 9450 600 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+1800 9525 m
+gs 1 -1 sc (type: Type) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+n 4800 7650 900 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+4800 7725 m
+gs 1 -1 sc (type: DataType) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+n 4500 4200 600 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+4500 4275 m
+gs 1 -1 sc (value: int) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+n 4800 4500 900 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+4800 4575 m
+gs 1 -1 sc (type: Enumeration) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+n 12300 2850 300 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+12300 2925 m
+gs 1 -1 sc (cv) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+n 600 2100 m 1800 2100 l 1800 2400 l 600 2400 l
+ cp gs col12 s gr 
+/Times-Roman ff 180.00 scf sf
+1200 2325 m
+gs 1 -1 sc (Scope) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Polyline
+n 2700 3600 m 3900 3600 l 3900 3900 l 2700 3900 l
+ cp gs col12 s gr 
+/Times-Roman ff 180.00 scf sf
+3300 3825 m
+gs 1 -1 sc (BlockScope) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Polyline
+n 7800 1500 m 9000 1500 l 9000 1800 l 7800 1800 l
+ cp gs col18 s gr 
+/Times-Roman ff 180.00 scf sf
+8400 1725 m
+gs 1 -1 sc (FunctionType) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Ellipse
+n 8100 2550 900 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+8100 2625 m
+gs 1 -1 sc (recv: Reference) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+n 600 4500 m 1800 4500 l 1800 4800 l 600 4800 l
+ cp gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+1200 4725 m
+gs 1 -1 sc (Variable) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Polyline
+n 9000 8400 m 10800 8400 l 10800 8700 l 9000 8700 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 9000 8475 m 8850 8550 l
+ 9000 8625 l gs col10 s gr 
+% Polyline
+n 8400 8550 m
+ 8850 8550 l gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+9900 8625 m
+gs 1 -1 sc (MemberFunction) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+7.500 slw
+n 9000 9000 m 10800 9000 l 10800 9300 l 9000 9300 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 9000 9075 m 8850 9150 l
+ 9000 9225 l gs col10 s gr 
+% Polyline
+n 8400 9150 m
+ 8850 9150 l gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+9900 9225 m
+gs 1 -1 sc (MemberTypeName) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+7.500 slw
+n 7200 4350 300 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+7200 4425 m
+gs 1 -1 sc (cv) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+n 9300 4350 300 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+9300 4425 m
+gs 1 -1 sc (cv) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+n 5100 6150 600 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+5100 6225 m
+gs 1 -1 sc (type: Type) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+ [60] 0 sd
+n 6900 1950 600 150 0 360 DrawEllipse gs col-1 s gr
+ [] 0 sd
+/Times-Roman ff 180.00 scf sf
+6900 2025 m
+gs 1 -1 sc (exnSpec?) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+n 6300 1650 1200 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+6300 1725 m
+gs 1 -1 sc (params: FuncParam[]) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+n 6900 1350 600 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+6900 1425 m
+gs 1 -1 sc (ret: Type) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+ [60] 0 sd
+n 4500 6900 m 5700 6900 l 5700 7200 l 4500 7200 l
+ cp gs col-1 s gr  [] 0 sd
+/Times-Roman ff 180.00 scf sf
+5100 7125 m
+gs 1 -1 sc (ClassDefn) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+n 6900 7200 m 8100 7200 l 8100 7500 l 6900 7500 l
+ cp gs col0 s gr 
+/Times-Roman ff 180.00 scf sf
+7500 7425 m
+gs 1 -1 sc (BaseClass) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Ellipse
+n 6300 7350 600 150 0 360 DrawEllipse gs col-1 s gr
+
+/Times-Roman ff 180.00 scf sf
+6300 7425 m
+gs 1 -1 sc (access) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+15.000 slw
+n 7425 7800 m 7500 7650 l
+ 7575 7800 l gs col0 s gr 
+% Polyline
+n 7500 7500 m
+ 7500 7650 l gs col0 s gr 
+% Polyline
+7.500 slw
+n 6900 7800 m 8100 7800 l 8100 8100 l 6900 8100 l
+ cp gs col-1 s gr 
+/Times-Roman ff 180.00 scf sf
+7500 8025 m
+gs 1 -1 sc (VirtualBC) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+n 11400 7800 m 12600 7800 l 12600 8100 l 11400 8100 l
+ cp gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+12000 8025 m
+gs 1 -1 sc (ImplicitMF) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+n 11400 7500 m 12600 7500 l 12600 7800 l 11400 7800 l
+ cp gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+12000 7725 m
+gs 1 -1 sc (VirtualMF) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+n 8700 7500 m 9900 7500 l 9900 7800 l 8700 7800 l
+ cp gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+9300 7725 m
+gs 1 -1 sc (Constructor) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+n 8700 7950 m 9900 7950 l 9900 8250 l 8700 8250 l
+ cp gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+9300 8175 m
+gs 1 -1 sc (ExplicitCtor) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Arc
+gs  clippath
+3620 873 m 3566 899 l 3633 1035 l 3607 915 l 3687 1009 l cp
+eoclip
+n 3300.0 1125.0 375.0 -143.1 -36.9 arcn
+gs col-1 s gr
+ gr
+
+% arrowhead
+n 3687 1009 m 3607 915 l 3633 1035 l 3687 1009 l  cp gs 0.00 setgray ef gr  col-1 s
+% Ellipse
+ [60] 0 sd
+n 4650 8550 150 150 0 360 DrawEllipse gs col-1 s gr
+ [] 0 sd
+% Ellipse
+n 2550 8550 150 150 0 360 DrawEllipse gs col-1 s gr
+
+% Ellipse
+n 2550 8850 150 150 0 360 DrawEllipse gs col-1 s gr
+
+% Ellipse
+n 12000 4950 600 150 0 360 DrawEllipse gs col-1 s gr
+
+% Ellipse
+n 12000 9300 600 150 0 360 DrawEllipse gs col-1 s gr
+
+% Ellipse
+n 7050 6450 450 150 0 360 DrawEllipse gs col-1 s gr
+
+% Ellipse
+ [60] 0 sd
+n 6450 8700 150 150 0 360 DrawEllipse gs col-1 s gr
+ [] 0 sd
+% Ellipse
+ [60] 0 sd
+n 4650 9150 150 150 0 360 DrawEllipse gs col-1 s gr
+ [] 0 sd
+% Ellipse
+n 750 3900 150 600 0 360 DrawEllipse gs col-1 s gr
+
+% Ellipse
+n 3300 2850 600 150 0 360 DrawEllipse gs col-1 s gr
+
+% Ellipse
+ [45] 0 sd
+n 4650 8250 150 150 0 360 DrawEllipse gs col-1 s gr
+ [] 0 sd
+% Polyline
+n 2700 600 m 3900 600 l 3900 900 l 2700 900 l
+ cp gs col32 s gr 
+% Polyline
+n 10200 1500 m 11400 1500 l 11400 1800 l 10200 1800 l
+ cp gs col18 s gr 
+% Polyline
+n 9000 600 m 10200 600 l 10200 900 l 9000 900 l
+ cp gs col18 s gr 
+% Polyline
+n 2700 1800 m 4500 1800 l 4500 2100 l 2700 2100 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 2700 825 m 2400 825 l 2400 6750 l
+ 6600 6750 l gs col12 s gr 
+% Polyline
+n 2700 750 m 2100 750 l 2100 7650 l
+ 2700 7650 l gs col10 s gr 
+% Polyline
+n 2100 1950 m
+ 2700 1950 l gs col10 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+3855 885 m 3795 885 l 3795 1036 l 3825 916 l 3855 1036 l cp
+eoclip
+n 3825 1800 m
+ 3825 900 l gs col-1 s gr gr
+
+% arrowhead
+n 3855 1036 m 3825 916 l 3795 1036 l 3855 1036 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+n 4500 600 m 5700 600 l 5700 900 l 4500 900 l
+ cp gs col32 s gr 
+% Polyline
+15.000 slw
+n 3000 7800 m 3000 9450 l
+ 3300 9450 l gs col10 s gr 
+% Polyline
+n 9600 3000 m 9600 2100 l 11700 2100 l
+ 11700 2400 l gs col18 s gr 
+% Polyline
+n 900 8100 m 900 9150 l
+ 1200 9150 l gs col-1 s gr 
+% Polyline
+7.500 slw
+n 1200 8400 m 2400 8400 l 2400 8700 l 1200 8700 l
+ cp gs col0 s gr 
+% Polyline
+n 1200 8700 m 2400 8700 l 2400 9000 l 1200 9000 l
+ cp gs col0 s gr 
+% Polyline
+n 1200 9000 m 2400 9000 l 2400 9300 l 1200 9300 l
+ cp gs col0 s gr 
+% Polyline
+n 600 7800 m 1800 7800 l 1800 8100 l 600 8100 l
+ cp gs col0 s gr 
+% Polyline
+gs  clippath
+1170 7815 m 1230 7815 l 1230 7664 l 1200 7784 l 1170 7664 l cp
+eoclip
+n 1200 4800 m
+ 1200 7800 l gs col-1 s gr gr
+
+% arrowhead
+n 1170 7664 m 1200 7784 l 1230 7664 l 1170 7664 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+gs  clippath
+1170 4515 m 1230 4515 l 1230 4364 l 1200 4484 l 1170 4364 l cp
+1230 2385 m 1170 2385 l 1170 2536 l 1200 2416 l 1230 2536 l cp
+eoclip
+n 1200 2400 m
+ 1200 4500 l gs col-1 s gr gr
+
+% arrowhead
+n 1230 2536 m 1200 2416 l 1170 2536 l 1230 2536 l  cp gs 0.00 setgray ef gr  col-1 s
+% arrowhead
+n 1170 4364 m 1200 4484 l 1230 4364 l 1170 4364 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+n 2700 2400 m 3900 2400 l 3900 2700 l 2700 2700 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 3900 3750 m 4650 3750 l
+ 4650 3450 l gs col12 s gr 
+% Polyline
+n 2700 2550 m
+ 2100 2550 l gs col10 s gr 
+% Polyline
+n 2700 4350 m
+ 2100 4350 l gs col10 s gr 
+% Polyline
+n 5100 5700 m 5100 5400 l 9000 5400 l
+ 9000 5700 l gs col10 s gr 
+% Polyline
+n 2100 4950 m
+ 6300 4950 l gs col10 s gr 
+% Polyline
+7.500 slw
+n 7800 2100 m 9000 2100 l 9000 2400 l 7800 2400 l
+ cp gs col18 s gr 
+% Polyline
+n 9900 3900 m 11100 3900 l 11100 4200 l 9900 4200 l
+ cp gs col18 s gr 
+% Polyline
+n 11400 3900 m 12600 3900 l 12600 4200 l 11400 4200 l
+ cp gs col18 s gr 
+% Polyline
+15.000 slw
+n 10500 3900 m
+ 10500 3600 l gs col18 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+9180 885 m 9120 885 l 9120 1036 l 9150 916 l 9180 1036 l cp
+eoclip
+n 9150 3000 m
+ 9150 900 l gs col-1 s gr gr
+
+% arrowhead
+n 9180 1036 m 9150 916 l 9120 1036 l 9180 1036 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+15.000 slw
+n 1800 2250 m
+ 2400 2250 l gs col12 s gr 
+% Polyline
+n 2100 4650 m
+ 1800 4650 l gs col10 s gr 
+% Polyline
+n 2400 2175 m 2250 2250 l 2400 2325 l
+ cp gs col12 1.00 shd ef gr gs col12 s gr 
+% Polyline
+n 2100 4575 m 1950 4650 l 2100 4725 l
+ cp gs col10 1.00 shd ef gr gs col10 s gr 
+% Polyline
+n 4500 675 m 4350 750 l
+ 4500 825 l gs col32 s gr 
+% Polyline
+n 4575 3300 m 4650 3450 l
+ 4725 3300 l gs col12 s gr 
+% Polyline
+n 9600 900 m
+ 9600 1050 l gs col18 s gr 
+% Polyline
+7.500 slw
+n 8700 3000 m 10500 3000 l 10500 3300 l 8700 3300 l
+ cp gs col18 s gr 
+% Polyline
+15.000 slw
+n 9600 3300 m
+ 9600 3450 l gs col18 s gr 
+% Polyline
+n 8400 1800 m
+ 8400 1950 l gs col18 s gr 
+% Polyline
+n 8325 2100 m 8400 1950 l
+ 8475 2100 l gs col18 s gr 
+% Polyline
+n 9525 1200 m 9600 1050 l 9675 1200 l
+ cp gs col18 1.00 shd ef gr gs col18 s gr 
+% Polyline
+n 10725 2100 m 10800 1950 l 10875 2100 l
+ cp gs col18 1.00 shd ef gr gs col18 s gr 
+% Polyline
+n 9525 3600 m 9600 3450 l 9675 3600 l
+ cp gs col18 1.00 shd ef gr gs col18 s gr 
+% Polyline
+n 2925 8250 m 3000 8100 l 3075 8250 l
+ cp gs col10 1.00 shd ef gr gs col10 s gr 
+% Polyline
+n 825 8550 m 900 8400 l 975 8550 l
+ cp gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 900 8550 m
+ 1200 8550 l gs col-1 s gr 
+% Polyline
+n 900 8850 m
+ 1200 8850 l gs col-1 s gr 
+% Polyline
+n 8400 1500 m 8400 1200 l 10800 1200 l
+ 10800 1500 l gs col18 s gr 
+% Polyline
+n 10800 1800 m
+ 10800 1950 l gs col18 s gr 
+% Polyline
+n 3900 750 m
+ 4350 750 l gs col32 s gr 
+% Polyline
+n 3000 8250 m
+ 3300 8250 l gs col10 s gr 
+% Polyline
+n 3000 8550 m
+ 3300 8550 l gs col10 s gr 
+% Polyline
+n 3000 8850 m
+ 3300 8850 l gs col10 s gr 
+% Polyline
+n 3000 9150 m
+ 3300 9150 l gs col10 s gr 
+% Polyline
+7.500 slw
+n 10800 2400 m 12600 2400 l 12600 2700 l 10800 2700 l
+ cp gs col18 s gr 
+% Polyline
+n 2700 4200 m 3900 4200 l 3900 4500 l 2700 4500 l
+ cp gs col10 s gr 
+% Polyline
+n 2700 5100 m 4500 5100 l 4500 5400 l 2700 5400 l
+ cp gs col12 s gr 
+% Polyline
+15.000 slw
+n 2700 5250 m
+ 2400 5250 l gs col12 s gr 
+% Polyline
+7.500 slw
+n 2700 7500 m 3900 7500 l 3900 7800 l 2700 7800 l
+ cp gs col10 s gr 
+% Polyline
+n 3300 8400 m 4500 8400 l 4500 8700 l 3300 8700 l
+ cp gs col10 s gr 
+% Polyline
+n 3300 8700 m 4500 8700 l 4500 9000 l 3300 9000 l
+ cp gs col10 s gr 
+% Polyline
+n 3300 9000 m 4500 9000 l 4500 9300 l 3300 9300 l
+ cp gs col10 s gr 
+% Polyline
+n 3300 9300 m 4500 9300 l 4500 9600 l 3300 9600 l
+ cp gs col10 s gr 
+% Polyline
+ [60] 0 sd
+n 4200 3000 m 6000 3000 l 6000 3300 l 4200 3300 l
+ cp gs col-1 s gr  [] 0 sd
+% Polyline
+n 3300 8100 m 4500 8100 l 4500 8400 l 3300 8400 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 6900 3900 m 6900 3600 l 12000 3600 l
+ 12000 3900 l gs col18 s gr 
+% Polyline
+n 2700 3750 m
+ 2400 3750 l gs col12 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+1530 4785 m 1470 4785 l 1470 4936 l 1500 4816 l 1530 4936 l cp
+eoclip
+n 2700 7125 m 1500 7125 l
+ 1500 4800 l gs col0 s gr gr
+
+% arrowhead
+n 1530 4936 m 1500 4816 l 1470 4936 l 1530 4936 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+15.000 slw
+n 9000 8775 m 8850 8850 l
+ 9000 8925 l gs col10 s gr 
+% Polyline
+n 8400 8850 m
+ 8850 8850 l gs col10 s gr 
+% Polyline
+7.500 slw
+n 9000 8700 m 10800 8700 l 10800 9000 l 9000 9000 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 10800 8550 m 11100 8550 l 11100 9450 l
+ 10800 9450 l gs col10 s gr 
+% Polyline
+n 11100 8850 m
+ 10800 8850 l gs col10 s gr 
+% Polyline
+n 11100 9150 m
+ 10800 9150 l gs col10 s gr 
+% Polyline
+n 11100 8925 m 11250 9000 l 11100 9075 l
+ cp gs col10 1.00 shd ef gr gs col10 s gr 
+% Polyline
+n 11400 9000 m
+ 11100 9000 l gs col10 s gr 
+% Polyline
+7.500 slw
+n 9600 6600 m 10800 6600 l 10800 6900 l 9600 6900 l
+ cp gs col33 s gr 
+% Polyline
+n 6300 4800 m 7500 4800 l 7500 5100 l 6300 5100 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 6900 5100 m
+ 6900 5700 l gs col10 s gr 
+% Polyline
+n 6825 5400 m 6900 5250 l 6975 5400 l
+ cp gs col10 1.00 shd ef gr gs col10 s gr 
+% Polyline
+7.500 slw
+n 6300 3900 m 7500 3900 l 7500 4200 l 6300 4200 l
+ cp gs col18 s gr 
+% Polyline
+15.000 slw
+n 8700 3900 m
+ 8700 3600 l gs col18 s gr 
+% Polyline
+7.500 slw
+n 7800 3900 m 9600 3900 l 9600 4200 l 7800 4200 l
+ cp gs col18 s gr 
+% Polyline
+n 8400 5700 m 10200 5700 l 10200 6000 l 8400 6000 l
+ cp gs col33 s gr 
+% Polyline
+15.000 slw
+n 8700 6600 m 8700 6300 l 9900 6300 l
+ 9900 6600 l gs col33 s gr 
+% Polyline
+n 9300 6000 m
+ 9300 6300 l gs col33 s gr 
+% Polyline
+n 9225 6300 m 9300 6150 l 9375 6300 l
+ cp gs col33 1.00 shd ef gr gs col33 s gr 
+% Polyline
+7.500 slw
+n 2700 6900 m 3900 6900 l 3900 7200 l 2700 7200 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 2700 7050 m
+ 2100 7050 l gs col10 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+8070 6615 m 8130 6615 l 8130 6464 l 8100 6584 l 8070 6464 l cp
+eoclip
+n 8100 4200 m
+ 8100 6600 l gs col-1 s gr gr
+
+% arrowhead
+n 8070 6464 m 8100 6584 l 8130 6464 l 8070 6464 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+n 9600 4800 m 10800 4800 l 10800 5100 l 9600 5100 l
+ cp gs col22 s gr 
+% Polyline
+15.000 slw
+n 10200 5400 m
+ 10200 5100 l gs col22 s gr 
+% Polyline
+n 10125 5400 m 10200 5250 l 10275 5400 l
+ cp gs col22 1.00 shd ef gr gs col22 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+10768 4789 m 10810 4831 l 10917 4725 l 10811 4789 l 10874 4682 l cp
+eoclip
+n 11250 2700 m 11250 4350 l
+ 10800 4800 l gs col-1 s gr gr
+
+% arrowhead
+n 10874 4682 m 10811 4789 l 10917 4725 l 10874 4682 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+n 11400 4500 m 12600 4500 l 12600 4800 l 11400 4800 l
+ cp gs col18 s gr 
+% Polyline
+15.000 slw
+n 11925 4500 m 12000 4350 l
+ 12075 4500 l gs col18 s gr 
+% Polyline
+n 12000 4200 m
+ 12000 4350 l gs col18 s gr 
+% Polyline
+7.500 slw
+n 4500 5700 m 5700 5700 l 5700 6000 l 4500 6000 l
+ cp gs col10 s gr 
+% Polyline
+n 6000 5700 m 7800 5700 l 7800 6000 l 6000 6000 l
+ cp gs col10 s gr 
+% Polyline
+ [60] 0 sd
+gs  clippath
+7620 6615 m 7680 6615 l 7680 6464 l 7650 6584 l 7620 6464 l cp
+eoclip
+n 7650 6000 m
+ 7650 6600 l gs col-1 s gr gr
+ [] 0 sd
+% arrowhead
+n 7620 6464 m 7650 6584 l 7680 6464 l 7620 6464 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+gs  clippath
+7980 1815 m 7944 1766 l 7822 1857 l 7937 1810 l 7858 1905 l cp
+eoclip
+n 3900 2475 m 7050 2475 l
+ 7950 1800 l gs col-1 s gr gr
+
+% arrowhead
+n 7858 1905 m 7937 1810 l 7822 1857 l 7858 1905 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+gs  clippath
+4620 3015 m 4680 3015 l 4680 2864 l 4650 2984 l 4620 2864 l cp
+eoclip
+n 3900 2625 m 4650 2625 l
+ 4650 3000 l gs col-1 s gr gr
+
+% arrowhead
+n 4620 2864 m 4650 2984 l 4680 2864 l 4620 2864 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+15.000 slw
+n 11925 8850 m 12000 8700 l
+ 12075 8850 l gs col10 s gr 
+% Polyline
+n 12000 8550 m
+ 12000 8700 l gs col10 s gr 
+% Polyline
+7.500 slw
+n 7800 1650 m
+ 7500 1650 l gs col-1 s gr 
+% Polyline
+n 7800 1575 m
+ 7500 1350 l gs col-1 s gr 
+% Polyline
+n 7800 1725 m
+ 7500 1950 l gs col-1 s gr 
+% Polyline
+n 10800 5700 m 12600 5700 l 12600 6000 l 10800 6000 l
+ cp gs col22 s gr 
+% Polyline
+15.000 slw
+n 9600 5700 m 9600 5400 l 11700 5400 l
+ 11700 5700 l gs col22 s gr 
+% Polyline
+n 11100 6000 m 11100 7050 l
+ 11400 7050 l gs col22 s gr 
+% Polyline
+7.500 slw
+n 11400 6300 m 12600 6300 l 12600 6600 l 11400 6600 l
+ cp gs col22 s gr 
+% Polyline
+n 11400 6900 m 12600 6900 l 12600 7200 l 11400 7200 l
+ cp gs col22 s gr 
+% Polyline
+15.000 slw
+n 11100 6450 m
+ 11400 6450 l gs col22 s gr 
+% Polyline
+n 11025 6450 m 11100 6300 l 11175 6450 l
+ cp gs col22 1.00 shd ef gr gs col22 s gr 
+% Polyline
+ [15 68] 68 sd
+n 11400 6600 m
+ 11400 6900 l gs col22 s gr  [] 0 sd
+% Polyline
+ [15 68] 68 sd
+n 12600 6600 m
+ 12600 6900 l gs col22 s gr  [] 0 sd
+% Polyline
+7.500 slw
+gs  clippath
+9870 7215 m 9930 7215 l 9930 7064 l 9900 7184 l 9870 7064 l cp
+eoclip
+n 9900 6900 m
+ 9900 7200 l gs col-1 s gr gr
+
+% arrowhead
+n 9870 7064 m 9900 7184 l 9930 7064 l 9870 7064 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+n 11400 8850 m 12600 8850 l 12600 9150 l 11400 9150 l
+ cp gs col10 s gr 
+% Polyline
+gs  clippath
+5685 7020 m 5685 7080 l 5836 7080 l 5716 7050 l 5836 7020 l cp
+eoclip
+n 6600 6900 m 6450 7050 l
+ 5700 7050 l gs col-1 s gr gr
+
+% arrowhead
+n 5836 7020 m 5716 7050 l 5836 7080 l 5836 7020 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+n 6600 6600 m 9000 6600 l 9000 6900 l 6600 6900 l
+ cp gs col34 s gr 
+% Polyline
+gs  clippath
+7320 7215 m 7380 7215 l 7380 7064 l 7350 7184 l 7320 7064 l cp
+eoclip
+n 7350 6900 m
+ 7350 7200 l gs col-1 s gr gr
+
+% arrowhead
+n 7320 7064 m 7350 7184 l 7380 7064 l 7320 7064 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+gs  clippath
+7680 6885 m 7620 6885 l 7620 7036 l 7650 6916 l 7680 7036 l cp
+eoclip
+n 7650 7200 m
+ 7650 6900 l gs col-1 s gr gr
+
+% arrowhead
+n 7680 7036 m 7650 6916 l 7620 7036 l 7680 7036 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+15.000 slw
+n 11400 7875 m 11250 7950 l
+ 11400 8025 l gs col10 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+9005 8433 m 9022 8375 l 8877 8331 l 8984 8395 l 8860 8389 l cp
+eoclip
+n 8250 6900 m 8250 8175 l
+ 9000 8400 l gs col-1 s gr gr
+
+% arrowhead
+n 8860 8389 m 8984 8395 l 8877 8331 l 8860 8389 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+gs  clippath
+8895 7515 m 8955 7515 l 8955 7364 l 8925 7484 l 8895 7364 l cp
+eoclip
+n 8925 6900 m
+ 8925 7500 l gs col-1 s gr gr
+
+% arrowhead
+n 8895 7364 m 8925 7484 l 8955 7364 l 8895 7364 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+15.000 slw
+n 10650 8400 m 10650 7950 l
+ 11250 7950 l gs col10 s gr 
+% Polyline
+n 4500 8850 m
+ 4950 8850 l gs col10 s gr 
+% Polyline
+n 5100 8775 m 4950 8850 l 5100 8925 l
+ cp gs col10 1.00 shd ef gr gs col10 s gr 
+% Polyline
+7.500 slw
+n 5100 8850 m 6300 8850 l 6300 9150 l 5100 9150 l
+ cp gs col10 s gr 
+% Polyline
+n 5100 8550 m 6300 8550 l 6300 8850 l 5100 8850 l
+ cp gs col10 s gr 
+% Polyline
+n 5100 9300 m 6300 9300 l 6300 9600 l 5100 9600 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 5625 9300 m 5700 9150 l
+ 5775 9300 l gs col10 s gr 
+% Polyline
+n 11400 7575 m 11250 7650 l
+ 11400 7725 l gs col10 s gr 
+% Polyline
+n 10425 8400 m 10425 7650 l
+ 11250 7650 l gs col10 s gr 
+% Polyline
+n 9900 7575 m 10050 7650 l
+ 9900 7725 l gs col10 s gr 
+% Polyline
+n 10200 8400 m 10200 7650 l
+ 10050 7650 l gs col10 s gr 
+% Polyline
+n 9225 7950 m 9300 7800 l
+ 9375 7950 l gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+3300 825 m
+gs 1 -1 sc (Namespace) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+10800 1725 m
+gs 1 -1 sc (DataType) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+9600 825 m
+gs 1 -1 sc (Type) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3300 1350 m
+gs 1 -1 sc (using*!) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3900 1725 m
+gs 1 -1 sc (target) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5100 825 m
+gs 1 -1 sc (GlobalScope) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3900 9525 m
+gs 1 -1 sc (HandlerParam) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3900 8625 m
+gs 1 -1 sc (GlobalVar) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3900 8325 m
+gs 1 -1 sc (LocalVar) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+1800 8625 m
+gs 1 -1 sc (Identifier) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+1800 8925 m
+gs 1 -1 sc (Operator) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+1800 9225 m
+gs 1 -1 sc (Conversion) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+1200 8025 m
+gs 1 -1 sc (Name) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+1275 2625 m
+gs 1 -1 sc (memb*!) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1275 4425 m
+gs 1 -1 sc (scope) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3300 2625 m
+gs 1 -1 sc (Function) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+5100 3225 m
+gs 1 -1 sc (FunctionDefn) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8400 2325 m
+gs 1 -1 sc (MethodType) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+10500 4125 m
+gs 1 -1 sc (Reference) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 4125 m
+gs 1 -1 sc (Array) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+9600 3225 m
+gs 1 -1 sc (IndirectionType) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+11325 2925 m
+gs 1 -1 sc (atomic) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+9075 2925 m
+gs 1 -1 sc (referent) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4650 8325 m
+gs 1 -1 sc (i?!) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4650 8625 m
+gs 1 -1 sc (i?!) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 270.00 scf sf
+7350 825 m
+gs 1 -1 sc (C++ Static Semantics) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+2550 8625 m
+gs 1 -1 sc (id) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+2550 8925 m
+gs 1 -1 sc (op) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 2625 m
+gs 1 -1 sc (CVAtomicType) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3300 4425 m
+gs 1 -1 sc (Enumerator) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 5325 m
+gs 1 -1 sc (PrototypeScope) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3300 7725 m
+gs 1 -1 sc (DataVariable) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+7350 1050 m
+gs 1 -1 sc (\(without templates\)) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1125 5025 m
+gs 1 -1 sc (name?!) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+9900 8925 m
+gs 1 -1 sc (MemberUsingAlias) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 6825 m
+gs 1 -1 sc (Enumeration) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+6900 5025 m
+gs 1 -1 sc (TypeName) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+9300 5925 m
+gs 1 -1 sc (NamedAtomicType) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6900 4125 m
+gs 1 -1 sc (Pointer) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+8700 4125 m
+gs 1 -1 sc (PointerToMember) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3300 7125 m
+gs 1 -1 sc (UsingAlias) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+2625 7275 m
+gs 1 -1 sc (target) dup sw pop neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+8175 4425 m
+gs 1 -1 sc (class) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 5025 m
+gs 1 -1 sc (AtomicType) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 5025 m
+gs 1 -1 sc (size: int) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 4725 m
+gs 1 -1 sc (SizedArray) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5100 5925 m
+gs 1 -1 sc (Typedef) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+6900 5925 m
+gs 1 -1 sc (InjectedClassName) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+7575 6225 m
+gs 1 -1 sc (self = scope) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4200 2400 m
+gs 1 -1 sc (type) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4725 2775 m
+gs 1 -1 sc (defn?!) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 5925 m
+gs 1 -1 sc (FundamentalType) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 6525 m
+gs 1 -1 sc (char) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 7125 m
+gs 1 -1 sc (void) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 6825 m
+gs 1 -1 sc (...) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+9975 7125 m
+gs 1 -1 sc (enumerators*) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 2025 m
+gs 1 -1 sc (NamespaceAlias) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 9075 m
+gs 1 -1 sc (ClassMember) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 9375 m
+gs 1 -1 sc (access) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+7800 6825 m
+gs 1 -1 sc (ClassType) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+7050 6525 m
+gs 1 -1 sc (keyword) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 7425 m
+gs 1 -1 sc (\(Enumerator\)) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6450 6975 m
+gs 1 -1 sc (defn?!) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+7725 7125 m
+gs 1 -1 sc (base) col0 sh gr
+/Times-Roman ff 180.00 scf sf
+7275 7125 m
+gs 1 -1 sc (bases[]) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 8475 m
+gs 1 -1 sc (\(Variable\)) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8325 7125 m
+gs 1 -1 sc (dtor?!) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+9000 7125 m
+gs 1 -1 sc (ctor*!) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8325 8625 m
+gs 1 -1 sc (\(Function\)) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8325 8925 m
+gs 1 -1 sc (\(UsingAlias\)) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8325 9225 m
+gs 1 -1 sc (\(TypeName\)) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+10725 9525 m
+gs 1 -1 sc (\(DataMember\)) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3900 9225 m
+gs 1 -1 sc (FuncParam) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3900 8925 m
+gs 1 -1 sc (DataMember) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+5700 9075 m
+gs 1 -1 sc (NonstaticDM) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+5700 8775 m
+gs 1 -1 sc (StaticDM) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+6450 8775 m
+gs 1 -1 sc (i?!) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4650 9225 m
+gs 1 -1 sc (d?!) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5700 9525 m
+gs 1 -1 sc (MutableNDM) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+825 3900 m
+gs 1 -1 sc  90.0 rot (storage*!) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3300 2925 m
+gs 1 -1 sc (inline?) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% here ends figure;
+$F2psEnd
+rs
+showpage

Added: vendor/elsa/current/elsa/doc/faq.html
===================================================================
--- vendor/elsa/current/elsa/doc/faq.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/faq.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elsa FAQ</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175% }
+    a.toc:link { text-decoration: none }
+    a.toc:visited { text-decoration: none }
+  </style>
+</HEAD>
+
+<body>
+
+<center>
+<p class="title"><b>Elsa Frequently Asked Questions</b></p>
+</center>
+
+<p>
+This page has answers to questions that I've received and think
+might be useful generally.
+
+<h1>Contents</h1>
+
+<p>
+<!-- BEGIN CONTENTS -->
+<!-- automatically generated by insert-html-toc; do not edit the TOC directly -->
+<ul>
+  <li><a class="toc" href="#dependent_base_names">1. Why can't Elsa find names in template base classes?</a>
+</ul>
+<!-- END CONTENTS -->
+
+<a name="dependent_base_names"></a>
+<h1>1. Why can't Elsa find names in template base classes?</h1>
+
+<p>
+Given the input:
+<pre>
+  // foo.cc
+
+  template &lt;class T&gt;
+  class Base {
+  public:
+    int x;
+  };
+
+  template &lt;class T&gt;
+  class Derived : public Base&lt;T&gt; {
+  public:
+    int get_x() {
+      return x;            // line 13
+    }
+  };
+</pre>
+
+<p>
+Elsa (invoked via ccparse) says:
+<pre>
+  foo.cc:13:12: error: there is no variable called `x' (from template; would be suppressed in permissive mode)
+  typechecking results:
+    errors:   1
+    warnings: 0
+</pre>
+
+<p>
+The reason Elsa rejects this input is that it is doing what
+is usually called
+<a href="http://www.google.com/search?q=two+phase+lookup+c%2B%2B">"two phase lookup"</a>,
+officially known as non-dependent name resolution, in template bodies.
+These rules are specified in the C++ Standard, section 14.6.
+
+<p>
+Basically, since the name <tt>x</tt> does not appear to depend on the
+template arguments, it is looked up at the time the template
+definition is being processed.  Further, at definition time, we cannot
+know which specialization of <tt>Base</tt> will be used (since that
+<emph>is</emph> dependent on the template arguments), so none of the
+names from <tt>Base</tt> are visible.  Consequently, no declaration for
+<tt>x</tt> can be found.
+
+<p>
+As the diagnostic indicates, this error is suppressed in permissive
+mode (say <tt>-tr permissive</tt> to <tt>ccparse</tt>) for compatibility
+with gcc prior to version 3.4.
+
+<p>
+To fix the code, change it to:
+<pre>
+    int get_x() {
+      return this-&gt;x;            // line 13
+    }
+</pre>
+
+<p>
+This change has the effect of making <tt>x</tt> depend on the template
+arguments (since <tt>this</tt> inside a template class is considered
+dependent), and hence lookup of <tt>x</tt> will be delayed until 
+the template is instantiated, at which point we will know which <Tt>Base</Tt>
+will be used and can therefore look inside it.  Assuming the <Tt>Base</Tt>
+used is the one shown above, <tt>x</tt> will then be found.
+
+
+</body>
+</html>

Added: vendor/elsa/current/elsa/doc/function_templates.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/function_templates.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/gv-xwd-convert-png
===================================================================
--- vendor/elsa/current/elsa/doc/gv-xwd-convert-png	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/gv-xwd-convert-png	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+#!/bin/sh
+# script to:
+#   - run gv to view a postscript image
+#   - run xwd to capture that image to a file
+#   - run convert to crop and convert format
+#   - ending up in PNG
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 basename"
+  echo "  converts <basename>.ps"
+  exit 0
+fi
+
+if [ ! -f "$1".ps ]; then
+  echo "file not found: $1".ps
+  exit 2
+fi
+
+# run gv in background
+gv "$1".ps &
+gvPid=$!
+
+# xwd, wait for user
+echo "when the GV window appears, and the cross hair changes, click it"
+sleep 2
+xwd >"$1".xwd || exit
+
+# kill gv
+kill $gvPid
+
+# convert the image
+convert -crop 889x707+133+87 "$1".xwd "$1".png || exit
+echo "created $1.png"
+
+rm "$1".xwd
+
+
+
+
+
+
+


Property changes on: vendor/elsa/current/elsa/doc/gv-xwd-convert-png
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/doc/hex_float_lit.dot
===================================================================
--- vendor/elsa/current/elsa/doc/hex_float_lit.dot	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/hex_float_lit.dot	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+// hex_float_lot.dot
+// automaton for recognizing hexadecimal floating-point literals
+
+digraph "Hex Floating Literals" {
+
+  rankdir = LR;
+  orientation = land;
+
+  node [ shape = doublecircle ]; i j;
+
+  node [ 
+//    label = ""
+    shape = circle
+  ];
+
+  a -> b  [ label = "0" ];
+
+  b -> c  [ label = "[xX]" ];
+
+  c -> d  [ label = "HEX" ];
+  c -> "e'" [ label = "\".\"" 
+              //constraint = false 
+              ];
+
+  d -> d  [ label = "HEX" ];
+
+  d -> e  [ label = "\".\"" ];
+  d -> g  [ label = "[pP]" 
+            constraint = false 
+          ];
+
+  e -> f  [ label = "HEX" ];
+  e -> g  [ label = "[pP]" 
+            constraint = false ];
+
+  "e'" -> f [ label = "HEX"
+              constraint = false ];
+
+  f -> f  [ label = "HEX" ];
+
+  f -> g  [ label = "[pP]" ];
+
+  g -> h  [ label = "\"+\"" ];
+  g -> h  [ label = "\"-\"" ];
+
+  h -> i  [ label = "[0-9]" ];
+
+  i -> i  [ label = "[0-9]" ];
+
+  i -> j  [ label = "[fFlL]" ];
+
+
+
+
+}

Added: vendor/elsa/current/elsa/doc/index.html
===================================================================
--- vendor/elsa/current/elsa/doc/index.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/index.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2 @@
+Please see 
+<a href="../index.html">../index.html</a>.

Added: vendor/elsa/current/elsa/doc/lexer_build.dot
===================================================================
--- vendor/elsa/current/elsa/doc/lexer_build.dot	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/lexer_build.dot	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,54 @@
+// lexer_build.dot
+// information flow for building the Elsa lexer
+
+digraph "Elsa Lexer Build Process" {
+
+  // ------- left half: produce lexer.yy.cc -------
+
+  "cc.lex" [
+    URL = "cc.lex"
+  ];
+
+  "cc.lex" -> "merge_lexer_exts.pl";
+  "gnu.lex" -> "merge_lexer_exts.pl";
+
+  "merge_lexer_exts.pl" [
+    shape = rectangle
+  ];
+
+  "merge_lexer_exts.pl" -> "lexer.lex";
+  "lexer.lex" -> "flex";
+
+  "flex" [
+    shape = rectangle
+  ];
+
+  "flex" -> "lexer.yy.cc";
+
+
+  // ------- right half: produce cc_tokens.* -------
+
+  "cc_tokens.tok" -> "make-token-files";
+  "gnu_ext.tok" -> "make-token-files";
+
+  "make-token-files" [
+    shape = rectangle
+  ];
+
+  "make-token-files" -> "cc_tokens.h";
+  "make-token-files" -> "cc_tokens.cc";
+  "make-token-files" -> "cc_tokens.ids";
+
+
+  // ------- extra --------
+
+  "cc_tokens.h" -> "lexer.yy.cc" [
+    style = dashed
+    constraint = false
+  ];
+
+  "cc_tokens.ids" -> "cc.gr" [
+    style = dashed
+  ];
+
+}

Added: vendor/elsa/current/elsa/doc/lexer_build.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/lexer_build.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/lookup.txt
===================================================================
--- vendor/elsa/current/elsa/doc/lookup.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/lookup.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,464 @@
+lookup.txt
+
+This is my attempt to document what the lookup rules of C++ are (in a
+more digested, concise form than the standard itself, but with liberal
+references to the standard), and how Elsa implements them.  Initially
+the document just covers a few special cases that I have investigated
+carefully, but ideally it will grow to cover all the cases of name
+lookup in C++.
+
+The main difference between the account here and that in the standard
+is that this document will attempt to provide a complete narrative
+from start to finish (i.e., temporally coherent) of how lookup happens
+for a given syntax/context, whereas the standard is organized by
+language feature and so often scatters relevant details in many
+places.
+
+One reference worth mentioning: Brian Malloy has done some
+investigation of how to implement lookup in C++, and his papers are
+at http://www.cs.clemson.edu/~malloy/projects/keystone/keystone.html.
+My analysis is independent, however.
+
+
+
+----------------------------------------------------
+Notions of syntactic context
+
+There are two notions of syntactic context for a lookup.  
+
+Global syntactic context:
+
+The first, which I call "global syntactic context", specifies the
+sequence of scopes to look in for a nominal unqualified lookup.  It is
+affected by the nesting of scope-containing constructs such as
+functions and namespaces.  It is also affected by issues such as
+definitions of class and namespace members outside the syntax of their
+containing entity, and visibility of various scopes during template
+instantiation.
+
+Local syntactic context:
+
+The second kind of context, what I call "local syntactic context", is
+the immediately surrounding neighborhood of tokens, giving contexts
+like "function name in a function call", "type specifier in a
+declaration", etc.  The nominal lookup rules are in many cases
+slightly adjusted depending on this local context.
+
+This rest of this file has two parts.  The first part discusses global
+syntactic context, and the second part discusses local syntactic
+context.  Then, in principle, to find out the procedure for lookup of
+a given occurrence of a name, one first consults the global syntactic
+context rules to determine a nominal scope search order, which is then
+modified by the rules for the local syntactic context.
+
+
+====================================================
+============= Global syntactic context =============
+====================================================
+
+
+----------------------------------------------------
+Scope chaining
+
+As with most languages, C++ lookup often provides for searching in a
+sequence of locations (scopes), with priority given to the earliest
+scope that contains the name being looked up (e.g., 3.4.1p1).  I call
+this phenomenon "scope chaining".
+
+There are four kinds of scope chaining mechanisms:
+  1. syntactic nesting for the current scope (Env::scopes)
+  2. syntactic nesting for non-current scopes (Scope::parentScope)
+  3. namespace 'using' directives (Scope::usingEdges)
+  4. base classes (CompoundType::bases)
+
+Env is responsible for internally following chains 1 and 2; they are
+(only) used for unqualified lookup.  Scope is responsible for
+following chains 3 and 4; Env delegates to Scope as necessary.
+Consequently, using Scope::lookup (as opposed to Env::lookup) disables
+use of chains 1 and 2.  LF_IGNORE_USING disables chain 3.
+LF_INNER_ONLY disables all four chains.  Currently, nothing disables
+chain 4 by itself.
+
+
+-------------------------------------------------------
+Scope::lookup: Lookup within a particular Scope
+
+Lookup within a scope has input:
+  - StringRef name     : name of symbol to look up
+  - Env env            : for error reporting (if not LF_SUPPRESS_ERROR)
+  - LookupFlags flags  : lookup modifiers
+And has output:
+  - LookupSet &set     : set of entities referred to by 'name'
+
+First, Scope::variables or Scope::typeTags is queried, depending
+on LF_QUERY_TAGS.  If this yields a hit, the resulting variable's
+overload set (if any) is expanded and placed in a temporary 'set'.
+
+If LF_INNER_ONLY, return what we have.
+
+Next, if this Scope is a namespace, and LF_IGNORE_USING is not
+specified, the 'using' directive edges are considered, as per 7.3.4
+and 3.4.3.2, adding to 'set' (scope chain 3 above):
+
+  (TODO: explain this process)
+
+If 'set' is not empty, return.
+
+Finally, if this Scope is a class, its base classes are searched
+according to 10.2 (scope chain 4 above):
+
+  - For each of the base class subobject, we search for 'name' in the
+    scope corresponding to the subobject's class (Scope::lookup with
+    LF_INNER_ONLY).
+
+  - If we find entities v1 and v2 with the given name:
+    - If v1 hides v2 (v2's subobject is an ancestor of v1's
+      subobject), or vice versa, ignore the hidden entity (10.2p6).
+    - If v1 and v2 are the same entity (just in different subobjects),
+      we can regard them as the same if the entity is static, a type,
+      or an enumerator (10.2p5).
+
+
+-------------------------------------------------
+Env::lookupPQ: Lookup of possibly-qualified names
+
+Input:
+  - Possibly empty sequence of qualifiers; each qualifier is
+    - StringRef name
+    - Possibly empty sequence of template arguments
+  - StringRef name (final name)
+  - Possibly empty sequence of template arguments (final targs)
+  - Lookup flags
+Output:
+  - LookupSet &set
+
+If the name is unqualified, then the lookup is delegated to
+Env::unqualifiedLookup (with scope=NULL).  See below.
+
+For qualified lookup (3.4.3), the first qualifier in the chain is
+looked up using unqualified lookup (in Env::lookupScope), and any
+template arguments applied, to obtain a Scope object.  If the
+qualifier is "::", the global Scope is used.
+
+Subsequent lookups are done in the Scope computed from the previous
+qualifiers, forming a chain of lookups, until the final name is
+looked up in the final qualifier's Scope.
+
+Finally, unless LF_TEMPL_PRIMARY is set in 'flags', the template
+arguments are applied to the final name.  For this to be possible,
+the lookup must have been unambiguous, so any caller of lookup that
+*can* accept a lookup set *must* specify LF_TEMPL_PRIMARY.
+
+If LF_TEMPL_PRIMARY *is* set, then the final template arguments (if
+any) are ignored.
+
+If the lookup is being done in the context of an uninstantiated
+template, and any of the qualifiers are dependent types (14.6.2.1),
+then either Env::dependentTypeVar or Env::dependentVar will be the
+final result of lookup (depending on whether we are expecting to find
+a type or a variable).  It is the responsibility of the caller to
+decide what to do about lookups that turn out to be dependent.
+(Sometimes the dependent(Type)Var can be used directly, and sometimes
+it cannot.)
+
+
+-------------------------------------------------
+Env::unqualifiedLookup: Lookup of unqualified names
+
+Input:
+  - StringRef name
+  - LookupFlags flags
+Output:
+  - LookupSet &set
+
+(It turns out to be convenient to allow callers to pass a Scope, in
+which case this function simply delegates to Scope::lookup.  The
+description here ignores this possibility.)
+
+This function is responsible for doing lookup in the "current" scope,
+i.e., the set of scopes visible where the name appears.  The sequence
+of scopes to be searched is maintained in Env::scopes, and is updated
+as the recursive tcheck traversal enters/exits syntactic constructs
+that contain scopes (functions, blocks, namespaces, etc.).  
+
+This function is responsible for interpreting the contents of
+Env::scope.  At least at the moment, it contains scopes arising from
+both chains 1 and 2 above; where necessary, Scope::parentScope is
+traversed in the process of updating Env::scope.
+
+If LF_INNER_ONLY is specified, only the topmost element of Env::scope
+is used.  This corresponds to the innermost enclosing scope.  This is
+useful when a name is about to be added to the innermost scope, and we
+need to check if the name has already been declared.
+
+Otherwise, the scopes in Env::scope are searched in turn, stopping
+when the name is found.  
+
+As a wrinkle, the current design allows for certain Scopes to be
+searched in an order different from their physical ordering in
+Env::scope, via the Scope "delegation" mechanism.  This is a design
+wart that should probably be fixed.
+
+
+-------------------------------------------
+How is class member use-before-declaration implemented?
+
+One well-known difficulty with C++ name lookup is 3.3.6p1b1, which
+says that the scope of a class member includes (among other things)
+function bodies that occur textually *before* the member declaration.
+This is problematic because it means that it is not possible to
+classify each identifier as type or variable name based only on the
+text that precedes it.
+
+The (somewhat novel) solution adopted in Elsa is to allow each
+identifier to be interpreted as *both* a type and a variable.  The
+parser yields *all* possible resulting parses (represented compactly
+with nearly maximal sharing of identical subparses).  Later, this
+representation is disambiguated by the type checker.
+
+The reason this makes things easier is that, having created an
+(ambiguous) AST, it is easy for the type checker to skip over method
+bodies during a first pass over the class member declarations, and
+then make a second pass once the class' scope is completed.  The
+mechanism is implemented in TS_classSpec::tcheckIntoCompound.
+
+The alternative, using the traditional feedback loop from the symbol
+table to the lexer, would be to have the lexer save the method bodies
+(perhaps as a textual string) somewhere, and then re-lex them once the
+class symbol table is built.  It is my engineering opinion that it is
+better to avoid complicating lexing and parsing, and instead do
+disambiguation during type checking, where the full lookup mechanism
+is already present.
+
+
+
+====================================================
+============= Local syntactic context ==============
+====================================================
+
+
+-----------------------------------------------------------
+E_funCall: Function name of a function call
+
+Note that context-specific name lookup only occurs if the 'func' is an
+E_variable or an E_fieldAcc.  Both contain a PQName, here called 'name'.
+
+At an E_funCall, we have the following information:
+  - func
+    - receiver object expression (if is E_fieldAcc)
+    - qualifiers (optional)
+    - StringRef name (name->getName())
+    - template arguments (optional), 'targs'
+  - function (expression) arguments, 'eargs'
+
+Lookup is split across E_funCall::inner1_tcheck and
+E_funCall::inner2_tcheck.  This split is for performance reasons, and
+forces a certain partition of the work (see comments in
+Expression::tcheck for more details).
+
+inner1's main job is to map the 'name' to an initial set of Variable 
+object pointers.  The set includes all overloaded instances from all
+relevant namespaces (i.e., those found via 'using' directives).
+
+  * Do an ordinary (as opposed to argument dependent) lookup of the
+    name, using the receiver object type, the qualifiers, and the
+    StringRef name.  Lookup is as specified in 10.2 if E_fieldAcc, or
+    3.4 if E_variable.
+
+  * If template arguments are present but the lookup did not find any
+    template functions, issue an error.
+
+The result of the inner1 lookup is carried in the 'candidates' list.
+
+inner2's job is to pick up where inner1 left off, and use the
+remaining information in the E_funCall to pick exactly the right
+Variable for the function call site, doing template instantiation and
+overload resolution as necessary.  It does these steps:
+
+  * It regards the set computed by inner1 (and stored in 'candidates') 
+    as denoting an initial candidate set (possibly empty).
+
+  * If no receiver object and no qualifiers are present, augment the
+    candidate set by using argument dependent lookup (3.4.2).
+
+  * Refine/filter the candidate set; for each candidate:
+
+    - If template arguments are explicitly present, but the candidate
+      is not a template, remove it.
+
+    - If the candidate is a template, bind the 'targs' (if present) to
+      template parameters (14.8.1), and then do template argument
+      deduction (using the 'eargs') to determine the remaining template
+      parameters (14.8.2, 14.8.2.1).  If any incompatibility is found,
+      or not all template arguments have been determined, remove the
+      candidate.  Otherwise, replace the candidate with its (fully
+      concrete) instantiation Variable.
+
+  * Use 'eargs' to do overload resolution (13.3) to select the best
+    candidate from the refined candidate set.
+
+
+-----------------------------------------------------------
+E_fieldAcc: Lookup of a field name after '.' or '->'
+
+Sections discussed here:
+  - 3.4.5: Lookup rules for field names.
+  - 5.2.4, 5.2.5: Meaning of expressions with '.' and '->'.
+  
+Other relevant sections:
+  - 13.3: Overloaded function name used in a function call.
+  - 13.4: Overloaded function name used in other contexts.
+  - 13.5.6: If '->' is overloaded.
+  - 14.6.2.2: Issues relating to dependent lookup.
+
+I am going to ignore the possibility of '->' and concentrate only on
+the '.' option.  (Perhaps I will ammend this later to discuss '->'.)
+
+The structure of an arbitrary E_fieldAcc can be dissected as follows:
+
+  LHS           ICC QUAL          FIELD
+  -----------   --- ------------- -------------------------------
+  object-expr . ::  qualifiers :: identifier            (FIELD case 1)
+                                  ~ identifier                     (2)
+                                  operator (op)                    (3)
+                                  operator (type-id)               (4)
+                                  identifier < targs >             (5)
+                                  'template' identifier < targs >  (6)
+
+with components:
+  LHS, "left-hand side": the object being accessed.
+  ICC, "initial colon-colon": A leading "::".  Optional.
+  QUAL, "qualifiers": Qualifiers before FIELD.  Optional.
+  FIELD: The field being accessed.  There are six possibilities.
+  
+Note that the presence of ICC implies that either QUAL is also
+present, or that FIELD is case 1, 3 or 5.
+
+I will divide this space along four dimensions:
+  - Whether the LHS is a class type or a scalar (non-class) type.
+  - Whether ICC is present.
+  - Whether QUAL is present.
+  - Which of the six options for FIELD is used.
+The notation "X" means "don't care".
+
+For each case, this table says which paragraphs of section 3.4.5 of
+the standard are applicable:
+
+  col:  1   2     3     4      5
+  LHS:  X   class class scalar scalar
+  ICC:  yes no    no    no     no
+  QUAL: X   yes   no    yes    no
+        --- ----- ----- ------ ------
+        5   4     1,2   E      E      identifier            (FIELD case 1)
+        5   4     2,3   **     2,3    ~ identifier                     (2)
+        5   4     2     E      E      operator (op)                    (3)
+        5   4     2,7   E      E      operator (type-id)               (4)
+        5   4     1,2   E      E      identifier < targs >             (5)
+        5   4     2*    E      E      'template' identifier < targs >  (6)
+        5   4     2     E      E      ~ identifier < targs >           (7)
+
+The code 'E' means it is a syntax error.
+
+The code '**' is a case that is not covered by the standard.  Below,
+I give my best guess as to the intention.
+
+Note: The cell marked '2*' *is* covered by paragraph 2, because the
+leading 'template' is not considered part of the id-expression, so it
+does not prevent it from being an unqualified-id.
+
+Note: The rules of paragraph 1 are used to decide between cases 1 and
+5 of FIELD, so I show paragraph 1 in both cells without qualifiers.
+The standard does not explicitly state how to distinguish between
+cases 1 and 5 if qualifiers are present; I assume the intent is to
+generalize paragraph 1 in the obvious way, respecting which paragraph
+specifies how to lookup the qualified name.
+
+Note: Paragraph 6 (type checking template arguments in the scope where
+the E_fieldAcc occurs) potentially applies to columns 1, 2 and 4, and
+rows 5, 6 and 7.
+
+Section 3.4.3 (qualified lookup) is also relevant.  3.4.3p4 applies
+to column 1, and 3.4.3p5 applies to columns 1 and 2.
+
+So, given all of the above, the procedure for resolving the RHS of
+an E_fieldAcc is:
+
+  1. Type-check the LHS.
+
+  2. If the LHS type is not a class, check that the FIELD is case 2,
+     then:
+
+     2a. If QUAL is present (code '**'), divide the RHS as follows:
+
+           true-qualifiers :: identifier1 :: ~ identifier2
+
+         Do qualified lookups of true-qualifiers::identifier1 and
+         true-qualifiers::identifier2.  Both lookups should yield the
+         same type as the LHS (5.2.4).
+
+     2b. If QUAL is not present, lookup the identifier in the current
+         scope, and check that it is the same type as the LHS 
+         (3.4.5p2,3).
+
+     Stop.  
+     
+  The remaining procedure is for class-typed LHSs.  Call the class C.
+
+  3. If ICC is present (3.4.5p5), let N be the global scope.  Go to
+     step 5.
+
+  4. If ICC is not present but QUAL is present (3.4.5p4), call the
+     first qualifier in the sequence Q.  (Does this apply if Q is
+     a template-id?  I am going to assume so, but a strict reading
+     would say no.)
+
+     4a. Perform unqualified lookup of Q.  If found, this must be
+         a class or namespace.
+     4b. Lookup Q in C.  If found, this must be a class.
+     4c. If lookups 4a and 4b both succeed, they must name the same
+         class N.  If only one succeeds, call its result N.  If neither
+         succeeds, report error.       
+
+  5. Given the computed initial scope N above, divide the RHS:
+
+       N :: leading-qualifiers :: final-qualifier :: FIELD
+
+     (3.4.3p4)  Do qualified lookup of leading-qualifiers, starting in
+     scope N.  Call the result LQ.  Lookup final-qualifier in LQ; call
+     the result FQ.
+
+     5a. If FQ is a namespace, lookup FIELD in FQ.
+     5b. If FQ is a class, lookup FIELD in LQ.
+
+  6. If neither ICC nor QUAL are present (3.4.5p1,2,3):
+
+     6a. If FIELD is case 1, 3, 5 or 6 (3.4.5p2), lookup FIELD in C.
+
+     6b. If FIELD is case 2 (3.4.5p3):
+           - Perform unqualified lookup of the identifier.
+           - Lookup the identifier in C.
+         The lookups must yield a class, the same class if they both
+         succeed.
+
+     6c. If FIELD is case 4 (3.4.5p7):
+           - Perform unqualified lookup of the type.
+           - Lookup the type in C.
+         *Both* must succeed, and name the same type.
+
+         Actually, this applies even to qualified names (3.4.3.1p1).
+
+  7. Having looked up the FIELD, it must name a nonempty set of members
+     of C, or a nonempty set of members of one of C's base classes.  If
+     the set contains more than one element, overload resolution will
+     happen later, depending on the local syntactic context of this
+     E_fieldAcc.
+
+
+
+
+
+
+
+
+
+EOF

Added: vendor/elsa/current/elsa/doc/parser_build.dot
===================================================================
--- vendor/elsa/current/elsa/doc/parser_build.dot	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/parser_build.dot	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// parser_build.dot
+// information flow for building the Elsa parser
+
+digraph "Elsa Parser Build Process" {
+
+  "cc_tokens.ids" -> "Elkhound";
+  "cc.gr" -> "Elkhound";
+  "gnu.gr" -> "Elkhound";
+  
+  "Elkhound" [
+    shape = rectangle
+  ];
+
+  "Elkhound" -> "cc.gr.gen.h";
+  "Elkhound" -> "cc.gr.gen.cc";
+  "Elkhound" -> "cc.gr.gen.out\n(optional)";
+}

Added: vendor/elsa/current/elsa/doc/parser_build.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/parser_build.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/permissive.txt
===================================================================
--- vendor/elsa/current/elsa/doc/permissive.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/permissive.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,104 @@
+2005-08-09 03:17
+
+The "permissive" Flag
+---------------------
+
+Elsa can be set in a mode that I call "permissive".  From the ccparse
+command line, "-tr permissive" will do it.  Internally, this has the
+effect of setting Env::doReportTemplateErrors to false.
+
+The effect of the flag is to suppress errors (and warnings) that arise
+during processing of uninstantiated template bodies.  Normally, Elsa
+diagnoses (flags as an error) any syntax in a template body that
+cannot generate a valid specialization (instantiation).  However, in
+permissive mode, most of those errors will be discarded (EF_STRONG
+errors and warnings are the exception), and therefore the syntax will
+only be diagnosed if/when the template is instantiated.
+
+Quoting the Standard, 14.6p7:
+
+  ... No diagnostic shall be issued for a template definition for which
+  a valid specialization can be generated.  If no valid specialization
+  can be generated for a template definition, and that template is not
+  instantiated, the template definition is ill-formed, no diagnostic
+  required.  ...  Note: if a template is instantiated, errors will be
+  diagnosed according to other rules in this Standard.
+
+  // example in 14.6p7
+  int j;
+  template<class T> class X {
+          // ...
+          void f(T t, int i, char* p)
+          {
+                  t = i;          // diagnosed if X::f is instantiated
+                                  // and the assignment to t is an error
+                  p = i;          // may be diagnosed even if X::f is
+                                  // not instantiated
+                  p = j;          // may be diagnosed even if X::f is
+                                  // not instantiated
+          }
+          void g(T t) {
+                  +;              // may be diagnosed even if X::g is
+                                  // not instantiated
+          }
+  };
+
+Note that Elsa is only supposed to report an error in a template when
+no specialization can be generated, meaning the input code is truly
+invalid.  It has lots of checks (even in non-permissive mode) to avoid
+emitting spurious errors, i.e., errors that in fact would not be
+errors if the right set of template arguments were provided.  If you
+observe Elsa behaving contrary to this intent, please report it as a
+bug.
+
+Now, you might ask why bother attempting to typecheck (uninstantiated)
+template bodies at all, given that diagnosing errors is in some sense
+optional?  The answer is that to implement non-dependent lookup (also
+known as two phase lookup), template bodies must be analyzed in
+sufficient detail to distinguish dependent from non-dependent names,
+and perform lookup on the non-dependent names:
+
+  // example in 14.6.3p1
+  void g(double);
+  void h();
+
+  template<class T> class Z {
+  public:
+          void f() {
+                  g(1);          // calls g(double)
+                  h++;           // ill-formed: cannot increment function;
+                                 // this could be diagnosed either here or
+                                 // at the point of instantiation
+          }
+  };
+
+  void g(int);                   // not in scope at the point of the template
+                                 // definition, not considered for the call g(1)
+
+So in fact the Standard effectively *requires* that template bodies be
+typechecked, and Elsa does.  Given that Elsa has to do such checking
+anyway, it reports the errors it finds, because that helps to debug
+Elsa (since we don't have to wait for an instantiation to observe
+certain bugs).
+
+But, GCC and ICC do not do this.  They implement two phase lookup, but
+apparently also suppress errors not related to lookup.  This causes a
+problem for automatic minimization, since the minimizer tends to just
+home in on syntax that Elsa diagnoses earlier than GCC would.
+
+Therefore, Elsa has the permissive flag.  With this flag enabled, Elsa
+delays diagnosis as well, making its behavior more similar to GCC and
+thereby improving the likelihood of successful automatic minimization.
+So, usually, inputs that GCC accepts and Elsa rejects should be
+minimized with Elsa in permissive mode.
+
+The specification of the behavior of this flag is a bit ugly.
+Basically, if an error arises from checking a template and neither GCC
+or ICC report it, it should be suppressed in permissive mode.  Since
+there is no easy way to determine exactly what is reported by these
+compilers, its behavior necessarily must evolve as more testcases are
+seen.
+
+
+
+EOF

Added: vendor/elsa/current/elsa/doc/serialization.txt
===================================================================
--- vendor/elsa/current/elsa/doc/serialization.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/serialization.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,349 @@
+2005-08-19 15:46
+
+XML Serialization
+-----------------
+Daniel S. Wilkerson
+
+Elsa provides Xml serialization and de-serialization for the AST
+classes and the Type system classes (which include Scope, Variable,
+templates etc.)
+
+**** The meaning of serialization
+
+Elsa provides strong guarantees as to the meaning of serialization;
+this is not a best-effort feature.  More specifically, the following
+diagrams commute.  These diagrams are actually tested in checkxml.mk
+which contains optional tests that are not run by default but will run
+if you type "make checkxml".  In particular, diagram C is currently
+tested on 714 test and thus is considered to be very reliable.  Note
+that the later the serialization comes, the more information it must
+preserve and thus the more difficult it is to make the diagram
+commute.
+
+In diagram B below, "print" means pretty-print.  Note that "parse"
+really means "parse and then typecheck to disambiguate the AST and
+then discard the derived types".  That is, we do not test serializing
+an ambiguous "ASForest".
+
+    diagram B:
+    parse ------------------------> typecheck -> print
+         \                      /
+          -> toXml -> fromXml -
+
+In diagram C below, "print" means debug-print, which Scott says
+contains strictly more information than pretty-printing.
+
+    diagram C:
+    parse -> typecheck ------------------------> print
+                      \                      /
+                       -> toXml -> fromXml -
+
+There are plans to make diagram D, below, commute, but for that to
+happen we have to finish deciding exactly what it means 1) to
+de-serialize a lowered AST with some of the template constructs
+missing, and 2) to print a lowered AST (should it print the template
+instantiations without the primary in such a way that it would compile
+and produce a program with the same semantics?).
+
+    diagram D:
+    parse -> typecheck -> lower ------------------------> print
+                               \                      /
+                                -> toXml -> fromXml -
+
+**** How serialization works
+
+The Elsa AST classes are maintained in Scott's AST language in .ast
+files and are generated by the astgen tool.  Generic traverse()
+methods are generated on each AST class for use with the Visitor
+design pattern; the Visitor class is also generated.  AST Xml
+serialization is done as a Visitor using this pattern.  All of this
+auto-generation is necessitated by the fact that there are over 140 AST
+classes; it also ensures uniformity.
+
+The Elsa Type-system classes, by which we also mean Scope, Variable,
+and template related classes, are serialized with a special-purpose
+serialization walk rather than a Visitor design pattern.  There is a
+generic type-system traverse() but it is not used; a special-purpose
+walk is more straightforward for this purpose.
+
+The AST and Type graphs are serialized by separate modules.  However,
+the AST and Type graphs also point into one another.  Thus the two
+modules call into one another at those points, and the tags for the
+two sets of objects interleave with one another in the output.
+
+* Mapping objects to tags
+
+All classes map to a tag of the same name that is used to serialize
+the state of the class.  Each member of a class maps to an attribute
+of its tag.
+
+        The state of "simple" members, such as a bool, int, or string,
+are fully captured in the attribute value.
+
+        The state of "complex" members, such as an object, cannot fit
+into an attribute string, so we employ a layer of indirection which
+Scott calls the "Rat's Nest Scheme" as follows.  Given a parent
+pointing to a child: 1) in the parent tag for the attribute pointing
+to the child a unique id value for the child is written out; 2) the
+child is serialized as a child-tag nested within the parent tag; 3)
+the child tag gets a unique "_id" field so that upon de-serialization
+it can be matched up with the parent field pointing at it.  Since in
+an OO language potentially any object can be pointed to, in practice
+all tags corresponding objects get an "_id".  See below for more on
+the non-trivial task of generating unique ids.
+
+        The state of "container" members, such as lists or maps, is
+dealt with by simply promoting this particular "static instance" of a
+container to its own tag "class": that is, the tag name is made up of
+1) the parent class and 2) the member name of the container in that
+parent.  See below for more on tag naming convention.
+
+        Containers being classes gives rise to the need for "item"
+members: anonymous members of the new container "classes".  That is,
+if we just serialize each member of a container, we might hit an
+object that has been serialized before and therefore will be skipped
+(see below); there would then be no record at all that it is in this
+container.  Therefore we wrap members of list and map classes with
+"Item" tags; they just hold a pointer to the contained object in case
+it doesn't actually get serialized there.  These "item" tags are the
+only ones that do not get their own "_id" tag as during parsing their
+single attribute is just stored directly into their container parent;
+they don't have a separate existence in the OO world so no one ever
+points to them.
+
+Circularities in the object graph to not pose a problem: All
+*pointers* to objects are *always* serialized as an attribute, however
+an *object* is only serialized *once*.
+
+Note that to simplify things, all tags are container tags whether they
+point to any complex objects or not.
+
+**** How de-serialization works
+
+Separate modules are also used for de-serializing the AST and Type
+graphs.  However recall that their tags are mixed in a fine-grained
+way in the Xml.  This situation is handled by the use of a design
+pattern I call: "non-deterministic virtual-dispatch".  We take the
+de-serializers for the AST and for the Types and register them both
+with the general-purpose class XmlReader.  During parsing when a tag
+or attribute is encountered XmlReader asks both of the registered
+readers to handle it in turn.  Each reader 1) either handles it or not
+and then 2) returns a boolean saying whether it was able to: that is,
+we "non-deterministically" do virtual dispatch to both registered
+reader "subclasses" at once.  It is an error if neither can handle it,
+and the dispatch is really done serially and short-circuits at the
+first call that says it handled the tag.  The consequence is that
+parsers for multiple Xml sub-languages can be written separately and
+their tags interleaved.
+
+The de-serializer is a stack machine.  When we de-serialize a tag, an
+object is constructed to represent it and pushed onto the stack.
+Every tag has a special "_id" attribute and when an object is
+de-serialized it is filed in the id2obj hashtable under its id.  When
+we encounter a close tag, we check that it matches the object on the
+top of the stack and pop.
+
+An attribute is always parsed in the context of the object on the top
+of the stack.  If it is a simple type, we just write it into the
+appropriate field of the top object.  If it is an object id, we create
+an UnsatLink object to record 1) the id, 2) a pointer to the member of
+the top object that should be updated to point at the referent object
+having that id when it is found later during link satisfaction, see
+below, 3) the type of the pointer so we can deal with up-casting
+problems that arise with multiple inheritance (see below), and 4)
+whether this parent/child relationship is a pointer or is one of
+embedding.
+
+When the tags have been de-serialized we satisfy all of the dangling
+links as follows.  For each UnsatLink we 1) look up its id in the
+id2obj hashtable.  If the parent/child relationship is a pointer (as
+recorded earlier) we 2a1) do an up-cast if needed from the
+de-serialized object type to the link type, 2a2) do a pointer
+assignment satisfying the link.  If the parent/child relationship is
+one of embedding we 2b) call operator=() to initialize the object from
+the temporary one created on the stack (which is no longer needed).
+
+Note that there is an alternative possible design for the temporary
+representation of unsatisfied links during de-serialization.  If you
+create an UnsatLink object for each unsatisfied link it is going to fragment
+your heap even if you delete them, it is slow to make them all etc.
+When the parent points to the child rather than embedding it, the
+unsatisfied link can be simply written as an int into the still-unused
+pointer to the child.  To distinguish it from a real pointer, recall
+that real points have at least two low-order zero bits; just set them
+to something else.  There is an additional restriction: there are only
+3 other possibilities on a 32-bit machine, so only up to three
+identity prefixes (see below) can be stored this way.  When an object
+is de-serialized we can now just look at the top of the stack and
+search through every pointer member looking for an id that matches
+that of the object we just de-serialized and replace it with the real
+pointer.  This scheme reduces the load on the list of UnsatLink-s as
+state above, and also on the id2obj hashtable.  Given the memory
+locality, it is probably more cache friendly as well.  It is currently
+unimplemented.
+
+**** Identity
+
+An object needs a unique id both so 1) we can make sure we don't
+serialize it twice by "checking it off" in some hashtable when we
+serialize it, and 2) so we can serialize separately a) the reference
+to an object and b) the object itself.
+
+This second feature is needed so that we can deal with circularities
+in the object graph, but it also makes any graph, even a tree, easier
+to serialize because we can separate 1) serializing the header node
+with its references to its children from 2) serializing the children.
+The consequence is that we can now use a Visitor design pattern to
+serialize rather than a walk.  This design is essential to using a
+generic lowered traversal to serialize the lowered AST rather than a
+special-purpose lowered-serializing walk.  Such a special-purpose
+design would be error prone and not a good factoring since both
+serialization and generating a lowered view of the AST/Types are
+complex.
+
+It turns out that a unique id is harder to come up with than you
+might thing.  The heap address of an object is not a unique id!  1)
+There are circumstances where more than one object can have the same
+heap address.  2) There are circumstances where one object can have
+more than one heap address.  As an exercise you might want to come up
+with an example of each situation before reading further.
+
+Two objects with the same heap address: The situation where more than
+one object can share the same heap address is with inheritance and
+embedding.  If a class A has a member B that 1) comes first in the
+list of A's members, 2) is embedded, not pointed to, then A and B will
+share the same heap address.  The solution to this is to break
+symmetry with a system of id-prefixes.  The prefix of an object is
+just a function of its class and we choose prefixes such that no two
+classes with the same prefix ever embed within each other, even
+transitively(!); now the ids are unique.  Prefixes are documented
+below.
+
+The situation of two objects sharing the same heap address also arises
+with inheritance, as usually in C++ the superclass is implemented as
+an anonymous embedded member of the subclass.  With single inheritance
+though, there is an easy trick: never serialize the superclass, just
+serialize its members as if they were the members of the subclass
+(which is the illusion that the OO name lookup rules give you anyway);
+do the reverse during de-serialization.  Now, when a pointer points to
+the subclass as if it were the superclass (the whole point of
+inheritance) the fact that they share the same heap address is a
+feature, not a bug.
+
+Two heap addresses for the same object: With multiple inheritance, an
+object can have more than one heap address: if an object A has
+superclasses B and C, then a B-pointer to A and a C-pointer to A do
+*not* have the same value as raw ints.  The solution has two parts.
+
+        1) During serialization, we are sure to always attempt to
+downcast any B or C to an A and render it as an A if we can so that 1)
+information is not lost and that 2) the ids in the pointer attribute
+of the parent and the _id attribute of the child will match.
+
+        2) During de-serialization, when we de-serialize the pointer
+to a B or C, we record that it was a B or C pointer.  When we match up
+the pointer with the de-serialized object later, we up-cast the C
+object to an A or B before setting the pointer.  Recall that since
+serialization is not type-safe and we are not using the real
+type-system to manipulate these objects so we have to record what casts
+are genuinely correct as a separate hand-rolled run-time-type-system as
+we do this.
+
+**** Container non-uniformity
+
+Containers within Elsa come in several templatized classes which are
+in turn instantiated with several container classes.  We don't want to
+make this externally visible in the Xml schema as other analysis tools
+may have different external representations.  We therefore only
+maintain two kinds of containers externally: a "List", sequence of
+objects, and a "NameMap", a map from strings to objects.
+
+Note that the de-serialization handles this situation by using one
+kind of list for de-serializing lists, an ASTList, and one kind of
+name-map for de-serializing NameMaps, a StringRefMap.  This
+one-class-fits-all approach during de-serialization is particularly
+important for the problematic FakeLists which exist only in the
+type-system and have no distinct existence separate from their
+contents.  It is also helpful for lists that do not have a constant
+time append and would have to be prepended to and then reversed.  All
+of this could be handled without the use of ASTList intermediaries at
+the expense of more complexity in the de-serialization code.
+
+However, the situation is more complex than that: when a list tag is
+initially de-serialized, we construct an ASTList template instantiation
+appropriate to the kind of objects that will eventually be contained,
+such as an ASTList<Type>.  We do not want to special-purpose the code
+for appending to a list as new list items are encountered, though it
+could be done.  We therefore exploit our internal knowledge of the
+implementation of ASTList that its contents are pointed to and not
+embedded.  Since all pointers are the same size (on my machine anyway)
+this makes a diagram commute that should not according to the C++ type
+system: we simply cast all ASTLists to ASTList<char> and treat them as
+such for purposes of appending a new element.  Recall that there is a
+final conversion of the list into the actual type that it will be
+after serialization is complete, which may not even be an ASTList.
+Something similar is done for name maps.
+
+Note that there is a separate problem related to containers in that
+the ephemeral "item" tags mentioned above which wrap their contents do
+not map to an object that has permanent existence.  When an item close
+tag is encountered, we simply use the id2obj hashtable right then to
+look up the pointed to object and insert it into the container; the
+item object on the stack can then be deleted.  (Note that at the
+*close* item tag, the contained object must have been de-serialized
+already, either immediately before or before that at some earlier
+time.)  This process prevents item objects from participating in the
+final linker satisfaction process, which, given their ephemeral
+existence, would be unnatural.
+
+However this scheme has one unfortunate consequence: this is the only
+place where the id2obj hashtable has lookups called on it before
+linker satisfaction time.  Since there are *no* insertions into the
+hashtable once linker satisfaction starts if there were also *no*
+lookups at all before linker satisfaction starts we could employ a
+faster algorithm for hashtable construction: 1) while inserting into
+the table, just maintain a list, not a proper hashtable, 2) just at
+the point where the insertions stop and the lookups start, sort.
+
+**** Conventions
+
+Tag names for classes are just the class name.  For nested classes, we
+use the fully qualified name and replace the '::' with an underscore.
+
+Tag names for containers the following three things concatenated with
+underscores 1) the kind (List, NameMap, Map), 2) the name of the class
+that has the container as a member, and 3) the name of the member of
+that class that is the container.  For example the tag of this member
+    class CompoundType {
+      const ObjList<BaseClass> bases;
+    }
+is
+    <List_CompoundType_bases>  // Type system list 'class' convention
+
+You might wonder why it is not something bottom up instead, which might
+more naturally make for a re-usable tag, like this:
+    <List_BaseClass>           // AST system list 'class' convention
+We do not do this because two different classes can have a list of
+BaseClasses that needs to be handled differently, so the
+de-serialization depends on the containing context, which also
+contains implicitly the information that it is a list of BaseClasses.
+
+Each object has an _id attribute which is unique.  Note that the id is
+basically the heap address prefixed by a letter code; the letter code
+is to break symmetry for object with the same heap address, such as a
+class with a first member that is embedded or a non-class such as a
+FakeList node.  Neither the address nor the prefix has no semantics so
+another program rendering out XML in this schema need not use the same
+method, but any method for generating unique ids will work.  The
+prefixes we use are "AST" for AST nodes and the rest are given at the
+top of cc_type_xml.cc at the block of calls to the "identity" and
+"identityTempl" macros.
+
+Each container has a tag that wraps contained items in case the item
+has been previously serialized and therefore may not appear.  They are
+as follows.  Note that they do not correspond to objects constructed
+internally and therefore do not have an '_id' field.  Their unique
+metadata status is indicated by the leading underscore, similarly to
+the '_id' field itself for objects.
+    <_List_Item item=id>
+    <_NameMap_Item name=<name> item=id>

Added: vendor/elsa/current/elsa/doc/template_er.fig
===================================================================
--- vendor/elsa/current/elsa/doc/template_er.fig	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/template_er.fig	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,439 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+0 32 #008a94
+0 33 #733cc6
+0 34 #63799c
+0 35 #080808
+0 36 #946508
+6 6000 3900 7200 4200
+2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 6000 3900 7200 3900 7200 4200 6000 4200 6000 3900
+4 1 0 50 0 0 12 0.0000 4 135 855 6600 4125 MetaValue\001
+-6
+6 2400 4500 3600 4800
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 3600 4800 2400 4800 2400 4500 3600 4500 3600 4800
+4 1 35 50 0 0 12 0.0000 4 180 915 3000 4725 NontypeMP\001
+-6
+6 600 3000 1800 3300
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 1800 3300 600 3300 600 3000 1800 3000 1800 3300
+4 1 35 50 0 0 12 0.0000 4 180 645 1200 3225 TypeMP\001
+-6
+6 600 3600 1800 3900
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 1800 3900 600 3900 600 3600 1800 3600 1800 3900
+4 1 35 50 0 0 12 0.0000 4 180 975 1200 3825 TemplateMP\001
+-6
+6 4200 7500 6600 8175
+6 5400 7500 6600 8175
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 5400 7500 6600 7500 6600 7800 5400 7800 5400 7500
+2 3 0 2 0 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 5925 8100 6000 7950 6075 8100 5925 8100
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 6000 7800 6000 8100
+4 1 0 50 0 0 12 0.0000 4 180 1065 6000 7725 Specialization\001
+-6
+6 4200 7500 5400 7800
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 4800 7650 600 150 4200 7500 5400 7800
+4 1 0 50 0 0 12 0.0000 4 180 630 4800 7725 explicit?\001
+-6
+-6
+6 4200 8625 9600 9675
+1 2 0 1 0 -1 50 0 -1 4.000 1 0.0000 6900 9450 900 150 6000 9300 7800 9600
+1 2 0 1 0 -1 50 0 -1 4.000 1 0.0000 9000 9450 600 150 8400 9300 9600 9600
+2 2 1 1 10 -1 50 0 -1 4.000 0 0 -1 0 0 5
+	 4200 9000 5400 9000 5400 9300 4200 9300 4200 9000
+2 2 0 1 10 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 6000 9000 7800 9000 7800 9300 6000 9300 6000 9000
+2 2 0 1 10 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 8400 9000 9600 9000 9600 9300 8400 9300 8400 9000
+2 3 0 2 10 10 50 0 20 0.000 0 0 -1 0 0 4
+	 5700 9075 5550 9150 5700 9225 5700 9075
+2 1 0 2 10 -1 50 0 -1 6.000 0 0 -1 0 0 2
+	 5400 9150 6000 9150
+2 1 0 2 10 -1 50 0 -1 6.000 0 0 -1 0 0 2
+	 5700 8925 5700 9375
+2 1 2 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 5700 9600 5700 9375
+2 1 2 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 5700 8925 5700 8700
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 8400 9075 8250 9150 8400 9225
+2 1 0 2 10 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 7800 9150 8250 9150
+4 1 0 50 0 0 12 0.0000 4 135 645 4800 9225 Variable\001
+4 1 0 50 0 0 12 0.0000 4 135 1560 6900 9225 AbstractEnumerator\001
+4 1 0 50 0 0 12 0.0000 4 135 885 9000 9225 Enumerator\001
+4 1 0 50 0 0 12 0.0000 4 180 1380 6900 9525 type: Enumeration\001
+4 1 0 50 0 0 12 0.0000 4 135 690 9000 9525 value: int\001
+-6
+6 600 6000 1200 6300
+1 2 1 1 0 7 50 0 -1 4.000 1 0.0000 900 6150 300 150 600 6000 1200 6300
+4 1 0 50 0 0 12 0.0000 4 135 405 900 6225 defn?\001
+-6
+6 7800 6000 8400 6300
+1 2 1 1 0 7 50 0 -1 4.000 1 0.0000 8100 6150 300 150 7800 6000 8400 6300
+4 1 0 50 0 0 12 0.0000 4 135 405 8100 6225 defn?\001
+-6
+6 600 600 4200 1200
+1 2 0 1 -1 -1 50 0 -1 3.000 1 0.0000 3300 1050 900 150 2400 900 4200 1200
+2 2 1 1 18 -1 50 0 -1 3.000 0 0 -1 0 0 5
+	 600 600 1800 600 1800 900 600 900 600 600
+2 2 0 1 18 -1 50 0 -1 3.000 0 0 -1 0 0 5
+	 2400 600 4200 600 4200 900 2400 900 2400 600
+2 1 0 2 18 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 2400 675 2250 750 2400 825
+2 1 0 2 18 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 1800 750 2250 750
+4 1 -1 50 0 0 12 0.0000 4 180 810 1200 825 ArrayType\001
+4 1 -1 50 0 0 12 0.0000 4 180 1440 3300 825 AbstractSizeArray\001
+4 1 -1 50 0 0 12 0.0000 4 180 1260 3300 1125 size: Expression\001
+-6
+6 5700 1500 7500 1800
+2 2 1 1 33 -1 50 0 -1 4.000 0 0 -1 0 0 5
+	 5700 1500 7500 1500 7500 1800 5700 1800 5700 1500
+4 1 0 50 0 0 12 0.0000 4 180 1470 6600 1725 NamedAtomicType\001
+-6
+6 9000 525 12600 2175
+2 2 1 1 12 -1 50 0 -1 4.000 0 0 -1 0 0 5
+	 9000 1200 10200 1200 10200 1500 9000 1500 9000 1200
+2 2 0 1 12 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 10800 900 12600 900 12600 1200 10800 1200 10800 900
+2 2 0 1 12 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 10800 1500 12600 1500 12600 1800 10800 1800 10800 1500
+2 3 0 2 12 12 50 0 20 0.000 0 0 -1 0 0 4
+	 10500 1275 10350 1350 10500 1425 10500 1275
+2 1 0 2 12 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 10200 1350 10500 1350
+2 1 0 2 12 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 10500 825 10500 1875
+2 1 0 2 12 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 10800 1050 10500 1050
+2 1 0 2 12 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 10800 1650 10500 1650
+2 1 2 2 12 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 10500 2100 10500 1875
+2 1 2 2 12 -1 50 0 -1 4.500 0 0 -1 0 0 2
+	 10500 600 10500 825
+4 1 -1 50 0 0 12 0.0000 4 180 465 9600 1425 Scope\001
+4 1 -1 50 0 0 12 0.0000 4 180 1650 11700 1125 MetaParameterScope\001
+4 1 -1 50 0 0 12 0.0000 4 180 1440 11700 1725 MetaBindingScope\001
+-6
+1 2 0 1 35 7 50 0 -1 4.000 1 0.0000 9600 3150 600 150 9000 3000 10200 3300
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 750 4350 150 150 600 4200 900 4500
+1 2 0 1 0 7 50 0 -1 0.000 1 0.0000 750 4950 150 150 600 4800 900 5100
+1 2 0 1 35 7 50 0 -1 4.000 1 0.0000 11700 4200 900 150 10800 4050 12600 4350
+1 2 0 1 35 7 50 0 -1 4.000 1 0.0000 11715 4508 900 150 10815 4358 12615 4658
+1 2 0 1 35 7 50 0 -1 4.000 1 0.0000 11714 4808 900 150 10814 4658 12614 4958
+1 2 0 1 35 7 50 0 -1 4.000 1 0.0000 11720 3608 900 150 10820 3458 12620 3758
+1 2 0 1 35 7 50 0 -1 4.000 1 0.0000 11719 5108 900 150 10819 4958 12619 5258
+1 2 0 1 35 7 50 0 -1 4.000 1 0.0000 11720 3908 900 150 10820 3758 12620 4058
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 7800 3000 9000 3000 9000 3300 7800 3300 7800 3000
+2 3 0 2 -1 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 7500 3975 7350 4050 7500 4125 7500 3975
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 2
+	 7200 4050 7500 4050
+2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 4200 3900 5400 3900 5400 4200 4200 4200 4200 3900
+2 3 0 2 -1 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 3900 4125 4050 4050 3900 3975 3900 4125
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 2
+	 3900 4050 4200 4050
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 4
+	 3600 4650 3900 4650 3900 3450 3600 3450
+2 3 0 1 0 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 2925 4500 3000 4350 3075 4500 2925 4500
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 1800 4500 900 4500 900 4200 1800 4200 1800 4500
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 1800 5100 900 5100 900 4800 1800 4800 1800 5100
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 1800 3150 2100 3150 2100 3750 1800 3750
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 1800 4350 2100 4350 2100 4950 1800 4950
+2 3 0 2 0 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 2100 4575 2250 4650 2100 4725 2100 4575
+2 3 0 2 0 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 2100 3375 2250 3450 2100 3525 2100 3375
+2 1 0 2 0 -1 50 0 20 0.000 0 0 -1 0 0 2
+	 2400 3450 2100 3450
+2 1 0 2 0 -1 50 0 20 0.000 0 0 -1 0 0 2
+	 2400 4650 2100 4650
+2 1 0 2 34 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2700 6300 2700 8250
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 900 7500 900 9150
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+	1 1 1.00 60.00 120.00
+	1 1 1.00 60.00 120.00
+	 1500 7500 1500 8400
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 1200 8400 3600 8400 3600 8700 1200 8700 1200 8400
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 3300 8400 3300 8100 7500 8100 7500 8400
+2 1 0 2 34 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 2625 8400 2700 8250 2775 8400
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 600 9300 3600 9300 3600 9600 600 9600 600 9300
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 2325 9300 2400 9150 2475 9300
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 825 9300 900 9150 975 9300
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 2400 8700 2400 9150
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 6450 7500 6450 4200
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 7800 4800 9000 4800 9000 5100 7800 5100 7800 4800
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 7800 4200 9000 4200 9000 4500 7800 4500 7800 4200
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 9600 4050 10800 4050 10800 4350 9600 4350 9600 4050
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 9600 4350 10800 4350 10800 4650 9600 4650 9600 4350
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 9600 4650 10800 4650 10800 4950 9600 4950 9600 4650
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 9600 4950 10800 4950 10800 5250 9600 5250 9600 4950
+2 3 0 2 -1 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 9300 4275 9150 4350 9300 4425 9300 4275
+2 3 0 2 -1 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 9300 4875 9150 4950 9300 5025 9300 4875
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 2
+	 9000 4350 9300 4350
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 2
+	 9000 4950 9300 4950
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 4
+	 9600 5100 9300 5100 9300 4800 9600 4800
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 4
+	 9600 4500 9300 4500 9300 4200 9600 4200
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 7800 3600 9000 3600 9000 3900 7800 3900 7800 3600
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 9600 3450 10800 3450 10800 3750 9600 3750 9600 3450
+2 2 0 1 35 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 9600 3750 10800 3750 10800 4050 9600 4050 9600 3750
+2 3 0 2 -1 -1 50 0 20 0.000 0 0 -1 0 0 4
+	 9300 3675 9150 3750 9300 3825 9300 3675
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 2
+	 9000 3750 9300 3750
+2 1 0 2 -1 7 50 0 -1 6.000 0 0 -1 0 0 4
+	 9600 3900 9300 3900 9300 3600 9600 3600
+2 1 1 1 0 -1 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 5400 4050 6000 4050
+2 1 0 1 0 -1 50 0 20 4.000 0 0 -1 0 0 2
+	 1800 5025 2100 5025
+2 1 2 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 2
+	 2100 5025 2400 5025
+2 1 0 1 0 -1 50 0 20 4.000 0 0 -1 0 0 2
+	 1800 4275 2100 4275
+2 1 0 1 0 -1 50 0 20 4.000 0 0 -1 0 0 2
+	 1800 3825 2100 3825
+2 1 0 1 0 -1 50 0 20 4.000 0 0 -1 0 0 2
+	 1800 3075 2100 3075
+2 1 0 1 0 -1 50 0 20 3.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 7500 5025 7800 5025
+2 1 0 1 0 -1 50 0 20 3.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 7350 4275 7800 4275
+2 1 0 1 0 -1 50 0 20 3.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 7350 3825 7800 3825
+2 1 0 1 0 -1 50 0 20 3.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 7500 3075 7800 3075
+2 1 2 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 2
+	 7350 3075 7500 3075
+2 3 0 1 0 -1 50 0 20 3.000 0 0 -1 0 0 4
+	 7650 4575 7500 4650 7650 4725 7650 4575
+2 3 0 1 0 -1 50 0 20 3.000 0 0 -1 0 0 4
+	 7650 3375 7500 3450 7650 3525 7650 3375
+2 1 0 2 0 -1 50 0 -1 0.000 0 0 -1 0 0 2
+	 7500 3450 7500 4650
+2 1 0 2 0 -1 50 0 -1 4.500 0 0 -1 0 0 4
+	 7800 3150 7650 3150 7650 3750 7800 3750
+2 1 0 2 0 -1 50 0 -1 4.500 0 0 -1 0 0 4
+	 7800 4350 7650 4350 7650 4950 7800 4950
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 5250 5700 5250 4200
+2 2 0 1 -1 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 2400 3300 3600 3300 3600 3600 2400 3600 2400 3300
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 600 7200 2400 7200 2400 7500 600 7500 600 7200
+2 1 0 2 34 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 1500 6300 1500 7050
+2 1 0 2 34 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 1425 7200 1500 7050 1575 7200
+2 2 1 1 34 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 1200 6000 3000 6000 3000 6300 1200 6300 1200 6000
+2 1 0 2 35 7 50 0 -1 0.000 0 0 -1 0 0 4
+	 2100 7200 2100 6900 8100 6900 8100 7200
+2 2 0 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 5
+	 4200 4500 5100 4500 5100 4800 4200 4800 4200 4500
+2 1 0 2 0 -1 50 0 -1 4.500 0 0 -1 0 0 3
+	 4575 4500 4650 4350 4725 4500
+2 1 0 2 -1 -1 50 0 -1 6.000 0 0 -1 0 0 2
+	 4650 4200 4650 4350
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+	1 1 1.00 60.00 120.00
+	1 1 1.00 60.00 120.00
+	 7800 7500 7800 8400
+2 2 1 1 10 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 8400 6000 9600 6000 9600 6300 8400 6300 8400 6000
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 7200 7200 9000 7200 9000 7500 7200 7500 7200 7200
+2 1 0 1 -1 -1 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 6150 2700 6150 3900
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 6600 8400 9600 8400 9600 8700 6600 8700 6600 8400
+2 3 0 2 35 35 50 0 20 0.000 0 0 -1 0 0 4
+	 4725 6900 4800 6750 4875 6900 4725 6900
+2 1 0 2 35 7 50 0 -1 0.000 0 0 -1 0 0 2
+	 4800 6600 4800 6900
+2 1 0 1 -1 -1 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 5850 2400 5850 1800
+2 1 0 2 33 -1 50 0 -1 0.000 0 0 -1 0 0 2
+	 6600 1800 6600 2100
+2 3 0 2 33 33 50 0 20 0.000 0 0 -1 0 0 4
+	 6525 2100 6600 1950 6675 2100 6525 2100
+2 2 0 1 33 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 6900 2400 8100 2400 8100 2700 6900 2700 6900 2400
+2 1 0 1 -1 -1 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 7350 2400 7350 1800
+2 2 0 1 33 -1 50 0 -1 0.000 0 0 -1 0 0 5
+	 4500 2400 6300 2400 6300 2700 4500 2700 4500 2400
+2 1 0 2 33 -1 50 0 -1 0.000 0 0 -1 0 0 2
+	 6150 2100 6150 2400
+2 1 0 1 -1 -1 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 8100 2550 8700 2550
+2 2 1 1 -1 -1 50 0 -1 4.000 0 0 -1 0 0 5
+	 8700 2400 9900 2400 9900 2700 8700 2700 8700 2400
+2 1 0 2 33 -1 50 0 -1 0.000 0 0 -1 0 0 4
+	 3000 3300 3000 2100 7050 2100 7050 2400
+2 1 0 1 -1 -1 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 5100 1650 5700 1650
+2 1 0 1 -1 -1 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 8100 1650 7500 1650
+2 1 0 2 10 7 50 0 -1 0.000 0 0 -1 0 0 3
+	 8925 6600 9000 6450 9075 6600
+2 1 0 2 10 -1 50 0 -1 6.000 0 0 -1 0 0 2
+	 9000 6300 9000 6450
+2 1 0 2 10 -1 50 0 -1 6.000 0 0 -1 0 0 4
+	 8700 7200 8700 6600 9300 6600 9300 8400
+2 1 2 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 2
+	 2100 4275 2400 4275
+2 1 2 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 2
+	 2100 3825 2400 3825
+2 1 2 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 2
+	 2100 3075 2400 3075
+2 1 2 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 2
+	 7200 3825 7350 3825
+2 1 2 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 2
+	 7200 4275 7350 4275
+2 1 2 1 0 -1 50 0 -1 3.000 0 0 -1 0 0 2
+	 7350 5025 7500 5025
+2 2 0 1 35 7 50 0 -1 0.000 0 0 -1 0 0 5
+	 3900 6300 5700 6300 5700 6600 3900 6600 3900 6300
+2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 3900 5700 5700 5700 5700 6000 3900 6000 3900 5700
+2 1 0 2 0 7 50 0 -1 6.000 0 0 -1 0 0 3
+	 4725 6300 4800 6150 4875 6300
+2 1 0 2 0 7 50 0 -1 6.000 0 0 -1 0 0 2
+	 4800 6000 4800 6150
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
+	1 1 1.00 60.00 120.00
+	1 1 1.00 60.00 120.00
+	 5550 6600 5550 7500
+2 2 1 1 10 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 11400 9300 12600 9300 12600 9600 11400 9600 11400 9300
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+	1 1 1.00 60.00 120.00
+	1 1 1.00 60.00 120.00
+	 12000 9300 12000 8700
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 60.00 120.00
+	 12000 8400 12000 8100
+2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 11400 8400 12600 8400 12600 8700 11400 8700 11400 8400
+4 1 35 50 0 0 12 0.0000 4 180 990 8400 3225 TypeMValue\001
+4 1 35 50 0 0 12 0.0000 4 180 795 9600 3225 type: Type\001
+4 1 0 50 0 0 12 0.0000 4 135 945 4800 4125 MParameter\001
+4 1 35 50 0 0 12 0.0000 4 135 720 1350 5025 NameMP\001
+4 1 35 50 0 0 12 0.0000 4 135 480 1350 4425 IntMP\001
+4 1 0 50 0 0 12 0.0000 4 135 240 750 4425 AT\001
+4 1 0 50 0 0 12 0.0000 4 135 165 750 5025 IT\001
+4 1 35 50 0 0 12 0.0000 4 180 795 3000 4275 (Variable)\001
+4 1 0 50 0 0 12 0.0000 4 180 2205 2400 8625 ClassTemplateSpecialization\001
+4 1 0 50 0 0 12 0.0000 4 180 2700 2100 9525 ClassTemplatePartialSpecialization\001
+4 0 0 50 0 0 12 0.0000 4 180 660 1575 8325 template\001
+4 1 35 50 0 0 12 0.0000 4 135 1065 8400 5025 NameMValue\001
+4 1 35 50 0 0 12 0.0000 4 135 825 8400 4425 IntMValue\001
+4 1 35 50 0 0 12 0.0000 4 135 750 10200 4275 ConcIMV\001
+4 1 35 50 0 0 12 0.0000 4 135 675 10200 4575 AbsIMV\001
+4 1 35 50 0 0 12 0.0000 4 135 750 10200 5175 AbsNMV\001
+4 1 35 50 0 0 12 0.0000 4 135 825 10200 4875 ConcNMV\001
+4 1 35 50 0 0 12 0.0000 4 135 1215 11700 5175 name: NameMP\001
+4 1 35 50 0 0 12 0.0000 4 135 1140 11700 4875 name: Variable\001
+4 1 35 50 0 0 12 0.0000 4 180 1350 11700 4575 value: Expression\001
+4 1 35 50 0 0 12 0.0000 4 135 690 11700 4275 value: int\001
+4 1 35 50 0 0 12 0.0000 4 180 1080 8400 3825 TemplMValue\001
+4 1 35 50 0 0 12 0.0000 4 135 795 10200 3675 ConcTMV\001
+4 1 35 50 0 0 12 0.0000 4 135 720 10200 3975 AbsTMV\001
+4 1 35 50 0 0 12 0.0000 4 180 1650 11700 3675 templ: ClassTemplate\001
+4 1 35 50 0 0 12 0.0000 4 180 1485 11700 3975 templ: TemplateMP\001
+4 1 0 50 0 0 12 0.0000 4 135 345 2100 5250 val?!\001
+4 1 0 50 0 0 12 0.0000 4 135 300 5700 4275 val?\001
+4 1 -1 50 0 0 12 0.0000 4 180 1095 3000 3525 TypeNameMP\001
+4 1 0 50 0 0 12 0.0000 4 180 1140 1500 7425 ClassTemplate\001
+4 0 0 50 0 0 12 0.0000 4 180 585 1575 7725 specs*!\001
+4 1 0 50 0 0 12 0.0000 4 180 810 2100 6225 ClassType\001
+4 1 0 50 0 0 12 0.0000 4 180 735 4650 4725 MBinding\001
+4 0 0 50 0 0 12 0.0000 4 180 660 7875 8325 template\001
+4 0 0 50 0 0 12 0.0000 4 180 585 7875 7725 specs*!\001
+4 1 0 50 0 0 12 0.0000 4 135 660 9000 6225 Function\001
+4 1 0 50 0 0 12 0.0000 4 180 1365 8100 7425 FunctionTemplate\001
+4 1 -1 50 0 0 18 0.0000 4 255 1710 6600 825 C++ Templates\001
+4 1 0 50 0 0 12 0.0000 4 180 2430 8100 8625 FunctionTemplateSpecialization\001
+4 2 -1 50 0 0 12 0.0000 4 180 660 5775 2325 template\001
+4 1 -1 50 0 0 12 0.0000 4 165 915 7500 2625 AbstractQT\001
+4 1 -1 50 0 0 12 0.0000 4 180 1530 5400 2625 AbstractTemplateId\001
+4 0 -1 50 0 0 12 0.0000 4 135 315 7425 2325 first\001
+4 2 -1 50 0 0 12 0.0000 4 180 450 6075 2925 args[]\001
+4 0 -1 50 0 0 12 0.0000 4 105 300 8175 2475 rest\001
+4 1 -1 50 0 0 12 0.0000 4 165 690 9300 2625 PQName\001
+4 2 -1 50 0 0 12 0.0000 4 180 1890 5100 1725 (PointerToMemberType)\001
+4 1 -1 50 0 0 12 0.0000 4 135 405 5400 1575 class\001
+4 0 -1 50 0 0 12 0.0000 4 180 975 8175 1725 (BaseClass)\001
+4 1 -1 50 0 0 12 0.0000 4 135 360 7800 1575 base\001
+4 2 0 50 0 0 12 0.0000 4 180 450 6375 7425 args[]\001
+4 1 0 50 0 0 12 0.0000 4 180 705 4800 6525 Template\001
+4 1 0 50 0 0 12 0.0000 4 135 1485 4800 5925 MetaParameterList\001
+4 2 0 50 0 0 12 0.0000 4 180 675 5175 5625 params[]\001
+4 2 0 50 0 0 12 0.0000 4 180 540 5475 6825 specs*\001
+4 2 0 50 0 0 12 0.0000 4 180 660 5475 7425 template\001
+4 1 -1 50 0 0 12 0.0000 4 135 1065 12000 9525 ClassMember\001
+4 1 -1 50 0 0 12 0.0000 4 180 1095 12000 8025 (MParamList)\001
+4 2 0 50 0 0 12 0.0000 4 180 1410 11925 8325 enclosingParams[]\001
+4 1 0 50 0 0 12 0.0000 4 135 1020 12000 8625 OOLTMDefn\001
+4 2 0 50 0 0 12 0.0000 4 135 825 11925 9225 ooltmdefn?\001
+4 0 -1 50 0 0 12 0.0000 4 90 135 12075 8850 m\001

Added: vendor/elsa/current/elsa/doc/template_er.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/template_er.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/template_er.ps
===================================================================
--- vendor/elsa/current/elsa/doc/template_er.ps	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/template_er.ps	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1028 @@
+%!PS-Adobe-2.0
+%%Title: template.ps
+%%Creator: /usr/X11R6/bin/fig2dev Version 3.2 Patchlevel 4
+%%CreationDate: Fri Sep  2 23:14:55 2005
+%%For: scott at seamonkey (,,,)
+%%Orientation: Landscape
+%%Pages: 1
+%%BoundingBox: 0 0 612 792
+%%DocumentPaperSizes: letter
+%%BeginSetup
+[{
+%BeginFeature: *PageRegion Letter
+<</PageSize [612 792]>> setpagedevice
+%EndFeature
+} stopped cleartomark
+%%EndSetup
+%%Magnification: 1.0000
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+/col32 {0.000 0.539 0.578 srgb} bind def
+/col33 {0.449 0.234 0.773 srgb} bind def
+/col34 {0.387 0.473 0.609 srgb} bind def
+/col35 {0.031 0.031 0.031 srgb} bind def
+/col36 {0.578 0.395 0.031 srgb} bind def
+
+end
+save
+newpath 0 792 moveto 0 0 lineto 612 0 lineto 612 792 lineto closepath clip newpath
+-0.0 0.0 translate
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+  bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+  4 -2 roll mul srgb} bind def
+ /DrawEllipse {
+	/endangle exch def
+	/startangle exch def
+	/yrad exch def
+	/xrad exch def
+	/y exch def
+	/x exch def
+	/savematrix mtrx currentmatrix def
+	x y tr xrad yrad sc 0 0 1 startangle endangle arc
+	closepath
+	savematrix setmatrix
+	} def
+
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+$F2psBegin
+10 setmiterlimit
+0 slj 0 slc
+ 0.06000 0.06000 sc
+%%Page: 1 1
+%%BeginPageSetup
+ 90 rotate
+1 -1 scale
+%%EndPageSetup
+%
+% Fig objects follow
+%
+% 
+% here starts figure with depth 50
+% Polyline
+7.500 slw
+n 6000 3900 m 7200 3900 l 7200 4200 l 6000 4200 l
+ cp gs col0 s gr 
+/Times-Roman ff 180.00 scf sf
+6600 4125 m
+gs 1 -1 sc (MetaValue) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Polyline
+n 3600 4800 m 2400 4800 l 2400 4500 l 3600 4500 l
+ cp gs col35 s gr 
+/Times-Roman ff 180.00 scf sf
+3000 4725 m
+gs 1 -1 sc (NontypeMP) dup sw pop 2 div neg 0 rm  col35 sh gr
+% Polyline
+n 1800 3300 m 600 3300 l 600 3000 l 1800 3000 l
+ cp gs col35 s gr 
+/Times-Roman ff 180.00 scf sf
+1200 3225 m
+gs 1 -1 sc (TypeMP) dup sw pop 2 div neg 0 rm  col35 sh gr
+% Polyline
+n 1800 3900 m 600 3900 l 600 3600 l 1800 3600 l
+ cp gs col35 s gr 
+/Times-Roman ff 180.00 scf sf
+1200 3825 m
+gs 1 -1 sc (TemplateMP) dup sw pop 2 div neg 0 rm  col35 sh gr
+% Polyline
+n 5400 7500 m 6600 7500 l 6600 7800 l 5400 7800 l
+ cp gs col0 s gr 
+% Polyline
+15.000 slw
+n 5925 8100 m 6000 7950 l 6075 8100 l
+ cp gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 6000 7800 m
+ 6000 8100 l gs col0 s gr 
+/Times-Roman ff 180.00 scf sf
+6000 7725 m
+gs 1 -1 sc (Specialization) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Ellipse
+7.500 slw
+n 4800 7650 600 150 0 360 DrawEllipse gs col0 s gr
+
+/Times-Roman ff 180.00 scf sf
+4800 7725 m
+gs 1 -1 sc (explicit?) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Ellipse
+n 6900 9450 900 150 0 360 DrawEllipse gs col0 s gr
+
+% Ellipse
+n 9000 9450 600 150 0 360 DrawEllipse gs col0 s gr
+
+% Polyline
+ [60] 0 sd
+n 4200 9000 m 5400 9000 l 5400 9300 l 4200 9300 l
+ cp gs col10 s gr  [] 0 sd
+% Polyline
+n 6000 9000 m 7800 9000 l 7800 9300 l 6000 9300 l
+ cp gs col10 s gr 
+% Polyline
+n 8400 9000 m 9600 9000 l 9600 9300 l 8400 9300 l
+ cp gs col10 s gr 
+% Polyline
+15.000 slw
+n 5700 9075 m 5550 9150 l 5700 9225 l
+ cp gs col10 1.00 shd ef gr gs col10 s gr 
+% Polyline
+n 5400 9150 m
+ 6000 9150 l gs col10 s gr 
+% Polyline
+n 5700 8925 m
+ 5700 9375 l gs col10 s gr 
+% Polyline
+ [15 68] 68 sd
+n 5700 9600 m
+ 5700 9375 l gs col10 s gr  [] 0 sd
+% Polyline
+ [15 68] 68 sd
+n 5700 8925 m
+ 5700 8700 l gs col10 s gr  [] 0 sd
+% Polyline
+n 8400 9075 m 8250 9150 l
+ 8400 9225 l gs col10 s gr 
+% Polyline
+n 7800 9150 m
+ 8250 9150 l gs col10 s gr 
+/Times-Roman ff 180.00 scf sf
+4800 9225 m
+gs 1 -1 sc (Variable) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+6900 9225 m
+gs 1 -1 sc (AbstractEnumerator) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+9000 9225 m
+gs 1 -1 sc (Enumerator) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+6900 9525 m
+gs 1 -1 sc (type: Enumeration) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+9000 9525 m
+gs 1 -1 sc (value: int) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Ellipse
+7.500 slw
+ [60] 0 sd
+n 900 6150 300 150 0 360 DrawEllipse gs col0 s gr
+ [] 0 sd
+/Times-Roman ff 180.00 scf sf
+900 6225 m
+gs 1 -1 sc (defn?) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Ellipse
+ [60] 0 sd
+n 8100 6150 300 150 0 360 DrawEllipse gs col0 s gr
+ [] 0 sd
+/Times-Roman ff 180.00 scf sf
+8100 6225 m
+gs 1 -1 sc (defn?) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Ellipse
+n 3300 1050 900 150 0 360 DrawEllipse gs col-1 s gr
+
+% Polyline
+ [45] 0 sd
+n 600 600 m 1800 600 l 1800 900 l 600 900 l
+ cp gs col18 s gr  [] 0 sd
+% Polyline
+n 2400 600 m 4200 600 l 4200 900 l 2400 900 l
+ cp gs col18 s gr 
+% Polyline
+15.000 slw
+n 2400 675 m 2250 750 l
+ 2400 825 l gs col18 s gr 
+% Polyline
+n 1800 750 m
+ 2250 750 l gs col18 s gr 
+/Times-Roman ff 180.00 scf sf
+1200 825 m
+gs 1 -1 sc (ArrayType) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3300 825 m
+gs 1 -1 sc (AbstractSizeArray) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3300 1125 m
+gs 1 -1 sc (size: Expression) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Polyline
+7.500 slw
+ [60] 0 sd
+n 5700 1500 m 7500 1500 l 7500 1800 l 5700 1800 l
+ cp gs col33 s gr  [] 0 sd
+/Times-Roman ff 180.00 scf sf
+6600 1725 m
+gs 1 -1 sc (NamedAtomicType) dup sw pop 2 div neg 0 rm  col0 sh gr
+% Polyline
+ [60] 0 sd
+n 9000 1200 m 10200 1200 l 10200 1500 l 9000 1500 l
+ cp gs col12 s gr  [] 0 sd
+% Polyline
+n 10800 900 m 12600 900 l 12600 1200 l 10800 1200 l
+ cp gs col12 s gr 
+% Polyline
+n 10800 1500 m 12600 1500 l 12600 1800 l 10800 1800 l
+ cp gs col12 s gr 
+% Polyline
+15.000 slw
+n 10500 1275 m 10350 1350 l 10500 1425 l
+ cp gs col12 1.00 shd ef gr gs col12 s gr 
+% Polyline
+n 10200 1350 m
+ 10500 1350 l gs col12 s gr 
+% Polyline
+n 10500 825 m
+ 10500 1875 l gs col12 s gr 
+% Polyline
+n 10800 1050 m
+ 10500 1050 l gs col12 s gr 
+% Polyline
+n 10800 1650 m
+ 10500 1650 l gs col12 s gr 
+% Polyline
+ [15 68] 68 sd
+n 10500 2100 m
+ 10500 1875 l gs col12 s gr  [] 0 sd
+% Polyline
+ [15 68] 68 sd
+n 10500 600 m
+ 10500 825 l gs col12 s gr  [] 0 sd
+/Times-Roman ff 180.00 scf sf
+9600 1425 m
+gs 1 -1 sc (Scope) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 1125 m
+gs 1 -1 sc (MetaParameterScope) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 1725 m
+gs 1 -1 sc (MetaBindingScope) dup sw pop 2 div neg 0 rm  col-1 sh gr
+% Ellipse
+7.500 slw
+n 9600 3150 600 150 0 360 DrawEllipse gs col35 s gr
+
+% Ellipse
+n 750 4350 150 150 0 360 DrawEllipse gs col0 s gr
+
+% Ellipse
+n 750 4950 150 150 0 360 DrawEllipse gs col0 s gr
+
+% Ellipse
+n 11700 4200 900 150 0 360 DrawEllipse gs col35 s gr
+
+% Ellipse
+n 11715 4508 900 150 0 360 DrawEllipse gs col35 s gr
+
+% Ellipse
+n 11714 4808 900 150 0 360 DrawEllipse gs col35 s gr
+
+% Ellipse
+n 11720 3608 900 150 0 360 DrawEllipse gs col35 s gr
+
+% Ellipse
+n 11719 5108 900 150 0 360 DrawEllipse gs col35 s gr
+
+% Ellipse
+n 11720 3908 900 150 0 360 DrawEllipse gs col35 s gr
+
+% Polyline
+n 7800 3000 m 9000 3000 l 9000 3300 l 7800 3300 l
+ cp gs col35 s gr 
+% Polyline
+15.000 slw
+n 7500 3975 m 7350 4050 l 7500 4125 l
+ cp gs 0.00 setgray ef gr gs col-1 s gr 
+% Polyline
+n 7200 4050 m
+ 7500 4050 l gs col-1 s gr 
+% Polyline
+7.500 slw
+n 4200 3900 m 5400 3900 l 5400 4200 l 4200 4200 l
+ cp gs col0 s gr 
+% Polyline
+15.000 slw
+n 3900 4125 m 4050 4050 l 3900 3975 l
+ cp gs 0.00 setgray ef gr gs col-1 s gr 
+% Polyline
+n 3900 4050 m
+ 4200 4050 l gs col-1 s gr 
+% Polyline
+n 3600 4650 m 3900 4650 l 3900 3450 l
+ 3600 3450 l gs col-1 s gr 
+% Polyline
+7.500 slw
+n 2925 4500 m 3000 4350 l 3075 4500 l
+ cp gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 1800 4500 m 900 4500 l 900 4200 l 1800 4200 l
+ cp gs col35 s gr 
+% Polyline
+n 1800 5100 m 900 5100 l 900 4800 l 1800 4800 l
+ cp gs col35 s gr 
+% Polyline
+15.000 slw
+n 1800 3150 m 2100 3150 l 2100 3750 l
+ 1800 3750 l gs col0 s gr 
+% Polyline
+n 1800 4350 m 2100 4350 l 2100 4950 l
+ 1800 4950 l gs col0 s gr 
+% Polyline
+n 2100 4575 m 2250 4650 l 2100 4725 l
+ cp gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 2100 3375 m 2250 3450 l 2100 3525 l
+ cp gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 2400 3450 m
+ 2100 3450 l gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 2400 4650 m
+ 2100 4650 l gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 2700 6300 m
+ 2700 8250 l gs col34 s gr 
+% Polyline
+n 900 7500 m
+ 900 9150 l gs col0 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+1470 8415 m 1530 8415 l 1530 8264 l 1500 8384 l 1470 8264 l cp
+1530 7485 m 1470 7485 l 1470 7636 l 1500 7516 l 1530 7636 l cp
+eoclip
+n 1500 7500 m
+ 1500 8400 l gs col0 s gr gr
+
+% arrowhead
+n 1530 7636 m 1500 7516 l 1470 7636 l 1530 7636 l  cp gs 0.00 setgray ef gr  col0 s
+% arrowhead
+n 1470 8264 m 1500 8384 l 1530 8264 l 1470 8264 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+n 1200 8400 m 3600 8400 l 3600 8700 l 1200 8700 l
+ cp gs col0 s gr 
+% Polyline
+15.000 slw
+n 3300 8400 m 3300 8100 l 7500 8100 l
+ 7500 8400 l gs col0 s gr 
+% Polyline
+n 2625 8400 m 2700 8250 l
+ 2775 8400 l gs col34 s gr 
+% Polyline
+7.500 slw
+n 600 9300 m 3600 9300 l 3600 9600 l 600 9600 l
+ cp gs col0 s gr 
+% Polyline
+15.000 slw
+n 2325 9300 m 2400 9150 l
+ 2475 9300 l gs col0 s gr 
+% Polyline
+n 825 9300 m 900 9150 l
+ 975 9300 l gs col0 s gr 
+% Polyline
+n 2400 8700 m
+ 2400 9150 l gs col0 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+6480 4185 m 6420 4185 l 6420 4336 l 6450 4216 l 6480 4336 l cp
+eoclip
+n 6450 7500 m
+ 6450 4200 l gs col0 s gr gr
+
+% arrowhead
+n 6480 4336 m 6450 4216 l 6420 4336 l 6480 4336 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+n 7800 4800 m 9000 4800 l 9000 5100 l 7800 5100 l
+ cp gs col35 s gr 
+% Polyline
+n 7800 4200 m 9000 4200 l 9000 4500 l 7800 4500 l
+ cp gs col35 s gr 
+% Polyline
+n 9600 4050 m 10800 4050 l 10800 4350 l 9600 4350 l
+ cp gs col35 s gr 
+% Polyline
+n 9600 4350 m 10800 4350 l 10800 4650 l 9600 4650 l
+ cp gs col35 s gr 
+% Polyline
+n 9600 4650 m 10800 4650 l 10800 4950 l 9600 4950 l
+ cp gs col35 s gr 
+% Polyline
+n 9600 4950 m 10800 4950 l 10800 5250 l 9600 5250 l
+ cp gs col35 s gr 
+% Polyline
+15.000 slw
+n 9300 4275 m 9150 4350 l 9300 4425 l
+ cp gs 0.00 setgray ef gr gs col-1 s gr 
+% Polyline
+n 9300 4875 m 9150 4950 l 9300 5025 l
+ cp gs 0.00 setgray ef gr gs col-1 s gr 
+% Polyline
+n 9000 4350 m
+ 9300 4350 l gs col-1 s gr 
+% Polyline
+n 9000 4950 m
+ 9300 4950 l gs col-1 s gr 
+% Polyline
+n 9600 5100 m 9300 5100 l 9300 4800 l
+ 9600 4800 l gs col-1 s gr 
+% Polyline
+n 9600 4500 m 9300 4500 l 9300 4200 l
+ 9600 4200 l gs col-1 s gr 
+% Polyline
+7.500 slw
+n 7800 3600 m 9000 3600 l 9000 3900 l 7800 3900 l
+ cp gs col35 s gr 
+% Polyline
+n 9600 3450 m 10800 3450 l 10800 3750 l 9600 3750 l
+ cp gs col35 s gr 
+% Polyline
+n 9600 3750 m 10800 3750 l 10800 4050 l 9600 4050 l
+ cp gs col35 s gr 
+% Polyline
+15.000 slw
+n 9300 3675 m 9150 3750 l 9300 3825 l
+ cp gs 0.00 setgray ef gr gs col-1 s gr 
+% Polyline
+n 9000 3750 m
+ 9300 3750 l gs col-1 s gr 
+% Polyline
+n 9600 3900 m 9300 3900 l 9300 3600 l
+ 9600 3600 l gs col-1 s gr 
+% Polyline
+7.500 slw
+ [60] 0 sd
+gs  clippath
+6015 4080 m 6015 4020 l 5864 4020 l 5984 4050 l 5864 4080 l cp
+eoclip
+n 5400 4050 m
+ 6000 4050 l gs col0 s gr gr
+ [] 0 sd
+% arrowhead
+n 5864 4080 m 5984 4050 l 5864 4020 l 5864 4080 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+n 1800 5025 m
+ 2100 5025 l gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+ [15 45] 45 sd
+n 2100 5025 m
+ 2400 5025 l gs col0 s gr  [] 0 sd
+% Polyline
+n 1800 4275 m
+ 2100 4275 l gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 1800 3825 m
+ 2100 3825 l gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 1800 3075 m
+ 2100 3075 l gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+gs  clippath
+7815 5055 m 7815 4995 l 7664 4995 l 7784 5025 l 7664 5055 l cp
+eoclip
+n 7500 5025 m
+ 7800 5025 l gs 0.00 setgray ef gr gs col0 s gr gr
+
+% arrowhead
+n 7664 5055 m 7784 5025 l 7664 4995 l 7664 5055 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+gs  clippath
+7815 4305 m 7815 4245 l 7664 4245 l 7784 4275 l 7664 4305 l cp
+eoclip
+n 7350 4275 m
+ 7800 4275 l gs 0.00 setgray ef gr gs col0 s gr gr
+
+% arrowhead
+n 7664 4305 m 7784 4275 l 7664 4245 l 7664 4305 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+gs  clippath
+7815 3855 m 7815 3795 l 7664 3795 l 7784 3825 l 7664 3855 l cp
+eoclip
+n 7350 3825 m
+ 7800 3825 l gs 0.00 setgray ef gr gs col0 s gr gr
+
+% arrowhead
+n 7664 3855 m 7784 3825 l 7664 3795 l 7664 3855 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+gs  clippath
+7815 3105 m 7815 3045 l 7664 3045 l 7784 3075 l 7664 3105 l cp
+eoclip
+n 7500 3075 m
+ 7800 3075 l gs 0.00 setgray ef gr gs col0 s gr gr
+
+% arrowhead
+n 7664 3105 m 7784 3075 l 7664 3045 l 7664 3105 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+ [15 45] 45 sd
+n 7350 3075 m
+ 7500 3075 l gs col0 s gr  [] 0 sd
+% Polyline
+n 7650 4575 m 7500 4650 l 7650 4725 l
+ cp gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+n 7650 3375 m 7500 3450 l 7650 3525 l
+ cp gs 0.00 setgray ef gr gs col0 s gr 
+% Polyline
+15.000 slw
+n 7500 3450 m
+ 7500 4650 l gs col0 s gr 
+% Polyline
+n 7800 3150 m 7650 3150 l 7650 3750 l
+ 7800 3750 l gs col0 s gr 
+% Polyline
+n 7800 4350 m 7650 4350 l 7650 4950 l
+ 7800 4950 l gs col0 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+5280 4185 m 5220 4185 l 5220 4336 l 5250 4216 l 5280 4336 l cp
+eoclip
+n 5250 5700 m
+ 5250 4200 l gs col0 s gr gr
+
+% arrowhead
+n 5280 4336 m 5250 4216 l 5220 4336 l 5280 4336 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+n 2400 3300 m 3600 3300 l 3600 3600 l 2400 3600 l
+ cp gs col-1 s gr 
+% Polyline
+n 600 7200 m 2400 7200 l 2400 7500 l 600 7500 l
+ cp gs col0 s gr 
+% Polyline
+15.000 slw
+n 1500 6300 m
+ 1500 7050 l gs col34 s gr 
+% Polyline
+n 1425 7200 m 1500 7050 l
+ 1575 7200 l gs col34 s gr 
+% Polyline
+7.500 slw
+ [60] 0 sd
+n 1200 6000 m 3000 6000 l 3000 6300 l 1200 6300 l
+ cp gs col34 s gr  [] 0 sd
+% Polyline
+15.000 slw
+n 2100 7200 m 2100 6900 l 8100 6900 l
+ 8100 7200 l gs col35 s gr 
+% Polyline
+7.500 slw
+n 4200 4500 m 5100 4500 l 5100 4800 l 4200 4800 l
+ cp gs col0 s gr 
+% Polyline
+15.000 slw
+n 4575 4500 m 4650 4350 l
+ 4725 4500 l gs col0 s gr 
+% Polyline
+n 4650 4200 m
+ 4650 4350 l gs col-1 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+7770 8415 m 7830 8415 l 7830 8264 l 7800 8384 l 7770 8264 l cp
+7830 7485 m 7770 7485 l 7770 7636 l 7800 7516 l 7830 7636 l cp
+eoclip
+n 7800 7500 m
+ 7800 8400 l gs col0 s gr gr
+
+% arrowhead
+n 7830 7636 m 7800 7516 l 7770 7636 l 7830 7636 l  cp gs 0.00 setgray ef gr  col0 s
+% arrowhead
+n 7770 8264 m 7800 8384 l 7830 8264 l 7770 8264 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+ [60] 0 sd
+n 8400 6000 m 9600 6000 l 9600 6300 l 8400 6300 l
+ cp gs col10 s gr  [] 0 sd
+% Polyline
+n 7200 7200 m 9000 7200 l 9000 7500 l 7200 7500 l
+ cp gs col0 s gr 
+% Polyline
+gs  clippath
+6120 3915 m 6180 3915 l 6180 3764 l 6150 3884 l 6120 3764 l cp
+eoclip
+n 6150 2700 m
+ 6150 3900 l gs col-1 s gr gr
+
+% arrowhead
+n 6120 3764 m 6150 3884 l 6180 3764 l 6120 3764 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+n 6600 8400 m 9600 8400 l 9600 8700 l 6600 8700 l
+ cp gs col0 s gr 
+% Polyline
+15.000 slw
+n 4725 6900 m 4800 6750 l 4875 6900 l
+ cp gs col35 1.00 shd ef gr gs col35 s gr 
+% Polyline
+n 4800 6600 m
+ 4800 6900 l gs col35 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+5880 1785 m 5820 1785 l 5820 1936 l 5850 1816 l 5880 1936 l cp
+eoclip
+n 5850 2400 m
+ 5850 1800 l gs col-1 s gr gr
+
+% arrowhead
+n 5880 1936 m 5850 1816 l 5820 1936 l 5880 1936 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+15.000 slw
+n 6600 1800 m
+ 6600 2100 l gs col33 s gr 
+% Polyline
+n 6525 2100 m 6600 1950 l 6675 2100 l
+ cp gs col33 1.00 shd ef gr gs col33 s gr 
+% Polyline
+7.500 slw
+n 6900 2400 m 8100 2400 l 8100 2700 l 6900 2700 l
+ cp gs col33 s gr 
+% Polyline
+gs  clippath
+7380 1785 m 7320 1785 l 7320 1936 l 7350 1816 l 7380 1936 l cp
+eoclip
+n 7350 2400 m
+ 7350 1800 l gs col-1 s gr gr
+
+% arrowhead
+n 7380 1936 m 7350 1816 l 7320 1936 l 7380 1936 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+n 4500 2400 m 6300 2400 l 6300 2700 l 4500 2700 l
+ cp gs col33 s gr 
+% Polyline
+15.000 slw
+n 6150 2100 m
+ 6150 2400 l gs col33 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+8715 2580 m 8715 2520 l 8564 2520 l 8684 2550 l 8564 2580 l cp
+eoclip
+n 8100 2550 m
+ 8700 2550 l gs col-1 s gr gr
+
+% arrowhead
+n 8564 2580 m 8684 2550 l 8564 2520 l 8564 2580 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+ [60] 0 sd
+n 8700 2400 m 9900 2400 l 9900 2700 l 8700 2700 l
+ cp gs col-1 s gr  [] 0 sd
+% Polyline
+15.000 slw
+n 3000 3300 m 3000 2100 l 7050 2100 l
+ 7050 2400 l gs col33 s gr 
+% Polyline
+7.500 slw
+gs  clippath
+5715 1680 m 5715 1620 l 5564 1620 l 5684 1650 l 5564 1680 l cp
+eoclip
+n 5100 1650 m
+ 5700 1650 l gs col-1 s gr gr
+
+% arrowhead
+n 5564 1680 m 5684 1650 l 5564 1620 l 5564 1680 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+gs  clippath
+7485 1620 m 7485 1680 l 7636 1680 l 7516 1650 l 7636 1620 l cp
+eoclip
+n 8100 1650 m
+ 7500 1650 l gs col-1 s gr gr
+
+% arrowhead
+n 7636 1620 m 7516 1650 l 7636 1680 l 7636 1620 l  cp gs 0.00 setgray ef gr  col-1 s
+% Polyline
+15.000 slw
+n 8925 6600 m 9000 6450 l
+ 9075 6600 l gs col10 s gr 
+% Polyline
+n 9000 6300 m
+ 9000 6450 l gs col10 s gr 
+% Polyline
+n 8700 7200 m 8700 6600 l 9300 6600 l
+ 9300 8400 l gs col10 s gr 
+% Polyline
+7.500 slw
+ [15 45] 45 sd
+n 2100 4275 m
+ 2400 4275 l gs col0 s gr  [] 0 sd
+% Polyline
+ [15 45] 45 sd
+n 2100 3825 m
+ 2400 3825 l gs col0 s gr  [] 0 sd
+% Polyline
+ [15 45] 45 sd
+n 2100 3075 m
+ 2400 3075 l gs col0 s gr  [] 0 sd
+% Polyline
+ [15 45] 45 sd
+n 7200 3825 m
+ 7350 3825 l gs col0 s gr  [] 0 sd
+% Polyline
+ [15 45] 45 sd
+n 7200 4275 m
+ 7350 4275 l gs col0 s gr  [] 0 sd
+% Polyline
+ [15 45] 45 sd
+n 7350 5025 m
+ 7500 5025 l gs col0 s gr  [] 0 sd
+% Polyline
+n 3900 6300 m 5700 6300 l 5700 6600 l 3900 6600 l
+ cp gs col35 s gr 
+% Polyline
+n 3900 5700 m 5700 5700 l 5700 6000 l 3900 6000 l
+ cp gs col0 s gr 
+% Polyline
+15.000 slw
+n 4725 6300 m 4800 6150 l
+ 4875 6300 l gs col0 s gr 
+% Polyline
+n 4800 6000 m
+ 4800 6150 l gs col0 s gr 
+% Polyline
+7.500 slw
+ [60] 0 sd
+gs  clippath
+5520 7515 m 5580 7515 l 5580 7364 l 5550 7484 l 5520 7364 l cp
+5580 6585 m 5520 6585 l 5520 6736 l 5550 6616 l 5580 6736 l cp
+eoclip
+n 5550 6600 m
+ 5550 7500 l gs col0 s gr gr
+ [] 0 sd
+% arrowhead
+n 5580 6736 m 5550 6616 l 5520 6736 l 5580 6736 l  cp gs 0.00 setgray ef gr  col0 s
+% arrowhead
+n 5520 7364 m 5550 7484 l 5580 7364 l 5520 7364 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+ [60] 0 sd
+n 11400 9300 m 12600 9300 l 12600 9600 l 11400 9600 l
+ cp gs col10 s gr  [] 0 sd
+% Polyline
+gs  clippath
+12030 8685 m 11970 8685 l 11970 8836 l 12000 8716 l 12030 8836 l cp
+11970 9315 m 12030 9315 l 12030 9164 l 12000 9284 l 11970 9164 l cp
+eoclip
+n 12000 9300 m
+ 12000 8700 l gs col0 s gr gr
+
+% arrowhead
+n 11970 9164 m 12000 9284 l 12030 9164 l 11970 9164 l  cp gs 0.00 setgray ef gr  col0 s
+% arrowhead
+n 12030 8836 m 12000 8716 l 11970 8836 l 12030 8836 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+gs  clippath
+12030 8085 m 11970 8085 l 11970 8236 l 12000 8116 l 12030 8236 l cp
+eoclip
+n 12000 8400 m
+ 12000 8100 l gs col0 s gr gr
+
+% arrowhead
+n 12030 8236 m 12000 8116 l 11970 8236 l 12030 8236 l  cp gs 0.00 setgray ef gr  col0 s
+% Polyline
+n 11400 8400 m 12600 8400 l 12600 8700 l 11400 8700 l
+ cp gs col0 s gr 
+/Times-Roman ff 180.00 scf sf
+8400 3225 m
+gs 1 -1 sc (TypeMValue) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+9600 3225 m
+gs 1 -1 sc (type: Type) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+4800 4125 m
+gs 1 -1 sc (MParameter) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+1350 5025 m
+gs 1 -1 sc (NameMP) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+1350 4425 m
+gs 1 -1 sc (IntMP) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+750 4425 m
+gs 1 -1 sc (AT) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+750 5025 m
+gs 1 -1 sc (IT) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3000 4275 m
+gs 1 -1 sc (\(Variable\)) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+2400 8625 m
+gs 1 -1 sc (ClassTemplateSpecialization) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+2100 9525 m
+gs 1 -1 sc (ClassTemplatePartialSpecialization) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+1575 8325 m
+gs 1 -1 sc (template) col0 sh gr
+/Times-Roman ff 180.00 scf sf
+8400 5025 m
+gs 1 -1 sc (NameMValue) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+8400 4425 m
+gs 1 -1 sc (IntMValue) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 4275 m
+gs 1 -1 sc (ConcIMV) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 4575 m
+gs 1 -1 sc (AbsIMV) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 5175 m
+gs 1 -1 sc (AbsNMV) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 4875 m
+gs 1 -1 sc (ConcNMV) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 5175 m
+gs 1 -1 sc (name: NameMP) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 4875 m
+gs 1 -1 sc (name: Variable) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 4575 m
+gs 1 -1 sc (value: Expression) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 4275 m
+gs 1 -1 sc (value: int) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+8400 3825 m
+gs 1 -1 sc (TemplMValue) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 3675 m
+gs 1 -1 sc (ConcTMV) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+10200 3975 m
+gs 1 -1 sc (AbsTMV) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 3675 m
+gs 1 -1 sc (templ: ClassTemplate) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+11700 3975 m
+gs 1 -1 sc (templ: TemplateMP) dup sw pop 2 div neg 0 rm  col35 sh gr
+/Times-Roman ff 180.00 scf sf
+2100 5250 m
+gs 1 -1 sc (val?!) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+5700 4275 m
+gs 1 -1 sc (val?) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3000 3525 m
+gs 1 -1 sc (TypeNameMP) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1500 7425 m
+gs 1 -1 sc (ClassTemplate) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+1575 7725 m
+gs 1 -1 sc (specs*!) col0 sh gr
+/Times-Roman ff 180.00 scf sf
+2100 6225 m
+gs 1 -1 sc (ClassType) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+4650 4725 m
+gs 1 -1 sc (MBinding) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+7875 8325 m
+gs 1 -1 sc (template) col0 sh gr
+/Times-Roman ff 180.00 scf sf
+7875 7725 m
+gs 1 -1 sc (specs*!) col0 sh gr
+/Times-Roman ff 180.00 scf sf
+9000 6225 m
+gs 1 -1 sc (Function) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+8100 7425 m
+gs 1 -1 sc (FunctionTemplate) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 270.00 scf sf
+6600 825 m
+gs 1 -1 sc (C++ Templates) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8100 8625 m
+gs 1 -1 sc (FunctionTemplateSpecialization) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+5775 2325 m
+gs 1 -1 sc (template) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+7500 2625 m
+gs 1 -1 sc (AbstractQT) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5400 2625 m
+gs 1 -1 sc (AbstractTemplateId) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+7425 2325 m
+gs 1 -1 sc (first) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6075 2925 m
+gs 1 -1 sc (args[]) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8175 2475 m
+gs 1 -1 sc (rest) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+9300 2625 m
+gs 1 -1 sc (PQName) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5100 1725 m
+gs 1 -1 sc (\(PointerToMemberType\)) dup sw pop neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5400 1575 m
+gs 1 -1 sc (class) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8175 1725 m
+gs 1 -1 sc (\(BaseClass\)) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+7800 1575 m
+gs 1 -1 sc (base) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6375 7425 m
+gs 1 -1 sc (args[]) dup sw pop neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+4800 6525 m
+gs 1 -1 sc (Template) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+4800 5925 m
+gs 1 -1 sc (MetaParameterList) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+5175 5625 m
+gs 1 -1 sc (params[]) dup sw pop neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+5475 6825 m
+gs 1 -1 sc (specs*) dup sw pop neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+5475 7425 m
+gs 1 -1 sc (template) dup sw pop neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 9525 m
+gs 1 -1 sc (ClassMember) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 8025 m
+gs 1 -1 sc (\(MParamList\)) dup sw pop 2 div neg 0 rm  col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+11925 8325 m
+gs 1 -1 sc (enclosingParams[]) dup sw pop neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+12000 8625 m
+gs 1 -1 sc (OOLTMDefn) dup sw pop 2 div neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+11925 9225 m
+gs 1 -1 sc (ooltmdefn?) dup sw pop neg 0 rm  col0 sh gr
+/Times-Roman ff 180.00 scf sf
+12075 8850 m
+gs 1 -1 sc (m) col-1 sh gr
+% here ends figure;
+$F2psEnd
+rs
+showpage

Added: vendor/elsa/current/elsa/doc/tutorial.html
===================================================================
--- vendor/elsa/current/elsa/doc/tutorial.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/tutorial.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,514 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elsa Tutorial</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175% }
+  </style>
+</HEAD>
+
+<body>
+
+<center>
+<p class="title"><b>Elsa Tutorial</b></p>
+</center>
+
+<h1>1. Introduction</h1>
+
+<p>
+This tutorial is intended to help get a new Elsa user learn about
+the Elsa and develop a basic familiarity with the core components.
+After doing this tutorial, you will know how to do the following
+tasks:
+<ul>
+<li>Build Elsa
+<li>Parse and pretty-print a C++ file
+<li>Write a simple tree traversal analysis with ASTVisitor.
+<li>Write a simple language extension, including extensions to
+    the lexer, parser, AST, type checker, and pretty printer.
+</ul>
+
+<p>
+If you run into difficulties you cannot resolve, you can email me at
+<pre>
+  smcpeak cs berkeley edu
+         @  .        .
+</pre>
+though I might not respond right away.
+
+<p>
+At the end of this tutorial I will give pointers for more exploration.
+
+
+
+<h1>2. Building Elsa</h1>
+
+<p>
+If you have not already, download and 
+<span style="border-bottom: thin dashed blue"
+      title="To unpack, say 'tar xvfz elsa-XXXX.XX.XX.tar.gz'.">unpack</span>
+the Elsa distribution tarball, available from the
+<a href="http://www.cs.berkeley.edu/~smcpeak/elkhound/">Elkhound page</a>.
+Inside the Elsa distribution you will find a directory structure like this:
+<pre>
+  elsa-XXXX.XX.XX
+    |
+    +- smbase               utility library
+    |
+    +- ast                  AST generator
+    |
+    +- elkhound             parser generator
+    |
+    +- elsa                 C++ parser/frontend/etc.
+       |
+       +- in                  C/C++ input files for regression testing
+       |
+       +- include             Elsa's compiler-specific headers
+</pre>
+          
+<h2>2.1 Configure</h2>
+
+<p>
+At the top <tt>elsa-XXXX.XX.XX</tt> directory, just run <tt>configure</tt>:
+<pre>
+  elsa-XXXX.XX.XX$ ./configure
+</pre>
+The above command just runs <tt>configure</tt> scripts in each of the four
+subdirectories.  If you want to pass specific options to a configure script
+inside a specific directory, just go into the directory and run its
+particular script.
+
+<p>
+In particular, if you want to be able to use the
+<a href="../../smbase/trace.html">tracing flags</a>, which I recommend,
+then pass the <tt>-debug</tt> option to <tt>elsa/configure</tt>:
+<pre>
+  elsa-XXXX.XX.XX$ cd elsa
+  elsa$ ./configure -debug
+  elsa$ cd ..
+</pre>
+
+<h2>2.2 Make</h2>
+
+<p>
+At the top, run <tt>make</tt>:
+<pre>
+  elsa-XXXX.XX.XX$ make
+</pre>
+This just runs <tt>make</tt> in each of the four directories.
+
+<p>
+Hopefully, everything will build without problems.  If not, it's
+possible you will have to change one or more of the source files
+to get them to compile.  In that case, please send me the changes
+that you found necessary.
+
+<h2>2.3 Make check</h2>
+
+<p>
+At the top, run <tt>make check</tt>:
+<pre>
+  elsa-XXXX.XX.XX$ make check
+</pre>
+Again, this just runs <tt>make check</tt> in each of the four directories.
+While this step is in principle optional, if something fails during the
+<tt>make check</tt> then it's likely there is a serious problem.
+
+<h1>3. Run ccparse</h1>
+
+<p>
+Among the executables produced by <tt>make</tt> is <tt>elsa/ccparse</tt>,
+a program that runs the C++ parser and optionally does a number of
+post-processing activities.  While developing Elsa, <tt>ccparse</tt>
+is the program that I run most often.
+
+<h2>3.1 Parsing alone</h2>
+
+<p>
+<tt>ccparse</tt> takes the name of file to parse on the command line:
+<pre>
+  elsa-XXXX.XX.XX$ cd elsa
+  elsa$ ./ccparse in/t0001.cc
+  %%% progress: 0ms: done parsing (1 ms, 0_234564 cycles)
+  ambiguous nodes: 0
+  %%% progress: 5ms: done type checking (4 ms)
+  typechecking results:
+    errors:   0
+    warnings: 0
+  %%% progress: 6ms: done elaborating (0 ms)
+</pre>
+The output includes "<tt>%%% progress</tt>" lines that report on stages
+of processing and timing information, the number of ambiguous nodes in
+the AST, and the number of warnings and errors emitted by the type
+checker.  Since everything worked, the output isn't all that interesting.
+
+<h2>3.2 Pretty printing</h2>
+
+<p>
+We can ask <tt>ccparse</tt> to print out the source code it has just
+parsed in, by using the <tt>-tr prettyPrint</tt> command-line argument:
+<pre>
+  elsa$ ./ccparse -tr prettyPrint in/t0001.cc
+  %%% progress: 0ms: done parsing (0 ms, 0_235561 cycles)
+  ambiguous nodes: 0
+  %%% progress: 5ms: done type checking (3 ms)
+  typechecking results:
+    errors:   0
+    warnings: 0
+  %%% progress: 7ms: done elaborating (0 ms)
+  %%% progress: 7ms: dsw pretty print...
+  ---- START ----
+  // -*-c++-*-
+  int x;
+  ---- STOP ----
+  %%% progress: 9ms: dsw pretty print... done
+</pre>
+Buried in amongst all that noise is the pretty-printed input file:
+<pre>
+  // -*-c++-*-
+  int x;
+</pre>
+
+<p>
+Obviously, <tt>in/t0001.cc</tt> is a fairly trivial input file.  
+You're free to experiment with other files in the <tt>in/</tt>
+directory, or even with your own input files.  <b>Note:</b> You
+must preprocess with the input files with <tt>cpp</tt> first!  
+Elsa does not include a preprocessor.
+
+<h2>3.3 Printing the Abstract Syntax Tree</h2>
+
+<h3>3.3.1 <tt>in/t0001.cc</tt></h3>
+
+<p>
+<tt>ccparse</tt> can print the Abstract Syntax Tree (AST) produced
+by the parser, by passing <tt>-tr printAST</tt>:
+<pre>
+  elsa$ ./ccparse -tr printAST in/t0001.cc
+  %%% progress: 0ms: done parsing (1 ms, 0_235436 cycles)
+  tree = TranslationUnit:
+    topForms:
+      topForms[0] = TF_decl:
+        loc = in/t0001.cc:3:1
+        decl = Declaration:
+          dflags =
+          spec = TS_simple:
+            cv =
+            loc = in/t0001.cc:3:1
+            id = int
+          decllist:
+            decllist[0] = Declarator:
+              context = DC_UNKNOWN
+              decl = D_name:
+                loc = in/t0001.cc:3:5
+                name = PQ_name:
+                  loc = in/t0001.cc:3:5
+                  name = x
+              init is null
+              ctorStatement is null
+              dtorStatement is null
+  ambiguous nodes: 0
+  %%% progress: 9ms: done type checking (3 ms)
+  typechecking results:
+    errors:   0
+    warnings: 0
+  %%% progress: 11ms: done elaborating (0 ms)
+</pre>
+From this printout we can see that the entire input is a
+<tt>TranslationUnit</tt>, whose first <tt>topForm</tt> is a <tt>Declaration</tt>.
+The declaration has a type specifier, <tt>TS_simple</tt>, denoting <tt>int</tt>.
+It also has a single </tt>Declarator</tt>, with a <tt>D_name</tt> containing
+<tt>x</tt>.
+
+<p>
+Besides the structural information, the printout includes source locations,
+such as "<tt>in/t0001.cc:3:1</tt>".  This means line 3, column 1 of the 
+file <tt>in/t0001.cc</tt>.
+
+<h3>3.3.1 <tt>in/t0008.cc</tt> (ambiguous)</h3>
+
+<p>
+The AST above is <em>unambiguous</em>; the parser was able to completely
+determine the syntactic interpretation of the input file, without any
+help from the type checker.  This isn't always possible with C++, and
+since the Elsa type checker runs only <em>after</em> the parser, the
+parser sometimes produces an ambiguous AST.  A simple example is in
+<tt>in/t0008.cc</tt>:
+<pre>
+  elsa$ ./ccparse -tr printAST in/t0008.cc
+  %%% progress: 0ms: done parsing (3 ms, 3_369729 cycles)
+  tree = TranslationUnit:
+    topForms:
+      topForms[0] = TF_func:
+        loc = in/t0008.cc:4:1
+        f = Function:
+          receiver: NULL
+          retVal: NULL
+          dflags = 
+          retspec = TS_simple:
+            cv = 
+            loc = in/t0008.cc:4:1
+            id = int
+          nameAndParams = Declarator:
+            context = DC_UNKNOWN
+            decl = D_func:
+              loc = in/t0008.cc:4:5
+              base = D_name:
+                loc = in/t0008.cc:4:5
+                name = PQ_name:
+                  loc = in/t0008.cc:4:5
+                  name = main
+              params:
+              cv = 
+              exnSpec is null
+            init is null
+            ctorStatement is null
+            dtorStatement is null
+          inits:
+          body = S_compound:
+            succ={ }
+            loc = in/t0008.cc:5:1
+            stmts:
+              stmts[0] = S_decl:
+                succ={ }
+                loc = in/t0008.cc:6:3
+                decl = Declaration:
+                  dflags = 
+                  spec = TS_simple:
+                    cv = 
+                    loc = in/t0008.cc:6:3
+                    id = int
+                  decllist:
+                    decllist[0] = Declarator:
+                      context = DC_UNKNOWN
+                      decl = D_name:
+                        loc = in/t0008.cc:6:7
+                        name = PQ_name:
+                          loc = in/t0008.cc:6:7
+                          name = a
+                      init is null
+                      ctorStatement is null
+                      dtorStatement is null
+              stmts[1] = S_decl:
+                succ={ }
+                loc = in/t0008.cc:7:3
+                decl = Declaration:
+                  dflags = 
+                  spec = TS_simple:
+                    cv = 
+                    loc = in/t0008.cc:7:3
+                    id = int
+                  decllist:
+                    decllist[0] = Declarator:
+                      context = DC_UNKNOWN
+                      decl = D_name:
+                        loc = in/t0008.cc:7:7
+                        name = PQ_name:
+                          loc = in/t0008.cc:7:7
+                          name = b
+                      init is null
+                      ctorStatement is null
+                      dtorStatement is null
+              stmts[2] = S_expr:
+                succ={ }
+                loc = in/t0008.cc:9:3
+                expr = FullExpression:
+                  --------- ambiguous Expression: 2 alternatives ---------
+                    tree = E_binary:
+                      e1 = E_grouping:
+                        expr = E_variable:
+                          var: NULL
+                          name = PQ_name:
+                            loc = in/t0008.cc:9:4
+                            name = a
+                      op = &
+                      e2 = E_grouping:
+                        expr = E_variable:
+                          var: NULL
+                          name = PQ_name:
+                            loc = in/t0008.cc:9:10
+                            name = b
+                  ---- or ----
+                    tree = E_cast:
+                      ctype = ASTTypeId:
+                        spec = TS_name:
+                          cv = 
+                          loc = in/t0008.cc:9:4
+                          name = PQ_name:
+                            loc = in/t0008.cc:9:4
+                            name = a
+                          typenameUsed = false
+                        decl = Declarator:
+                          context = DC_UNKNOWN
+                          decl = D_name:
+                            loc = in/t0008.cc:9:5
+                            name is null
+                          init is null
+                          ctorStatement is null
+                          dtorStatement is null
+                      expr = E_addrOf:
+                        expr = E_grouping:
+                          expr = E_variable:
+                            var: NULL
+                            name = PQ_name:
+                              loc = in/t0008.cc:9:10
+                              name = b
+                  --------- end of ambiguous Expression ---------
+          handlers:
+          dtorStatement is null
+          implicitlyDefined = false
+  ambiguous nodes: 1
+  %%% progress: 5ms: done type checking (4 ms)
+  typechecking results:
+    errors:   0
+    warnings: 0
+  %%% progress: 6ms: done elaborating (0 ms)
+</pre>
+
+<h3>3.3.1 <tt>in/t0008.cc</tt> (unambiguous)</h3>
+
+<p>
+The ambiguity can be resolved (in favor of <tt>E_binary</tt>) by
+considering that the name <tt>x</tt> refers to a variable, not a
+type.  The type checker does just this, and produces an
+unambiguous AST.  The <tt>-tr printTypedAST</tt> command line
+option will print the AST as it exists after the type checker
+runs:
+<pre>
+  elsa$ ./ccparse -tr printTypedAST in/t0008.cc
+  %%% progress: 0ms: done parsing (0 ms, 0_541155 cycles)
+  ambiguous nodes: 1
+  %%% progress: 5ms: done type checking (5 ms)
+  tree = TranslationUnit:
+    topForms:
+      topForms[0] = TF_func:
+        loc = in/t0008.cc:4:1
+        f = Function:
+          funcType: int ()()
+          receiver: NULL
+          retVal: NULL
+          dflags = 
+          retspec = TS_simple:
+            cv = 
+            loc = in/t0008.cc:4:1
+            id = int
+          nameAndParams = Declarator:
+            var: <global> <definition> int main()
+            context = DC_FUNCTION
+            decl = D_func:
+              loc = in/t0008.cc:4:5
+              base = D_name:
+                loc = in/t0008.cc:4:5
+                name = PQ_name:
+                  loc = in/t0008.cc:4:5
+                  name = main
+              params:
+              cv = 
+              exnSpec is null
+            init is null
+            ctorStatement is null
+            dtorStatement is null
+          inits:
+          body = S_compound:
+            succ={ 6:3 }
+            loc = in/t0008.cc:5:1
+            stmts:
+              stmts[0] = S_decl:
+                succ={ 7:3 }
+                loc = in/t0008.cc:6:3
+                decl = Declaration:
+                  dflags = 
+                  spec = TS_simple:
+                    cv = 
+                    loc = in/t0008.cc:6:3
+                    id = int
+                  decllist:
+                    decllist[0] = Declarator:
+                      var: <definition> int a
+                      context = DC_S_DECL
+                      decl = D_name:
+                        loc = in/t0008.cc:6:7
+                        name = PQ_name:
+                          loc = in/t0008.cc:6:7
+                          name = a
+                      init is null
+                      ctorStatement is null
+                      dtorStatement is null
+              stmts[1] = S_decl:
+                succ={ 9:3 }
+                loc = in/t0008.cc:7:3
+                decl = Declaration:
+                  dflags = 
+                  spec = TS_simple:
+                    cv = 
+                    loc = in/t0008.cc:7:3
+                    id = int
+                  decllist:
+                    decllist[0] = Declarator:
+                      var: <definition> int b
+                      context = DC_S_DECL
+                      decl = D_name:
+                        loc = in/t0008.cc:7:7
+                        name = PQ_name:
+                          loc = in/t0008.cc:7:7
+                          name = b
+                      init is null
+                      ctorStatement is null
+                      dtorStatement is null
+              stmts[2] = S_expr:
+                succ={ }
+                loc = in/t0008.cc:9:3
+                expr = FullExpression:
+                  expr = E_binary:
+                    type: int
+                    e1 = E_grouping:
+                      type: int &
+                      expr = E_variable:
+                        type: int &
+                        var: int a, at in/t0008.cc:6:7 (0x08271940)
+                        name = PQ_name:
+                          loc = in/t0008.cc:9:4
+                          name = a
+                    op = &
+                    e2 = E_grouping:
+                      type: int &
+                      expr = E_variable:
+                        type: int &
+                        var: int b, at in/t0008.cc:7:7 (0x082719F8)
+                        name = PQ_name:
+                          loc = in/t0008.cc:9:10
+                          name = b
+          handlers:
+          dtorStatement is null
+          implicitlyDefined = false
+  typechecking results:
+    errors:   0
+    warnings: 0
+  %%% progress: 6ms: done elaborating (0 ms)
+</pre>
+
+<p>
+If you look carefully at the output, you will see that in addition
+to being unambiguous, the post-tcheck AST also has been annotated
+with information about the types of expressions, and the variables
+to which names refer.  This information is very useful to analyses
+that come after the type checker.
+                 
+<p>
+If you want, take some time to experiment with <tt>ccparse</tt> and
+the trees it can print.  Find some nasty C++ and see what Elsa
+thinks of it!  Try to crash Elsa!  When you've had your fill of
+segfaults (send me bug reports please?), you're ready to go on
+to the next part of the tutorial.
+
+<h1>Go to <a href="tutorial_part2.html">Part 2: Modifying Elsa</a></h1>
+
+
+</body>
+</html>

Added: vendor/elsa/current/elsa/doc/tutorial_part2.html
===================================================================
--- vendor/elsa/current/elsa/doc/tutorial_part2.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/doc/tutorial_part2.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,378 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Modifying Elsa</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175% }
+  </style>
+</HEAD>
+
+<body>
+
+<center>
+<p class="title"><b>Part 2: Modifying Elsa</b></p>
+</center>
+
+<p>
+You presumably just came from <a href="tutorial.html">Part 1</a>,
+which introduces the Elsa build process and <tt>ccparse</tt> tool.
+In Part 2, you will modify Elsa's source code to achieve
+various effects, and to familiarize yourself with a few of its
+key data structures.
+
+<h1>4. Count the casts</h1>
+
+<p>
+One of the complaints people typically have about C is that one
+of its most unsafe features, type casts, has just about the hardest
+syntax to <tt>grep</tt> for: a parenthesized type, juxtaposed with
+an expression.  But with a parser like Elsa, casts are easy to find,
+so we will write a simple AST visitor to do just this.
+
+<p>
+Open <tt>main.cc</tt> (in <tt>elsa/</tt>), and near the top (say,
+after the block of #includes but before <tt>DeclTypeChecker</tt>),
+add the following:
+<pre>
+  class CastCounter : public ASTVisitor {
+  public:      // data
+    int count;
+
+  public:      // funcs
+    CastCounter() : count(0) {}
+    virtual bool visitExpression(Expression *obj);
+  };
+
+  bool CastCounter::visitExpression(Expression *obj)
+  {
+    if (obj-&gt;isE_cast()) {
+      count++;         // found a cast!
+    }
+    return true;       // visit my children too
+  }
+</pre>
+          
+<p>
+This declares class <tt>CastCounter</tt>, which inherits from
+<tt>ASTVisitor</tt>.  <tt>ASTVisitor</tt> contains a bunch of virtual
+methods, one for each kind of AST node (superclass, not subclass).
+By default these methods do nothing, but we can override that behavior
+in subclasses like <tt>CastCounter</tt>.
+
+<p>
+In <tt>CastCounter</tt>, we have a <tt>count</tt> member to keep track
+of how many casts are found.  We also override
+<tt>visitExpression</tt>, which will be called whenever the visitor
+encounters an <tt>Expression</tt> AST node.  The implementation of
+this method simply increments <tt>count</tt> whenever the expression
+is an <tt>E_cast</tt>.  (The rest of the AST is defined in
+<a href="../cc.ast">cc.ast</a> and documented in 
+<a href="cc.ast.html">cc.ast.html</a>.)
+
+<p>Now, go to the bottom of the <tt>doit()</tt> function, and just
+before the call to <tt>strTable.clear()</tt>, add the following code:
+<pre>
+  CastCounter cc;
+  unit-&gt;traverse(cc);
+  cout &lt;&lt; inputFname &lt;&lt; ": found " &lt;&lt; cc.count &lt;&lt; " casts\n";
+</pre>
+This code creates an instance of <tt>CastCounter</tt>, initiates
+an AST traversal with <tt>traverse()</tt>, and finally prints out
+the count.
+
+<p>
+Rebuild <tt>ccparse</tt> with these changes:
+<pre>
+  elsa$ make
+</pre>
+     
+<p>
+Now, run it on some input:
+<pre>
+  elsa$ ./ccparse in/t0001.cc
+  %%% progress: 0ms: done parsing (1 ms, 0_249063 cycles)
+  ambiguous nodes: 0
+  %%% progress: 4ms: done type checking (3 ms)
+  typechecking results:
+    errors:   0
+    warnings: 0
+  %%% progress: 6ms: done elaborating (0 ms)
+  in/t0001.cc: found 0 casts
+</pre>
+Well that wasn't too exciting, there aren't any casts in <tt>in/t0001.cc</tt>.
+Here are some other files to try:
+<ul>
+<li>t0001.cc: 0 casts
+<li>t0004.cc: 1 cast
+<li>t0014.cc: 1 function-style cast, plus one each of the keyword casts
+<li>t0059.cc: 3 casts
+<li>t0117.cc: 184 casts
+</ul>
+
+<p>
+One interesting aspect of 
+<a href="../in/t0014.cc"><tt>in/t0014.cc</tt></a> is that the "cast" on
+line 11 is actually parsed as an <tt>E_constructor</tt> (constructor
+call), but because the type it constructs is not a class, the
+type checker <em>replaces</em> it with an <tt>E_cast</tt>.  This
+makes the meaning of the code more obvious to an analysis: there is
+no function call there, despite the syntax suggesting it.  
+
+<p>
+If you want, you can verify the absence of the <tt>E_cast</tt> by
+moving the cast-counting code up to between the parser and type
+checking phases in <tt>doit()</tt>.
+
+<h1>5. Print the casts</h1>
+
+<p>
+Let's try something a little more ambitious: instead of just 
+counting the casts, we will print for each cast its source location,
+the source expression, the destination type, and which C++ cast
+keyword it uses (if any).
+
+<p>
+To accomplish all of this, replace the existing <tt>visitExpression</tt>
+implementation with the following:
+<pre>
+  // find the location of a type-id; as locations are not stored on
+  // all AST nodes, we must dig a little to get it
+  inline SourceLoc locOfType(ASTTypeId *id)
+  {
+    return id-&gt;decl-&gt;decl-&gt;loc;
+  }
+
+  bool CastCounter::visitExpression(Expression *obj)
+  {
+    if (obj-&gt;isE_cast()) {
+      count++;
+      E_cast *cast = obj-&gt;asE_cast();
+
+      cout &lt;&lt; toString(locOfType(cast-&gt;ctype))
+           &lt;&lt; ": C cast of `" &lt;&lt; cast-&gt;expr-&gt;exprToString()
+           &lt;&lt; "' to type `" &lt;&lt; cast-&gt;ctype-&gt;getType()-&gt;toString() &lt;&lt; "'\n";
+    }
+
+    else if (obj-&gt;isE_keywordCast()) {
+      count++;
+      E_keywordCast *cast = obj-&gt;asE_keywordCast();
+
+      cout &lt;&lt; toString(locOfType(cast-&gt;ctype))
+           &lt;&lt; ": " &lt;&lt; toString(cast-&gt;key)
+           &lt;&lt; " of `" &lt;&lt; cast-&gt;expr-&gt;exprToString()
+           &lt;&lt; "' to type `" &lt;&lt; cast-&gt;ctype-&gt;getType()-&gt;toString() &lt;&lt; "'\n";
+    }
+
+    return true;       // visit my children too
+  }
+</pre>
+
+<p>
+Source locations have type <tt>SourceLoc</tt>, which is defined
+in <a href="../../smbase/srcloc.h">srcloc.h</a>.  Not all AST nodes
+have locations, because I was concerned about wasting space.
+As in this example, there's usually a location "nearby" that will
+suffice.  The <tt>locOfType</tt> function goes and gets it.
+
+<p>
+The printing code uses the <tt>toString(SourceLoc)</tt> function,
+the <tt>toString(CastKeyword)</tt> function,
+the <tt>Expression::exprToString()</tt> method, and 
+the <tt>Type::toString</tt> method to print the AST components.
+Most things in Elsa can be printed with such routines.  
+
+<p>
+Since keyword casts are their own AST node, there are two conditional
+blocks.  Each uses a "downcast" method such as <tt>asE_cast()</tt> or
+<tt>asE_keywordCast()</tt>, only after checking the type with a type
+interrogation method such as <tt>isE_cast()</tt> or
+<tt>isE_keywordCast()</tt>.  If you call a downcast method and the
+object is not of the appropriate type, an assertion will fail.
+(You <em>can</em> also use the C++ RTTI mechanisms like
+<tt>dynamic_cast</tt> to do this; I just prefer to do it my way.)
+
+<p>
+Build and run this program:
+<pre>
+  elsa$ make
+  [...]
+  elsa$ ./ccparse in/t0014.cc
+  %%% progress: 0ms: done parsing (1 ms, 1_080294 cycles)
+  ambiguous nodes: 2
+  %%% progress: 6ms: done type checking (5 ms)
+  typechecking results:
+    errors:   0
+    warnings: 0
+  %%% progress: 9ms: done elaborating (1 ms)
+  in/t0014.cc:11:7: C cast of ` (6)' to type `int'
+  in/t0014.cc:28:21: const_cast of ` (x)' to type `int'
+  in/t0014.cc:29:23: dynamic_cast of ` (x)' to type `int'
+  in/t0014.cc:30:22: static_cast of ` (x)' to type `int'
+  in/t0014.cc:31:27: reinterpret_cast of ` (x)' to type `int'
+  in/t0014.cc: found 5 casts
+</pre>
+
+<p>
+One annoyance with the output above is the leading space that
+gets printed before the expressions.  That comes from the
+pretty printer module, <tt>cc_print</tt> 
+(<a href="../cc_print.ast">cc_print.ast</a>,
+<a href="../cc_print.h">cc_print.h</a> and
+<a href="../cc_print.cc">cc_print.cc</a>), because it is trying
+to avoid problems with printing things too close together.
+Eventually, the pretty printer will be fixed to not do that.
+A simple short-term fix, if you're inclined, is to pass
+the expression text through <tt>trimWhitespace()</tt> like this
+(be sure to #include <a href="../../smbase/strutil.h">strutil.h</a>):
+<pre>
+  &lt;&lt; ": C cast of `" &lt;&lt; trimWhitespace(cast-&gt;expr-&gt;exprToString())
+</pre>
+
+<h1>6. Semantic grep</h1>
+
+<p>
+A frequent programmer's task is to find all uses of some variable or
+function.  People often use the Unix <tt>grep</tt> utility for this task, but
+<tt>grep</tt> is easily confused by entities that have the same name
+(but are declared in different scopes).  Using Elsa, we can write a
+tool that will report all uses of a given variable.  
+
+<p>
+Rather than have you type in the code for the grepper, it is a
+part of the distribution tarball, in <a href="../semgrep.cc"><tt>semgrep.cc</tt></a>.
+The targets for building it are already in the
+<A href="../Makefile.in"><tt>Makefile</tt></A>, so let's build and
+use it right away:
+<pre>
+  elsa$ make semgrep
+  [...]
+  elsa$$ ./semgrep f 6 in/t0005.cc
+  in/t0005.cc:6:6: declaration
+  in/t0005.cc:13:4: use as variable
+  in/t0005.cc:15:3: use as variable
+</pre>
+
+<p>
+I've chosen to denote variables by their name and the line on
+which they are declared or defined.  This is both reasonably
+convenient and unambiguous.  The usage is then
+<pre>
+  ./semgrep &lt;name&gt; &lt;line&gt; input.cc
+</pre>
+Try a few more examples.
+
+<p>
+Now let's look at how <a href="../semgrep.cc"><tt>semgrep.cc</tt></a> works.
+Near the top is <tt>GrepVisitor</tt>, the visitor that looks for
+uses of a variable.  It visits <tt>E_variable</tt> and <tt>E_fieldAcc</tt>
+nodes to find uses in expressions.  It also looks in <tt>Declarators</tt>,
+to try to find the definition (of, say, a function).
+
+<p>
+Both kinds of expressions are annotated by the type checker with
+a field "<tt>var</tt>", which points at the <tt>Variable</tt> object
+that represents the variable referred-to.  The <tt>var</tt> field
+is declared in <a href="../cc_tcheck.ast"><tt>cc_tcheck.ast</tt></a>,
+an extension module to <a href="../cc.ast"><tt>cc.ast</tt></a> that
+specifies what annotations the type checker adds.
+
+<p>
+<tt>Variable</tt> objects are used for quite a few things, including functions; see
+<a href="../variable.h"><tt>variable.h</tt></a> for more details.
+Each variable has an associated location, and that is what the grep
+checks.  When a hit is found, the location of the <em>reference</em>
+to that variable is printed.
+
+<p>
+The <tt>Declarator</tt> case works similarly, as it has been
+annotated with the <tt>Variable</tt> to which the declarator
+refers.
+
+<p>
+One problem with this grepper is that <tt>Variable</tt> only has
+one location, but a variable can be declared in multiple places,
+and it's not always obvious which location will be stored there
+(look in <a href="../variable.h"><tt>variable.h</tt></a> for details).
+A better grepper would use one traversal to robustly find the 
+<tt>Variable</tt> of interest using any of a variety of identification
+criteria, and then another traversal to identify uses.  I leave
+this as an exercise for the interested reader.
+
+<h1>7. Example language extension</h1>
+
+<p>
+This is for the moment a TODO item ....
+
+
+<h1>8. Directions for further exploration</h1>
+
+<p>
+(outline)
+<ul>
+<li>cc.ast
+<li>cc_type
+<li>cc.gr (just skim it)
+<li>cc_tcheck.cc (skim)
+<li>look at the regression tester, ERROR lines, etc; learn how to add
+    a new test
+<li>... what else?
+</ul>
+
+<!--
+<p>
+ideas for more projects
+<ul>
+<li>lint-like checking
+  <ul>
+  <li>don't make an iterator without also advancing it at some point
+  <li>don't pass large objects by value
+  <li>simpleminded leak checker: for every "new x" where "x" is a local,
+      there should be a "delete x" in same function
+  <li>scan for uses of List::append(), which can lead to quadratic behavior
+  <li>find places that string::pchar()'s result is stored in a
+      variable instead of being used right away
+  <li>find clashes between char* and StringRef
+  <li>look for places where an iterator is outstanding on a data structure
+      and it might be modified
+  </ul>
+<li>?
+</ul>
+-->
+
+
+
+
+
+
+<!-- blank space -->
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+
+
+
+
+
+
+
+
+
+
+</body>
+</html>

Added: vendor/elsa/current/elsa/doc/valid-html401.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/valid-html401.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/doc/variables.png
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/doc/variables.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/extradep.mk
===================================================================
--- vendor/elsa/current/elsa/extradep.mk	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/extradep.mk	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+cc.gr.gen.o: cc_tokens.h
+cc.gr.gen.o: cc.ast.gen.h
+cc_ast_aux.o: cc.ast.gen.h
+cc_env.o: cc.ast.gen.h
+cc_print.o: cc.ast.gen.h
+cc_scope.o: cc.ast.gen.h
+cc_tcheck.o: cc.ast.gen.h
+cc_tokens.o: cc_tokens.h
+ccparse.o: cc.ast.gen.h
+lexer.o: cc_tokens.h
+lexer.yy.o: cc_tokens.h
+main.o: cc_tokens.h
+main.o: cc.ast.gen.h
+main.o: cc.gr.gen.h
+parssppt.o: cc_tokens.h
+tlexer.o: cc_tokens.h
+const_eval.o: cc.ast.gen.h

Added: vendor/elsa/current/elsa/filter_elsa_noise
===================================================================
--- vendor/elsa/current/elsa/filter_elsa_noise	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/filter_elsa_noise	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,49 @@
+#!/usr/bin/perl -w
+use strict;
+
+# This script used to filter out source locations from the printAST,
+# but now we serialize the source locations correctly, so that is no
+# longer necessary.  However, we still need to filter out:
+#
+#   1) warnings and other progress messages
+#
+#   2) successor pointers as we don't serialize those
+#
+#   3) actual pointer values that Scott likes to print out
+#
+#   4) comments on the number of overloadings as that gets resolved
+#      during typechecking and is not serialized out
+
+while(<STDIN>) {
+  # source locations
+#  next if /^\s*loc =/;
+
+  # warnings and other messages
+  next if /^\s*parse=.* tcheck=.* integ=.* elab=.*/;
+  next if /^\s*typechecking results:/;
+  next if /^\s*errors:/;
+  next if /^\s*warnings:/;
+  next if /^\s*no-typecheck/;
+  next if /^\s*no-elaborate/;
+  next if /^.*:\d+:\d+: warning:/;
+
+  # successor pointers
+  next if /^\s*succ=/;
+
+  # source locations
+#    s|\b\S+\.cc:\d+:\d+ \(0x.*\)||g;
+#    s|<init>:\d+:\d+ \(0x.*\)||g;
+#    s|<noloc>:\d+:\d+ \(0x.*\)||g;
+#    # without
+#    s|\b\S+\.cc:\d+:\d+||g;
+#    s|<init>:\d+:\d+||g;
+#    s|<noloc>:\d+:\d+||g;
+
+  # pointer values
+  s|(0x[0-9A-F]+)||;
+
+  # number of overloadings
+  s| \(\d+ overloadings?\)$||;
+
+  print;
+}


Property changes on: vendor/elsa/current/elsa/filter_elsa_noise
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/five-errors
===================================================================
--- vendor/elsa/current/elsa/five-errors	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/five-errors	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+#!/bin/sh
+# hack for in/t0151.cc
+
+if ./ccparse "$@" | grep -v 'left side of ->' | grep 'error:'; then
+  # an error remained after removing the known ones
+  false
+else
+  true
+fi
+


Property changes on: vendor/elsa/current/elsa/five-errors
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/generic_amb.h
===================================================================
--- vendor/elsa/current/elsa/generic_amb.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/generic_amb.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,275 @@
+// generic_amb.h
+// generic ambiguity resolution; was in cc_tcheck.cc, but gnu.cc
+// wants to use it too
+
+#ifndef GENERIC_AMB_H
+#define GENERIC_AMB_H
+
+#include "cc_ast.h"         // C++ AST
+#include "cc_env.h"         // Env, DisambiguationErrorTrapper
+#include "objlist.h"        // ObjList
+#include "trace.h"          // TRACE
+
+
+// defined in cc_tcheck.cc
+bool noDisambErrors(ErrorList const &list);
+
+
+// when I print a message saying how an ambiguity was resolved,
+// I want to describe the selected node; in most cases the name
+// of that node's type suffices
+template <class NODE>
+string ambiguousNodeName(NODE const *n)
+{
+  return n->kindName();
+}
+
+// definitions in cc_tcheck.cc
+string ambiguousNodeName(Declarator const *n);
+string ambiguousNodeName(Expression const *e);
+
+
+// after a node has failed to typecheck, I may need to mark it
+// as "never been typechecked", so that if it's a shared subtree
+// in an ambiguous region we'll attempt to check it in each
+// context (since that's what's needed to put errors into the
+// environment); in the common case I don't need anything
+//
+// update: this doesn't work, because the problem may be one
+// level down from the top node..
+//  template <class NODE>
+//  inline void markAsFailed(NODE *n) {}
+
+//  // but for Expressions I need to nullify the 'type' field
+//  inline void markAsFailed(Expression *n)
+//  {
+//    n->type = NULL;
+//  }
+
+
+// Generic ambiguity resolution:  We check all the alternatives, and
+// select the one which typechecks without errors.  Complain if the
+// number of successful alternatives is not 1.
+template <class NODE, class EXTRA>
+NODE *resolveAmbiguity(
+  // pointer to the first alternative; we find other alternatives
+  // by following the 'ambiguity' links
+  NODE *ths,
+
+  // typechecking context
+  Env &env,
+
+  // actual type name of 'NODE' (superclass type in the AST)
+  char const *nodeTypeName,
+
+  // when 'priority' is true, then the alternatives are considered to
+  // be listed in order of preference, such that the first one to
+  // successfully typecheck is immediately chosen
+  bool priority,
+
+  // This extra argument will be passed to NODE->mid_tcheck, and
+  // whatever the succeeding tcheck puts back into its 'extra' will
+  // be copied into the caller's version.  (Currently, EXTRA is
+  // always either 'Declarator::Tcheck' or it is 'int' (and ignored),
+  // if that helps for concreteness.)
+  EXTRA &callerExtra)
+{
+  // grab location before checking the alternatives
+  SourceLoc loc = env.loc();
+
+  // how many alternatives?
+  int numAlts = 1;
+  {
+    for (NODE *a = ths->ambiguity; a != NULL; a = a->ambiguity) {
+      numAlts++;
+    }
+  }
+
+  TRACE("disamb",
+    toString(loc) << ": ambiguous " << nodeTypeName
+                  << " with " << numAlts << " alternatives");
+
+  // make an array of lists to hold the errors generated by the
+  // various alternatives
+  enum { NOMINAL_MAX_ALT = 3 };
+  ErrorList altErrorsArray[NOMINAL_MAX_ALT];
+  ErrorList *altErrors = altErrorsArray;
+  if (numAlts > NOMINAL_MAX_ALT) {
+    // there are too many ambiguities to fit into the stack-allocated
+    // array, so use an array on the heap instead; this is very
+    // unusual, but not impossible (see e.g. in/t0328.cc)
+    altErrors = new ErrorList[numAlts];
+  }
+
+  // copy the caller's 'extra' so we can make untainted copies
+  // for each iteration
+  EXTRA origExtra(callerExtra);
+
+  // check each one
+  int altIndex = 0;
+  int numOk = 0;
+  NODE *lastOk = NULL;
+  int lastOkIndex = -1;
+  
+  // save current error messages so we will only be dealing with
+  // those generated by the current alternative
+  {
+    DisambiguationErrorTrapper trapper(env);
+
+    for (NODE *alt = ths; alt != NULL; alt = alt->ambiguity, altIndex++) {
+      int beforeChange = env.getChangeCount();
+
+      TRACE("disamb",
+            toString(loc) << ": considering " << ambiguousNodeName(alt));
+
+      // tcheck 'alt'
+      EXTRA extra(origExtra);
+      try {
+        alt->mid_tcheck(env, extra);
+      }
+      catch (x_assert &x) {
+        HANDLER();
+        env.errors.markAllAsFromDisamb();
+        throw;
+      }
+
+      // move that run's errors into a per-alternative list
+      altErrors[altIndex].takeMessages(env.errors);
+
+      // did that alternative succeed?
+      if (noDisambErrors(altErrors[altIndex])) {
+        // yes; update our success trackers
+        numOk++;
+        lastOk = alt;
+        lastOkIndex = altIndex;
+
+        // copy that alternative's 'extra' to the caller's
+        callerExtra = extra;
+
+        if (priority) {
+          // the alternatives are listed in priority order, so once an
+          // alternative succeeds, stop and select it
+          break;
+        }
+      }
+      else {
+        // if this NODE failed to check, then it had better not
+        // have modified the environment
+        if (beforeChange != env.getChangeCount()) {
+          // 1/02/03: there used to be an assertion here, but
+          // this actually happens sometimes, and it's unavoidable.
+          // for example,
+          //   int foo(smanip<TP> &m);
+          // when interpreted as an integer with an initializer has
+          // both of its initializers fail to tcheck (unless TP is
+          // a variable), but that's only after 'foo' has been added;
+          // and the language requires that 'foo' be visible inside
+          // its own initializer, so it has to be added first.
+          //
+          // what I really want here is to make sure this now-corrupt
+          // environment can't participate in any eventually successful
+          // parse, so I'll just insert one more (non-disambiguating)
+          // error, so this entire interpretation line has to be rejected
+          // one way or another
+          altErrors[altIndex].addError(new ErrorMsg(
+            loc, "a rejected alternative modified this environment", EF_NONE));
+        }
+
+        // make sure we don't consider this subtree to be finished
+        //markAsFailed(alt);
+      }
+    }
+    
+    // env's error messages restored at this point
+  }
+
+  if (numOk == 0) {
+    // none of the alternatives checked out
+    TRACE("disamb",
+      toString(loc) << ": ambiguous " << nodeTypeName << ": all bad");
+    //breaker();  // nsFastLoadFile.i provokes this many times, but all benign (?)
+
+    // add a note about the ambiguity
+    env.errors.addError(new ErrorMsg(
+      loc, "---- BEGIN: messages from an ambiguity ----", EF_NONE));
+    for (int i=0; i<numAlts; i++) {
+      if (i > 0) {
+        env.errors.addError(new ErrorMsg(
+          loc, "---- SEPARATOR: messages from an ambiguity ----", EF_NONE));
+      }
+      env.errors.takeMessages(altErrors[i]);
+    }
+    env.errors.addError(new ErrorMsg(
+      loc, "---- END: messages from an ambiguity ----", EF_NONE));
+  }
+
+  else if (numOk == 1) {
+    // one alternative succeeds, which is what we want
+    TRACE("disamb",
+      toString(loc) << ": ambiguous " << nodeTypeName
+                    << ": selected " << ambiguousNodeName(lastOk));
+
+    // put back succeeding alternative's errors (non-disambiguating,
+    // and warnings); errors associated with other alternatives will
+    // be deleted automatically
+    env.errors.takeMessages(altErrors[lastOkIndex]);
+    
+    // select 'lastOk'
+    ths = lastOk;
+  }
+
+  else {
+    // more than one alternative succeeds, not good
+    TRACE("disamb",
+      toString(loc) << ": ambiguous " << nodeTypeName << ": multiple good!");
+
+    // now complain; mark it 'disambiguating' so that we'll see
+    // this show up even in template code
+    env.error("more than one ambiguous alternative succeeds",
+              EF_DISAMBIGUATES);
+  }
+
+  // 2005-03-27: I moved this down here so that we always resolve
+  // the ambiguity, even when there is no basis for choosing.  The
+  // failed resolution will still generate an error, but this way
+  // subsequent stages will find an unambiguous AST (in/t0459.cc).
+  //
+  // break the ambiguity link (if any) in 'lastOk', so if someone
+  // comes along and tchecks this again we can skip the last part
+  // of the ambiguity list
+  const_cast<NODE*&>(ths->ambiguity) = NULL;
+
+  // cleanup the array if necessary
+  if (numAlts > NOMINAL_MAX_ALT) {
+    delete[] altErrors;
+  }
+
+  return ths;
+}
+
+
+// swap the order of the first two elements of the ambiguity link
+// list before passing to 'resolveAmbiguity'
+template <class NODE, class EXTRA>
+NODE *swap_then_resolveAmbiguity(
+  NODE *ths,
+  Env &env,
+  char const *nodeTypeName,
+  bool priority,
+  EXTRA &callerExtra)
+{                          
+  // original configuration: a b rest
+  NODE *a = ths;
+  NODE *b = ths->ambiguity;
+
+  // new configuration: b a rest
+  a->ambiguity = b->ambiguity;
+  b->ambiguity = a;
+
+  // run with priority
+  return resolveAmbiguity(b, env, nodeTypeName, priority, callerExtra);
+}
+
+
+
+#endif // GENERIC_AMB_H

Added: vendor/elsa/current/elsa/generic_aux.h
===================================================================
--- vendor/elsa/current/elsa/generic_aux.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/generic_aux.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,130 @@
+// generic_aux.h
+// some templatized routines that used to be in cc_ast_aux.cc,
+// but gnu.cc wants to use them too
+
+#include "cc_ast.h"         // C++ AST
+
+ 
+// generic get/set 'ambiguity'
+template <class NODE>
+NODE *getAmbiguity(NODE const *n)
+{
+  return n->ambiguity;
+}
+
+template <class NODE>
+void setAmbiguity(NODE *n, NODE *newAmbig)
+{
+  n->ambiguity = newAmbig;
+}
+
+
+// get/set 'ambiguity' for PQName (implemented in cc_ast_aux.cc)
+PQName *getAmbiguity(PQName const *n);
+void setAmbiguity(PQName *n, PQName *newAmbig);
+
+
+template <class NODE>
+void genericPrintAmbiguities(NODE const *ths, char const *typeName,
+                             ostream &os, int indent)
+{
+  // count the number of alternatives
+  int numAlts = 0;
+  {
+    for (NODE const *p = ths; p != NULL; p = getAmbiguity(p)) {
+      numAlts++;
+    }
+  }
+
+  // print a visually obvious header
+  ind(os, indent) << "--------- ambiguous " << typeName << ": "
+                  << numAlts << " alternatives ---------\n";
+
+  // walk down the list of ambiguities, printing each one by
+  // temporarily nullifying the 'ambiguity' pointer; cast away
+  // the constness so I can do the temporary modification
+  int ct=0;
+  for (NODE *e = const_cast<NODE*>(ths);
+       e != NULL;
+       e = getAmbiguity(e)) {
+    if (ct++ > 0) {
+      ind(os, indent) << "---- or ----\n";
+    }
+
+    NODE *tempAmbig = getAmbiguity(e);
+    setAmbiguity(e, (NODE*)NULL);
+    e->debugPrint(os, indent+2);
+    setAmbiguity(e, tempAmbig);
+  }
+
+  ind(os, indent) << "--------- end of ambiguous " << typeName
+                  << " ---------\n";
+}
+
+
+// make sure that all the 'next' fields end up the same
+template <class NODE>
+void genericCheckNexts(NODE const *main)
+{
+  for (NODE const *a = main->ambiguity; a != NULL; a = a->ambiguity) {
+    xassert(main->next == a->next);
+  }
+}
+
+// add another ambiguous alternative to 'main', with care given
+// to the fact that NODE has 'next' links
+template <class NODE>
+void genericAddAmbiguity(NODE *main, NODE *alt)
+{
+  // 'alt' had better not already be on a list (shouldn't be,
+  // because it's the RHS argument to merge, which means it's
+  // never been yielded to anything)
+  xassert(alt->next == NULL);
+
+  // same reasoning for 'ambiguity'
+  //xassert(alt->ambiguity == NULL);
+  // no, it turns out the RHS could have been yielded if the
+  // reduction action is the identity function.. so instead
+  // find the last node in the 'alt' list and we'll splice
+  // that entire list into 'main's ambiguity list
+  NODE *altLast = alt;
+  while (altLast->ambiguity) {
+    altLast = altLast->ambiguity;
+
+    // the assignment below will only get the first node, so
+    // this takes care of the other ones in 'alt'
+    altLast->next = main->next;
+  }
+
+  if (main->next) {
+    // I don't expect 'main' to already be on a list, so I'll
+    // make some noise; but I think it will work anyway
+    cout << "note: ambiguous " << main->kindName()
+         << "node leader is already on a list..\n";
+  }
+
+  // if 'main' has been added to a list, add 'alt' also
+  alt->next = main->next;
+
+  // finally, prepend 'alt's ambiguity list to 'main's ambiguity list
+  altLast->ambiguity = main->ambiguity;
+  main->ambiguity = alt;
+}
+
+
+// set the 'next' field of 'main' to 'newNext', with care given
+// to possible ambiguities
+template <class NODE>
+void genericSetNext(NODE *main, NODE *newNext)
+{
+  // 'main's 'next' should be NULL; if it's not, then it's already
+  // on a list, and setting 'next' now will lose information
+  xassert(main->next == NULL);
+  main->next = newNext;
+
+  // if 'main' has any ambiguous alternatives, set all their 'next'
+  // pointers too
+  if (main->ambiguity) {
+    genericSetNext(main->ambiguity, newNext);     // recursively set them all
+  }
+}

Added: vendor/elsa/current/elsa/gnu.ast
===================================================================
--- vendor/elsa/current/elsa/gnu.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/gnu.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,333 @@
+// gnu.ast            see license.txt for copyright and terms of use
+// extension to cc.ast to support GNU language extensions
+
+// sm: this contains both the representation language and the
+// annotations used by the type checker, unlike the cc.ast
+// vs. cc_tcheck.ast split, since there seemed little profit in that
+// split for this file
+
+verbatim {
+  #define GNU_EXTENSION         // this extension module is active
+
+  #include <limits.h>           // INT_MIN
+}
+
+
+// additional contexts in the GNU extensions
+enum DeclaratorContext {
+                          // inside ASTTypeId
+  DC_TS_TYPEOF_TYPE,      //   TS_typeof_type::atype
+  DC_E_COMPOUNDLIT,       //   E_compoundLit::stype
+  DC_E_ALIGNOFTYPE,       //   E_alignofType::atype
+  // DC_E_OFFSETOF,          //   E_offsetof::atype
+  DC_E_BUILTIN_VA_ARG,    //   E___builtin_va_arg::atype
+}
+
+
+// The AST extensions in this file are organized in parallel with the
+// syntactic extensions in gnu.gr.
+
+
+// ----------- gcc statement expression -----------
+class Expression {
+  // statement-expression
+  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Statement-Exprs.html
+  -> E_statement(S_compound s) {
+       // sort of like E_compoundLit::tcheckedType, this ensures we
+       // only tcheck this once even though it might appear in
+       // ambiguous contexts
+       public bool tchecked = false;
+     }
+}
+
+
+// ----------- gcc compound literals -----------
+class Expression {
+  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Compound-Literals.html
+  // and C99 6.5.2.5
+  -> E_compoundLit(ASTTypeId stype, IN_compound init) {
+       // help for dealing with expressions being tchecked more than once
+       public bool tcheckedType = false;
+     }
+}
+
+
+// ----------- gcc misc -----------
+class Statement {
+  // nested function definition
+  -> S_function(Function f);
+
+  // case ranges
+  -> S_rangeCase(Expression exprLo, Expression exprHi, Statement s) {
+       public(xml) int labelValLo = 0;
+       public(xml) int labelValHi = 0;
+  }
+}
+
+class Expression {
+  // miscellanous builtins that for whatever reason find themselves
+  // as AST nodes instead of ordinary function calls (...)
+  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Other-Builtins.html
+  -> E___builtin_constant_p(SourceLoc loc, Expression expr);
+
+  // varargs; dsw: I think that we should make all of these their own
+  // AST node, I just don't want to deal with the parsing ambiguity
+  // with E_funCall right now
+//   -> E___builtin_va_start(SourceLoc loc, Expression expr, Expression expr2);
+//   -> E___builtin_va_copy(SourceLoc loc, Expression expr, Expression expr2);
+  -> E___builtin_va_arg(SourceLoc loc, Expression expr, ASTTypeId atype);
+//   -> E___builtin_va_end(SourceLoc loc, Expression expr);
+
+  // alignment inquiry
+  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Alignment.html
+  -> E_alignofType(ASTTypeId atype) {
+       public virtual CValue extConstEval(ConstEval &env) const;
+       public(xml) int alignment = 0; // set by tcheck
+     }
+
+  -> E_alignofExpr(Expression expr) {
+       public virtual CValue extConstEval(ConstEval &env) const;
+       public(xml) int alignment = 0;
+     }
+
+  // conditional with no middle operand
+  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Conditionals.html
+  -> E_gnuCond(Expression cond, Expression el) {
+       public virtual CValue extConstEval(ConstEval &env) const;
+       public virtual bool extHasUnparenthesizedGT();
+     }
+
+  // // quarl 2006-07-12
+  // //    Handle __offsetof__ (gcc-3.4), __builtin_offsetof (gcc-4.x)
+  // -> E_offsetof(ASTTypeId atype, PQName fieldName) {
+  //      public virtual CValue extConstEval(ConstEval &env) const;
+  //    }
+}
+
+
+// ----------- gcc dangling labels -----------
+// (no AST extensions required)
+
+
+// ----------- gcc typeof -----------
+// types denoted with 'typeof' keyword
+new class ASTTypeof {
+  // same as we do for statements
+  public ASTTypeof *ambiguity;  ctor ambiguity=NULL;
+  public void addAmbiguity(ASTTypeof *alternative);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  // yield the ASTTypeof selected by ambiguity resolution; the
+  // type is in its 'type' member
+  public ASTTypeof *tcheck(Env &env, DeclFlags dflags);
+  public void mid_tcheck(Env &env, DeclFlags &dflags);
+  pure_virtual Type *itcheck(Env &env, DeclFlags dflags);
+
+  // dsw: I had to move this here to deal with the mid_tcheck design
+  // pattern that is used to resolve ambiguities.
+  public(xml_TY) Type *type;
+
+  // dsw: I'm assuming that ASTTypeof should terminate the top of the
+  // Expression tree, but I don't feel absolutely sure about it.
+  -> TS_typeof_expr(FullExpression expr);
+
+  -> TS_typeof_type(ASTTypeId atype);
+}
+
+
+class TypeSpecifier {
+  -> TS_typeof(ASTTypeof atype);
+}
+
+
+// ----------- gcc C++ min and max operators -----------
+// (2005-04-07: there used to be a special E_gnuMinMax, but because
+// those operators are overloadable, they become intertwined with much
+// more of the tchecker structure, and therefore I folded them into
+// BinaryOp)
+
+
+// ----------- gcc asm -----------
+// (no AST extension b/c extra info dropped on floor)
+
+
+// ----------- gcc asm labels -----------
+// (no AST extension b/c extra info dropped on floor)
+
+
+// ----------- C99 designated initializers -----------
+class Initializer {
+  // a designator (list of fields/subscripts) in front of an
+  // undesignated initializer
+  -> IN_designated(FakeList<Designator> *designator_list,
+                   Initializer init);
+}
+
+class Designator (SourceLoc loc) {
+  // FakeList link; use setNext
+  public Designator *next;  ctor next=NULL;
+  public void setNext(Designator *newNext);
+
+  // dsw: I seem to need all of this ambiguity stuff in order to use
+  // genericSetNext
+
+  // ambiguity representation
+  public Designator *ambiguity; ctor ambiguity=NULL;
+  public void addAmbiguity(Designator *alternative);
+  custom traverse { if (ambiguity) ambiguity->traverse(vis); }
+
+  // print ambiguities
+  public void printAmbiguities(ostream &os, int indent) const;
+  custom preemptDebugPrint {
+    if (ambiguity) {
+      printAmbiguities(os, indent);
+      return;     // skip the normal, unambiguous-node print code
+    }
+  }
+
+  pure_virtual void print(PrintEnv &env);
+
+  -> FieldDesignator(StringRef id);
+
+  -> SubscriptDesignator(Expression idx_expr, // taken from D_array
+                         Expression /*nullable*/ idx_expr2)
+  {
+    public(xml) int idx_computed  = INT_MIN; // index computed at compile time
+    public(xml) int idx_computed2 = INT_MIN; // index range end computed at compile time
+  }
+}
+
+
+// ----------- C99 restrict keyword -----------
+// (no AST extensions required b/c cc_flags.h already has *_RESTRICT)
+
+
+// ----------- C99 qualifiers in array brackets -----------
+// (no AST extension b/c extra info dropped on floor)
+
+
+// ------------ gcc computed goto ----------
+class Expression {
+  // address of a label, e.g., "&&labelName"
+  -> E_addrOfLabel(StringRef labelName);
+}
+
+class Statement {
+  // goto a label whose address has been taken
+  -> S_computedGoto(Expression target);
+}
+
+
+// ----------- gcc/C99 complex/imaginary ----------
+class Expression {
+  -> E_fieldAcc {
+       // tcheck a __real__ or __imag__
+       public Type *itcheck_complex_selector(Env &env, LookupFlags flags,
+                                             LookupSet &candidates);
+     }
+
+  -> E_binary {
+       // tcheck arith involving complex or imaginary types
+       public Type *itcheck_complex_arith(Env &env);
+     }
+}
+
+
+// ----------- gcc __attribute__ -----------
+// For now, this is a very literal, parse-tree-like representation of
+// attributes.  I don't know very much about how they will be used (I
+// don't know much about what they *mean*), so it is hard to do any
+// semantic digestion.  Therefore, I will not try.
+
+
+// a sequence of __attribute__((..)) specifiers
+class AttributeSpecifierList(
+  AttributeSpecifier spec,
+  AttributeSpecifierList /*nullable*/ next
+);
+
+
+// a single __attribute__((...)) specifier; there may be many
+// individual attributes inside the parens
+class AttributeSpecifier(
+  Attribute attr,
+  AttributeSpecifier /*nullable*/ next
+);
+
+
+// one attribute, somewhere inside __attribute((...)); syntactically,
+// attributes are separated by commas in the parens
+class Attribute(SourceLoc loc) {
+  // e.g., __attribute__(( ))
+  //                      ^
+  // I decided to keep these even though the GNU documentation states
+  // that they are always ignored, because it would be a bit awkward
+  // to drop them in the parser, and they shouldn't occur frequently
+  // anyway.
+  -> AT_empty();
+
+  // e.g., __attribute__((packed))
+  //                      ^^^^^^
+  // Note that even C++ keywords will just get stored as StringRefs.
+  -> AT_word(StringRef w);
+
+  // e.g., __attribute__((format(printf, 1, 2)))
+  //                      ^^^^^^^^^^^^^^^^^^^^
+  // the 'args' can be empty (NULL) to indicate an empty list (which
+  // is still different from AT_word)
+  -> AT_func(StringRef f, FakeList<ArgExpression> *args);
+}
+
+
+// Here's a clever idea: rather than making a completely new node to
+// carry the attributes, I will inherit from D_grouping!  Then
+// everyone will treat D_attribute like D_grouping, basically ignoring
+// it, except the few pieces of code that want to know about it.  This
+// seems much better than polluting the code with explicit knowledge
+// of D_attribute.
+//
+// My astgen tool does not know how to introduce ad-hoc inheritance,
+// so I will write this one by hand.
+verbatim {
+  // __attribute__ occurring directly after a declarator
+  class D_attribute : public D_grouping {
+  public:
+    // NOTE: 'traverse' does *not* automatically go into this field,
+    // because I want most clients to be oblivious to its presence.
+    // They can explicitly intercept D_grouping and check for
+    // D_attribute if traversal is desired.
+    AttributeSpecifierList *alist;       // owner
+
+  public:
+    D_attribute(SourceLoc loc, IDeclarator *base,
+                AttributeSpecifierList *alist);
+    virtual ~D_attribute();
+
+    virtual void debugPrint(ostream &os, int indent, char const *subtreeName = "tree") const;
+    virtual void traverse(ASTVisitor &vis);
+
+    virtual D_attribute *clone() const;
+
+    virtual void tcheck(Env &env, Declarator::Tcheck &dt);
+
+    // Return the attribute(alias("name")) name, or NULL if none.  There
+    // mustn't be more than one.
+    virtual StringRef getAlias() const;
+
+  private:
+    // Return the attribute alias, and check for errors
+    StringRef tcheck_getAlias(Env *penv) const;
+  };
+}
+// TODO: IDeclarator::isD_attribute(), asD_attribute(), ifD_attribute()
+
+// EOF

Added: vendor/elsa/current/elsa/gnu.cc
===================================================================
--- vendor/elsa/current/elsa/gnu.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/gnu.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1468 @@
+// gnu.cc
+// tcheck and print routines for gnu.ast/gnu.gr extensions
+
+#include "generic_aux.h"      // C++ AST, and genericPrintAmbiguities, etc.
+#include "cc_env.h"           // Env
+#include "cc_print.h"         // olayer, PrintEnv
+#include "generic_amb.h"      // resolveAmbiguity, etc.
+#include "stdconv.h"          // usualArithmeticConversions
+#include "astvisit.h"         // ASTVisitorEx
+#include <string.h>           // strcmp
+
+
+// fwd in this file
+SimpleTypeId constructFloatingType(int prec, int axis);
+
+
+// --------------------------- Env ---------------------------------
+// Caveat: All of the uses of GNU builtin functions arise from
+// preprocessing with the gcc compiler's headers.  Strictly speaking,
+// this is inappropriate, as Elsa is a different implementation and
+// has its own compiler-specific headers (in the include/ directory).
+// But in practice people don't often seem to be willing to adjust
+// their build process enough to actually use Elsa's headers, and
+// insist on using the gcc headers since that's what (e.g.) gcc -E
+// finds by default.  Therefore Elsa makes a best-effort attempt to
+// accept the resulting files, even though they are gcc-specific (and
+// sometimes specific to a particular *version* of gcc).  This
+// function is part of that effort.
+//
+// See  http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Other-Builtins.html
+// also http://gcc.gnu.org/onlinedocs/gcc-3.4.3/gcc/Other-Builtins.html
+void Env::addGNUBuiltins()
+{
+  Type *t_void = getSimpleType(ST_VOID);
+  Type *t_ellipsis_ptr = makePtrType(getSimpleType(ST_ELLIPSIS));
+//    Type *t_voidconst = getSimpleType(SL_INIT, ST_VOID, CV_CONST);
+//    Type *t_voidptr = makePtrType(t_void);
+//    Type *t_voidconstptr = makePtrType(SL_INIT, t_voidconst);
+
+  Type *t_int = getSimpleType(ST_INT);
+//    Type *t_unsigned_int = getSimpleType(ST_UNSIGNED_INT);
+  Type *t_char = getSimpleType(ST_CHAR);
+  Type *t_charconst = getSimpleType(ST_CHAR, CV_CONST);
+  Type *t_charptr = makePtrType(t_char);
+  Type *t_charconstptr = makePtrType(t_charconst);
+
+  // dsw: This is a form, not a function, since it takes an expression
+  // AST node as an argument; however, I need a function that takes no
+  // args as a placeholder for it sometimes.
+  var__builtin_constant_p = declareSpecialFunction("__builtin_constant_p");
+
+  // typedef void *__builtin_va_list;
+  Variable *var__builtin_va_list =
+    makeVariable(SL_INIT, str("__builtin_va_list"),
+                 // dsw: in Oink, it really helps if the type is
+                 // ST_ELLIPSIS instead of void*; explanation upon
+                 // request; UPDATE: ok, that doesn't let d0125.cc
+                 // typecheck so how about a pointer to an ST_ELLIPSIS
+//                  t_voidptr, DF_TYPEDEF | DF_BUILTIN | DF_GLOBAL);
+                 t_ellipsis_ptr, DF_TYPEDEF | DF_BUILTIN | DF_GLOBAL);
+  addVariable(var__builtin_va_list);
+  env.builtinVars.push(var__builtin_va_list);
+
+  // void __builtin_stdarg_start(__builtin_va_list __list, char const *__format);
+  // trying this instead:
+  // void __builtin_stdarg_start(__builtin_va_list __list, void const *__format);
+  // nope; see in/d0120.cc.  It doesn't work if the arg to '__format' is an int.
+  // ironically, making it vararg does work
+  declareFunction1arg(t_void, "__builtin_stdarg_start",
+                      var__builtin_va_list->type, "__list",
+//                        t_charconstptr, "__format",
+//                        t_voidconstptr, "__format",
+                      FF_VARARGS, NULL);
+
+
+  // varargs; dsw: I think that we should make all of these their own
+  // AST node, I just don't want to deal with the parsing ambiguity
+  // with E_funCall right now
+  // void __builtin_va_start(__builtin_va_list __list, ...);
+  declareFunction1arg(t_void, "__builtin_va_start",
+                      var__builtin_va_list->type, "__list",
+                      FF_VARARGS, NULL);
+  // void __builtin_va_copy(__builtin_va_list dest, __builtin_va_list src);
+  declareFunction2arg(t_void, "__builtin_va_copy",
+                      var__builtin_va_list->type, "dest",
+                      var__builtin_va_list->type, "src",
+                      FF_NONE, NULL);
+  // void __builtin_va_end(__builtin_va_list __list);
+  declareFunction1arg(t_void, "__builtin_va_end",
+                      var__builtin_va_list->type, "__list");
+
+
+  // // void *__builtin_alloca(unsigned int __len);
+  // declareFunction1arg(t_voidptr, "__builtin_alloca",
+  //                     t_unsigned_int, "__len");
+
+  // char *__builtin_strchr(char const *str, int ch);
+  declareFunction2arg(t_charptr, "__builtin_strchr",
+                      t_charconstptr, "str",
+                      t_int, "ch",
+                      FF_NONE, NULL);
+
+  // char *__builtin_strpbrk(char const *str, char const *accept);
+  declareFunction2arg(t_charptr, "__builtin_strpbrk",
+                      t_charconstptr, "str",
+                      t_charconstptr, "accept",
+                      FF_NONE, NULL);
+
+  // char *__builtin_strchr(char const *str, int ch);
+  declareFunction2arg(t_charptr, "__builtin_strrchr",
+                      t_charconstptr, "str",
+                      t_int, "ch",
+                      FF_NONE, NULL);
+
+  // char *__builtin_strstr(char const *haystack, char const *needle);
+  declareFunction2arg(t_charptr, "__builtin_strstr",
+                      t_charconstptr, "haystack",
+                      t_charconstptr, "needle",
+                      FF_NONE, NULL);
+
+  // we made some attempts to get accurate prototypes for the above
+  // functions, but at some point just started using "int ()(...)"
+  // as the type; the set below all get this generic type
+
+  static char const * const arr[] = {
+    // ------------------------------------------------
+    // group 1: "Outside strict ISO C mode ..."
+
+    // this set is from the 3.1 list
+
+    // quarl 2006-09-07
+    //    The above prototype causes linking to fail.  Use this until
+    //    builtin-declarations.h is used.
+
+    "alloca",              // prototyped above
+    "bcmp",
+    "bzero",
+    "index",
+    "rindex",
+    "ffs",
+    "fputs_unlocked",
+    "printf_unlocked",
+    "fprintf_unlocked",
+
+    // this set is from the 3.4.3 list; the commented lines are
+    // either prototyped above or in the 3.1 list
+    "_exit",
+    //"alloca",
+    //"bcmp",
+    //"bzero",
+    "dcgettext",
+    "dgettext",
+    "dremf",
+    "dreml",
+    "drem",
+    "exp10f",
+    "exp10l",
+    "exp10",
+    "ffsll",
+    "ffsl",
+    //"ffs",
+    //"fprintf_unlocked",
+    //"fputs_unlocked",
+    "gammaf",
+    "gammal",
+    "gamma",
+    "gettext",
+    //"index",
+    "j0f",
+    "j0l",
+    "j0",
+    "j1f",
+    "j1l",
+    "j1",
+    "jnf",
+    "jnl",
+    "jn",
+    "mempcpy",
+    "pow10f",
+    "pow10l",
+    "pow10",
+    //"printf_unlocked",
+    //"rindex",
+    "scalbf",
+    "scalbl",
+    "scalb",
+    "significandf",
+    "significandl",
+    "significand",
+    "sincosf",
+    "sincosl",
+    "sincos",
+    "stpcpy",
+    "strdup",
+    "strfmon",
+    "y0f",
+    "y0l",
+    "y0",
+    "y1f",
+    "y1l",
+    "y1",
+    "ynf",
+    "ynl",
+    "yn",
+
+    // ------------------------------------------------
+    // group 2: "The ISO C99 functions ..."
+
+    // this is the 3.1 list
+    "conj",
+    "conjf",
+    "conjl",
+    "creal",
+    "crealf",
+    "creall",
+    "cimag",
+    "cimagf",
+    "cimagl",
+    "llabs",
+    "imaxabs",
+
+    // this is the 3.4.3 list, with those from 3.1 commented
+    "_Exit",
+    "acoshf",
+    "acoshl",
+    "acosh",
+    "asinhf",
+    "asinhl",
+    "asinh",
+    "atanhf",
+    "atanhl",
+    "atanh",
+    "cabsf",
+    "cabsl",
+    "cabs",
+    "cacosf",
+    "cacoshf",
+    "cacoshl",
+    "cacosh",
+    "cacosl",
+    "cacos",
+    "cargf",
+    "cargl",
+    "carg",
+    "casinf",
+    "casinhf",
+    "casinhl",
+    "casinh",
+    "casinl",
+    "casin",
+    "catanf",
+    "catanhf",
+    "catanhl",
+    "catanh",
+    "catanl",
+    "catan",
+    "cbrtf",
+    "cbrtl",
+    "cbrt",
+    "ccosf",
+    "ccoshf",
+    "ccoshl",
+    "ccosh",
+    "ccosl",
+    "ccos",
+    "cexpf",
+    "cexpl",
+    "cexp",
+    //"cimagf",
+    //"cimagl",
+    //"cimag",
+    //"conjf",
+    //"conjl",
+    //"conj",
+    "copysignf",
+    "copysignl",
+    "copysign",
+    "cpowf",
+    "cpowl",
+    "cpow",
+    "cprojf",
+    "cprojl",
+    "cproj",
+    //"crealf",
+    //"creall",
+    //"creal",
+    "csinf",
+    "csinhf",
+    "csinhl",
+    "csinh",
+    "csinl",
+    "csin",
+    "csqrtf",
+    "csqrtl",
+    "csqrt",
+    "ctanf",
+    "ctanhf",
+    "ctanhl",
+    "ctanh",
+    "ctanl",
+    "ctan",
+    "erfcf",
+    "erfcl",
+    "erfc",
+    "erff",
+    "erfl",
+    "erf",
+    "exp2f",
+    "exp2l",
+    "exp2",
+    "expm1f",
+    "expm1l",
+    "expm1",
+    "fdimf",
+    "fdiml",
+    "fdim",
+    "fmaf",
+    "fmal",
+    "fmaxf",
+    "fmaxl",
+    "fmax",
+    "fma",
+    "fminf",
+    "fminl",
+    "fmin",
+    "hypotf",
+    "hypotl",
+    "hypot",
+    "ilogbf",
+    "ilogbl",
+    "ilogb",
+    //"imaxabs",
+    "lgammaf",
+    "lgammal",
+    "lgamma",
+    //"llabs",
+    "llrintf",
+    "llrintl",
+    "llrint",
+    "llroundf",
+    "llroundl",
+    "llround",
+    "log1pf",
+    "log1pl",
+    "log1p",
+    "log2f",
+    "log2l",
+    "log2",
+    "logbf",
+    "logbl",
+    "logb",
+    "lrintf",
+    "lrintl",
+    "lrint",
+    "lroundf",
+    "lroundl",
+    "lround",
+    "nearbyintf",
+    "nearbyintl",
+    "nearbyint",
+    "nextafterf",
+    "nextafterl",
+    "nextafter",
+    "nexttowardf",
+    "nexttowardl",
+    "nexttoward",
+    "remainderf",
+    "remainderl",
+    "remainder",
+    "remquof",
+    "remquol",
+    "remquo",
+    "rintf",
+    "rintl",
+    "rint",
+    "roundf",
+    "roundl",
+    "round",
+    "scalblnf",
+    "scalblnl",
+    "scalbln",
+    "scalbnf",
+    "scalbnl",
+    "scalbn",
+    "snprintf",
+    "tgammaf",
+    "tgammal",
+    "tgamma",
+    "truncf",
+    "truncl",
+    "trunc",
+    "vfscanf",
+    "vscanf",
+    "vsnprintf",
+    "vsscanf",
+
+    // ------------------------------------------------
+    // group 3: "There are also built-in versions of the ISO C99 functions ..."
+
+    // 3.1 list
+    "cosf",
+    "cosl",
+    "fabsf",
+    "fabsl",
+    "sinf",
+    "sinl",
+    "sqrtf",
+    "sqrtl",
+
+    // 3.4.3 list with 3.1 elements commented
+    "acosf",
+    "acosl",
+    "asinf",
+    "asinl",
+    "atan2f",
+    "atan2l",
+    "atanf",
+    "atanl",
+    "ceilf",
+    "ceill",
+    //"cosf",
+    "coshf",
+    "coshl",
+    //"cosl",
+    "expf",
+    "expl",
+    //"fabsf",
+    //"fabsl",
+    "floorf",
+    "floorl",
+    "fmodf",
+    "fmodl",
+    "frexpf",
+    "frexpl",
+    "ldexpf",
+    "ldexpl",
+    "log10f",
+    "log10l",
+    "logf",
+    "logl",
+    "modfl",
+    "modf",
+    "powf",
+    "powl",
+    //"sinf",
+    "sinhf",
+    "sinhl",
+    //"sinl",
+    //"sqrtf",
+    //"sqrtl",
+    "tanf",
+    "tanhf",
+    "tanhl",
+    "tanl",
+
+    // gcc-3.4.3 seems to have this, though it is not documented
+    "modff",
+
+    // same for these
+    "huge_val",
+    "huge_valf",
+    "huge_vall",
+    "nan",
+
+    // ------------------------------------------------
+    // group 4: "The ISO C90 functions ..."
+
+    // this is the 3.1 list, with things prototyped above commented
+    "abs",
+    "cos",
+    "fabs",
+    "fprintf",
+    "fputs",
+    "labs",
+    "memcmp",
+    "memcpy",
+    "memset",
+    "printf",
+    "sin",
+    "sqrt",
+    "strcat",
+    //"strchr",
+    "strcmp",
+    "strcpy",
+    "strcspn",
+    "strlen",
+    "strncat",
+    "strncmp",
+    "strncpy",
+    //"strpbrk",
+    //"strrchr",
+    "strspn",
+    //"strstr",
+
+    // this is the 3.4.3 list, with things either prototyped above or
+    // in the 3.1 list commented
+    "abort",
+    //"abs",
+    "acos",
+    "asin",
+    "atan2",
+    "atan",
+    "calloc",
+    "ceil",
+    "cosh",
+    //"cos",
+    "exit",
+    "exp",
+    //"fabs",
+    "floor",
+    "fmod",
+    //"fprintf",
+    //"fputs",
+    "frexp",
+    "fscanf",
+    //"labs",
+    "ldexp",
+    "log10",
+    "log",
+    "malloc",
+    //"memcmp",
+    //"memcpy",
+    //"memset",
+    "modf",
+    "pow",
+    "powi",
+    "powif",
+    "powil",
+    //"printf",
+    "putchar",
+    "puts",
+    "scanf",
+    "sinh",
+    //"sin",
+    "snprintf",
+    "sprintf",
+    //"sqrt",
+    "sscanf",
+    //"strcat",
+    //"strchr",
+    //"strcmp",
+    //"strcpy",
+    //"strcspn",
+    //"strlen",
+    //"strncat",
+    //"strncmp",
+    //"strncpy",
+    //"strpbrk",
+    //"strrchr",
+    //"strspn",
+    //"strstr",
+    "tanh",
+    "tan",
+    "vfprintf",
+    "vprintf",
+    "vsprintf",
+
+    // ------------------------------------------------
+    // group 5: "... ISO C99 floating point comparison macros ..."
+
+    // this is the 3.1 list, which is identical to the 3.4.3 list
+    "isgreater",
+    "isgreaterequal",
+    "isless",
+    "islessequal",
+    "islessgreater",
+    "isunordered",
+
+    // ------------------------------------------------
+    // group 6: miscellaneous compiler interrogations/hints
+
+    // types_compatible_p: not yet implemented in Elsa
+    // choose_expr: not yet implemented in Elsa
+    // constant_p: implemented elsewhere
+    // expect: implemented elsewhere
+    "prefetch",
+
+    // ------------------------------------------------
+    // group 7: low-level arithmetic stuff
+
+    // full prototypes:
+    //   float __builtin_nanf (const char *str);
+    //   long double __builtin_nanl (const char *str);
+    //   double __builtin_nans (const char *str);
+    //   float __builtin_nansf (const char *str);
+    //   long double __builtin_nansl (const char *str);
+    //   int __builtin_ffs (unsigned int x);
+    //   int __builtin_clz (unsigned int x);
+    //   int __builtin_ctz (unsigned int x);
+    //   int __builtin_popcount (unsigned int x);
+    //   int __builtin_parity (unsigned int x);
+    //   int __builtin_ffsl (unsigned long);
+    //   int __builtin_clzl (unsigned long);
+    //   int __builtin_ctzl (unsigned long);
+    //   int __builtin_popcountl (unsigned long);
+    //   int __builtin_parityl (unsigned long);
+    //   int __builtin_ffsll (unsigned long long);
+    //   int __builtin_clzll (unsigned long long);
+    //   int __builtin_ctzll (unsigned long long);
+    //   int __builtin_popcountll (unsigned long long);
+    //   int __builtin_parityll (unsigned long long);
+
+    // just the names, but those that appear above are commented
+    "nanf",
+    "nanl",
+    "nans",
+    "nansf",
+    "nansl",
+    //"ffs",
+    "clz",
+    "ctz",
+    "popcount",
+    "parity",
+    //"ffsl",
+    "clzl",
+    "ctzl",
+    "popcountl",
+    "parityl",
+    //"ffsll",
+    "clzll",
+    "ctzll",
+    "popcountll",
+    "parityll",
+  };
+
+  for (int i=0; i < TABLESIZE(arr); i++) {
+    Variable *v = makeImplicitDeclFuncVar(str(stringc << "__builtin_" << arr[i]));
+    env.builtinVars.push(v);
+  }
+
+  // initialize 'complexComponentFields'
+  for (int axis=0; axis<=1; axis++) {
+    for (int prec=0; prec<=2; prec++) {
+      StringRef n = axis==0? string_realSelector : string_imagSelector;
+      Type *t = env.getSimpleType(constructFloatingType(prec, axis));
+      Variable *v = makeVariable(SL_INIT, n, t, DF_BUILTIN | DF_MEMBER);
+      complexComponentFields[axis][prec] = v;
+    }
+  }
+}
+
+
+// -------------------- tcheck --------------------
+ASTTypeof *ASTTypeof::tcheck(Env &env, DeclFlags dflags)
+{
+  if (!ambiguity) {
+    mid_tcheck(env, dflags);
+    return this;
+  }
+
+  return resolveAmbiguity(this, env, "ASTTypeof", false /*priority*/, dflags);
+}
+
+void ASTTypeof::mid_tcheck(Env &env, DeclFlags &dflags)
+{
+  type = itcheck(env, dflags);
+}
+
+
+Type *TS_typeof_expr::itcheck(Env &env, DeclFlags dflags)
+{
+  // FIX: dflags discarded?
+  expr->tcheck(env);
+  // FIX: check the asRval(); A use in kernel suggests it should be
+  // there as otherwise you get "error: cannot create a pointer to a
+  // reference" when used to specify the type in a declarator that
+  // comes from a de-reference (which yeilds a reference).
+  return expr->getType()->asRval();
+}
+
+
+Type *TS_typeof_type::itcheck(Env &env, DeclFlags dflags)
+{
+  ASTTypeId::Tcheck tc(DF_NONE /*dflags don't apply to this type*/,
+                       DC_TS_TYPEOF_TYPE);
+  atype = atype->tcheck(env, tc);
+  Type *t = atype->getType();
+  return t;
+}
+
+
+Type *TS_typeof::itcheck(Env &env, DeclFlags dflags)
+{
+  atype = atype->tcheck(env, dflags);
+  return atype->type;
+}
+
+
+void S_function::itcheck(Env &env)
+{
+  env.setLoc(loc);
+  f->tcheck(env);
+}
+
+
+void S_rangeCase::itcheck(Env &env)
+{
+  exprLo->tcheck(env, exprLo);
+  exprHi->tcheck(env, exprHi);
+  s = s->tcheck(env);
+
+  // compute case label values
+  exprLo->constEval(env, labelValLo);
+  exprHi->constEval(env, labelValHi);
+}
+
+void S_computedGoto::itcheck(Env &env)
+{
+  target->tcheck(env, target);
+
+  // The GCC manual seems to imply it wants 'target' to have type
+  // 'void*'.  It seems pointless to specifically require void* as
+  // opposed to some other pointer type, since any other pointer type
+  // can be implicitly converted to void*.  Even so, EDG does in fact
+  // enforce that the arg is exactly void*.  GCC itself does not
+  // appear to enforce any restrictions on the type (!).
+  Type *t = target->type->asRval();
+  if (!t->isPointer()) {
+    env.error(t, stringc
+      << "type of expression in computed goto must be a pointer, not `"
+      << t->toString() << "'");
+  }
+}
+
+
+Type *E_compoundLit::itcheck_x(Env &env, Expression *&replacement)
+{
+  ASTTypeId::Tcheck tc(DF_NONE, DC_E_COMPOUNDLIT);
+
+  // typechedk the type only once, and isolated from ambiguities
+  if (!tcheckedType) {
+    InstantiationContextIsolator isolate(env, env.loc());
+    tcheckedType = true;
+
+    stype = stype->tcheck(env, tc);
+  }
+
+  init->tcheck(env, stype->getType());
+
+  // dsw: Scott says: "The gcc manual says nothing about whether a
+  // compound literal is an lvalue.  But, compound literals are now
+  // part of C99 (6.5.2.5), which says they are indeed lvalues (but
+  // says nothing about being const)."
+  Type *t0 = stype->getType();
+  Type *t1 = env.computeArraySizeFromCompoundInit(env.loc(), t0, t0, init);
+  return env.makeReferenceType(t1);
+  // TODO: check that the cast (literal) makes sense
+}
+
+
+Type *E___builtin_constant_p::itcheck_x(Env &env, Expression *&replacement)
+{
+  expr->tcheck(env, expr);
+
+//    // TODO: this will fail an assertion if someone asks for the
+//    // size of a variable of template-type-parameter type..
+//    // dsw: If this is turned back on, be sure to catch the possible
+//    // XReprSize exception and add its message to the env.error-s
+//    size = expr->type->asRval()->reprSize();
+//    TRACE("sizeof", "sizeof(" << expr->exprToString() <<
+//                    ") is " << size);
+
+  // dsw: the type of a __builtin_constant_p is an int:
+  // http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Other-Builtins.html#Other%20Builtins
+  // TODO: is this right?
+  return expr->type->isError()?
+           expr->type : env.getSimpleType(ST_UNSIGNED_INT);
+}
+
+
+Type *E___builtin_va_arg::itcheck_x(Env &env, Expression *&replacement)
+{
+  ASTTypeId::Tcheck tc(DF_NONE, DC_E_BUILTIN_VA_ARG);
+  expr->tcheck(env, expr);
+  atype = atype->tcheck(env, tc);
+  return atype->getType();
+}
+
+
+Type *E_alignofType::itcheck_x(Env &env, Expression *&replacement)
+{
+  ASTTypeId::Tcheck tc(DF_NONE, DC_E_ALIGNOFTYPE);
+  atype = atype->tcheck(env, tc);
+  Type *t = atype->getType();
+
+  // just assume that the type's size is its alignment; this may
+  // be a little conservative for 'double', and will be wrong for
+  // large structs, but at the moment it does not seem worthwhile
+  // to delve into the details of accurately computing this
+  return env.sizeofType(t, alignment, NULL /*expr*/);
+}
+
+
+Type *E_alignofExpr::itcheck_x(Env &env, Expression *&replacement)
+{
+  expr->tcheck(env, expr);
+
+  // as above, assume size=alignment
+  return env.sizeofType(expr->type, alignment, expr);
+}
+
+
+// Type *E_offsetof::itcheck_x(Env &env, Expression *&replacement)
+// {
+//   ASTTypeId::Tcheck tc(DF_NONE, DC_E_OFFSETOF);
+//   atype = atype->tcheck(env, tc);
+
+//   return env.getSimpleType(ST_UNSIGNED_INT);
+// }
+
+
+Type *E_statement::itcheck_x(Env &env, Expression *&replacement)
+{
+  // An E_statement can contain declarations, and tchecking a
+  // declaration modifies the environment.  But expressions can occur
+  // in ambiguous contexts, and hence their tcheck should not modify
+  // the environment.
+  //
+  // Since the E_statements are themselves interpreted independently
+  // of such contexts, tcheck each E_statement exactly once.  Each
+  // ambiguous alternative will use the same interpretation.
+  //
+  // This avoids problems with e.g. in/gnu/c0001.c
+  if (!tchecked) {
+
+    // having committed to tchecking here, isolate these actions
+    // from the context
+    InstantiationContextIsolator isolate(env, env.loc());
+
+    s = s->tcheck(env)->asS_compound();
+
+    tchecked = true;
+  }
+
+  if (s->stmts.isNotEmpty()) {
+    Statement *last = s->stmts.last();
+    if (last->isS_expr()) {
+      return last->asS_expr()->expr->getType();
+    }
+  }
+
+  return env.getSimpleType(ST_VOID, CV_NONE);
+}
+
+
+Type *E_gnuCond::itcheck_x(Env &env, Expression *&replacement)
+{
+  cond->tcheck(env, cond);
+  el->tcheck(env, el);
+
+  // presumably the correct result type is some sort of intersection
+  // of the 'cond' and 'el' types?
+
+  return el->type;
+}
+
+
+Type *E_addrOfLabel::itcheck_x(Env &env, Expression *&replacement)
+{
+  // TODO: check that the label exists in the function
+
+  // type is void*
+  return env.makePtrType(env.getSimpleType(ST_VOID));
+}
+
+
+// decompose a real/imaginary/complex type:
+//   prec: 0=float, 1=double, 2=longdouble
+//   axis: 0=real, 1=imag, 2=complex
+// return false if not among the nine floating types
+bool dissectFloatingType(int &prec, int &axis, Type *t)
+{
+  t = t->asRval();
+
+  if (!t->isSimpleType()) {
+    return false;
+  }
+  SimpleTypeId id = t->asSimpleTypeC()->type;
+
+  switch (id) {
+    case ST_FLOAT:                  prec=0; axis=0; return true;
+    case ST_DOUBLE:                 prec=1; axis=0; return true;
+    case ST_LONG_DOUBLE:            prec=2; axis=0; return true;
+
+    case ST_FLOAT_IMAGINARY:        prec=0; axis=1; return true;
+    case ST_DOUBLE_IMAGINARY:       prec=1; axis=1; return true;
+    case ST_LONG_DOUBLE_IMAGINARY:  prec=2; axis=1; return true;
+
+    case ST_FLOAT_COMPLEX:          prec=0; axis=2; return true;
+    case ST_DOUBLE_COMPLEX:         prec=1; axis=2; return true;
+    case ST_LONG_DOUBLE_COMPLEX:    prec=2; axis=2; return true;
+
+    default: return false;
+  }
+}
+
+SimpleTypeId constructFloatingType(int prec, int axis)
+{
+  static SimpleTypeId const map[3/*axis*/][3/*prec*/] = {
+    { ST_FLOAT, ST_DOUBLE, ST_LONG_DOUBLE },
+    { ST_FLOAT_IMAGINARY, ST_DOUBLE_IMAGINARY, ST_LONG_DOUBLE_IMAGINARY },
+    { ST_FLOAT_COMPLEX, ST_DOUBLE_COMPLEX, ST_LONG_DOUBLE_COMPLEX }
+  };
+
+  xassert((unsigned)axis < 3);
+  xassert((unsigned)prec < 3);
+
+  return map[axis][prec];
+}
+
+
+Type *E_fieldAcc::itcheck_complex_selector(Env &env, LookupFlags flags,
+                                           LookupSet &candidates)
+{
+  int isImag = fieldName->getName()[2] == 'i';
+
+  int prec, axis;
+  if (!dissectFloatingType(prec, axis, obj->type) ||
+      axis != 2/*complex*/) {
+    return env.error(stringc << "can only apply " << fieldName->getName()
+                             << " to complex types, not `"
+                             << obj->type->toString() << "'");
+  }
+
+  field = env.complexComponentFields[isImag][prec];
+  return env.tfac.makeReferenceType(field->type);
+}
+
+
+Type *E_binary::itcheck_complex_arith(Env &env)
+{
+  int prec1, axis1;
+  int prec2, axis2;
+  if (!dissectFloatingType(prec1, axis1, e1->type) ||
+      !dissectFloatingType(prec2, axis2, e2->type)) {
+    return env.error(stringc << "invalid complex arithmetic operand types `"
+                             << e1->type->toString() << "' and `"
+                             << e2->type->toString() << "'");
+  }
+
+  // NOTE: The following computations have not been thoroughly tested.
+
+  // result precision: promote to larger
+  int prec = max(prec1, prec2);
+
+  // result axis
+  int axis;
+  switch (op) {
+    case BIN_PLUS:
+    case BIN_MINUS:
+      if (axis1 == axis2) {
+        axis = axis1;
+      }
+      else {
+        axis = 2/*complex*/;
+      }
+      break;
+
+    case BIN_MULT:
+    case BIN_DIV:
+      if (axis1 + axis2 == 0) {
+        axis = 0/*real*/;     // but then how'd we reach this code anyway?
+      }
+      else if (axis1 + axis2 == 1) {
+        axis = 1/*imag*/;
+      }
+      else {
+        axis = 2/*complex*/;
+      }
+      break;
+
+    default:
+      // who the heck knows
+      axis = 2/*complex*/;
+      break;
+  }
+
+  // result id
+  return env.getSimpleType(constructFloatingType(prec, axis));
+}
+
+
+// in/c/k00016.c: this function takes a reference to 'e' because it
+// invokes the type checker, which (due to disambiguation) may need to
+// change it to a different value, which in turn must be propagated to
+// the caller
+static void compile_time_compute_int_expr(Env &env, Expression *&e, int &x, char *error_msg) {
+  e->tcheck(env, e);
+  if (!e->constEval(env, x)) env.error(error_msg);
+}
+
+static void check_designator_list(Env &env, FakeList<Designator> *dl)
+{
+  xassert(dl);
+  FAKELIST_FOREACH_NC(Designator, dl, d) {
+    if (SubscriptDesignator *sd = dynamic_cast<SubscriptDesignator*>(d)) {
+      compile_time_compute_int_expr(env, sd->idx_expr, sd->idx_computed,
+                                    "compile-time computation of range start designator array index fails");
+      if (sd->idx_expr2) {
+        compile_time_compute_int_expr(env, sd->idx_expr2, sd->idx_computed2,
+                                      "compile-time computation of range end designator array index fails");
+      }
+    }
+    // nothing to do for FieldDesignator-s
+  }
+}
+
+void IN_designated::tcheck(Env &env, Type *type)
+{
+  init->tcheck(env, type);
+  check_designator_list(env, designator_list);
+}
+
+
+// ------------------ const-eval, etc. -------------------
+CValue E_alignofType::extConstEval(ConstEval &env) const
+{
+  CValue ret;
+  ret.setUnsigned(ST_UNSIGNED_INT, alignment);
+  return ret;
+}
+
+
+CValue E_alignofExpr::extConstEval(ConstEval &env) const
+{
+  CValue ret;
+  ret.setUnsigned(ST_UNSIGNED_INT, alignment);
+  return ret;
+}
+
+
+CValue E_gnuCond::extConstEval(ConstEval &env) const
+{
+  CValue v = cond->constEval(env);
+  if (v.isSticky()) {
+    return v;
+  }
+
+  if (!v.isZero()) {
+    return v;
+  }
+  else {
+    return el->constEval(env);
+  }
+}
+
+bool E_gnuCond::extHasUnparenthesizedGT()
+{
+  return hasUnparenthesizedGT(cond) ||
+         hasUnparenthesizedGT(el);
+}
+
+// // quarl 2006-07-12
+// //    Handle __offsetof__ (gcc-3.4), __builtin_offsetof (gcc-4.x)
+// //
+// //    based on Expression::constEvalAddr#E_fieldAcc
+// bool E_offsetof::extConstEval(ConstEval &env) const
+// {
+//   CompoundType *ct = t->asRval()->ifCompoundType();
+//   if (ct) {
+//     CValue val;
+//     val.setUnsigned(CValue::K_UNSIGNED, ct->getDataMemberOffset(e->field));
+//     return val;
+//   } else {
+//     return CValue("invalid operand to offsetof, must be a compound type");
+//   }
+// }
+
+// ------------------------ print --------------------------
+void TS_typeof::print(PrintEnv &env)
+{
+  xassert(0);                   // I'll bet this is never called.
+//    TreeWalkDebug treeDebug("TS_typeof_expr");
+}
+
+
+void ASTTypeof::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "TypeSpecifier", os, indent);
+
+  // sm: what was this here for?
+  //genericCheckNexts(this);
+}
+
+
+void ASTTypeof::addAmbiguity(ASTTypeof *alt)
+{
+  //genericAddAmbiguity(this, alt);
+
+  // insert 'alt' at the head of the 'ambiguity' list
+  xassert(alt->ambiguity == NULL);
+  alt->ambiguity = ambiguity;
+  ambiguity = alt;
+}
+
+
+void S_function::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_function::iprint");
+  f->print(env);
+}
+
+
+void S_rangeCase::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_rangeCase::iprint");
+  *env.out << "case";
+  exprLo->print(env);
+  *env.out << "...";
+  exprHi->print(env);
+  *env.out << ":";
+  s->print(env);
+}
+
+
+void S_computedGoto::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("S_computedGoto::iprint");
+  *env.out << "goto *";
+  target->print(env);
+  *env.out << ";\n";
+}
+
+
+void E_compoundLit::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_compoundLit::iprint");
+  {
+    PairDelim pair(*env.out, "", "(", ")");
+    stype->print(env);
+  }
+  init->print(env);
+}
+
+void E___builtin_constant_p::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E___builtin_constant_p::iprint");
+  PairDelim pair(*env.out, "__builtin_constant_p", "(", ")");
+  expr->print(env);
+}
+
+void E___builtin_va_arg::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E___builtin_va_arg::iprint");
+  PairDelim pair(*env.out, "__builtin_va_arg", "(", ")");
+  expr->print(env);
+  *env.out << ", ";
+  atype->print(env);
+}
+
+void E_alignofType::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_alignofType::iprint");
+  PairDelim pair(*env.out, "__alignof__", "(", ")");
+  atype->print(env);
+}
+
+void E_alignofExpr::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_alignofType::iprint");
+  PairDelim pair(*env.out, "__alignof__", "(", ")");
+  expr->print(env);
+}
+
+// void E_offsetof:iprint(PrintEnv &env)
+// {
+//   TreeWalkDebug treeDebug("E_alignofType::iprint");
+//   PairDelim pair(*env.out, "__offsetof__", "(", ")");
+//   atype->print(env);
+//   fieldName->print(env);
+// }
+
+void E_statement::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_statement::iprint");
+  PairDelim pair(*env.out, "", "(", ")");
+  s->iprint(env);
+}
+
+void E_gnuCond::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_gnuCond::iprint");
+  PairDelim pair(*env.out, "", "(", ")");
+  cond->print(env);
+  *env.out << " ?: ";
+  el->print(env);
+}
+
+void E_addrOfLabel::iprint(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("E_addrOfLabel::iprint");
+  *env.out << "&&" << labelName;
+}
+
+
+// prints designators in the new C99 style, not the obsolescent ":"
+// style
+static void print_DesignatorList(PrintEnv &env, FakeList<Designator> *dl) {
+  xassert(dl);
+  FAKELIST_FOREACH_NC(Designator, dl, d) {
+    d->print(env);
+  }
+  *env.out << "=";
+}
+
+void IN_designated::print(PrintEnv &env)
+{
+  print_DesignatorList(env, designator_list);
+  init->print(env);
+}
+
+// -------------------- Designator ---------------
+
+void FieldDesignator::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("FieldDesignator");
+  xassert(id);
+  *env.out << "." << id;
+}
+
+void SubscriptDesignator::print(PrintEnv &env)
+{
+  TreeWalkDebug treeDebug("SubscriptDesignator");
+  xassert(idx_expr);
+  PairDelim pair(*env.out, "", "[", "]");
+  idx_expr->print(env);
+  if (idx_expr2) {
+    *env.out << " ... ";
+    idx_expr2->print(env);
+  }
+}
+
+
+void Designator::printAmbiguities(ostream &os, int indent) const
+{
+  genericPrintAmbiguities(this, "Designator", os, indent);
+
+  genericCheckNexts(this);
+}
+
+void Designator::addAmbiguity(Designator *alt)
+{
+  genericAddAmbiguity(this, alt);
+}
+
+void Designator::setNext(Designator *newNext)
+{
+  genericSetNext(this, newNext);
+}
+
+
+// ------------------------ cfg --------------------------
+
+// WARNING: The control flow graph will show that the statement before
+// the S_function flows into the S_function and that the S_function
+// flows into the next statement.  If you know that an S_function is
+// just a function definition and does nothing at run time, this is
+// harmless, but it is a little odd, as in reality control would jump
+// over the S_function.  The only way to prevent this that I can see
+// would be for cfg.cc:Statement::computeCFG() to know about
+// S_function which would eliminate the usefulness of having it in the
+// gnu extension, or for S_function::icfg to go up and do some surgery
+// on edges that have already been added, which I consider to be too
+// weird.
+//
+// Scott says: "the entire S_function::icfg can be empty, just like
+// S_skip."
+void S_function::icfg(CFGEnv &env) {}
+
+void S_rangeCase::icfg(CFGEnv &env)
+{
+  env.connectEnclosingSwitch(this, "'case'");
+  s->computeCFG(env);
+}
+
+
+void S_computedGoto::icfg(CFGEnv &env)
+{
+  // The CFG mechanism is not really prepared to deal with computed
+  // gotos, so I will do nothing here (so, the CFG will look like
+  // control simply flows to the next statement).  It will fall to the
+  // client to realize that this is a computed goto, and try to do
+  // something appropriate.
+}
+
+
+// ---------------------- D_attribute -------------------------
+D_attribute::D_attribute(SourceLoc loc, IDeclarator *base,
+                         AttributeSpecifierList *alist_)
+  : D_grouping(loc, base),
+    alist(alist_)
+{}
+
+D_attribute::~D_attribute()
+{
+  delete alist;
+}
+
+
+void D_attribute::debugPrint(ostream &os, int indent, char const *subtreeName) const
+{
+  // I don't call D_grouping::debugPrint because I want the
+  // output to say "D_attribute", not "D_grouping".
+
+  PRINT_HEADER(subtreeName, D_attribute);
+
+  IDeclarator::debugPrint(os, indent, subtreeName);
+
+  PRINT_SUBTREE(base);
+  PRINT_SUBTREE(alist);
+}
+
+
+void D_attribute::traverse(ASTVisitor &vis)
+{
+  // I chose to override this method purely so that I would be able to
+  // put a breakpoint in it if desired, and to have a place to
+  // document this intention: its behavior is intended to remain
+  // identical to D_grouping.  Don't change it without asking me first.
+  D_grouping::traverse(vis);
+}
+
+
+D_attribute *D_attribute::clone() const
+{
+  D_attribute *ret = new D_attribute(
+    loc,
+    base? base->clone() : NULL,
+    alist? alist->clone() : NULL
+  );
+  return ret;
+}
+
+
+class AttributeDisambiguator : public ASTVisitorEx {
+public:
+  virtual void foundAmbiguous(void *obj, void **ambig, char const *kind);
+};
+
+void AttributeDisambiguator::foundAmbiguous(void *obj, void **ambig, char const *kind)
+{
+  // I have virtually no basis for doing actual disambiguation of
+  // __attribute__ arguments, and no expectation that I will need any.
+  // I will just arbitrarily throw away all of the alternatives beyond
+  // the first.
+  *ambig = NULL;
+}
+
+
+void D_attribute::tcheck(Env &env, Declarator::Tcheck &dt)
+{
+  // tcheck the underlying declarator
+  D_grouping::tcheck(env, dt);
+
+  // "disambiguate" the attribute list
+  AttributeDisambiguator dis;
+  alist->traverse(dis);
+
+  // if the type is not a simple type, don't even consider
+  // the __mode__ possibility, since I do not know what it
+  // would mean in that case
+  if (dt.type->isSimpleType()) {
+    // get details about current type
+    SimpleTypeId existingId = dt.type->asSimpleTypeC()->type;
+    CVFlags existingCV = dt.type->getCVFlags();
+    bool uns = isExplicitlyUnsigned(existingId);
+
+    // check for a __mode__ attribute
+    SimpleTypeId id = ST_ERROR;    // means no mode was found yet
+    for (AttributeSpecifierList *l = alist; l; l = l->next) {
+      for (AttributeSpecifier *s = l->spec; s; s = s->next) {
+        if (s->attr->isAT_func()) {
+          AT_func *f = s->attr->asAT_func();
+          if (0==strcmp(f->f, "__mode__") && f->args) {
+            Expression *e = f->args->first()->expr;
+            if (e->isE_variable()) {
+              StringRef mode = e->asE_variable()->name->getName();
+              if (0==strcmp(mode, "__QI__")) {
+                id = uns? ST_UNSIGNED_CHAR : ST_SIGNED_CHAR;
+              }
+              else if (0==strcmp(mode, "__HI__")) {
+                id = uns? ST_UNSIGNED_SHORT_INT : ST_SHORT_INT;
+              }
+              else if (0==strcmp(mode, "__SI__")) {
+                id = uns? ST_UNSIGNED_INT : ST_INT;
+              }
+              else if (0==strcmp(mode, "__DI__")) {
+                id = uns? ST_UNSIGNED_LONG_LONG : ST_LONG_LONG;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    // change the type according to the mode (if any)
+    if (id != ST_ERROR) {
+      dt.type = env.getSimpleType(id, existingCV);
+    }
+  }
+
+  // transparent union?
+  if (dt.type->isUnionType()) {
+    CompoundType *u = dt.type->asCompoundType();
+
+    for (AttributeSpecifierList *l = alist; l; l = l->next) {
+      for (AttributeSpecifier *s = l->spec; s; s = s->next) {
+        if (s->attr->isAT_word()) {
+          AT_word *w = s->attr->asAT_word();
+          if (0==strcmp(w->w, "transparent_union") ||
+              0==strcmp(w->w, "__transparent_union__")) {
+            u->isTransparentUnion = true;
+          }
+        }
+      }
+    }
+  }
+
+  tcheck_getAlias(&env);
+}
+
+StringRef D_attribute::getAlias() const
+{
+  return tcheck_getAlias(NULL);
+}
+
+// quarl 2006-07-13
+//    Type check attribute((alias("aliasTarget"))), and return alias target if
+//    any.  If penv==NULL, then we must have already typechecked.
+StringRef D_attribute::tcheck_getAlias(Env *penv) const
+{
+  StringRef foundAlias = NULL;
+
+  for (AttributeSpecifierList *l = alist; l; l = l->next) {
+    for (AttributeSpecifier *s = l->spec; s; s = s->next) {
+      if (s->attr->isAT_func()) {
+        AT_func *f = s->attr->asAT_func();
+
+        if (streq(f->f, "alias")) {
+          if (foundAlias) {
+            xassert(penv);
+            penv->error(loc, "more than one attribute alias");
+          }
+          if (f->args->count() != 1) {
+            xassert(penv);
+            penv->error(loc, "too many arguments to attribute alias");
+          }
+          Expression *&expr = f->args->first()->expr;
+          if (!expr->isE_stringLit()) {
+            xassert(penv);
+            penv->error(loc, "illegal argument to attribute alias");
+          }
+          if (penv) {
+            expr->tcheck(*penv, expr);
+          }
+          E_stringLit *str = expr->asE_stringLit();
+          xassert(str->text);
+          xassert(str->fullTextNQ);
+          foundAlias = str->fullTextNQ;
+        }
+      }
+    }
+  }
+  return foundAlias;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/gnu.gr
===================================================================
--- vendor/elsa/current/elsa/gnu.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/gnu.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,955 @@
+// gnu.gr            see license.txt for copyright and terms of use
+// extension to cc.gr for GNU C/C++ language extensions
+
+// NOTE: Though the name of this module is "gnu.gr", in fact we also
+// put our C99 support here.  For the moment, it isn't worth it to
+// split out C99 from GNU, because our usage model is that either you
+// want to parse ANSI C++, or you want to parse whatever gcc/g++
+// accepts.  The "gnu" extensions (try to) provide the latter.  (Also,
+// there are a few extensions like "long long" that are provided by
+// both, so the split wouldn't be 100% clean.)
+//
+// 9/27/04: The current concept is that gnu.gr contains the syntactic
+// extensions included in the modern, extended C++ language,
+// especially as used on linux.  It does *not* include old K&R syntax,
+// which will be put in kandr.gr.
+//
+// Specifically, the extensions found in this file are:
+//   - gcc statement expression: "({ ... })"
+//   - gcc compound literals: "(struct Foo){ ... }"
+//   - gcc misc: __FUNCTION__, __alignof__, etc.
+//   - gcc dangling labels: "{ ... foo: }"
+//   - gcc typeof
+//   - gcc C++ min and max operators ">?" and "<?"
+//   - gcc asm with register constraints, etc.
+//   - gcc asm labels: "int foo asm("myfoo") = 2"
+//   - C99 designated initializers: "... = { .x=..., .y=... }"
+//     including gcc range extension: "[ 1 ... 3 ] = ..."
+//   - C99 restrict keyword
+//   - C99 qualifiers in array brackets: "[const ...]"
+//   - gcc __attribute__
+//   - gcc bug: typedef names + type modifiers: "u32 long"
+//   - gcc computed gotos
+//   - gcc/C99 complex/imaginary
+
+
+// expected statistics
+option shift_reduce_conflicts 87;
+option reduce_reduce_conflicts 86;
+
+
+terminals {
+  precedence {
+    // see note at end regarding implementation of __attribute__
+    prec  190 "__attribute__" "restrict";
+
+    // the experimentation I did in in/gnu/g0019.cc suggests that
+    // these operators have the same prec/assoc as "<" and ">"
+    //left   80 "<?" ">?";
+  }
+}
+
+
+// ----------- gcc statement expression -----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Statement-Exprs.html
+nonterm(Expression*) PrimaryExpression {
+  -> "(" cs:CompoundStatement ")"
+       { return new E_statement(cs); }
+}
+
+
+// ----------- gcc compound literals -----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Compound-Literals.html
+// (notation for literal struct values)
+// e.g.:
+//   struct Foo { int x; int y; } myfoo;
+//   myfoo = (struct Foo) { 4, 5 };        <-- here
+// which would assign x=4 and y=5 in 'myfoo'
+nonterm(Expression*) PrimaryExpression {
+  -> "(" t:TypeId ")" i:CompoundInitializer
+       { return new E_compoundLit(t, i); }
+}
+
+
+// ----------- gcc misc -----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Function-Names.html
+nonterm(StringRef) PreprocString {
+  // slightly subtle: ordinary strings are yielded *with quotes*,
+  // whereas these special guys are not quoted; also note that
+  // yielding of these token codes depends on lang.gccFuncBehavior
+  -> TOK___FUNCTION__                       { return str("__FUNCTION__"); }
+  -> TOK___PRETTY_FUNCTION__                { return str("__PRETTY_FUNCTION__"); }
+}
+
+nonterm(Expression*) UnaryExpression {
+  // GNU extension; dsw: Since the argument is an expression, I know
+  // of no way to handle this other than putting it into the grammar
+  // directly.
+  -> "__builtin_constant_p" pe:ParenthesizedExpression
+       { return new E___builtin_constant_p(loc, pe); }
+
+  // http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Alignment.html
+  -> "__alignof__" "(" t:TypeId ")"
+       { return new E_alignofType(t); }
+  -> "__alignof__" "(" e:Expression ")"
+       { return new E_alignofExpr(e); }
+
+  // quarl 2006-07-12
+  //    Handle __offsetof__ (gcc-3.4), __builtin_offsetof (gcc-4.x)
+  -> "__builtin_offsetof" "(" t:TypeId "," n:NameAfterDot ")"
+       // { return new E_offsetof(t, n); }
+       {
+         // just create "(unsigned long) &((t*)0)->n)"
+
+         // make it a pointer
+         t->decl->decl = new D_pointer(loc, CV_NONE, t->decl->decl);
+
+         ASTTypeId *ulong = new ASTTypeId(new TS_simple(loc, ST_UNSIGNED_INT),
+                                          new Declarator(new D_name(loc, NULL), NULL));
+
+         return new E_cast(ulong,
+                           (new E_addrOf(
+                             new E_arrow(
+                               new E_cast(t, new E_intLit("0")),
+                               n))));
+       }
+
+  -> "__offsetof__" "(" e:Expression ")"
+       { return new E_grouping(e); }
+
+  // sm: __builtin_expect is for static branch prediction, but none of
+  // the analyses I forsee for this parser care about such things, so
+  // I will simply pretend I never even saw it (though, this is a
+  // small problem for source to source ...); the alternative is to make
+  // a new AST node for it, or else squeeze it into E_funCall, neither of
+  // which is very attractive
+  //
+  // A third possibility is a new "semantically transparent but
+  // annotated in some way" AST node, of which __builtin_expect could
+  // be one kind.  I'm not sure what other kinds there would be,
+  // though.
+  -> "__builtin_expect" "(" e:Expression "," /*prediction*/Expression ")"
+       { return new E_grouping(e); }
+
+  // varargs; dsw: I think that we should make all of these their own
+  // AST node, I just don't want to deal with the parsing ambiguity
+  // with E_funCall right now
+//   -> "__builtin_va_start" "(" e:Expression "," e2:Expression ")"
+//        { return new E___builtin_va_start(loc, e, e2); }
+//   -> "__builtin_va_copy" "(" e:Expression "," e2:Expression ")"
+//        { return new E___builtin_va_copy(loc, e, e2); }
+  -> "__builtin_va_arg" "(" e:Expression "," t:TypeId ")"
+       { return new E___builtin_va_arg(loc, e, t); }
+//   -> "__builtin_va_end" "(" e:Expression ")"
+//        { return new E___builtin_va_end(loc, e); }
+}
+
+// dsw: had to break this out for location recording reasons
+nonterm(Expression*) ParenthesizedExpression {
+  -> "(" e:Expression ")"
+       { return new E_grouping(e); }
+}
+
+
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Conditionals.html
+nonterm(Expression*) ConditionalExpression {
+  -> cond:BinaryExpression "?" /*th:Expression*/ ":" el:AssignmentExpression
+       { return new E_gnuCond(cond, el); }
+}
+
+
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Nested-Functions.html
+nonterm(Statement*) Statement {
+  -> f:FunctionDefinition
+       { return new S_function(loc, f); }
+  // quarl 2006-06-15
+  //    nested K&R functions; unimplemented for now but I guess we just need
+  //    to do the same as above?  see in/gnu/k0010.c
+  -> k:KandRFunctionDefinition
+       { xunimp(stringc << loc << "nested K&R function definition"
+                " (d00aa531-ca12-4d72-9caf-ca9db9941179)"); }
+}
+
+
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Template-Instantiation.html
+nonterm(TopForm*) ExplicitInstantiation {
+  // here's one for things like (in/gnu/g0002.cc)
+  //   extern template class allocator<char>;
+  -> "extern" "template" d:BlockDeclaration
+       { return new TF_explicitInst(loc, DF_EXTERN, d); }
+}
+
+
+// http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Case-Ranges.html
+nonterm(Statement*) Statement {
+  -> "case" e:ConstantExpression "..." e2:ConstantExpression ":" s:Statement
+       { return new S_rangeCase(loc, e, e2, s); }
+}
+
+
+// ----------- gcc dangling labels -----------
+// gcc allows a compound statement to end with a label, whereas the C
+// and C++ grammars require a statement after every label; I can't
+// find any place in the gcc docs that specifically addresses this
+// extension; linux uses it heavily
+//
+// 10/17/04: It seems that gcc-3, even in C mode, rejects labels at
+// the end of compound blocks.  Therefore I suspect the tolerance in
+// gcc-2 was unintentional.  Oh well, Elsa allows it in all gcc modes..
+
+nonterm(S_compound*) CompoundStatement {
+  // special case for a block that ends in a label; Warning: no don't
+  // do this by making a label, case and/or default form not contain
+  // the statement that follows; It wouldn't work in this case:
+  //   if (0) gronk: printf("hello\n");
+  // The then branch would only contain the gronk label, whereas, at
+  // least in gcc, it also includes the printf() call.
+  -> seq:CompoundStmtHelper lesl:LabeledEmptyStatementList "}"
+       { seq->stmts.append(lesl); return seq; }
+}
+
+// a sequence of labels with no statement following, not even a skip
+nonterm(Statement*) LabeledEmptyStatementList {
+  -> n:LabelAndColon s:LabeledEmptyStatementListOpt
+       { return new S_label(loc, n, s); }
+  -> "case" e:ConstantExpression ":" s:LabeledEmptyStatementListOpt
+       { return new S_case(loc, e, new S_skip(loc)); }
+  -> "case" e:ConstantExpression "..." e2:ConstantExpression ":" s:LabeledEmptyStatementListOpt
+       { return new S_rangeCase(loc, e, e2, s); }
+  -> "default" ":" s:LabeledEmptyStatementListOpt
+       { return new S_default(loc, new S_skip(loc)); }
+}
+
+nonterm(Statement*) LabeledEmptyStatementListOpt {
+  -> empty
+       { return new S_skip(loc); }
+  -> s:LabeledEmptyStatementList
+       { return s; }
+}
+
+
+// ----------- gcc typeof -----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Typeof.html
+
+verbatim {
+  // make a TS_typeof, and supply CV flags
+  inline static TS_typeof *new_TS_typeof(SourceLoc loc, CVFlags cv, ASTTypeof *atype)
+  {
+    TS_typeof *ret = new TS_typeof(loc, atype);
+    ret->cv = cv;
+    return ret;
+  }
+}
+
+
+nonterm(Declaration*) DeclSpecifier {
+  // TS_typeof: triggered by TypeTypeSpecifier
+  -> te:TypeofTypeSpecifier m2:UberModifierSeqOpt
+       { return new Declaration(uberDeclFlags(m2),
+           new_TS_typeof(loc, uberCVFlags(m2), te), NULL); }
+
+  -> m1:UberModifierSeq te:TypeofTypeSpecifier m2:UberModifierSeqOpt
+       { UberModifiers m = uberCombine(loc, m1, m2);
+         return new Declaration(uberDeclFlags(m),
+           new_TS_typeof(loc, uberCVFlags(m), te), NULL); }
+}
+
+
+nonterm(TypeSpecifier*) TypeSpecifier {
+  // TS_typeof
+  -> te:TypeofTypeSpecifier cv2:UberCVQualifierSeqOpt
+       { return new_TS_typeof(loc, uberCVFlags(cv2), te); }
+
+  -> cv1:UberCVQualifierSeq te:TypeofTypeSpecifier cv2:UberCVQualifierSeqOpt
+       { UberModifiers cv = uberCombine(loc, cv1, cv2);
+         return new_TS_typeof(loc, uberCVFlags(cv), te); }
+}
+
+
+// this production isolates the ambiguity to within itself, rather
+// than letting it pollute upwards into TypeSpecifier
+nonterm(ASTTypeof*) TypeofTypeSpecifier {
+  // ambiguous:
+  //   typeof(x)
+  // could either be type of an expression 'x', or
+  // type (of a type) called 'x'
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> e:TypeofExpr       { return new TS_typeof_expr(e); }
+  -> t:TypeofType       { return new TS_typeof_type(t); }
+}
+
+
+// gnu extension
+nonterm(FullExpression*) TypeofExpr {
+  -> "__typeof__" "(" e:Expression ")"
+       { return new FullExpression(e); }
+}
+
+// gnu extension
+nonterm(ASTTypeId*) TypeofType {
+  -> "__typeof__" "(" t:TypeId ")"
+       { return t; }
+}
+
+
+// ----------- gcc C++ min and max operators -----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Min-and-Max.html
+nonterm(Expression*) BinExp_mid {
+  -> left:BinExp_mid "<?" right:BinExp_high
+       { return new E_binary(left, BIN_MINIMUM, right); }
+  -> left:BinExp_mid ">?" right:BinExp_high
+       { return new E_binary(left, BIN_MAXIMUM, right); }
+}
+
+// it turns out gcc lets users overload them too (in/gnu/k0004.cc)
+nonterm(OperatorName*) Operator {
+  -> "<?"    { return new ON_operator(OP_MINIMUM); }
+  -> ">?"    { return new ON_operator(OP_MAXIMUM); }
+}
+
+
+// ----------- gcc asm -----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Extended-Asm.html
+
+//  nonterm(UberModifiers) VolatileOpt {
+//    -> empty
+//         { return UM_NONE; }
+//    -> "volatile"
+//         { return UM_VOLATILE; }
+//  }
+
+
+// dsw: FIX: add returning semantic value
+nonterm BracketedWordOpt {
+  -> empty ;
+  -> "[" id:Identifier "]" ;
+}
+
+
+// dsw: FIX: add returning semantic value
+nonterm ParenthesizedExpressionOpt {
+  -> empty ;
+  ->  "(" e:Expression ")" ;
+}
+
+
+// dsw: FIX: add returning semantic value
+nonterm OpConstraint {
+  -> name:BracketedWordOpt constr:StringLiteral e:ParenthesizedExpressionOpt ;
+}
+
+
+// dsw: FIX: add returning semantic value
+nonterm OpConstraintList {
+  -> empty ;
+  -> oc:OpConstraint ;
+  -> oc:OpConstraint "," ocl:OpConstraintList ;
+}
+
+
+// dsw: FIX: add returning semantic value
+// note: technically you can only have up to 3, but I allow 0 or more
+nonterm OpConstraints {
+  -> empty;
+  -> NonemptyOpConstraints;
+}
+nonterm NonemptyOpConstraints {
+  -> ocs:OpConstraints ":" ocl:OpConstraintList ;
+  -> ocs:OpConstraints "::" ocl:OpConstraintList ;
+}
+
+
+// dsw: FIX: add returning rest of semantic value
+nonterm(E_stringLit*) AsmDefinition {
+  // 7/31/04: For some time we have allowed "volatile" after "asm", as
+  // is documented here:
+  //   http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Extended-Asm.html
+  // Recently we found some code that used "const" after "asm".  What
+  // is that?  Where is it documented?
+
+  // NOTE: CVQualifierSeqOpt is simply discarded here
+  -> "asm" q:CVQualifierSeq "(" s:StringLiteral ")" ";"
+       { return s; }
+
+  // I write two rules, exposing the optionality of CVQualifierSeq at
+  // this level instead of pushing it down into CVQualifierSeqOpt, to
+  // avoid an S/R conflict.
+  -> "asm" q:CVQualifierSeq "(" s:StringLiteral ocs:NonemptyOpConstraints ")" ";"
+       { return s; }
+  -> "asm" "(" s:StringLiteral ocs:NonemptyOpConstraints ")" ";"
+       { return s; }
+}
+
+
+// ----------- gcc asm labels -----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Asm-Labels.html
+nonterm(IDeclarator*) Declarator {
+  // Asm Labels after declarators; see in/gnu/asm01.c
+  -> d:DirectDeclarator "asm" "(" StringLiteral ")"
+       { return d; }
+
+  // asm label + attributes ...
+  -> d:DirectDeclarator "asm" "(" StringLiteral ")" /*DROPPED*/AttributeSpecifierList
+       { return d; }
+}
+
+
+// ----------- C99 designated initializers -----------
+// Designated Initializers
+nonterm(Initializer*) InitializerClause {
+  // obsolescent form
+  // http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Designated-Inits.html
+  -> d:Identifier ":" init:SimpleInitializerClause
+    { return new IN_designated(loc, FakeList<Designator>::makeList(new FieldDesignator(loc, d)),
+                               init); }
+  // C99 official form; C99 standard section 6.7.8
+  -> dl:DesignatorList "=" init:SimpleInitializerClause
+    { return new IN_designated(loc, dl, init); }
+  // dsw: another form I run into
+  -> dl:DesignatorList init:SimpleInitializerClause
+    { return new IN_designated(loc, dl, init); }
+}
+
+nonterm(FakeList<Designator>*) DesignatorList {
+  -> d:Designator
+    { return FakeList<Designator>::makeList(d); }
+  -> d:Designator dl:DesignatorList
+    { d->setNext(dl->first());
+    return FakeList<Designator>::makeList(d); }
+}
+
+nonterm(Designator*) Designator {
+  -> "." id:Identifier
+    { return new FieldDesignator(loc, id); }
+  -> "[" idx_expr:ConstantExpression "]"
+    { return new SubscriptDesignator(loc, idx_expr, NULL); }
+  // range designator "[ 1 ... 3 ] =".  This is a gcc-ism:
+  // http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Designated-Inits.html
+  -> "[" idx_expr:ConstantExpression "..." idx_expr2:ConstantExpression "]"
+    { return new SubscriptDesignator(loc, idx_expr, idx_expr2); }
+}
+
+
+// ----------- C99 restrict keyword -----------
+nonterm(enum CVFlags) CVQualifier {
+  -> "restrict"              { return CV_RESTRICT; }
+}
+
+nonterm(UberModifiers) UberModifier {
+  -> "restrict"              { return UM_RESTRICT; }
+}
+
+nonterm(UberModifiers) UberCVQualifier {
+  -> "restrict"              { return UM_RESTRICT; }
+}
+
+
+// ----------- C99 qualifiers in array brackets -----------
+nonterm(IDeclarator*) DirectDeclarator {
+  // array with qualifier in the brackets; see the version for
+  // DirectAbstractDeclarator for comments
+  -> d:DirectDeclarator "[" q:CVQualifierSeq "]"
+    {
+      // FIX: CVQualifierSeq goes on the array
+      return new D_array(loc, d, NULL /*size*/);
+    }
+}
+
+nonterm(IDeclarator*) DirectAbstractDeclarator {
+  // array with qualifier in the brackets
+  -> d:DirectAbstractDeclaratorOpt "[" q:CVQualifierSeq "]"
+    {
+      // FIX: Ben says the CVQualifierSeq goes on the array itself,
+      // just as if the array were a pointer and it was on the pointer
+      return new D_array(loc, d, NULL /*size*/);
+    }
+}
+
+
+// ----------- gcc2 bug: "u32 long" ----------
+// gcc-2.x allows one to combine typedefs and type keywords in a
+// single type specifier (e.g. in/gnu/dC0014.c); this is a bug, and is
+// fixed in gcc-3.x, but the linux kernel uses it so Elsa parses it (to
+// a limited degree)
+nonterm(Declaration*) DeclSpecifier {
+  -> n:PQTypeName BuggyGccTypeModifier/*ignored*/ m2:UberModifierSeqOpt
+     {
+       diagnose3(lang.allowModifiersWithTypedefNames, loc,
+                 "typedef and type keyword in a single type "
+                 "specifier (gcc2 bug accepts it)");
+       return new Declaration(uberDeclFlags(m2),
+         new_TS_name(loc, uberCVFlags(m2), n, false /*typename*/), NULL);
+     }
+
+  -> m1:UberModifierSeq n:PQTypeName BuggyGccTypeModifier/*ignored*/ m2:UberModifierSeqOpt
+     {
+       diagnose3(lang.allowModifiersWithTypedefNames, loc,
+                 "typedef and type keyword in a single type "
+                 "specifier (gcc2 bug accepts it)");
+       UberModifiers m = uberCombine(loc, m1, m2);
+       return new Declaration(uberDeclFlags(m),
+         new_TS_name(loc, uberCVFlags(m), n, false /*typename*/), NULL);
+     }
+}
+
+// these are the only ones that could be meaningfully combined with
+// an existing typedef, I think
+nonterm BuggyGccTypeModifier {
+  -> "long";
+  -> "short";
+  -> "signed";
+  -> "unsigned";
+
+  // make it a sequence...
+  -> "long"       BuggyGccTypeModifier;
+  -> "short"      BuggyGccTypeModifier;
+  -> "signed"     BuggyGccTypeModifier;
+  -> "unsigned"   BuggyGccTypeModifier;
+}
+
+
+// ------------ gcc computed goto ----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Labels-as-Values.html
+nonterm(Expression*) UnaryExpression {
+  -> "&&" n:Identifier
+       { return new E_addrOfLabel(n); }
+}
+
+nonterm(Statement*) Statement {
+  -> "goto" "*" e:Expression ";"
+       { return new S_computedGoto(loc, e); }
+}
+
+
+// ----------- gcc/C99 complex/imaginary ----------
+// http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Complex.html
+// C99 6.2.5p11, 6.7.2, Annex G
+nonterm(UberModifiers) UberTypeKeyword {
+  -> "_Complex"      { return UM_COMPLEX; }
+  -> "_Imaginary"    { return UM_IMAGINARY; }
+}
+
+// The gcc manual says the syntax is "__real__" Expression, but I'll
+// take a conservative approach for now and only allow primary
+// expressions, thus avoiding the need to specify precedence of these
+// keywords.
+//
+// I've chosen to create E_fieldAcc AST nodes because they are similar,
+// in that these are component accesses.
+nonterm(Expression*) PrimaryExpression {
+  -> "__real__" e:PrimaryExpression
+     { return new E_fieldAcc(e, new PQ_name(loc, str("__real__"))); }
+  -> "__imag__" e:PrimaryExpression
+     { return new E_fieldAcc(e, new PQ_name(loc, str("__imag__"))); }
+}
+
+
+// ----------- gcc __attribute__ -----------
+// This nonterminal gives me a good place to solve the ambiguity
+// between associating the attrs with the label and associating
+// them with the next declaration.
+nonterm(StringRef) LabelAndColon {
+  -> n:Identifier ":" /*DROPPED*/AttributeSpecifierList     precedence(TOK_PREFER_REDUCE)
+       { return n; }
+}
+
+
+// attributes between classkeys and their names
+nonterm(enum TypeIntr) ClassKey {
+  // *not* AttributeSpecifierList; this context is naturally repeating
+  -> k:ClassKey /*DROPPED*/AttributeSpecifier       { return k; }
+}
+
+// attributes after "enum"
+nonterm(TypeSpecifier*) ElaboratedTypeSpecifier {
+  -> "enum" /*DROPPED*/AttributeSpecifierList n:PQTypeName
+       { return new TS_elaborated(loc, TI_ENUM, n); }
+}
+
+nonterm(TS_enumSpec*) EnumSpecifier {
+  -> "enum" /*DROPPED*/AttributeSpecifierList "{" list:EnumeratorListOpt "}"
+       { return new TS_enumSpec(loc, NULL /*name*/, list); }
+
+  // Adding this adds one S/R conflict... it was 3 until I changed
+  // Identifier to PQTypeName.  I think cc.gr should similarly use
+  // PQName instead of Identifier, and catch qualifiers in tcheck...
+  -> "enum" /*DROPPED*/AttributeSpecifierList n:PQTypeName "{" list:EnumeratorListOpt "}"
+       { return new TS_enumSpec(loc, n->getName(), list); }
+}
+
+
+// As can be seen in the note at the end of this file, allowing
+// attributes in these two nonterminals is responsible for the
+// majority of the tolerance for them.  However, as UberModifiers are
+// an 'enum', this is also why retaining attributes in the AST is a
+// bit challenging: right here, there is nothing of substance to
+// attach them to!
+//
+// To fix this, one would probably have to find all occurrences of
+// UberModifier and UberCVQualifier, and add an alternative that goes
+// "... attr(one!) attrs-or-others-seq-opt ...", like below where I
+// use CVQualAttrSeqOpt.
+//
+// If all you care about is retaining one specific attribute that has
+// no arguments, you could get by with a new UberModifier flag and
+// associated DeclFlag.
+nonterm(UberModifiers) UberModifier {
+  -> AttributeSpecifier      { return UM_NONE; }
+}
+
+nonterm(UberModifiers) UberCVQualifier {
+  -> AttributeSpecifier      { return UM_NONE; }
+}
+
+
+// attribute after the "," in a sequence of declarators
+nonterm(FakeList<Declarator>*) InitDeclaratorList {
+  -> d:InitDeclarator "," /*DROPPED*/AttributeSpecifierList list:InitDeclaratorList
+       { d->setNext(list->first());
+         return FakeList<Declarator>::makeList(d); }
+}
+
+
+// cv-qualifiers mixed with __attribute__ arbitrarily
+nonterm(enum CVFlags) CVQualAttrSeqOpt {
+  -> empty                             { return CV_NONE; }
+  -> s:CVQualAttrSeq                   { return s; }
+}
+
+nonterm(enum CVFlags) CVQualAttrSeq {
+  -> q:CVQualAttr                      { return q; }
+  -> q:CVQualAttr s:CVQualAttrSeq      { return q | s; }
+}
+
+nonterm(enum CVFlags) CVQualAttr {
+  -> q:CVQualifier                     { return q; }
+  -> AttributeSpecifier                { return CV_NONE; }
+}
+
+
+nonterm(IDeclarator*) Declarator {
+  // "*", then some cv, then *one* __attribute__, which causes the
+  // parser to commit to this production, then cv+attr seq
+  -> "*" cv:CVQualifierSeqOpt /*DROPPED*/AttributeSpecifier cv2:CVQualAttrSeqOpt d:Declarator
+       { return new D_pointer(loc, cv | cv2, d); }
+
+  // perhaps attributes should be allowed after "&" and "C::*"?
+
+  // this is slightly more tolerant than gcc is, since it allows
+  // attributes just inside the ")" of a D_grouping, whereas gcc
+  // doesn't
+  -> d:DirectDeclarator attr:AttributeSpecifierList
+       { return new D_attribute(loc, d, attr); }
+}
+
+
+nonterm(IDeclarator*) DirectDeclarator {
+  -> "(" /*DROPPED*/AttributeSpecifierList d:Declarator ")"
+       { return new D_grouping(loc, d); }
+}
+
+
+nonterm(IDeclarator*) AbstractDeclarator {
+  -> "*" cv:CVQualifierSeqOpt attrspec:AttributeSpecifier cv2:CVQualAttrSeqOpt d:AbstractDeclaratorOpt
+       { return new D_pointer(loc, cv | cv2, d); }
+
+  -> d:DirectAbstractDeclarator attr:AttributeSpecifierList
+       { return new D_attribute(loc, d, attr); }
+}
+
+nonterm(IDeclarator*) DirectAbstractDeclarator {
+  -> "(" /*DROPPED*/AttributeSpecifierList d:AbstractDeclarator ")"
+       { return new D_grouping(loc, d); }
+}
+
+// dsw: attributes after bitfields; from the kernel:
+// UCHAR8 SampleResolution:2 __attribute__ ((packed));
+//
+// sm: the reason this wasn't handled by my catch-all Declarator
+// case above is that the bitfield syntax doesn't explicitly refer
+// to the Declarator nonterminal
+nonterm(Declarator*) MemberDeclarator {
+  -> n:IdentifierOpt ":" e:ConstantExpression /*DROPPED*/AttributeSpecifierList    // bitfield
+       // this body is an exact copy of the cc.gr one without attributes
+       { return new Declarator(new D_bitfield(loc, n? new PQ_name(loc, n) : NULL, e),
+                               NULL /*init*/); }
+}
+
+// dsw: from Taras Glek <tglek at mozilla.com>
+nonterm(DeclFlags) CDtorModifier {
+ -> /*DROPPED*/AttributeSpecifier      { return DF_NONE; }
+}
+
+// -- attributes themselves --
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Attribute-Syntax.html
+
+// "A word (which may be an identifier such as unused, or a reserved
+// word such as const)."
+nonterm(StringRef) AttributeWord {
+  // non-keyword name
+  -> n:TOK_NAME         { return n; }
+
+  // keywords
+  -> "asm"              { return str("asm"); }
+  -> "auto"             { return str("auto"); }
+  -> "break"            { return str("break"); }
+  -> "bool"             { return str("bool"); }
+  -> "case"             { return str("case"); }
+  -> "catch"            { return str("catch"); }
+  -> "cdecl"            { return str("cdecl"); }
+  -> "char"             { return str("char"); }
+  -> "class"            { return str("class"); }
+  -> "const"            { return str("const"); }
+  -> "const_cast"       { return str("const_cast"); }
+  -> "continue"         { return str("continue"); }
+  -> "default"          { return str("default"); }
+  -> "delete"           { return str("delete"); }
+  -> "do"               { return str("do"); }
+  -> "double"           { return str("double"); }
+  -> "dynamic_cast"     { return str("dynamic_cast"); }
+  -> "else"             { return str("else"); }
+  -> "enum"             { return str("enum"); }
+  -> "explicit"         { return str("explicit"); }
+  -> "export"           { return str("export"); }
+  -> "extern"           { return str("extern"); }
+  -> "false"            { return str("false"); }
+  -> "float"            { return str("float"); }
+  -> "for"              { return str("for"); }
+  -> "friend"           { return str("friend"); }
+  -> "goto"             { return str("goto"); }
+  -> "if"               { return str("if"); }
+  -> "inline"           { return str("inline"); }
+  -> "int"              { return str("int"); }
+  -> "long"             { return str("long"); }
+  -> "mutable"          { return str("mutable"); }
+  -> "namespace"        { return str("namespace"); }
+  -> "new"              { return str("new"); }
+  -> "operator"         { return str("operator"); }
+  -> "pascal"           { return str("pascal"); }
+  -> "private"          { return str("private"); }
+  -> "protected"        { return str("protected"); }
+  -> "public"           { return str("public"); }
+  -> "register"         { return str("register"); }
+  -> "reinterpret_cast" { return str("reinterpret_cast"); }
+  -> "return"           { return str("return"); }
+  -> "short"            { return str("short"); }
+  -> "signed"           { return str("signed"); }
+  -> "sizeof"           { return str("sizeof"); }
+  -> "static"           { return str("static"); }
+  -> "static_cast"      { return str("static_cast"); }
+  -> "struct"           { return str("struct"); }
+  -> "switch"           { return str("switch"); }
+  -> "template"         { return str("template"); }
+  -> "this"             { return str("this"); }
+  -> "throw"            { return str("throw"); }
+  -> "true"             { return str("true"); }
+  -> "try"              { return str("try"); }
+  -> "typedef"          { return str("typedef"); }
+  -> "typeid"           { return str("typeid"); }
+  -> "typename"         { return str("typename"); }
+  -> "union"            { return str("union"); }
+  -> "unsigned"         { return str("unsigned"); }
+  -> "using"            { return str("using"); }
+  -> "virtual"          { return str("virtual"); }
+  -> "void"             { return str("void"); }
+  -> "volatile"         { return str("volatile"); }
+  -> "wchar_t"          { return str("wchar_t"); }
+  -> "while"            { return str("while"); }
+
+  // don't know if I need to allow these; gcc 2.95.3 doesn't like them
+  //  // GNU extensions
+  //  TOK___ATTRIBUTE__,       "__attribute__",             :    n
+  //  TOK___FUNCTION__,        "__FUNCTION__",              :    n
+  //  TOK___LABEL__,           "__label__",                 :    n
+  //  TOK___PRETTY_FUNCTION__, "__PRETTY_FUNCTION__",       :    n
+  //  TOK___TYPEOF__,          "__typeof__",                :    n
+}
+
+nonterm(FakeList<ArgExpression>*) CommaSepExpressionListOpt {
+  -> empty                 { return FakeList<ArgExpression>::emptyList(); }
+  -> el:ExpressionList     { return el; }
+}
+
+nonterm(FakeList<ArgExpression>*) AttributeParameters {
+//    -> id:Identifier "," exprs:CommaSepExpressionListOpt ;
+  // NOTE: the below includes the above, except that the first
+  // expression, if an identifier, should not be typechecked as an
+  // E_variable, since it need not match a declared name; first it
+  // should be checked against known attribute parameters (maybe?).
+  -> exprs:CommaSepExpressionListOpt    { return exprs; }
+}
+
+nonterm(Attribute*) Attribute {
+  -> empty
+     { return new AT_empty(loc); }
+
+  -> w:AttributeWord
+     { return new AT_word(loc, w); }
+
+  -> w:AttributeWord "(" ap:AttributeParameters ")"
+     { return new AT_func(loc, w, ap); }
+}
+
+nonterm(AttributeSpecifier*) AttributeList {
+  -> at:Attribute
+     { return new AttributeSpecifier(at, NULL /*next*/); }
+
+  -> at:Attribute "," ap:AttributeList
+     { return new AttributeSpecifier(at, ap); }
+}
+
+nonterm(AttributeSpecifier*) AttributeSpecifier {
+  -> "__attribute__" "(" "(" ap:AttributeList ")" ")"
+     { return ap; }
+}
+
+nonterm(AttributeSpecifierList*) AttributeSpecifierList {
+  -> as:AttributeSpecifier
+     { return new AttributeSpecifierList(as, NULL /*next*/); }
+
+  -> as:AttributeSpecifier asl:AttributeSpecifierList
+     { return new AttributeSpecifierList(as, asl); }
+}
+
+// quarl 2006-06-14
+//    'using namespace N __attribute__(__strong__)'
+//    see in/gnu/k0009.cc or
+//    /usr/include/c++/3.4/i486-linux-gnu/bits/c++config.h
+
+nonterm(NamespaceDecl*) NamespaceDecl {
+  -> "using" "namespace" n:IdExpression AttributeSpecifierList ";"
+       { xunimp(stringc << loc << " using namespace __attribute__"
+                " (a86c8a1e-2cd7-41bd-8a23-f9049358c166)");
+         return new ND_usingDir(n); }
+}
+
+
+/*
+  2005-08-13: I have now added retention of attributes in some
+  places.  All places where it is still *not* retained are now
+  marked with "DROPPED".  My plan is to incrementally retain
+  more of the attributes as the need arises.
+
+  Implementation of __attribute__ (sm, 8/21/04).
+
+  NOTE: The current implementation drops all __attribute__s on the
+  floor after parsing them!  That is not ideal.  However, as
+  attributes can go in places that don't have ready access to (say) a
+  Type or a Declarator to attach them to, retaining them in the AST
+  isn't a trivial change.
+
+  The spec at
+  http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Attribute-Syntax.html does
+  a reasonably good job of documenting where __attribute__ can go and
+  what it means.  There are a number of things unclear about that
+  description, so I explored a bit with gcc-2 and gcc-2.
+  in/gnu/attr02.c contains a variety of syntax that gcc-3 accepts;
+  gcc-2 accepts most of it.
+
+  Based on this exploration, I decided to put attributes in a number
+  of places in cc.gr (via this gnu.gr extension grammar), listed
+  below.  In some cases I also determined (manually) the set of
+  contexts in which the modified construct would appear, so I could
+  better predict the effect of the modifications.
+
+    * right after ":" in labeled statement (did this with LabelAndColon)
+
+    * after ClassKey and "enum" where they occur
+
+    * UberModifer
+        - in DeclSpecifier
+          - in SimpleDeclaration
+            - in ForInitStatement
+            - in BlockDeclaration
+              - as a Statement
+              - as a TopForm
+              - in an ExplicitInstantiation
+          - in FunctionDefinition
+          - in MemberDeclaration
+          - in TemplateDeclaration, after the "template <...>"
+
+    * UberCVQualifier
+        - in TypeSpecifier
+          - in ParameterDeclaration
+          - in Condition
+          - in NewTypeId      ------------+   below here are places attr would
+            - in E_new                    |   be allowed, even though I don't
+          - in TypeId                     V   really want it to ...
+            - in E_keywordCast
+            - in E_typeidType
+            - in E_sizeofType
+            - in E_new
+            - in E_cast
+            - in TemplateTypeParameter default type
+            - in TemplateArgument (TA_type)
+            - in throw() cause
+          - in ConversionTypeId
+          - in HandlerParameter
+
+    * after "," in InitDeclaratorList's 2nd clause
+        - gets attr at outermost declarator level for 2nd or later declarator
+
+    * after "*" in (Abstract)Declarator
+    * after "(" in Direct(Abstract)Declarator D_grouping
+    / after "C::*" in (Abstract)Declarator
+    / after "&" in (Abstract)Declarator
+
+    * likewise for AbstractDeclarator
+
+      every place that (Abstract)Declarator occurs, other than in its recursive
+      structure, add an alternative with attrs after the Declarator
+    ~   - in fact, generalize that to let the "Asm Labels" go there too
+    *   - better: in Declarator after the Direct(Abstract)Declarator
+
+  The two "/" above means I didn't end up putting them after the C++
+  type constructors, since I doubt I'll need them there.
+
+  I found it useful to keep track, while I was modifying the grammar, of
+  the conflict totals.  This table shows the effect on conflicts of my
+  changes:
+
+    conflicts at various stages                               S/R   R/R
+    -------------------------------------------------------   ---------
+    starting                                                  142   104
+
+    removed attrs after ClassSpecifier in ElaboratedOrSpec    140   104
+
+    removed attrs between "*" and cv in Declarator            139   104
+    added attrs after cv in Declarator                        140   104
+    added cvattrseqopt after attr (one!) in Declarator        140   104
+
+    removed attrs between "*" and cv in AbstractDeclarator    138   104
+    removed attrs after DAD in AbstractDeclarator             138   104
+    added attrs after cv in AbstractDeclarator                140   111
+    added cvattrseqopt after attr (one!) in ADeclarator       140   104
+    added attrs after DAD in AbstractDeclarator               140   104
+
+    added attrs after class/enum in ElaboratedTypeSpecifier   140   104
+    for class, added to ClassKey instead                      140   104
+
+    added attrs after "enum" in EnumSpecifier                 141   104
+
+    removed attrspec from SimpleDeclaration (printk thing)     75   104
+
+    added attr to UberModifier                                 75   176
+
+    removed attr after labeled statements                      75   110
+
+    added attr to UberCVQualifier                              84   114
+
+    added attr after "," in InitDeclarator                     84   114
+
+    added attr after ":" in LabeledEmptyStatementList          84   116
+
+    removed attr after ":" in LabeledEmptyStatementList        84   114
+
+    created LabelAndColon in cc.gr                             81   108
+    added attrs after LabelAndColon                            83   108
+    added attrs after LabelAndColon with high precedence       82   108
+    added LabelAndColon to the LabeledEmptyStatementList       82   108
+
+*/
+
+
+// EOF

Added: vendor/elsa/current/elsa/gnu.lex
===================================================================
--- vendor/elsa/current/elsa/gnu.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/gnu.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,132 @@
+  /* gnu.lex
+   * extension to cc.lex, for GNU extensions
+   */
+
+"__builtin_constant_p" return tok(TOK_BUILTIN_CONSTANT_P);
+"__alignof"            return tok(TOK___ALIGNOF__);
+"__alignof__"          return tok(TOK___ALIGNOF__);
+
+ /* quarl 2006-07-12
+  *    gcc-4.0, gcc-4.1: __builtin_offsetof
+  *    gcc-3.4: __offsetof__
+  *    gcc-3.3 and earlier: offsetof macro expands to &(((t*)0)->s)
+  *  __builtin_offsetof and __offsetof__ are not the same!
+  */
+"__builtin_offsetof"   return tok(TOK___BUILTIN_OFFSETOF);
+"__offsetof__"         return tok(TOK___OFFSETOF__);
+
+"__attribute"          return tok(TOK___ATTRIBUTE__);
+"__attribute__"        return tok(TOK___ATTRIBUTE__);
+"__label__"            return tok(TOK___LABEL__);
+"typeof"               return tok(TOK___TYPEOF__);
+"__typeof"             return tok(TOK___TYPEOF__);
+"__typeof__"           return tok(TOK___TYPEOF__);
+"__builtin_expect"     return tok(TOK___BUILTIN_EXPECT);
+"__builtin_va_arg"     return tok(TOK___BUILTIN_VA_ARG);
+
+"__null" {
+  // gcc only recognizes __null as 0 in C++ mode, but I prefer the
+  // simplicity of always doing it; This is Scott's inlined and
+  // modified Lexer::svalTok()
+  checkForNonsep(TOK_INT_LITERAL);
+  updLoc();
+  sval = (SemanticValue)addString("0", 1);
+  return TOK_INT_LITERAL;
+}
+
+  /* behavior of these depends on CCLang settings */
+"__FUNCTION__"|"__PRETTY_FUNCTION__" {
+  if (lang.gccFuncBehavior == CCLang::GFB_string) {
+    // yield with special token codes
+    return tok(yytext[2]=='F'? TOK___FUNCTION__ : TOK___PRETTY_FUNCTION__);
+  }
+  else {
+    // ordinary identifier, possibly predefined (but that's not the
+    // lexer's concern)
+    return svalTok(TOK_NAME);
+  }
+}
+
+  /* hex floating literal: This is actually a C99-ism.
+     See http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Hex-Floats.html
+     and C99 6.4.4.2.
+  */
+[0][xX]{HEXDIGITS}"."{HEXDIGITS}?[pP]{SIGN}?{DIGITS}{FLOAT_SUFFIX}?   |
+[0][xX]{HEXDIGITS}"."?[pP]{SIGN}?{DIGITS}{FLOAT_SUFFIX}?              |
+[0][xX]"."{HEXDIGITS}[pP]{SIGN}?{DIGITS}{FLOAT_SUFFIX}?               {
+  return svalTok(TOK_FLOAT_LITERAL);
+}
+
+  /* malformed hex literal: missing 'p' */
+[0][xX]{HEXDIGITS}"."{HEXDIGITS}?     |
+[0][xX]"."{HEXDIGITS}?                {
+  err("hex literal missing 'p'");
+  return svalTok(TOK_FLOAT_LITERAL);
+}
+
+  /* malformed hex literal: no digits after 'p' */
+[0][xX]{HEXDIGITS}"."{HEXDIGITS}?[pP]{SIGN}?       |
+[0][xX]{HEXDIGITS}"."?[pP]{SIGN}?                  |
+[0][xX]"."{HEXDIGITS}[pP]{SIGN}?                   {
+  err("hex literal must have digits after 'p'");
+  return svalTok(TOK_FLOAT_LITERAL);
+}
+
+
+"__extension__" {
+  /* treat this like a token, in that nonseparating checks are done,
+   * but don't yield it to the parser */
+  (void)tok(TOK___EXTENSION__);
+}
+
+  /* GNU alternate spellings; the versions with both leading and trailling
+     underscores are explained here:
+       http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Alternate-Keywords.html
+     But, I see no explanation for the ones with only leading underscores,
+     though they occur in code in the wild so we support them...
+   */
+"__asm"                return tok(TOK_ASM);
+"__asm__"              return tok(TOK_ASM);
+"__const"              return tok(TOK_CONST);
+"__const__"            return tok(TOK_CONST);
+"__restrict"           return tok(TOK_RESTRICT);
+"__restrict__"         return tok(TOK_RESTRICT);
+"__inline"             return tok(TOK_INLINE);
+"__inline__"           return tok(TOK_INLINE);
+"__signed"             return tok(TOK_SIGNED);
+"__signed__"           return tok(TOK_SIGNED);
+"__volatile"           return tok(TOK_VOLATILE);
+"__volatile__"         return tok(TOK_VOLATILE);
+"__complex__"          return tok(TOK_COMPLEX);
+"__imaginary__"        return tok(TOK_IMAGINARY);
+"__real__"             return tok(TOK_REAL);
+"__imag__"             return tok(TOK_IMAG);
+
+"<?"                   return tok(TOK_MIN_OP);
+">?"                   return tok(TOK_MAX_OP);
+
+  /* Identifier with dollar-sign.
+   *   http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Dollar-Signs.html
+   * The rules are written so that at least one "$" must be present,
+   * to avoid obviating the rule in cc.lex. */
+"$"({ALNUM}|"$")* {
+  return svalTok(TOK_NAME);
+}
+{LETTER}{ALNUM}*"$"({ALNUM}|"$")* {
+  return svalTok(TOK_NAME);
+}
+
+  /* C99 stuff */
+"restrict" {
+  if (lang.restrictIsAKeyword) {
+    return tok(TOK_RESTRICT);
+  }
+  else {
+    return svalTok(TOK_NAME);
+  }
+}
+
+"_Complex"             return tok(TOK_COMPLEX);
+"_Imaginary"           return tok(TOK_IMAGINARY);
+
+  /* EOF */

Added: vendor/elsa/current/elsa/gnu_ext.tok
===================================================================
--- vendor/elsa/current/elsa/gnu_ext.tok	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/gnu_ext.tok	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// gnu_ext.tok  -*- c++ -*-
+// extension to cc_tokens.tok, for GNU language extensions
+
+// flags:
+//   MS(m): token has multiple spellings
+//   NS(n): token is a nonseparator; nonseparators cannot be adjacent
+//   CP(p): token is a keyword only in C++; in C it's an identifier
+
+// enumeration name      description                  : MS NS CP
+// ----------------      ---------------------------  : -- -- --
+
+// GNU extensions
+TOK_BUILTIN_CONSTANT_P,  "__builtin_constant_p",      :    n
+TOK___ALIGNOF__,         "__alignof__",               :    n
+TOK___OFFSETOF__,        "__offsetof__",              :    n
+TOK___BUILTIN_OFFSETOF,  "__builtin_offsetof",        :    n
+TOK___ATTRIBUTE__,       "__attribute__",             :    n
+TOK___FUNCTION__,        "__FUNCTION__",              :    n
+TOK___LABEL__,           "__label__",                 :    n
+TOK___PRETTY_FUNCTION__, "__PRETTY_FUNCTION__",       :    n
+TOK___TYPEOF__,          "__typeof__",                :    n
+TOK___EXTENSION__,       "__extension__",             :    n
+TOK___BUILTIN_EXPECT,    "__builtin_expect",          :    n
+
+  // varargs; dsw: I think that we should make all of these their own
+  // AST node, I just don't want to deal with the parsing ambiguity
+  // with E_funCall right now
+// TOK___BUILTIN_VA_START,  "__builtin_va_start",        :    n
+// TOK___BUILTIN_VA_COPY,   "__builtin_va_copy",         :    n
+TOK___BUILTIN_VA_ARG,    "__builtin_va_arg",          :    n
+// TOK___BUILTIN_VA_END,    "__builtin_va_end",          :    n
+
+TOK_MIN_OP,              "<?",                        :
+TOK_MAX_OP,              ">?",                        :
+TOK_REAL,                "__real__",                  :    n
+TOK_IMAG,                "__imag__",                  :    n
+
+// sm: these are C99 but I'm putting them here anyway..
+TOK_RESTRICT,            "restrict",                  :    n
+TOK_COMPLEX,             "_Complex",                  :    n
+TOK_IMAGINARY,           "_Imaginary",                :    n

Added: vendor/elsa/current/elsa/id_obj_dict.cc
===================================================================
--- vendor/elsa/current/elsa/id_obj_dict.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/id_obj_dict.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,96 @@
+// quarl 2006-05-30
+
+#include "id_obj_dict.h"
+
+#include <cctype>
+
+// TODO: It would simplify deserialization a lot of we got rid of the id
+// prefixes.  One way to solve the embedded member problem might be to add
+// {1,2,3} to embedded member pointers before checking the hash table.
+
+
+// parse an unsigned decimal integer from a string; returns true iff string is
+// an integer only.
+inline
+bool atoiFull(char const *p, unsigned &result)
+{
+  result = 0;
+
+  while (*p) {
+    if (!isdigit(*p)) return false;
+    result = result * 10 + (*p - '0');
+    ++p;
+  }
+  return true;
+}
+
+// static
+bool IdSObjDict::parseId(char const *id,
+                         Prefix &prefix,
+                         unsigned &idnum)
+{
+  if (!isupper(id[0]) || !isupper(id[1]))
+    return false;
+
+  if (!atoiFull(id+2, idnum)) return false;
+
+  prefix.set(id);
+
+  return true;
+}
+
+void *IdSObjDict::queryif(char const *id)
+{
+  Prefix prefix;
+  unsigned idnum;
+
+  if (parseId(id, prefix, idnum)) {
+    prefix.selfCheck();
+    if (idnum+1 > (unsigned) objectsById.size()) {
+      return NULL;
+    }
+
+    IdNode *node = &objectsById[idnum];
+    do {
+      if (node->prefix == prefix) {
+        return node->object;
+      }
+      node = node->next;
+    } while (node);
+    return NULL;
+  } else {
+    return objectsOther.queryif(id);
+  }
+}
+
+void IdSObjDict::add(char const *id, void *obj)
+{
+  Prefix prefix;
+  unsigned idnum;
+
+  if (parseId(id, prefix, idnum)) {
+    prefix.selfCheck();
+    objectsById.ensureIndexDoubler(idnum+1);
+
+    IdNode &entry = objectsById[idnum];
+    if (entry.object == NULL) {
+      // set it here
+      entry.object = obj;
+      entry.prefix = prefix;
+      xassert(entry.next == NULL);
+    } else {
+      // We don't care much for order.  Prepend; but we can't move the first
+      // item so insert after that.
+      //
+      // Does not check for duplicates!
+      IdNode *node = pool.alloc();
+      node->object = obj;
+      node->prefix = prefix;
+      node->next = entry.next;
+      entry.next = node;
+    }
+  } else {
+    objectsOther.add(id, obj);
+  }
+}
+

Added: vendor/elsa/current/elsa/id_obj_dict.h
===================================================================
--- vendor/elsa/current/elsa/id_obj_dict.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/id_obj_dict.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,95 @@
+
+// quarl 2006-05-30
+//    IdSObjDict is a data structure with the same interface as
+//    StringSObjDict<void> (actually subset), but optimized for the case where
+//    most (or all) ids are of the form "XY1234" (with the integer IDs densely
+//    increasing).
+//
+//    It is implemented via a map from strings (2-character prefixes) to
+//    arrays, where the integer ID is used directly as the array index.
+//
+//    This optimization reduces deserialization time by 60% and memory usage
+//    by 16%.
+//
+//    Other IDs are supported (using the old hashtable algorithm), but when
+//    parsing output produced by ourselves, we should never see IDs not of the
+//    form "XY1234".
+
+#ifndef IDOBJDICT_H
+#define IDOBJDICT_H
+
+#include "strobjdict.h"         // StringObjDict
+#include "strsobjdict.h"        // StringSObjDict
+#include "bitwise_array.h"      // BitwiseGrowArray
+
+class IdSObjDict {
+  class Prefix {
+    typedef short int16_t;
+    int16_t prefix;
+  public:
+    Prefix() : prefix(0) {}
+    Prefix(char const *p) { set(p); }
+    void set(char const *p) { prefix = *reinterpret_cast<int16_t const*>(p); }
+    bool operator==(Prefix o) const { return prefix == o.prefix; }
+    void selfCheck() { xassert(prefix); }
+  };
+
+  struct IdNode {
+    void *object;
+    Prefix prefix;
+    IdNode *next;
+
+    IdNode() { memset(this, 0, sizeof(*this)); }
+  };
+
+  // mini memory pool
+  class IdNodePool {
+    enum { PAGE_SIZE = 63 };
+    struct Page {
+      IdNode nodes[PAGE_SIZE];
+      Page *next;
+      Page() : next(0) {}
+    };
+    Page pages, *curPage;
+    IdNode *nextInPage;
+
+  public:
+    IdNodePool() { curPage=&pages; nextInPage=curPage->nodes; }
+    IdNode *alloc() {
+      if (nextInPage == curPage->nodes+PAGE_SIZE) {
+        curPage->next = new Page;
+        nextInPage = curPage->nodes;
+      }
+      return nextInPage++;
+    }
+    ~IdNodePool() {
+      Page *p = pages.next;
+      while (p) {
+        Page *next = p->next;
+        delete p;
+        p = next;
+      }
+    }
+
+  } pool;
+
+  // the data structure is an array of IdNodes.  Usually there is only 1
+  // object per id, only rarely is there more than one prefix per id.  In that
+  // case we use a linked list.
+
+  BitwiseGrowArray<IdNode> objectsById;
+  StringSObjDict<void> objectsOther;
+
+public:
+  IdSObjDict() : objectsById(64) {}
+  void *queryif(char const *id);
+  void *queryif(string const &id) { return queryif(id.c_str()); }
+  void add(char const *id, void *obj);
+  void add(string const &id, void *obj) { add(id.c_str(), obj); }
+  bool isMapped(char const *id) { return queryif(id) != NULL; }
+
+protected:
+  static bool parseId(char const *id, Prefix &prefix, unsigned &idnum);
+};
+
+#endif

Added: vendor/elsa/current/elsa/idemcheck
===================================================================
--- vendor/elsa/current/elsa/idemcheck	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/idemcheck	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,153 @@
+#!/usr/bin/perl -w
+# -*-perl-*-
+use strict;
+
+# Test the idempotency of the C++ parser.
+
+# Daniel S. Wilkerson dsw at cs.berkeley.edu
+
+my $parser = "./ccparse";
+die "No executable file: $parser\n" unless -x $parser;
+my @names = ();
+my @outfiles = ();
+my %outfile2command = ();
+
+my $outdir;
+
+my $usage=<<END
+Usage: idemcheck -d <outputdir> <inputlist>...
+END
+    ;
+
+if (+ at ARGV==0) {
+    print $usage;
+    exit 0;
+}
+
+#  for(@ARGV) {
+#      s/\s*\#.*$//;               # delete comments
+#      s/^\s*//;                   # delete leading whitespace
+#      s/\s*$//;                   # delete trailing whitespace
+#      next if /^\s*$/;            # skip blank lines
+#      if (/^(\S+)$/) {
+#          push @names, $1;
+#      } else {
+#          die "Malformed line: $_";
+#      }
+#  }
+{
+    my $arg = shift @ARGV;
+    last unless defined $arg;
+    if ($arg=~/^-d/) {
+        $outdir = shift @ARGV;
+        die "No argument to -d\n" unless defined $outdir;
+        # die "No such dir: $outdir\n" unless -d $outdir;
+        if (!-d $outdir) {
+            mkdir $outdir or die "mkdir $outdir: $!\n";
+        }
+    } else {
+        push @names, $arg;
+    }
+    redo;
+}
+die "You must specify an out directory with -d\n$usage" unless defined $outdir;
+
+sub run_only ($$) {
+    my ($command, $outfile) = @_;
+    my $realcommand = "$command >> $outfile";
+#    print "RUN: $realcommand\n";
+    unlink $outfile;
+    die if -f $outfile;
+    my $res = system "$realcommand";
+    if ($res!=0) {
+        my $exit_value  = $res >> 8;
+        my $signal_num  = $res & 127;
+        my $dumped_core = $res & 128;
+        system "echo >> $outfile '**** abnormal exit: exit_value $exit_value, " .
+            "signal_num $signal_num, dumped_core $dumped_core'\n";
+        die "Command fails: $realcommand\n";
+    }
+}
+
+sub run_command ($$) {
+    my ($command, $outfile) = @_;
+    my $realcommand = "$command >> $outfile";
+    $outfile2command{$outfile} = $realcommand;
+    push @outfiles, $outfile;
+    run_only $command, $outfile;
+}
+
+sub dump_outfiles {
+    for my $outfile(@outfiles) {
+        print "STAGE ****************\n";
+        print "$outfile2command{$outfile}\n";
+        system "cat $outfile";
+    }
+}
+
+my $numinputs = 0;
+my $numpass = 0;
+my @failingFiles = ();
+for my $name(@names) {
+    print "$name\n";
+    die "No such file $name\n" unless -f "$name";
+    ++$numinputs;
+
+    my $outname = $name;
+    if ($outname=~m|/|) {$outname=~s|^.*/([^/]+)|$1|;}
+    die "Bad outname:$outname:\n" if $outname=~/^\s*$/;
+    $outname = "$outdir/$outname";
+
+    @outfiles = ();
+    push @outfiles, $name;
+    $outfile2command{$name} = "ORIGINAL: $name";
+    eval {
+        # sm: added "-tr prettyPrint" to print the tree, since
+        # I made that printing conditional upon the tracing flag
+        my $flags = "-tr prettyPrint";
+#          my $cppflags = "-lang-c++";      # This doesn't work!
+        my $cpp = "cpp -D__cplusplus -D__LINUX__ -D__UNIX__ -DNDEBUG";
+        run_command "$cpp $name", "$outname.0cppout.cc";
+        run_command "$parser $flags $outname.0cppout.cc", "$outname.1rawout.cc";
+        run_only "cpp < $outname.1rawout.cc | perl ./chop_out", "$outname.2out.cc";
+        run_command "$parser $flags $outname.2out.cc", "$outname.3rawout.cc";
+        run_only "$cpp < $outname.3rawout.cc | perl ./chop_out", "$outname.4out.cc";
+    };
+    if ($@) {
+        dump_outfiles();
+        push @failingFiles, $name;
+        print "ERROR: $@\n";
+        next;
+    }
+
+    # sm: replaced -u with -c for portability
+    #
+    # sm: 2005-02-12: added -b (ignore blankspace differences)
+    # because on cygwin with DOS line endings in/c99/t0133.c has
+    # a CR vs CRLF difference that I don't want to track down...
+    my $diff_command = "diff -c -b $outname.2out.cc $outname.4out.cc > $outname.5diff";
+    $outfile2command{"$outname.5diff"} = $diff_command;
+    push @outfiles, "$outname.5diff";
+    my $diff_res = system $diff_command;
+    if ($diff_res == 0) {
+        ++$numpass;
+    } else {
+        dump_outfiles();
+        push @failingFiles, $name;
+    }
+}
+
+print "";
+print "Num inputs $numinputs\n";
+print "Num pass   $numpass\n";
+if (@failingFiles) {
+    print ("Failing files: ", join(' ', @failingFiles), "\n");
+}
+
+if ($numinputs==$numpass) {
+    print "PASS\n";
+    exit 0;
+} else {
+    print "FAIL\n";
+    exit 1;
+}


Property changes on: vendor/elsa/current/elsa/idemcheck
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/implconv.cc
===================================================================
--- vendor/elsa/current/elsa/implconv.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/implconv.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,420 @@
+// implconv.cc                       see license.txt for copyright and terms of use
+// code for implconv.h
+
+#include "implconv.h"      // this module
+#include "cc_env.h"        // Env
+#include "variable.h"      // Variable
+#include "overload.h"      // resolveOverload
+#include "trace.h"         // tracingSys
+
+
+// prototypes
+StandardConversion tryCallCtor
+  (Variable const *var, SpecialExpr special, Type const *src);
+
+
+
+// ------------------- ImplicitConversion --------------------
+char const * const ImplicitConversion::kindNames[NUM_KINDS] = {
+  "IC_NONE",
+  "IC_STANDARD",
+  "IC_USER_DEFINED",
+  "IC_ELLIPSIS",
+  "IC_AMBIGUOUS"
+};
+
+void ImplicitConversion::addStdConv(StandardConversion newScs)
+{
+  if (kind != IC_NONE) {
+    kind = IC_AMBIGUOUS;
+    return;
+  }
+
+  kind = IC_STANDARD;
+  scs = newScs;
+}
+
+
+void ImplicitConversion
+  ::addUserConv(StandardConversion first, Variable *userFunc,
+                StandardConversion second)
+{
+  if (kind != IC_NONE) {
+    kind = IC_AMBIGUOUS;
+    return;
+  }
+
+  kind = IC_USER_DEFINED;
+  scs = first;
+  user = userFunc;
+  scs2 = second;
+}
+
+
+void ImplicitConversion::addEllipsisConv()
+{
+  if (kind != IC_NONE) {
+    kind = IC_AMBIGUOUS;
+    return;
+  }
+
+  kind = IC_ELLIPSIS;
+}
+
+
+Type *ImplicitConversion::getConcreteDestType
+  (TypeFactory &tfac, Type *srcType, Type *destType) const
+{
+  // skip past the user-defined conversion, if any
+  StandardConversion sconv = scs;
+  if (kind == IC_USER_DEFINED) {
+    srcType = user->type->asFunctionType()->retType;
+    sconv = scs2;
+  }
+
+  // 2005-04-15: in/k0032.cc: if both src and dest are reference
+  // types, skip that
+  if (srcType->isReference() &&
+      destType->isReference()) {
+    Type *destAt = destType->getAtType();
+    Type *srcAt = srcType->getAtType();
+
+    Type *concrete = inner_getConcreteDestType(tfac, srcAt, destAt, sconv);
+    if (concrete == destAt) {
+      return destType;        // was concrete already
+    }
+    else {
+      // must re-construct the reference part of the type
+      return tfac.makeReferenceType(concrete);
+    }
+  }
+
+  return inner_getConcreteDestType(tfac, srcType, destType, sconv);
+}
+
+// this function exists just so that the reference/reference case
+// can use it as a subroutine ...
+Type *ImplicitConversion::inner_getConcreteDestType
+  (TypeFactory &tfac, Type *srcType, Type *destType, StandardConversion sconv) const
+{
+  if (destType->isPointer()) {
+    // hmm.. operator+ has '<any obj> *'
+
+    Type *destAtType = destType->getAtType();
+    if (!destAtType->isSimpleType()) {
+      return destType;      // easy
+    }
+
+    SimpleTypeId id = destAtType->asSimpleTypeC()->type;
+    if (isConcreteSimpleType(id)) {
+      return destType;      // also easy
+    }
+
+    // if 'destType' is a reference to a polymorphic type,
+    // then this wouldn't be right ....
+    srcType = srcType->asRval();
+
+    // apply the conversion
+    if (sconv == SC_ARRAY_TO_PTR) {
+      srcType = tfac.makePointerType(CV_NONE,
+        srcType->asArrayType()->eltType);
+    }
+
+    // anything more to do?  not sure...
+
+    return srcType;
+  }
+
+  // these first two conditions are the same as at the top
+  // of OverloadResolver::getReturnType ...
+
+  if (!destType->isSimpleType()) {
+    return destType;      // easy
+  }
+
+  SimpleTypeId id = destType->asSimpleTypeC()->type;
+  if (isConcreteSimpleType(id)) {
+    return destType;      // also easy
+  }
+
+  // ask the standard conversion module what type results when using
+  // 'sconv' to convert from 'srcType' to the polymorphic 'destType'
+  SimpleTypeId destPolyType = destType->asSimpleTypeC()->type;
+  return ::getConcreteDestType(tfac, srcType, sconv, destPolyType);
+}
+
+
+string ImplicitConversion::debugString() const
+{
+  stringBuilder sb;
+  sb << kindNames[kind];
+
+  if (kind == IC_STANDARD || kind == IC_USER_DEFINED) {
+    sb << "(" << toString(scs);
+
+    if (kind == IC_USER_DEFINED) {
+      sb << ", " << user->name << " @ " << toString(user->loc)
+         << ", " << toString(scs2);
+    }
+
+    sb << ")";
+  }
+
+  return sb;
+}
+
+
+// --------------------- getImplicitConversion ---------------
+ImplicitConversion getImplicitConversion
+  (Env &env, SpecialExpr special, Type *src, Type *dest, bool destIsReceiver)
+{
+  xassert(src && dest);
+  ImplicitConversion ret;
+
+  if (src->asRval()->isGeneralizedDependent()) {
+    ret.addStdConv(SC_IDENTITY);      // could be as good as this
+    return ret;
+  }
+
+  // 9/25/04: conversion from template class pointer requires
+  // instantiating the template class, so we can try derived-to-base
+  // conversions
+  if (src->asRval()->isPointerType()) {
+    Type *at = src->asRval()->asPointerType()->atType;
+    if (at->isCompoundType()) {
+      env.ensureClassBodyInstantiated(at->asCompoundType());
+    }
+  }
+
+  // check for a standard sequence
+  {
+    StandardConversion scs =
+      getStandardConversion(NULL /*errorMsg*/, special, src, dest, destIsReceiver);
+    if (scs != SC_ERROR) {
+      ret.addStdConv(scs);
+      return ret;
+    }
+  }
+
+  // 13.3.3.1p6: derived-to-base conversion? (acts like a standard
+  // conversion for overload resolution, but is not a "real" standard
+  // conversion, because in actuality a constructor call is involved)
+  if (dest->isCompoundType() &&
+      src->asRval()->isCompoundType()) {
+    CompoundType *destCt = dest->asCompoundType();
+    CompoundType *srcCt = src->asRval()->asCompoundType();
+
+    if (srcCt->hasBaseClass(destCt)) {
+      ret.addStdConv(SC_DERIVED_TO_BASE);
+      return ret;
+    }
+  }
+
+  // check for a constructor to make the dest type; for this to
+  // work, the dest type must be a class type or a const reference
+  // to one
+  if (dest->isCompoundType() ||
+      (dest->asRval()->isCompoundType() &&
+       dest->asRval()->isConst())) {
+    CompoundType *ct = dest->asRval()->asCompoundType();
+
+    // (in/t0514.cc) conversion to a template class specialization
+    // requires that the specialization be instantiated
+    env.ensureClassBodyInstantiated(ct);
+
+    // get the overload set of constructors
+    Variable *ctor = ct->getNamedField(env.constructorSpecialName, env);
+    if (!ctor) {
+      // ideally we'd have at least one ctor for every class, but I
+      // think my current implementation doesn't add all of the
+      // implicit constructors.. and if there are only implicit
+      // constructors, they're handled specially anyway (I think),
+      // so we can just disregard the possibility of using one
+    }
+    else {
+      if (ctor->overload) {
+        // multiple ctors, resolve overloading; but don't further
+        // consider user-defined conversions; note that 'explicit'
+        // constructors are disregarded (OF_NO_EXPLICIT)
+        GrowArray<ArgumentInfo> argTypes(1);
+        argTypes[0] = ArgumentInfo(special, src);
+        OVERLOADINDTRACE("overloaded call to constructor " << ct->name);
+        bool wasAmbig;
+        ctor = resolveOverload(env, env.loc(), NULL /*errors*/,
+                               OF_NO_USER | OF_NO_EXPLICIT,
+                               ctor->overload->set, NULL /*finalName*/,
+                               argTypes, wasAmbig);
+        if (ctor) {
+          // printing is now done inside 'resolveOverload'
+          //TRACE("overload", "  selected constructor at " << toString(ctor->loc));
+        }
+        else if (wasAmbig) {
+          //TRACE("overload", "  ambiguity while selecting constructor");
+          ret.addAmbig();
+        }
+        else {
+          //TRACE("overload", "  no constructor matches");
+        }
+      }
+
+      if (ctor) {
+        // only one ctor now.. can we call it?
+        StandardConversion first = tryCallCtor(ctor, special, src);
+        if (first != SC_ERROR) {
+          // success
+          ret.addUserConv(first, ctor, SC_IDENTITY);
+        }
+      }
+    }
+  }
+
+  // check for a conversion function
+  if (src->asRval()->isCompoundType()) {
+    ImplicitConversion conv = getConversionOperator(
+      env, env.loc(), NULL /*errors*/,
+      src, dest);
+    if (conv) {
+      if (ret) {
+        // there's already a constructor-based conversion, so this
+        // sequence is ambiguous
+        ret.addAmbig();
+      }
+      else {
+        ret = conv;
+      }
+    }
+  }
+
+  return ret;
+}
+
+
+StandardConversion tryCallCtor
+  (Variable const *var, SpecialExpr special, Type const *src)
+{
+  // certainly should be a function
+  FunctionType *ft = var->type->asFunctionType();
+
+  int numParams = ft->params.count();
+  if (numParams == 0) {
+    if (ft->acceptsVarargs()) {
+      // I'm not sure about this.. there's no SC_ELLIPSIS..
+      return SC_IDENTITY;
+    }
+    else {
+      return SC_ERROR;
+    }
+  }
+
+  if (numParams > 1) {
+    if (ft->params.nthC(1)->value) {
+      // the 2nd param has a default, which implies all params
+      // after have defaults, so this is ok
+    }
+    else {
+      return SC_ERROR;     // requires at least 2 arguments
+    }
+  }
+
+  Variable const *param = ft->params.firstC();
+  return getStandardConversion(NULL /*errorMsg*/, special, src, param->type);
+}
+
+
+// ----------------- test_getImplicitConversion ----------------
+int getLine(SourceLoc loc)
+{
+  return sourceLocManager->getLine(loc);
+}
+
+
+bool matchesExpectation(ImplicitConversion const &actual,
+  int expectedKind, int expectedSCS, int expectedUserLine, int expectedSCS2)
+{
+  if (expectedKind != actual.kind) return false;
+
+  if (actual.kind == ImplicitConversion::IC_STANDARD) {
+    return actual.scs == expectedSCS;
+  }
+
+  if (actual.kind == ImplicitConversion::IC_USER_DEFINED) {
+    int actualLine = getLine(actual.user->loc);
+    return actual.scs == expectedSCS &&
+           actualLine == expectedUserLine &&
+           actual.scs2 == expectedSCS2;
+  }
+
+  // other kinds are equal without further checking
+  return true;
+}
+
+
+void test_getImplicitConversion(
+  Env &env, SpecialExpr special, Type *src, Type *dest,
+  int expectedKind, int expectedSCS, int expectedUserLine, int expectedSCS2)
+{
+  // grab existing error messages
+  ErrorList existing;
+  existing.takeMessages(env.errors);
+
+  // run our function
+  ImplicitConversion actual = getImplicitConversion(env, special, src, dest);
+
+  // turn any resulting messags into warnings, so I can see their
+  // results without causing the final exit status to be nonzero
+  env.errors.markAllAsWarnings();
+
+  // put the old messages back
+  env.errors.takeMessages(existing);
+
+  // did it behave as expected?
+  bool matches = matchesExpectation(actual, expectedKind, expectedSCS,
+                                            expectedUserLine, expectedSCS2);
+  if (!matches || tracingSys("gIC")) {
+    // construct a description of the actual result
+    stringBuilder actualDesc;
+    actualDesc << ImplicitConversion::kindNames[actual.kind];
+    if (actual.kind == ImplicitConversion::IC_STANDARD ||
+        actual.kind == ImplicitConversion::IC_USER_DEFINED) {
+      actualDesc << "(" << toString(actual.scs);
+      if (actual.kind == ImplicitConversion::IC_USER_DEFINED) {
+        actualDesc << ", " << getLine(actual.user->loc)
+                   << ", " << toString(actual.scs2);
+      }
+      actualDesc << ")";
+    }
+
+    // construct a description of the call site
+    stringBuilder callDesc;
+    callDesc << "getImplicitConversion("
+             << toString(special) << ", `"
+             << src->toString() << "', `"
+             << dest->toString() << "')";
+
+    if (!matches) {
+      // construct a description of the expected result
+      stringBuilder expectedDesc;
+      xassert((unsigned)expectedKind <= (unsigned)ImplicitConversion::NUM_KINDS);
+      expectedDesc << ImplicitConversion::kindNames[expectedKind];
+      if (expectedKind == ImplicitConversion::IC_STANDARD ||
+          expectedKind == ImplicitConversion::IC_USER_DEFINED) {
+        expectedDesc << "(" << toString((StandardConversion)expectedSCS);
+        if (expectedKind == ImplicitConversion::IC_USER_DEFINED) {
+          expectedDesc << ", " << expectedUserLine
+                       << ", " << toString((StandardConversion)expectedSCS2);
+        }
+        expectedDesc << ")";
+      }
+
+      env.error(stringc
+        << callDesc << " yielded " << actualDesc
+        << ", but I expected " << expectedDesc);
+    }
+    else {
+      env.warning(stringc << callDesc << " yielded " << actualDesc);
+    }
+  }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/implconv.h
===================================================================
--- vendor/elsa/current/elsa/implconv.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/implconv.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,94 @@
+// implconv.h                       see license.txt for copyright and terms of use
+// implicit conversion sequences: cppstd 13.3.3.1, 13.3.3.2
+
+// implicit conversions occur most prominently when binding
+// an argument to a parameter at a call site; they're "implicit"
+// in that these conversions take place despite the absence of
+// syntax such as constructor calls or cast notation
+
+#ifndef IMPLCONV_H
+#define IMPLCONV_H
+
+#include "stdconv.h"     // StandardConversion
+
+class Variable;          // variable.h
+
+
+class ImplicitConversion {
+public:    // data
+  enum Kind {
+    IC_NONE,             // no conversion possible
+    IC_STANDARD,         // 13.3.3.1.1: standard conversion sequence
+    IC_USER_DEFINED,     // 13.3.3.1.2: user-defined conversion sequence
+    IC_ELLIPSIS,         // 13.3.3.1.3: ellipsis conversion sequence
+    IC_AMBIGUOUS,        // 13.3.3.1 para 10
+    NUM_KINDS
+  } kind;
+  static char const * const kindNames[NUM_KINDS];
+
+  // for IC_STANDARD, this is the conversion sequence
+  // for IC_USER_DEFINED, this is the *first* conversion sequence
+  StandardConversion scs;       // "standard conversion sequence"
+
+  // for IC_USER_DEFINED
+  Variable *user;               // the ctor or conversion operator function
+  StandardConversion scs2;      // second conversion sequence (convert return value of 'user' to param type)
+
+private:   // funcs
+  Type *inner_getConcreteDestType(TypeFactory &tfac, Type *srcType,
+                                  Type *destType, StandardConversion sconv) const;
+
+public:    // funcs
+  ImplicitConversion()
+    : kind(IC_NONE), scs(SC_IDENTITY), user(NULL), scs2(SC_IDENTITY) {}
+  ImplicitConversion(ImplicitConversion const &obj)
+    : DMEMB(kind), DMEMB(scs), DMEMB(user), DMEMB(scs2) {}
+
+  // for determining whether the conversion attempt succeeded
+  operator bool () const { return kind != IC_NONE; }
+
+  bool isAmbiguous() const { return kind == IC_AMBIGUOUS; }
+
+  // add specific conversion possibilities; automatically kicks
+  // over to IC_AMBIGUOUS if there's already a conversion
+  void addStdConv(StandardConversion scs);
+  void addUserConv(StandardConversion first, Variable *user,
+                   StandardConversion second);
+  void addEllipsisConv();
+  void addAmbig() { kind = IC_AMBIGUOUS; }
+
+  // reverse-engineer an already-computed conversion
+  Type *getConcreteDestType(TypeFactory &tfac, Type *srcType, Type *destType) const;
+
+  // debugging
+  // experiment: member function is called 'debugString', and
+  // global function is called 'toString'
+  string debugString() const;
+  friend string toString(ImplicitConversion const &ics)
+    { return ics.debugString(); }
+};
+
+
+// given two types, find an implicit conversion between them, or
+// return IC_NONE if none exists (do *not* insert error messages
+// into the environment, either way)
+ImplicitConversion getImplicitConversion(
+  Env &env,            // type checking environment
+  SpecialExpr special, // properties of the source expression
+  Type *src,           // source type
+  Type *dest,          // destination type
+  bool destIsReceiver = false    // true if destination type is to be receiver object for method call
+);
+
+
+// testing interface, for use by type checker
+void test_getImplicitConversion(
+  Env &env, SpecialExpr special, Type *src, Type *dest,
+  int expectedKind,      // ImplicitConversion::kind
+  int expectedSCS,       // ImplicitConversion::scs
+  int expectedUserLine,  // ImplicitConversion::user->loc's line number
+  int expectedSCS2       // ImplicitConversion::scs2
+);
+
+
+#endif // IMPLCONV_H

Added: vendor/elsa/current/elsa/implint.cc
===================================================================
--- vendor/elsa/current/elsa/implint.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/implint.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,90 @@
+// implint.cc            see license.txt for copyright and terms of use
+// implicit-int parsing support routines
+
+// this doesn't include implint.h b/c that's sort of different
+
+#include "cc_ast.h"       // AST
+#include "trace.h"        // trace
+#include "array.h"        // Array
+
+
+// Mutate 'params' filtering out any alternatives of the first param
+// (if there is one) that are of type implicit-int.  Return true if
+// we should really construct a D_func that the grammar rule wants
+// to construct.
+bool filterOutImplIntFirstParam
+  (SourceLoc loc,
+   IDeclarator *base,
+   FakeList<ASTTypeId> *&params) {
+  // skip unless are we an anonymous function with at least one
+  // parameter
+  if (! (base->isD_name() && !base->asD_name()->name && params && params->first())) {
+    return true;                // keep it
+  }
+
+  // dsw: remove all of the alternatives for the first parameter
+  // that are of type implicit-int; NOTE: this may be wrong in some
+  // strange circumstance where a preceeding const/volatile/register
+  // keyword makes the implicit-int legal.  To attempt to emulate
+  // that would complicate the code even more so I don't until we
+  // see a real example so at least we have something real to test
+  // against.
+
+  // NOTE: this is a mutating walk over a linked list, which is
+  // really error-prone; therefore I do the easy thing and copy it
+  // to another list and copy it back; this problem alone is reason
+  // enough not to use linked lists
+
+  // count the ambiguities
+  // NOTE: do NOT do this!  It is wrong: It counts the parameters.
+  //        int numAlt = params->count();
+  int numAlt = 0;
+  for (ASTTypeId *atid = params->first(); atid; atid = atid->ambiguity) {
+    ++numAlt;
+  }
+
+  // make a temporary array
+  Array<ASTTypeId*> tempList(numAlt);
+
+  // put them in there
+  int i = 0;
+  for (ASTTypeId *atid = params->first(); atid; atid = atid->ambiguity, ++i) {
+    tempList[i] = atid;
+  }
+
+  // remove the ambiguity pointers
+  for (i=0; i<numAlt; ++i) {
+    tempList[i]->ambiguity = NULL;
+  }
+
+  // remove the implicit-int possibilities
+  for (i=0; i<numAlt; ++i) {
+    ASTTypeId *atid = tempList[i];
+    if (atid->spec->isTS_simple() &&
+        atid->spec->asTS_simple()->id == ST_IMPLINT) {
+      trace("cancel") << loc << ": implicit-int function first param\n";
+      tempList[i] = NULL;
+    }
+  }
+
+  // rebuild a linked list from those that remain
+  ASTTypeId *newList = NULL;
+  for (i=0; i<numAlt; ++i) {
+    if (tempList[i]) {
+      tempList[i]->ambiguity = newList;
+      newList = tempList[i];
+    }
+  }
+
+  // NOTE: this will be in reverse order
+  params = FakeList<ASTTypeId>::makeList(newList);
+
+  // keep the D_func iff there are alternatives left for the first
+  // parameter; NOTE: Do NOT do 'return params->isNotEmpty()'; that
+  // returns the number of parameters, not the number of surviving
+  // ambiguous alternatives
+  return newList;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/implint.h
===================================================================
--- vendor/elsa/current/elsa/implint.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/implint.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,178 @@
+// implint.h            see license.txt for copyright and terms of use
+// ambiguity resolution for implicit-int
+
+/*
+  This is sort of an analogue to generic_amb.h, which contains
+  the generic ambiguity resolution procedure.  The one in this
+  file is for dealing with old-style C "implicit int", which
+  for the moment is only parsed by oink's grammar.
+
+  The basic parsing strategy is to have alternate syntactic forms for
+  toplevel declarations that can have implicit ints, for example
+  statement-decls with implicit ints.  This opposed to the more
+  obvious strategy of making TypeSpecifier be optional, since that
+  makes it more difficult to control where the ambiguities surface.
+
+  When a declaration is parsed as using implicit int, its type
+  specifier is set to TS_simple(ST_IMPLINT).  That way the ambiguity
+  resolution procedure can tell which construct used implicit int.
+
+  The resolution procedure itself is fairly simple: scan the list of
+  ambiguous alternatives for those beginning with
+  TS_simple(ST_IMPLINT).  If one exists, then check the first
+  identifier (i.e. the 'name' of the bottom-most D_name) to see if it
+  looks up to a type.  If so, then *reject* the implicit-int
+  interpretation, because the C compiler would have lexed the name as
+  a type and hence not used the implicit-int rule.  If the first name
+  is not a type, then *accept* the implicit-int interpretation (and
+  reject all the others), by the same reasoning.
+*/
+
+#ifndef IMPLINT_H
+#define IMPLINT_H
+
+#include "cc_ast.h"         // C++ AST
+#include "cc_env.h"         // Env
+
+
+// The 'hasImplicitInt' function returns true if the given node is
+// using the implicit-int rule, and if so, also fills in the OUT
+// parameter 'declarator', the declarator which has the name used to
+// do disambiguation.
+//
+// There are several overloaded versions, one for each kind of node
+// that has implicit-int ambiguity resolution to perform.  The
+// templatized resolution procedure below automatically selects the
+// appropriate one.
+
+bool isImplicitInt(TypeSpecifier *ts)
+{
+  return ts->isTS_simple() &&
+         ts->asTS_simple()->id == ST_IMPLINT;
+}
+
+bool hasImplicitInt(ASTTypeId *a, Declarator *&declarator)
+{
+  if (isImplicitInt(a->spec)) {
+    declarator = a->decl;
+    xassert(declarator);
+    return true;
+  }
+  return false;
+}
+
+bool hasImplicitInt(Declaration *d, Declarator *&declarator)
+{
+  if (isImplicitInt(d->spec)) {
+    declarator = d->decllist->first();
+    xassert(declarator);
+    return true;
+  }
+  return false;
+}
+
+bool hasImplicitInt(TopForm *tf, Declarator *&declarator)
+{
+  if (tf->isTF_decl()) {
+    return hasImplicitInt(tf->asTF_decl()->decl, declarator);
+  }
+  if (tf->isTF_func()) {
+    Function *f = tf->asTF_func()->f;
+    if (isImplicitInt(f->retspec)) {
+      declarator = f->nameAndParams;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool hasImplicitInt(Statement *s, Declarator *&declarator)
+{
+  if (s->isS_decl()) {
+    return hasImplicitInt(s->asS_decl()->decl, declarator);
+  }
+  return false;
+}
+
+
+// this returns a non-NULL value if it has selected the proper
+// interpretation (or set of interpretations to further resolve)
+// from the list; it returns NULL if it did not make any decision
+template <class NODE>
+NODE *resolveImplIntAmbig(Env &env, NODE *node)
+{
+  // find any of the ambiguities that are ST_IMPLINT and decide if we
+  // want them or not
+  for (NODE *s0 = node; s0; s0 = s0->ambiguity) {
+    // Note that this loop does not continue once this 'if' tests as
+    // true.
+    Declarator *d0 = NULL;
+    if (hasImplicitInt(s0, d0)) {
+      xassert(env.lang.allowImplicitInt);
+      xassert(d0);
+
+      // if this is an implicit int declaration, then we allow it
+      // *only if* the name of the declarator does not look up to a
+      // type, even if the type interpretation is also wrong!  This
+      // matches the gcc failure on this example for which both
+      // interpretations (implicit int or not) fail:
+      //   typedef int y;
+      //   int main() {
+      //     static *y;  // both interpretations fail here
+      //     ++(*y);
+      //   }
+
+      // assert that all the declarators have the same name; NOTE: we
+      // ignore any subsequent declarators for the purposes of
+      // determining if we want the implicit-int interpretation
+      //
+      // We check that all the ambiguous Declarators (the various
+      // parses of the *first* *user*-visible Declarator) all have the
+      // same name; again we ignore the subsequent *user*-visible
+      // Declarators
+      //
+      // NOTE: the name (and name1 below) should not be qualified but
+      // we don't check that, trusting in the goodness of Odin
+      StringRef name0 = d0->decl->getDeclaratorId()->getName();
+      xassert(name0);
+      for(Declarator *d1 = d0->ambiguity; d1; d1 = d1->ambiguity) {
+        StringRef name1 = d1->decl->getDeclaratorId()->getName();
+        xassert(name0 == name1);
+      }
+      // does this look up to a type?
+      Variable *var = env.lookupVariable(name0);
+      if (var && var->hasFlag(DF_TYPEDEF)) {
+        // we reject the implicit-int interpretation
+        if (s0 == node) {
+          // by doing this the caller will re-write the ast node that
+          // points to us
+          return s0->ambiguity;
+        } else {
+          // chop s0 out of the list and repeat
+          NODE *s2 = NULL;
+          for(s2 = node; s2->ambiguity != s0; s2 = s2->ambiguity)
+            {}
+          xassert(s2->ambiguity == s0);
+          s2->ambiguity = s2->ambiguity->ambiguity;
+          // we do the whole thing over again in case there are two
+          // implicit-int interpretations even though we think that
+          // is not possible
+          return node;
+        }
+      } else {
+        // we keep the implicit-int interpretation
+        s0->ambiguity = NULL;
+        
+        // there is no point to doing this here, since
+        // TS_simple::itcheck has to do it also
+        //simpSpec->id = ST_INT /*NOTE: was ST_IMPLINT*/;
+
+        return s0;
+      }
+    }
+  }
+  return NULL;
+}
+
+
+#endif // IMPLINT_H

Added: vendor/elsa/current/elsa/in/big/gz/nonport.i.gz
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/in/big/gz/nonport.i.gz
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/in/big/gz/nsAtomTable.i.gz
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/in/big/gz/nsAtomTable.i.gz
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/in/big/gz/nsCLiveconnectFactory.i.gz
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/in/big/gz/nsCLiveconnectFactory.i.gz
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/in/big/gz/nsHTMLEditRules.i.gz
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/in/big/gz/nsHTMLEditRules.i.gz
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/in/big/gz/nsMsgServiceProvider.i.gz
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/in/big/gz/nsMsgServiceProvider.i.gz
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/in/big/gz/nsSOAPPropertyBag.i.gz
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/in/big/gz/nsSOAPPropertyBag.i.gz
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/in/big/gz/nsUnicodeToTeXCMRt1.i.gz
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/in/big/gz/nsUnicodeToTeXCMRt1.i.gz
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/in/big/gz/ostream.i.gz
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/elsa/in/big/gz/ostream.i.gz
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/elsa/in/c/d0124b.c
===================================================================
--- vendor/elsa/current/elsa/in/c/d0124b.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/d0124b.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// see elsa/in/d0124.cc for contrast; this passes because string
+// literals are 'char (nonconst) []' in C
+char *a = "hello";
+char const *b = "hello";

Added: vendor/elsa/current/elsa/in/c/dC0010.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0010.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0010.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+// from the kernel
+typedef unsigned char u8;
+static int adm1025_read_value(u8 register);

Added: vendor/elsa/current/elsa/in/c/dC0011.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0011.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0011.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// from the kernel; as Simon points out, this is the trick for finding
+// the offset at static time of a struct member
+
+typedef int size_t;
+
+struct B {
+  int q;
+};
+
+struct scsi_cmnd {
+  struct B b;
+};
+
+int main() {
+  switch(3) {
+    // this was originally in a different context requiring const
+    // evaluation: an array size.  I just wanted to simplfy the
+    // expression
+  case ((size_t) &((struct scsi_cmnd *)0)->b.q) :
+    break;
+  }
+};

Added: vendor/elsa/current/elsa/in/c/dC0012.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0012.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0012.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// from the kernel; this checks that if you are in C mode, don't add
+// the implicit typedef generated by a struct to the namespace; note
+// the two meanings of 'dongle' below.
+
+struct dongle_reg {
+  int type;
+};
+
+void irda_device_unregister_dongle_R40b68423(struct dongle_reg *dongle)
+{
+  struct dongle *node;
+  dongle->type;
+}

Added: vendor/elsa/current/elsa/in/c/dC0013.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0013.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0013.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// from the kernel; please note the double-meaning of port_id; I don't
+// know if this is a gcc-ism or not
+typedef unsigned short __u16;
+typedef __u16 port_id;
+struct net_bridge_port
+{
+  port_id port_id;
+  port_id designated_port;
+};

Added: vendor/elsa/current/elsa/in/c/dC0017.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0017.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0017.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// gcc accepts this in C mode, not in C++ mode (per the C++ spec)
+
+typedef struct zone_struct {
+  int x;
+} zone_t;
+struct zone_t;

Added: vendor/elsa/current/elsa/in/c/dC0018.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0018.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0018.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// dC0018.c
+// this testcase provokes a const-eval of a still-ambiguous
+// expression, due to errors above the ambig expr
+
+void aa_fastrender (int x1, int y1, int x2, int y2)
+{
+  if (x2 < 0 || y2 < 0 || x1 > (3) || y1 > (4))
+    return;
+}

Added: vendor/elsa/current/elsa/in/c/dC0019.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0019.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0019.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+void CreateArray() {
+  int x = sizeof (struct {});
+
+  // this is from k0035.cc  
+  x = (x) + (sizeof(struct {}));
+}

Added: vendor/elsa/current/elsa/in/c/dC0020.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0020.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0020.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+struct A {};
+
+void f() {
+ 
+  struct {
+    struct A z;
+  } *p;
+
+  p->z;
+
+  (int) & (((struct Foo {struct A y;}*)0)->y);
+
+  (int) & (((struct {struct A y;}*)0)->y);
+}

Added: vendor/elsa/current/elsa/in/c/dC0021.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0021.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0021.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// dC0021.c
+// dynamically-sized parameter arrays
+
+// see C99, 6.7.5.2 and 6.7.5.3 example 4
+
+// prototype
+void remote_lookup (int tracknum, long int offset[tracknum]);
+
+// definition
+void remote_lookup (int tracknum, long int offset[tracknum])
+{}
+

Added: vendor/elsa/current/elsa/in/c/dC0022.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0022.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0022.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+void encode_rgb_frame (int w) {
+  int sample_buffer[3][w + 6];
+  sizeof sample_buffer;
+}

Added: vendor/elsa/current/elsa/in/c/dC0023.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0023.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0023.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// in gcc, in C mode, a foo and a struct foo have nothing to do with
+// one another
+typedef char *foo;
+struct foo *q;
+struct foo { int x; };
+//ERROR(1): struct foo { int x2; };    // duplicate
+
+typedef char *foo2;
+struct foo2 { int x; };
+
+typedef char *foo3;
+enum foo3 { SOMETHING };
+
+// the test exhibits the bug without the below, but the below extends
+// the test
+int main() {
+  struct foo *gronk = q;
+  foo zork;
+  char *bork = zork;
+}
+

Added: vendor/elsa/current/elsa/in/c/dC0024.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0024.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0024.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// dC0024.c
+// repeated type specifier keywords
+
+typedef int int;
+
+// sm: so far I've only seen 'int int' in the wild, though it is
+// true that gcc accepts more than that
+//typedef int float;              // !
+//typedef unsigned int unsigned int;

Added: vendor/elsa/current/elsa/in/c/dC0025.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0025.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0025.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+struct info_t {};
+int main ();
+int main (ac, av)
+     int ac;
+{}

Added: vendor/elsa/current/elsa/in/c/dC0026.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0026.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0026.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// dC0026.c
+// implicit int in K&R decl
+
+void pack12 (p, n, last)
+     register char *p;
+     register /*implicit-int*/ n;
+     int last;
+{}

Added: vendor/elsa/current/elsa/in/c/dC0027.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0027.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0027.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+void mbcheck () {
+  register int i, j, restrict;
+  for (i = 1; i < 9; i++) {}
+}

Added: vendor/elsa/current/elsa/in/c/dC0028.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0028.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0028.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+typedef float float4;
+
+long numeric_out () {
+  (float4)
+   (
+    ((union {unsigned __l; float __d;}) {__l: 0x7fc00000UL})
+    .__d
+    );
+}

Added: vendor/elsa/current/elsa/in/c/dC0029.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0029.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0029.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+int restrict (d, ts)
+  int d;
+{}

Added: vendor/elsa/current/elsa/in/c/dC0030.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0030.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0030.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+void f() {
+  int a;
+  a < 0 || 1 > 2 ||
+    a < 3 || 4 > (5) ||
+    6 < 7 || 8 > 9 ||
+    10 < 11 || 12 > 13;
+}

Added: vendor/elsa/current/elsa/in/c/dC0031.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0031.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0031.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+void f() {
+  int icnt;
+  sizeof (int[icnt]);
+  __alignof__ (int[icnt]);
+}

Added: vendor/elsa/current/elsa/in/c/dC0032.c
===================================================================
--- vendor/elsa/current/elsa/in/c/dC0032.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/dC0032.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+//  /home/dsw/oink_extra/ballAruns/tmpfiles/./oaf-0.6.10-5/ac-corba-hKmB.i:4985:57: error: reprSize of a sizeless array
+
+// Open array: you can have an array of no size in a struct and it
+// counts as 0.  It is even legal if it is not at the end!
+
+//  #include <stdio.h>
+struct foo {
+  int x;
+  char a[];                     // No size
+  // dsw: hmm, not anymore
+  //  double y;                     // can even have stuff afterward!
+};
+
+struct bar {
+  int x;
+  // no array here at all
+//    char a[];                     // No size
+  double y;
+};
+
+int main() {
+  // gcc 3.4.0 on my x86 machine at least says these both have size
+  // 12.
+//    printf("sizeof(foo) %d\n", sizeof(foo));
+//    printf("sizeof(bar) %d\n", sizeof(bar));
+  // force its size to be computed
+  int x = sizeof(struct foo);
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/c/k0001.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0001.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0001.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// apparently this is legal C (at least gcc -pedantic accepts it)
+
+// originally found in package e2fsprogs
+
+// ERR-MATCH: Parse error.*at long$
+
+typedef int fooint;
+
+// sm: I copied this test to in/gnu/dC0014.c; now the
+// present test is to ensure this syntax is *not* allowed
+// in ANSI mode
+//ERROR(1): typedef fooint long /*omitted*/;
+//ERROR(2): typedef fooint long blah;

Added: vendor/elsa/current/elsa/in/c/k0002.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0002.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0002.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// error: attempt to create an object of incomplete class `S'
+
+// originally found in package diff
+
+// ERR-MATCH: create incomplete class
+
+// ok at global scope
+
+struct S s;
+
+// not ok if static (well, gcc allows it, so whatever)
+//static struct S s3;
+
+void foo()
+{
+  // not ok in local scope
+  //ERROR(1): struct S s2;
+}
+
+struct S {};

Added: vendor/elsa/current/elsa/in/c/k0003.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0003.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0003.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// old-style function decl with parentheses around func name
+
+// originally found in package bash
+
+// error: Parse error (state 264) at int
+
+// ERR-MATCH: state 264
+
+int (foo) (c)
+    int c;
+{
+}

Added: vendor/elsa/current/elsa/in/c/k0003a.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0003a.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0003a.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// old-style function decl with parentheses around func name, returning a
+// struct-typedef
+
+// "WARNING: there is no action to merge nonterm KandRFunctionDefinition"
+
+// originally found in package gcl
+
+// ERR-MATCH: merge nonterm KandRFunctionDefinition
+
+typedef struct {} S;
+
+S (foo)(x)
+    int x;
+{
+}
+
+
+// similar, but this time using implicit-int
+/*implint*/ functionName(paramName)
+  int paramName;
+{}

Added: vendor/elsa/current/elsa/in/c/k0004.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0004.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0004.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// there is no action to merge nonterm MemberDeclaration
+
+// originally found in package tcl8.4
+
+// ERR-MATCH: merge nonterm MemberDeclaration
+
+typedef void (*func) ();
+struct S {
+    func (*proc);
+};

Added: vendor/elsa/current/elsa/in/c/k0005.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0005.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0005.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// error: multiply defined enum `option'
+
+// originally found in package tcl8.4
+
+// ERR-MATCH: multiply defined enum
+
+void foo()
+{
+    enum option { a=1 };
+    if(1) {
+        enum option { a=2 };
+    }
+}

Added: vendor/elsa/current/elsa/in/c/k0006.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0006.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0006.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// static inline function implicitly returning int
+
+// originally found in package framerd_2.4.1-1.1
+
+// a.i:4:1: Parse error (state 954) at {
+
+// ERR-MATCH: Parse error.*at {
+
+static inline foo()
+{
+    return 0;
+}
+
+inline static bar()
+{
+    return 0;
+}
+
+const inline static f1()
+{
+    return 0;
+}
+
+int main()
+{
+    return foo();
+}

Added: vendor/elsa/current/elsa/in/c/k0006a.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0006a.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0006a.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// static inline function implicitly returning int, old-style param decl
+
+// originally found in package xview
+
+// a.i:2:5: Parse error (state 254) at int
+
+// ERR-MATCH: Parse error.*at <name>
+
+extern func1(param)
+    int param;
+{
+    return param;
+}
+
+inline func2(param)
+    int param;
+{
+    return param;
+}
+
+static inline func3(param)
+    int param;
+{
+    return param;
+}
+
+inline static func4(param)
+    int param;
+{
+    return param;
+}
+
+const inline func5(param)
+    int param;
+{
+    return param;
+}

Added: vendor/elsa/current/elsa/in/c/k0007.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0007.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0007.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// duplicate modifiers in C as warning, not error (?)
+
+// originally found in package ffmpeg_0.cvs20050108-1
+
+// a.i:2:1: error: duplicate modifier: const
+
+// ERR-MATCH: duplicate modifier:
+
+const const int x;
+
+//ERROR(1): signed signed int y;

Added: vendor/elsa/current/elsa/in/c/k0008.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0008.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0008.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// function call vs type-cast ambiguity
+
+// this happens with 5 nested func calls, but not 4 or less.
+
+// originally found in package emacs21_21.3+1-8
+
+// a.i:10:25: error: variable name `func' used as if it were a type
+// a.i:10:13: error: variable name `func' used as if it were a type
+// a.i:10:19: error: variable name `func' used as if it were a type
+// Assertion failed: unexpected ASTTypeId ambiguity, file cc_tcheck.cc line 864
+
+// ERR-MATCH: as if it were a type
+
+int func(int x) {
+    return x;
+}
+
+int main()
+{
+    int foo;
+    return (func (func (func (func (foo))))) + 0;
+}

Added: vendor/elsa/current/elsa/in/c/k0009.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0009.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0009.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// func returning array of function pointers with old-style parm list
+
+// originally found in package eli_4.4.1-1
+
+// a.i:4:1: Parse error (state 312) at int
+
+long (*func(var))[42]
+    int var;
+{
+    return 0;
+}

Added: vendor/elsa/current/elsa/in/c/k0010.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0010.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0010.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// 'and' etc. not keywords in C
+
+// originally found in package
+
+// In state 86, I expected one of these tokens:
+//   <name>, auto, bool, char, const, double, extern, float, friend, inline, int, long, mutable, operator, register, short, signed, static, template, typedef, unsigned, virtual, void, volatile, wchar_t, (, ), [, ::, ~, &, *, >, ,, ;, __attribute__, restrict,
+// a.i:4:9: Parse error (state 86) at !
+
+// ERR-MATCH:
+
+int main() {
+    int not;
+    int and;
+    return 0;
+}

Added: vendor/elsa/current/elsa/in/c/k0011.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0011.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0011.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// c/k0011.c is the same file as k0011.cc, but it fails with -tr c_lang
+
+// error: more than one ambiguous alternative succeeds
+
+// originally found in package bzip2
+
+// ERR-MATCH: (cannot evaluate.*as a template integer argument|cannot apply template args to non-template)
+
+struct S{ int z; } *s;
+
+int foo() {
+    int x, y;
+
+    s->z < 1 || 2 > (3);
+    s->z < 1 && 2 > (3);
+
+    x < 1 || y > (3);
+    x < 1 && y > (3);
+
+    x < 1 || 2 > (3);
+    x < 1 && y > (3);
+}

Added: vendor/elsa/current/elsa/in/c/k0012.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0012.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0012.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+struct S {
+    int a;
+};
+
+struct S foo () {
+    struct S s;
+    int i;
+    s.a = i;
+    return s;
+}
+
+int main()
+{
+    int u;
+    u = foo().a;
+}

Added: vendor/elsa/current/elsa/in/c/k0013.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0013.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0013.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// enum variable declared earlier as int
+
+// originally found in package workman
+
+// a.i:7:13: error: prior declaration of `foo' at a.i:5:12 had type `int', but this one uses `enum MyEnum'
+
+// ERR-MATCH: prior declaration of `.*?' at .*? had type `int', but this one uses `enum .*?'
+
+enum MyEnum { DUMMY_WHICH_MUST_BE_NEGATIVE = -1, DUMMY2 };
+
+extern int foo;
+
+enum MyEnum foo = DUMMY2;
+
+// related: the unsigned version when no negative enumerators
+enum E2 { blah };
+extern unsigned int e2;
+enum E2 e2;

Added: vendor/elsa/current/elsa/in/c/k0014.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0014.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0014.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// offsetof cannot be assumed to be 0 (evaluated e.g. in case labels)
+
+// originally found in package ''
+
+// a.i:11:5: error: division by zero
+
+// ERR-MATCH: division by zero
+
+struct S {
+  int foo1;
+  int foo2;
+};
+
+int main() {
+  switch (42) {
+  case 100 / ((int) & ((struct S*) 0)->foo2):
+    break;
+  }
+};

Added: vendor/elsa/current/elsa/in/c/k0015.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0015.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0015.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// variable-sized character buffer in function-local struct using same name
+// for size as a member variable and another variable in outside scope
+
+// originally found in package 'rng-tools_2-unofficial-mt.10-1'
+
+// a.i:10:19: error: can only use 'this' in a nonstatic method
+
+// ERR-MATCH: can only use .this. in a nonstatic method
+
+int main()
+{
+  int size = 42;
+
+  struct S {
+    int size;
+    unsigned char data[size];
+  };
+}

Added: vendor/elsa/current/elsa/in/c/k0016.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0016.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0016.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// expression in compound initializer array index
+
+// originally found in package 'tcc'
+
+// ERR-MATCH: 48c58fcf-900a-4b17-bf13-17a2c93d799d
+
+char s[1] = { [(0+0)] = 1 };

Added: vendor/elsa/current/elsa/in/c/k0017.c
===================================================================
--- vendor/elsa/current/elsa/in/c/k0017.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/k0017.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// k0017.c:5:53: error: E_fieldAcc is not constEval'able
+
+// from aio.c on IA-64.
+
+struct S {
+	int A[32];
+};
+
+long x[(((char *) &((struct S *) 0)->A[0]) - (char *) 0)];
+

Added: vendor/elsa/current/elsa/in/c/t0001.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0001.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0001.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// t0001.c
+// use some C++ keywords but expect them to be parsed as identifiers
+
+int template = 1;

Added: vendor/elsa/current/elsa/in/c/t0002.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0002.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0002.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0002.c
+// problem with enums?
+
+typedef int wchar_t;
+
+int mbtowc (int y, wchar_t *   __pwc);
+
+enum { A, B = A, };

Added: vendor/elsa/current/elsa/in/c/t0003.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0003.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0003.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0003.c
+// __func___
+
+char const *foo()
+{
+  return __func__;
+}
+

Added: vendor/elsa/current/elsa/in/c/t0004.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0004.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0004.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0004.c
+// non-inner struct
+
+struct Outer {
+  struct Inner {     // not really!
+    int x;
+  } is;
+  enum InnerEnum { InnerEnumerator } ie;
+  int y;
+  
+  // not legal C, but I wanted to test the mechanism that pushes
+  // type definitions to the outer scope, so I'll leave it..
+  typedef int InnerTypedef;
+};
+
+int foo(struct Inner *i)
+{
+  enum InnerEnum gotcha;
+  InnerTypedef z;
+  return i->x + InnerEnumerator;
+}

Added: vendor/elsa/current/elsa/in/c/t0005.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0005.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0005.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// test constructs where doElaboration makes a difference and that are
+// still legal in C
+
+// implicit cdtors should not be being made
+struct A {
+  int x;
+};
+
+struct A f() {
+  // declarator should not make cdtor statements
+  struct A a2;
+  struct A a3 = {1};            // IN_compound
+  
+  // sm: commented this out because it's a gnu extension.. I suppose
+  // we could have a special directory for GNU/C tests..
+  //struct A a4 = (struct A) {2};
+
+  struct A a5;
+  struct A a6 = a5;             // IN_expr
+  return a2;
+}

Added: vendor/elsa/current/elsa/in/c/t0006.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0006.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0006.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0006.c
+// implicit return type of int
+
+// ordinary
+int f(int x)
+{
+  return 1;
+}
+
+// implicit
+g(int x)
+{
+  return 2;
+}
+
+// they are the same
+void foo()
+{
+  __elsa_checkType(f, g);
+}
+
+
+typedef int INT;
+typedef int h;
+
+void bar()
+{
+  // ambiguity between statement and declaration b/c of implint
+  extern h(INT);
+}
+
+
+
+

Added: vendor/elsa/current/elsa/in/c/t0007.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0007.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0007.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0007.c
+// GNU dynamically sized arrays
+
+void f(int sz)
+{
+  int arr[sz];
+}
+
+// not ok for globals
+int blah;
+//ERROR(1): int dorf[blah];

Added: vendor/elsa/current/elsa/in/c/t0008.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0008.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0008.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0008.c
+// in C it is legal to have a structure member with the same
+// name as the class (compare to in/d0087.cc)
+
+struct X {
+  int X;     // ok
+
+  int Y;     // ok too
+};

Added: vendor/elsa/current/elsa/in/c/t0009.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0009.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0009.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0009.c
+// oink/test2-cc/voidconditional.c
+
+// sm: I do not believe this is valid C99, but gcc accepts it ...
+
+void driv(void)
+{
+  1 ? 1 : driv();
+}
+
+
+void main(void)
+{
+  driv();
+}
+

Added: vendor/elsa/current/elsa/in/c/t0010.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0010.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0010.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0010.c
+// unsigned long and void* as operands to ?:
+
+// from mozilla/gfx/src/xlibrgb/xlibrgb.c
+
+unsigned long foo(int y)
+{
+  unsigned long x;
+
+  // gcc doesn't seem to care that this is a null pointer constant
+  return y? x : (void*)0;
+}
+
+

Added: vendor/elsa/current/elsa/in/c/t0011.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0011.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0011.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0011.c
+// implicit function declaration
+
+//ERROR(1): int g(int,int);
+
+void f()
+{
+  g(3);
+}
+
+void f2()
+{
+  g(3,4,5,6);
+}
+
+int g();
+
+int g(int x)
+{
+  return x;
+}
+
+int g(int);
+
+
+//ERROR(2): int h(int x, ...);
+
+int h();
+
+int h(int, int);

Added: vendor/elsa/current/elsa/in/c/t0012.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0012.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0012.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0012.c
+// generalized ?: lvalues
+
+void f(int x)
+{
+  int i,j,k;
+
+  __elsa_checkType(x? i : j, k);       // lval
+  __elsa_checkType(x? (i+1) : j, 1);   // rval
+  __elsa_checkType(x? i : (j+1), 1);   // rval
+}

Added: vendor/elsa/current/elsa/in/c/t0013.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0013.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0013.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// t0013.c
+// multiply-defined function
+
+int f(int) { return 1; }
+
+//ERROR(1): int f(int) { return 2; }

Added: vendor/elsa/current/elsa/in/c/t0014.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0014.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0014.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0014.c
+// type of character literals
+
+typedef long wchar_t;
+
+void foo()
+{
+  __elsa_checkType('a', (int)0);
+  __elsa_checkType('ab', (int)0);
+  __elsa_checkType(L'a', (wchar_t)0);
+}

Added: vendor/elsa/current/elsa/in/c/t0015.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0015.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0015.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0015.c
+// ambiguous FunctionDefinition?
+
+ttputc(c)
+{
+    return 3;
+}

Added: vendor/elsa/current/elsa/in/c/t0016.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0016.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0016.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0016.c
+// function prototype and definition with different parameter lists
+
+int fallowc(int);
+
+fallowc(c)
+char c;        // "default argument promotions" make this int
+{
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/c/t0017.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0017.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0017.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0017.c
+// tricky use of a name in a way that looks somewhat like
+// a constructor declaration
+
+typedef struct Foo *Foo;
+
+struct Foo {
+  Foo x;
+  int q;
+};

Added: vendor/elsa/current/elsa/in/c/t0018.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0018.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0018.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0018.c
+// ambiguity involving attributed labels vs. implicit-int
+
+void foo(int x, int y)
+{
+  label: __attribute__ ((__unused__))
+
+  foo (x, y - 0 );
+}

Added: vendor/elsa/current/elsa/in/c/t0019.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0019.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0019.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0019.c
+// like in/t0414.cc but for C
+
+struct S { int x; };
+typedef struct S S;
+
+void foo()
+{
+  struct S s;
+}

Added: vendor/elsa/current/elsa/in/c/t0020.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0020.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0020.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0020.c
+// ansi C coverage
+
+int     //ERRORIFMISSING(1): required
+foo()
+{
+  return 2;
+}
+
+void char1()
+{
+  int ch;
+
+  // illegal because wchar_t not defined yet
+  //ERROR(2): ch = L'x';
+}
+
+typedef int wchar_t;
+
+void char2()
+{
+  int ch;
+
+  ch = L'x';   // ok
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/c/t0021.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0021.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0021.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0021.c
+// c89 coverage
+
+int foo()
+{
+  // implicit decl
+  return not_declared();
+}

Added: vendor/elsa/current/elsa/in/c/t0022.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0022.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0022.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0022.c
+// differing prototypes for main()
+
+//ERROR(1): int main(int);
+//ERROR(2): int main;
+
+int main(int, char**, char **);
+int main(int, char**);
+int main(int, char*[]);
+//ERROR(3): int main(int, char**[]);
+int main(int, char**)
+  { return 0; }          //ERRORIFMISSING(4): avoid duplicate error
+
+//ERROR(4): ; int main;
+
+//int main();
+//int main(int);

Added: vendor/elsa/current/elsa/in/c/t0023.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0023.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0023.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+typedef int x;
+void f (y)
+     register x/*type*/ (y)/*parenthesized declarator*/;
+{
+}
+
+
+// hmm... gcc rejects this one, but I don't see why
+//  typedef int y;
+//  void g (z)
+//       register /*implicit-int*/ z/*func-name*/ (y/*parameter type*/)
+//  {}

Added: vendor/elsa/current/elsa/in/c/t0024.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0024.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0024.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0024.c
+// use of 'std' as an identifier
+
+enum { std };
+
+int foo()
+{
+  return std;
+}

Added: vendor/elsa/current/elsa/in/c/t0025.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0025.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0025.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0025.c
+// pointer and null ptr constant args to ?:
+
+typedef struct A {
+  int x;
+} A;
+
+void foo(int c, A *a)
+{
+  (c? 0 : a)->x;
+  (c? a : 0)->x;
+
+  (c? (void*)0 : a)->x;
+  (c? a : (void*)0)->x;
+}

Added: vendor/elsa/current/elsa/in/c/t0026.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0026.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0026.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0026.c
+// decls differ by cv-qualification of return type
+
+// Though both GCC and ICC accept this, I don't know why.
+
+// I think it should be illegal because:
+//   - 6.7p4 says declarations of same entity must use 
+//     compatible types
+//   - 6.7.5.3p15 says compatible function types require
+//     compatible return types
+//   - 6.7.3p9 says that for two types to be compatible,
+//     the qualifiers must be identical
+
+// Oh well, Elsa will accept it.
+
+typedef volatile int intfn();
+
+intfn foo;
+
+int foo(int x)
+{}

Added: vendor/elsa/current/elsa/in/c/t0027.c
===================================================================
--- vendor/elsa/current/elsa/in/c/t0027.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c/t0027.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+/* t0027.c
+ * pass structure by value */
+
+typedef struct S {
+  int x;
+  int y;
+} S;
+
+int f(S s)
+{
+  return s.x + s.y;
+}
+
+int g()
+{
+  S s;
+  s.x = 5;
+  s.y = 7;
+  return f(s);
+}
+
+/* EOF */

Added: vendor/elsa/current/elsa/in/c99/d0077.c
===================================================================
--- vendor/elsa/current/elsa/in/c99/d0077.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c99/d0077.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+//  ./zebra-0.93b-1/bgpd-h3ia.i.c_out:48:/home/dsw/oink_extra/ballAruns/tmpfiles/./zebra-0.93b-1/bgpd-h3ia.i:10087:125: Parse error (state 286) at __restrict__
+
+// Test qualifiers in array brackets; Ben tells me that this is a
+// C99-ism.  "__restrict" is implemented as a gnu extension so I have
+// it commented out for now since I don't see an elsa/c99.gr
+
+extern int regexec
+  (
+   int [/*__restrict*/ const volatile], // abstract
+   int __pmatch [const /*__restrict*/ volatile], // direct
+   int __eflags);

Added: vendor/elsa/current/elsa/in/c99/n0001.c
===================================================================
--- vendor/elsa/current/elsa/in/c99/n0001.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c99/n0001.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+/* n0001.c */
+/* _Bool */
+
+_Bool b;

Added: vendor/elsa/current/elsa/in/c99/n0002.c
===================================================================
--- vendor/elsa/current/elsa/in/c99/n0002.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c99/n0002.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// n0002.c
+// _Complex and _Imaginary
+
+_Complex float a;
+float _Complex b;
+_Complex double c;
+_Complex long double d;
+
+_Imaginary float a2;
+float _Imaginary b2;
+_Imaginary double c2;
+_Imaginary long double d2;

Added: vendor/elsa/current/elsa/in/c99/t0133.c
===================================================================
--- vendor/elsa/current/elsa/in/c99/t0133.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/c99/t0133.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,122 @@
+// test compound initializers according to C99 p.125
+void a() {
+  // non-designated
+  int *ip = 0;         // NULL
+  struct foo {int x; int *xp; int y;};
+  struct foo f = {1, ip, 2};
+
+  // designated
+  struct foo2 {int x2; int *xp2; int y2;};
+  struct foo2 f2 = {y2:2, x2:1, xp2:ip};
+
+
+  // non-designated compound literal
+  struct fooB {int xB; int *xpB; int yB;};
+  struct fooB fB;
+  fB = (struct fooB) {1, ip, 2};
+
+  // non-designated compound literal
+  struct foo2B {int x2B; int *xp2B; int y2B;};
+  struct foo2B f2B;
+  f2B = (struct foo2B) {y2B:2, x2B:1, xp2B:ip};
+
+  // embedded int array and struct
+  // Skip over vars that are methods/ctors/dtors
+  struct foo3 {int x3; int y3;};
+  struct foo4 {int x4; int y4;};
+  struct gronk {
+    struct foo3 f3;
+    int z[3];
+    struct foo4 f4;
+  };
+  struct gronk g = {
+    1, 2,        // f3
+    3, 4, 5,     // z
+    6, 7,        // f4
+  };
+
+  // embedded and nested int array and struct
+  struct foo3b {int x3b; int y3b;};
+  struct foo4b {int x4b; int y4b;};
+  struct gronkb {
+    struct foo3b f3b;
+    int zb[3];
+    struct foo4b f4b;
+  };
+  struct gronkb gb = {
+    1, 2,        // f3b
+    {3, 4, 5,},  // zb
+    {6, 7,}      // f4b
+  };
+
+  // nested int array and struct; top level designated
+  struct foo3c {int x3c; int y3c;};
+  struct foo4c {int x4c; int y4c;};
+  struct gronkc {
+    struct foo3c f3c;
+    int zc[3];
+    struct foo4c f4c;
+  };
+  struct gronkc gc = {
+    zc:{3, 4, 5,},
+    f4c:{6, 7,},
+    f3c:{y3c:2, x3c:1},
+  };
+
+  // array with no size
+  struct foo10d {int xd; int yd[];};
+  struct foo10d f10d = {3, 4, 5, 6};
+  struct foo10e {int xe; int ye[]; int ze; int z2e;};
+  struct foo10e f10e = {3, {4, 5}, 6, 7};
+}
+
+// testing nontrivial designated initializers
+void b() {
+  struct foo {
+    int fooa;                   // (6)
+    int foor;
+    int foox;                   // (5)
+    double fooy;
+    int fooz[2];                // (1)
+    double foow[];              // (2)
+    int fooq;
+  };
+  struct gronk {
+    struct foo f1[];
+    int gronk1;
+    struct {
+      int x;
+      double y;                 // (3)
+      int z[];                  // (4)
+      int w;
+    } f2;
+    double gronk2;
+    struct foo f3[];
+  };
+  struct bar {
+    struct gronk g[];
+    struct foo f;
+    struct gronk g2;
+  };
+
+  struct bar b[] = {
+    [3].g[2].f1[2].fooz[1] = 1, 2, // (1)
+    3,                          // should be foo.foow (2)
+    [2].g[2].f2.y = 3.2,        // anon(f2).y (3)
+    4, 5, 6, 7,                 // anon(f2).z (4)
+    [4] = {                     // current_object == bar now
+      .g2.f3 = {                // current_object == gronk.f3 now
+        [2] = {
+          .foox = 18            // foo.foox (5)
+        }
+      }
+    },
+    {
+      .f = 9                    // bar[5].f, the first elt of which is fooa (6)
+    }
+  };
+}
+
+void c() {
+  int x[] = { [1 ... 3] = 8 };
+}

Added: vendor/elsa/current/elsa/in/d0001.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0001.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0001.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// d0001.cc
+// overload resolution problem with arrays/references
+
+struct C {
+  static int strcmp (char *s1, char *s2);
+  static int strcmp (int *s1, int *s2);
+};
+void f () {
+  int *k;
+  int m[1];
+  //int *m;
+  C::strcmp(k, m);
+}

Added: vendor/elsa/current/elsa/in/d0002.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0002.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0002.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+struct _IO_FILE {
+  int unbuffered () {}
+  void unbuffered (int)   {
+    unbuffered ();
+  }
+};

Added: vendor/elsa/current/elsa/in/d0003.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0003.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0003.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+struct nsAString {
+  void Assign (const nsAString & aReadable) {}
+  void Assign (char aChar) {}
+  void f (const nsAString & aReadable) {
+    Assign (aReadable);
+  }
+};

Added: vendor/elsa/current/elsa/in/d0004.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0004.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0004.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+template < class T > struct already_AddRefed {};
+inline const int do_QueryInterface (int *aRawPtr, int *error = 0);
+template < class T > inline void do_QueryInterface (already_AddRefed < T > &);
+template < class T > class nsCOMPtr {
+  void Assert_NoQueryNeeded () {
+    T* mRawPtr;                 // added, since there was no declaration for mRawPtr
+    do_QueryInterface (mRawPtr);
+  }
+};

Added: vendor/elsa/current/elsa/in/d0005.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0005.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0005.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+void g ();
+void g (int *);
+
+template <class T> T m () {}
+
+void r() {
+  g(m<int*>());
+}

Added: vendor/elsa/current/elsa/in/d0006.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0006.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0006.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+struct C {
+  static int strcmp (char *s1, char *s2);
+  static int strcmp (int *s1, int *s2);
+};
+void f () {
+  int *k;
+  int m[1];
+  C::strcmp(k, m);
+}

Added: vendor/elsa/current/elsa/in/d0007.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0007.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0007.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+struct A {};
+struct C : A {};
+C g();
+void f (const A & x);
+void f ();
+int main () {
+  f (g ());
+}

Added: vendor/elsa/current/elsa/in/d0008.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0008.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0008.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// d0008.cc
+// tricky sequence of conversions, involving inheriting from template param
+
+// template inheriting from its parameter
+template <class T>
+struct D : T {};
+
+// mostly irrelevant
+struct Q {};
+
+// template with conversion operator to D<T>*
+template <class T>
+struct C {
+  C (Q &);
+  operator D<T> *();
+};
+
+struct A {};
+struct B {};
+
+// overloaded 'g'
+int g(A*);
+int g(B*);
+
+void f()
+{
+  Q q;
+  C<B> r(q);
+
+  // Force an instantiation of D<B>; does this help?
+  //
+  // Yes, this makes the conversion available.  Now to find
+  // out how to make it available w/o a forced instantiation...
+  //
+  // Got it, 14.7.1 para 4 says what to do, and it's implemented
+  // in overload.cc, look for 'ensureClassBodyInstantiated'.
+  //D<B> dummy;
+
+  // expected sequence of conversions:
+  //   'r' is of type C<B>, so can convert to D<B>* (user defined conv)
+  //   D<B> inherits from B, so D<B> can convert to B* (derived to base)
+  //   B* is one of the allowed params of 'g'
+  g(r);
+}

Added: vendor/elsa/current/elsa/in/d0009.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0009.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0009.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+void f();
+struct A {
+  A() {f();}
+  char x;
+  char &operator[] (unsigned int i) {
+    return x;
+  }
+  void g(int i) {
+    (*this)[i];
+  }
+};

Added: vendor/elsa/current/elsa/in/d0010.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0010.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0010.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+struct A {};
+template <class T> struct B {};
+template <class T> struct C {
+  operator void **();
+};
+template <class T> C<T> f(B<T>&) {}
+struct D {
+  static void g(A &, void **);
+  static void g(char *, void **);
+};
+int main () {
+  B<A> x;
+  A y;
+  D::g(y, f(x));
+}

Added: vendor/elsa/current/elsa/in/d0011.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0011.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0011.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+struct A {};
+template <class T> struct B {};
+struct C {
+  operator void **();
+};
+template <class T> C f(B<T>&) {}
+struct D {
+  static void g(A &, void **);
+  static void g(char *, void **);
+};
+int main () {
+  B<A> x;
+  A y;
+  D::g(y, f(x));
+}

Added: vendor/elsa/current/elsa/in/d0012.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0012.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0012.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+struct C {
+  operator int();
+};
+void g(int, int);
+void g(int, double);
+int main() {
+  C c;
+  g(c, 1);
+}

Added: vendor/elsa/current/elsa/in/d0013.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0013.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0013.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+struct A {};
+template <class T> struct B {};
+template <class T> struct C {
+  operator void **();
+};
+template <class T> C<T> f(B<T>&) {}
+void g(void **, double);
+void g(void **, int);
+int main() {
+  B<A> x;
+  g(f(x), 1);
+}

Added: vendor/elsa/current/elsa/in/d0014.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0014.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0014.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+/***/

Added: vendor/elsa/current/elsa/in/d0015.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0015.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0015.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+//ERROR(1): /* 

Added: vendor/elsa/current/elsa/in/d0016.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0016.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0016.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// this test was isolated from nsAtomTable.i; a change was made in
+// nsAtomTable.i to remove the failure here, but the fix was NOT that
+// which I present here; the fix was to just comment out the line
+// corresponding to the line at the bottom here where the ctor is
+// actually called; this was done because attempting to fix it the way
+// I have here somehow allowed another failure, where as the way I
+// fixed it removed all failures
+
+struct nsACString;
+struct nsAString;
+template <class CharT> struct nsStringTraits {
+  typedef nsAString abstract_string_type;
+};
+template <> struct nsStringTraits<char> {
+  typedef nsACString abstract_string_type;
+};
+template <class CharT> struct nsReadingIterator {
+  // if you replace this line
+  typedef typename nsStringTraits <CharT>::abstract_string_type abstract_string_type;
+  // with this line
+//    typedef nsACString abstract_string_type;
+  // then the test passes; this seems to be due to the way implicit
+  // copy ctors are added to classes; the line marked below is calling
+  // a copy ctor that seems to be missing
+
+  const abstract_string_type & string () const {}
+};
+struct nsACString {
+  typedef nsACString abstract_string_type;
+  typedef nsReadingIterator<char> const_iterator;
+};
+struct nsDependentCSubstring:nsACString {
+  const abstract_string_type & mString;
+  nsDependentCSubstring
+    (const const_iterator & aStart,
+     const const_iterator & aEnd)
+     // it seems that the copy ctor missing here for this initializer
+     // call
+      : mString (aStart.string ()) {}
+};

Added: vendor/elsa/current/elsa/in/d0017.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0017.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0017.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+int main() {
+  static const char sName[] = "SOAPPropertyBag" ;
+  sizeof(sName);
+}

Added: vendor/elsa/current/elsa/in/d0018.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0018.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0018.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// From in/big/nsAtomTable.i
+template <class T> struct f {};
+template <class T> class R {
+  f<T> m;
+};
+int d(R<int>&);

Added: vendor/elsa/current/elsa/in/d0019.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0019.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0019.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// minimized from in/big/nsCLiveconnectFactory.i
+
+template <class T>
+struct D : T {};
+
+struct Q {};
+
+template <class T>
+struct C {
+  C (Q const &h);
+  operator D<T> *();
+};
+
+struct N {};
+
+Q d(N *a);
+int s(N *lhs, N *rhs) {
+  C<N> (d (rhs));
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/d0020.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0020.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0020.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// test that a no-arg new works
+struct A {
+};
+
+int main() {
+  A *a = new A;
+}

Added: vendor/elsa/current/elsa/in/d0021.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0021.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0021.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+class S {};
+template <class T> class C {};
+template <> struct C <S> {};
+struct G {
+  C<S> m;
+};

Added: vendor/elsa/current/elsa/in/d0022.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0022.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0022.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+struct B {
+  B(int);
+};
+int main() {
+  //ERROR(1): B b;      // no default ctor
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/d0023.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0023.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0023.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+struct stat {};
+extern void stat ();
+void f() {
+  struct stat st;
+}

Added: vendor/elsa/current/elsa/in/d0024.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0024.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0024.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+extern void stat ();
+struct stat {};
+void f() {
+  struct stat st;
+}

Added: vendor/elsa/current/elsa/in/d0025.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0025.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0025.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+template <class T> struct Foo {};
+int main() {
+  Foo<int> h;
+}

Added: vendor/elsa/current/elsa/in/d0026.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0026.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0026.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+template <class T> struct F {};
+template <class T> struct I {
+  F<T> m;
+};
+struct C {
+  typedef short char_type;
+  typedef F<char_type> f;       // commenting this line out fixes it!
+  typedef I<char_type> i;
+};

Added: vendor/elsa/current/elsa/in/d0027.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0027.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0027.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+struct B {};
+struct C {
+  C (B *a);
+};
+C f = new B;
+C f2(new B);

Added: vendor/elsa/current/elsa/in/d0028.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0028.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0028.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+struct S {};
+struct N {
+  void a() {
+    new S[2];
+  }
+};

Added: vendor/elsa/current/elsa/in/d0029.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0029.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0029.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+struct S {
+  S (int);
+};
+struct T{
+  T(S const &);
+};
+void f() {
+  T x(S(1));
+}

Added: vendor/elsa/current/elsa/in/d0030.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0030.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0030.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// how come no FullExpression ?
+struct A{};
+void f() {
+  A const &a = A();
+}

Added: vendor/elsa/current/elsa/in/d0031.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0031.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0031.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// how come no FullExpression ?
+struct A{
+  operator int();
+};
+void f() {
+  int x;
+  x = A();
+}

Added: vendor/elsa/current/elsa/in/d0032.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0032.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0032.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// test function local statics
+struct A{};
+void f() {
+  static A a;
+  A a2;
+}

Added: vendor/elsa/current/elsa/in/d0034.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0034.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0034.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+struct A {
+  struct B {};
+  // member function declaration parameters should NOT get cdtors
+  void f(B a);
+};

Added: vendor/elsa/current/elsa/in/d0035.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0035.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0035.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+struct A {
+  struct B {};
+  // member function definitions parameters SHOULD get cdtors
+  void f2(B a){}
+};

Added: vendor/elsa/current/elsa/in/d0036.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0036.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0036.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+struct A{};
+// top level function definitions parameters should NOT get cdtors
+void f(A a);

Added: vendor/elsa/current/elsa/in/d0037.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0037.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0037.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+struct A{};
+// top level function definitions parameters SHOULD get cdtors
+void f(A a) {}

Added: vendor/elsa/current/elsa/in/d0038.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0038.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0038.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// test pass by value
+class A{};
+void g(A a) {
+}
+void f() {
+  A a2;
+  g(a2);
+}

Added: vendor/elsa/current/elsa/in/d0039.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0039.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0039.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// test throw by value
+struct A{};
+void f() {
+  A a;
+  throw a;
+}
+
+struct B{};
+void g() {
+  throw B();
+}

Added: vendor/elsa/current/elsa/in/d0040.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0040.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0040.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// isolated from nsCLiveconnectFactory.i:5637
+// NOTE: this is not legal C++
+struct ip_opts {
+  char ip_opts[40];		 
+};

Added: vendor/elsa/current/elsa/in/d0041.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0041.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0041.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// modified version of d0040.cc where I attempt to explicitly put in
+// the implicit copy ctor; g++ won't compile this
+// NOTE: this is not legal C++
+struct ip_opts {
+  char ip_opts[40];
+  ip_opts(ip_opts const &other)
+    : ip_opts(other.ip_opts)
+  {}
+};

Added: vendor/elsa/current/elsa/in/d0046.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0046.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0046.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// minimized from nsAtomTable.i
+typedef int A;
+
+template <class T>
+struct B {};
+
+template <class T2>
+struct B<T2*> {
+  int f(T2*) {
+    return A(3);
+  }
+};

Added: vendor/elsa/current/elsa/in/d0046elab.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0046elab.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0046elab.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// this is the elaborated version of d0046.cc; that is, I put in the
+// copy ctors, but not the copy assign operator, since those are the
+// conditions under which this test originally exposed a bug; this was
+// elaborated using the prettyPrinter but then hand edited.
+typedef int A;
+template <class T>
+struct B {
+  inline B(B<T> const &__other) {
+  }
+};
+template <class T2>
+struct B<T2 *> {
+  inline int f(/*m: template <class T2> struct B & */ T2 */*anon*/) {
+    return A(3);
+  }
+  inline B(B<T2*> const &__other) {
+  }
+};

Added: vendor/elsa/current/elsa/in/d0047.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0047.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0047.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// from nsCLiveconnectFactory.i
+template <class T>
+struct E {
+  // if you remove this line and (1) below, error goes away; if you
+  // move it to the bottom of the class, error does not go away.
+  E (T *a);
+
+  // if you make this definition into a declaration one of the errors goes away
+  E (const E<T> &s) {}
+};
+
+// replacing int with a struct maintains the error
+E<int> q = new int;                 // (1)

Added: vendor/elsa/current/elsa/in/d0048.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0048.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0048.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// d0048.cc:9:1: error: ambiguous overload, no function is better than all others
+struct B {};
+
+struct C : B {
+  C & operator = (C const &s);
+  C & operator = (B const &t);
+};
+
+struct D : C {};

Added: vendor/elsa/current/elsa/in/d0048elab.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0048elab.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0048elab.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// d0048elab.cc:19:11: error: ambiguous overload, no function is better than all others
+struct B {
+  inline B(struct B const &__other) {
+  }
+  inline struct B &operator=(/*m: struct B & */ struct B const &__other) {
+    return (* (this));
+  }
+};
+struct C:B {
+  struct C &operator=(/*m: struct C & */ struct C const &s);
+  struct C &operator=(/*m: struct C & */ struct B const &t);
+  inline C(struct C const &__other):B ( (__other)) {
+  }
+};
+struct D:C {
+  inline D(struct D const &__other):C ( (__other)) {
+  }
+  inline struct D &operator=(/*m: struct D & */ struct D const &__other) {
+    this->C::operator=(__other); // NOTE: this line doesn't pretty print right so fixed by hand
+    return (* (this));
+  }
+};

Added: vendor/elsa/current/elsa/in/d0049.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0049.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0049.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// from nonport.i
+// error: there is no variable called `temp-name-1'
+struct A {};
+A f (A);
+A g() {
+  A o;
+  return f(o);
+}

Added: vendor/elsa/current/elsa/in/d0050.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0050.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0050.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// from nsAtomTable.i
+// error: ambiguous overload, no function is better than all others
+struct B {};
+
+struct C : B {
+  C & operator = (C const &s);
+  C & operator = (B const &t);
+};
+
+struct D : C {};

Added: vendor/elsa/current/elsa/in/d0050elab.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0050elab.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0050elab.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// ERR-MATCH: 63c0166a-1679-419b-8a73-55635a86b703
+
+// this is the elaborated version of d0050.cc; here, I put in the the
+// copy assign operator but not the copy assignment operator, since
+// those are the conditions under which this test originally exposed a
+// bug; this was elaborated using the prettyPrinter but then hand
+// edited.
+struct B {
+  inline B(B const &__other) {}
+};
+struct C:B {
+  C &operator=(/*m: struct C & */ C const &s);
+  C &operator=(/*m: struct C & */ B const &t);
+};
+struct D:C {
+  inline D &operator=(/*m: struct D & */ D const &__other) {
+    this->C::operator=(__other);
+    return *this;
+  }
+};

Added: vendor/elsa/current/elsa/in/d0051.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0051.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0051.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// Found a bug that we were attempting to assign const members in the
+// body of an implicitly generated copy assign operator.
+struct A {};
+struct B {
+  const A x;
+};

Added: vendor/elsa/current/elsa/in/d0051elab.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0051elab.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0051elab.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// This is the (wrongly) elaborated version of d0051.cc; that is this
+// code is wrong.  G++ complains correctly, but elsa still doesn't
+// find the error that is exhibited here.
+struct A {};
+struct B {
+  A
+  //ERROR(1): const
+    x;
+  B &operator =(B const &other) {
+    x = other.x;
+    return *this;
+  }
+};

Added: vendor/elsa/current/elsa/in/d0052.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0052.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0052.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// this used to cause a failure due to ambiguous syntax and no merge
+// action for the Condition nonterminal in the grammar: "WARNING:
+// there is no action to merge nonterm Condition"
+struct A{};
+int main() {
+  if (A *a = 0) {
+  }
+}

Added: vendor/elsa/current/elsa/in/d0053.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0053.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0053.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,282 @@
+// d0053.cc
+// test function template argument inference
+
+// The way that this works as a test is that template arugment
+// inference is the only way to get an argument for the template.
+// Therefore if it doesn't work, you will get an error that there was
+// an attempt to instantiate a template and no template argument was
+// provided for a template parameter.  An example is provided by the
+// call "g1b(a, a)"; it results in "error: No argument for parameter
+// `S'"
+
+// ---
+
+//  cppstd: 14.8.2.4 para 9:
+
+//  A template type argument T, a template template argument TT or a
+//  template non-type argument i can be deduced if P and A have one of
+//  the following forms.
+
+//      T
+//      cv-list T
+//      T*
+//      T&
+//      T[integer-constant]
+//      template-name<T> (where template-name refers to a class template)
+//      type(*)(T)
+//      T(*)()
+//      T(*)(T)
+//      T type:*
+//      type T::*
+//      T T::*
+//      T (type:*)()
+//      type (type::*)(T)
+//      T (T::*)()
+//      T (T::*)(T)
+//      type[i]
+//      template-name<i> (where template-name refers to a class template)
+//      TT<T>
+//      TT<i>
+//      TT<>
+
+//  where (T) represents argument lists where at least one arugment
+//  type contains a T, and () represents argument lists where no
+//  parameter contains a T.  Similarly, <T> represents template
+//  arugment lists wher at least one argument contians a T, <i>
+//  represents template argument lists where at least one argument
+//  contians an i and <> represents template argument lists where no
+//  argument contains a T or an i.
+
+// ---
+
+//      T
+template<class T> void g1(T x) {}
+
+template<class T, class S> void g1b(T x, T y) {}
+
+template<class T, class S> void g1c(T x, S y) {}
+
+//      cv-list T
+template<class T> void g2(T const volatile x) {}
+
+//      T*
+template<class T> void g3(T *x) {}
+
+//      T&
+template<class T> void g4(T &x) {}
+
+//      T[integer-constant]
+// NOTE: this is NOT the "type[i]" case; see below
+template<class T> void g5(T x[4]) {}
+
+//      template-name<T> (where template-name refers to a class template)
+template<class T> struct A1 {};
+//ERROR(8): template<class T> struct A1b {}; // distractor
+template<class T> void g6(A1<T> x) {}
+
+//      template-name<i> (where template-name refers to a class template)
+template<int J> struct A2 {};
+template<int I> void g7(A2<I> x) {}
+
+//      type(*)(T)
+template<class T> void g8( int(*f)(T x) ) {}
+
+//      T(*)()
+template<class T> void g9( T(*f)() ) {}
+
+// testing the combination?
+//      T(*)(T)
+template<class T> void g10( T(*f)(T x) ) {}
+
+//      T type::*
+struct A3 {};
+template<class T> void g11( T A3::*x ) {}
+
+//      type T::*
+template<class T> void g12( int T::*x ) {}
+
+// testing the combination?
+//      T T::*
+template<class T> void g13( T T::*x ) {}
+
+//      T (type::*)()
+template<class T> void g14( T (A3::*x)() ) {}
+
+//      type (type::*)(T)
+template<class T> void g15( A3 (A3::*x)(T y) ) {}
+
+//      T (T::*)()
+template<class T> void g16( T (T::*x)() ) {}
+
+// testing the combination?!
+//      T (T::*)(T)
+template<class T> void g17( T (T::*x)(T y) ) {}
+
+//      type[i]
+// 14 April 2004: Scott decided that this feature is more work than it
+// is worth so we omit it for now.
+// cppstd 14.8.2.4 para 13: Note: except for reference and pointer
+// types, a major array bound is not part of a function parameter type
+// and cannot be deduced from an argument.
+template<int i> void f1(int a[10][i]);
+template<int i> void f2(int a[i][20]);
+template<int i> void f3(int (&a)[i][20]);
+void g()
+{
+  int v[10][20];
+  // FIX: unimplemented
+//    f1(v);                        // OK: i deduced to be 20
+
+  // FIX: unimplemented
+//    f1<20>(v);                    // OK
+
+  // error: cannot deduce template-argument i
+  //ERROR(1): f2(v);
+  // FIX: unimplemented
+//    f2<10>(v);                    // OK
+
+  // FIX: unimplemented
+//    f3(v);                        // OK: i deduced to be 10
+}
+
+// FIX: unimplemented; implement when do template template arguments
+//      TT<T>
+//      TT<i>
+//      TT<>
+
+// --- test conversions; in contrast to the above, this section is not
+// meant to be exhaustive
+
+// convert an array to a pointer
+template<class T> void h1(T *x) {}
+
+// convert a function to a pointer to a function
+template<class T> void h2(T (*f)()) {}
+int f_h2();
+
+// --- test failure
+
+template<class T, class S> S j1(T x, T y) {}
+
+// --- main body that causes the above to be instantiated
+
+int main() {
+  //      T
+  struct A {};
+  A a;
+  g1(a);
+
+  // NOTE: there is nothing to fix here; Just testing that if you fail
+  // to deduce an argument, it is caught.
+//  in/d0054.cc:147:3: error: No argument for parameter `S'
+  //ERROR(10): g1b(a, a);
+
+  // also, just testing that if you inconsistently over-determine the
+  // system that it is also caught
+  {
+    int x;
+    short y;
+    //  in/d0053.cc:177:5: error: during function template instantiation:  argument 2 `short int &' is incompatable with parameter, `T'
+    //ERROR(11): j1(x, y);
+  }
+
+  // Check that we iterate over the list and will do more than just
+  // the first one.
+  struct B {};
+  B b;
+  g1c(a, b);
+
+  //      cv-list T
+  A const volatile a2;
+  g2(a2);
+
+  //      T*
+  A *a3;
+  g3(a3);
+
+  //      T&
+  A &a4;
+  g4(a4);
+
+  //      T[integer-constant]
+  // NOTE: this is NOT the "type[i]" case; see below
+  A a5[4];
+  g5(a5);
+
+  //      template-name<T> (where template-name refers to a class template)
+  A1<A> a6;
+  g6(a6);
+  // a different but isomorphic atomic type construction should not match
+  //ERROR(8):    A1b<A> a6b;
+  //ERROR(8):    g6(a6b);
+
+  //      template-name<i> (where template-name refers to a class template)
+  A2<17> a7;
+  g7(a7);
+
+  //      type(*)(T)
+  int (*f8)(int x);
+  g8(f8);
+
+  //      T(*)()
+  int (*f9)();
+  g9(f9);
+
+  // testing the combination?
+  //      T(*)(T)
+  int (*f10)(int x);
+  g10(f10);
+  //ERROR(2): int (*f10b)(short x);
+  //ERROR(2): g10b(f10b);
+
+  //      T type::*
+  int A3::*a11;
+  g11(a11);
+
+  //      type T::*
+  int A3::*a12;
+  g12(a12);
+
+  // testing the combination?
+  //      T T::*
+  A3 A3::*a13;
+  g13(a13);
+  //ERROR(3): int A3::*a13;
+  //ERROR(3): g13b(a13b);
+
+  //      T (type::*)()
+  int (A3::*a14)();
+  g14(a14);
+
+  //      type (type::*)(T)
+  A3 (A3::*a15)(int y);
+  g15(a15);
+
+  //      T (T::*)()
+  A3 (A3::*a16)();
+  g16(a16);
+  //ERROR(4): int (A3::*a16b)();
+  //ERROR(4): g16(a16b);
+
+  // testing the combination?!
+  //      T (T::*)(T)
+  A3 (A3::*a17)(A3 y2);
+  g17(a17);
+//ERROR(5): int (A3::*a17)(A3 y2);
+//ERROR(5): g17b(a17b);
+//ERROR(6): A3 (A3::*a17)(int y2);
+//ERROR(6): g17c(a17c);
+//ERROR(7): struct A4 {};
+//ERROR(7): A3 (A4::*a17)(int y2);
+//ERROR(7): g17d(a17d);
+
+  // --- test conversions
+
+  // convert an array to a pointer
+  int x[4];
+  h1(x);
+
+  // convert a function to a pointer to a function; both should work:
+  h2(f_h2);                     // without & operator
+  h2(&f_h2);                    // with & operator
+}

Added: vendor/elsa/current/elsa/in/d0054.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0054.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0054.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// test what happens with const in template function argument
+// inference;
+
+// the function template argument inference stuff having to do with
+// qualifiers requires so many tests that I put it into another file
+
+// summary of conclusions from experiments with g++:
+// at the top level qualifiers are ignored
+// below that, they are not unless matched
+
+template<class T> T* f1(T const *x) {}
+template<class T> T* f2(T const * const x) {}
+template<class T> T* f3(T const * x) {}
+
+// These don't fail properly because I suppose that elsa isn't
+// checking constness.
+//  fconst1.cc:9: invalid conversion from `const int*' to `int*'
+// OFF ERROR(1): int const * f(int const *x) {}
+//  fconst1.cc:16: invalid conversion from `const int*' to `int*'
+// OFF ERROR(2): template<class T> T* f4(T * const x) {}
+
+int main() {
+  int const y = 3;
+
+  int const * yp = &y;
+  int const * const yp2 = &y;
+
+  int *zp1 = f1(yp);
+  int *zp2 = f2(yp);
+  int *zp3 = f3(yp);
+
+  int *zp1b = f1(yp2);
+  int *zp2b = f2(yp2);
+  int *zp3b = f3(yp2);
+
+// OFF ERROR(1): int *zp1c = f(yp);
+// OFF ERROR(2): int *zp1d = f4(yp);
+}

Added: vendor/elsa/current/elsa/in/d0055.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0055.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0055.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// if the const doesn't get removed, we will have an error
+
+// These don't fail properly because I suppose that elsa isn't
+// checking constness.
+//  fconst2.cc:9: invalid conversion from `const int*' to `int*'
+// OFF ERROR(1): int const * f3(int const x) {}
+//  fconst2.cc:13: invalid conversion from `const int*' to `int*'
+// OFF ERROR(2): template<class T> T const * f3(T x) {}
+
+// and this works, so it is getting removed
+template<class T> T * f1(T const x) {}
+// wow, this works also, so it is getting removed at the top level in
+// any case
+template<class T> T * f2(T x) {}
+
+int main() {
+  int const y = 3;
+  int *zp1 = f1( (int const) y);
+  int *zp2 = f2( (int const) y);
+  // OFF ERROR(1): int *zp3 = f3( (int const) y);
+  // OFF ERROR(2): int *zp3 = f3( (int const) y);
+}

Added: vendor/elsa/current/elsa/in/d0056.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0056.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0056.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// test recursive function template
+
+template<class T> T f(T x) {
+  // well, an infinite loop, but so what
+  return f<int>(x);
+}
+
+template<class T> T g(T x) {
+  // well, an infinite loop, but so what
+  return g(x);
+}
+
+int main() {
+  f<int>(3);
+  g(3);
+}

Added: vendor/elsa/current/elsa/in/d0057.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0057.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0057.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// test forwarded function template
+
+// forward
+template<class T> T g(T x);
+
+template<class T> T f(T x) {
+  // well, an infinite loop, but so what
+  return g(x);
+}
+
+template<class T> T g(T x) {
+  // well, an infinite loop, but so what
+  return f(x);
+}
+
+int main() {
+  f<int>(3);
+}

Added: vendor/elsa/current/elsa/in/d0058.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0058.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0058.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,69 @@
+// attempt at examples of all of the basic situations in which type
+// inference is used; redundant with other tests
+
+// class template
+template<class T> struct A {
+};
+
+// specialization of class template
+template<class T2> struct A<T2*> {
+};
+
+// class template that contains another class template instantiation
+template <class T> class B {
+  A<T> a3;
+};
+
+// standard function template
+template<class T> T f(T x) {
+  return x;
+}
+
+// recursive function template
+template<class T> T frec(T x) {
+  return frec(x);
+}
+
+// recursive function template with explicit arguments
+template<class T> T frec2(T x) {
+  return frec2<int>(x);
+}
+
+// function template that uses template inference
+template<class T> A<T> f2(A<T> x) {
+  return x;
+}
+
+// forwarded function template and mutual recursion
+template<class T> T gfwd(T x);
+template<class T> T ffwd(T x) {
+  return gfwd(x);
+}
+template<class T> T gfwd(T x) {
+  return ffwd(x);
+}
+
+int main() {
+  A<int> a;                     // primary A
+  A<int*> a2;                   // specialization of A
+  B<int> a3;                    // primary B containing primary A
+  B<int*> a4;                   // primary B containing specialization of A
+
+  int x1;
+  // implicit
+  int y1;
+  y1 = f(x1);                   // function template
+  y1 = frec(x1);                // recursive function template
+  y1 = frec2(x1);               // recursive function template
+  f2(a);                        // function template argument inference
+  f2(a2);                       // function template argument inference
+  ffwd(a);                      // function template argument inference
+
+  // explicit
+  y1 = f<int>(x1);              // function template
+  y1 = frec<int>(x1);           // recursive function template
+  y1 = frec2<int>(x1);          // recursive function template
+  f2<int>(a);                   // function template argument inference
+  f2<int*>(a2);                 // function template argument inference
+  ffwd<A<int> >(a);             // function template argument inference
+}

Added: vendor/elsa/current/elsa/in/d0059.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0059.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0059.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// function template instantiation with a default argument that is an
+// E_funCall to another function template instantiation
+
+template<class T> 
+T g(T x) {
+  return x;
+}
+
+template<class T2> 
+T2 f(T2 y = g(3)) {
+  return y;
+}
+
+int main() {
+  int z = f<int>();
+  z = f(4);
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/d0060.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0060.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0060.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// Here is another one minimized from nsCLiveconnectFactory.i that is
+// a counter example to some ideas I've tried.
+
+struct A {};
+
+template<class T> struct E {};
+
+template<class T> struct F {
+  void g(E<A> &a) {};
+};
+
+E<A> q;

Added: vendor/elsa/current/elsa/in/d0061.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0061.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0061.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+template<class T, class S>
+T f(T x, S y) {
+  f<int, int*>(3, &x);
+}
+
+template<class T, class S>
+T f2(T x, S y) {
+  f2(3, &x);
+}
+
+// can we have a "right" var that gets bound from the left first
+// before being bound from the right
+template<class T>
+T g(int x, T y) {
+  return g(y, y);
+}
+
+int main() {
+  int q;
+  f(q, &q);
+  f2(q, &q);
+  g(3, 4);
+}

Added: vendor/elsa/current/elsa/in/d0062.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0062.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0062.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// this one puts g++ 3.4.0 into an infinite loop but only if you have
+// the instantiation
+//  templrec2.cc: In function `void f(T, U) [with T = int*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************, U = int*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************]':
+//  templrec2.cc:5: error: template instantiation depth exceeds maximum of 500 (use -ftemplate-depth-NN to increase the maximum)
+
+template<class T, class U>
+void f(T x, U y) {
+  f(&y, &x);
+}
+
+int main() {
+  f(3, 4);
+}

Added: vendor/elsa/current/elsa/in/d0063.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0063.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0063.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// this one puts g++ 3.4.0 into an infinite loop also but again only
+// if you have the instantiation
+
+template<class T, class U>
+void f(T x, U y, T z) {
+  f(&y,                         // T bound to a pointer to U
+    &x,                         // U bound to a pointer to T
+    &x                          // infinite loop
+    );
+}
+
+int main() {
+  f(3, 4, 5);
+}

Added: vendor/elsa/current/elsa/in/d0064.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0064.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0064.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// test lots of combinations of forwarding
+template<class T, int I> T f(T x, T i[I]);
+template<class T, int I> T f(T x, T i[I]);
+template<class T, int I> T f(T x, T i[I]) {
+  return x;
+}
+template<class T, int I> T f(T x, T i[I]);
+template<class T, int I> T f(T x, T i[I]);
+
+template<class T, int I> struct A;
+template<class T, int I> struct A;
+template<class T, int I> struct A {
+  T x;
+  A() : x(I) {}
+};
+template<class T, int I> struct A;
+template<class T, int I> struct A;
+
+// Hmm, you just can't do this
+//  template<class T, int I> T g(A<T*, I+1> a, (*f1)f<T[], I+2>, I z);
+template<class T, int I> T g(A<T*, I> a, T i[I]);
+template<class T, int I> T g(A<T*, I> a, T i[I]);
+template<class T, int I> T g(A<T*, I> a, T i[I]) {
+  return i[0];
+}
+template<class T, int I> T g(A<T*, I> a, T i[I]);
+template<class T, int I> T g(A<T*, I> a, T i[I]);
+
+int main() {
+  int x = 3;
+  int y[4];
+  f<int, 4>(x, y);
+  A<int*, 0/*NULL*/> b;
+  g(b, y);
+}

Added: vendor/elsa/current/elsa/in/d0065.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0065.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0065.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// testing integer arithmetic in template parameters
+template<class T, int I> struct A;
+template<class T, int I> T g(A<T*, I+1> a, T i[I]);
+//  template<class T, int I> T g(A<T*, I+1> a, T i[I]) {
+//    return i[0];
+//  }
+
+// try instantiating it as well

Added: vendor/elsa/current/elsa/in/d0066.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0066.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0066.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// some testing of int template parameters
+template<int I> struct A;
+template<int I> int g(A<I> a);
+template<int I> int g(A<I> a);
+template<int I> int g(A<I> a) {
+}
+
+template<int I> struct A {
+};
+
+A<2> a2;
+A<3> a3;
+
+int main() {
+  g(a2);
+  g(a3);
+}

Added: vendor/elsa/current/elsa/in/d0067.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0067.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0067.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// testing two instantiations of class template with same integer
+// arguments
+template<int I> struct A {
+};
+A<2> a2;
+A<2> a2a;
+A<3> a3;

Added: vendor/elsa/current/elsa/in/d0068.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0068.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0068.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// testing two instantiations of class template with same integer
+// argument in function template definition parameter mode (mode 2); I
+// was attempting to test MM_ISO mode in matchtype.cc on int
+// parameters instead of type parameters
+template<int I> struct A;
+template<int J> int g(A<J> a);
+template<int J> int g(A<J> a) {
+  return 1;
+}
+template<int I> struct A {
+};
+int main() {
+  A<2> a2;
+  g(a2);
+}

Added: vendor/elsa/current/elsa/in/d0069.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0069.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0069.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// test function template overloading
+
+template <class T> struct A {};
+
+int f(A<int>&) {}
+int *f(int) {}
+
+int main() {
+  int *x = f(3);
+}

Added: vendor/elsa/current/elsa/in/d0070.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0070.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0070.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// minimized from nsAtomTable.i
+
+struct A {};
+template<class T> struct B {};
+
+template<class T> void f(B<T> &) {}
+template<class T> void f(const B<T> &) {}
+
+int g(B<A> &b) {
+  f(b);
+}
+  
+//  int main() {
+//    B<A> b;
+//    f(b);
+//  }

Added: vendor/elsa/current/elsa/in/d0071.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0071.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0071.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+template <class T>
+void m(const T & a, const T & b) {};
+void g() {
+  const int x = 3;
+  m(x, 4);
+}

Added: vendor/elsa/current/elsa/in/d0072.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0072.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0072.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// d0072.cc
+
+template <class T> 
+const T & m(const T & a, const T & b)
+{}
+
+template <class S> 
+struct R {
+};
+
+R<short> &e(R<short> &I)  
+{}
+
+const short *&e(const short *&)  
+{}
+
+void q() 
+{
+  const short *iter;
+  m(iter, e(iter));
+}

Added: vendor/elsa/current/elsa/in/d0073.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0073.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0073.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+struct A {};
+struct B {};
+
+// overloaded function f(); one is a template
+void f(A &) {}
+template<class T>
+void f(B &) {}
+
+int main() {
+  A x;
+  f(x);
+}

Added: vendor/elsa/current/elsa/in/d0074.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0074.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0074.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// dsw: This one passes in g++ but fails in elsa because at the end of
+// a translation unit we are instantiating a function member of a
+// template class in elsa that need not have been instantiated because
+// it was never called
+
+class A;
+
+enum enum0 {kNextFragment};
+
+template < class CharT > struct nsWritableFragment {};
+
+template < class CharT > struct nsStringTraits {
+  typedef A abstract_string_type;
+};
+
+template < class CharT > class nsWritingIterator {
+  typedef nsWritableFragment < CharT > fragment_type;
+  typedef typename nsStringTraits <
+    CharT >::abstract_string_type abstract_string_type;
+  fragment_type mFragment;
+  CharT *mPosition;
+  abstract_string_type *mOwningString;
+  inline void normalize_forward ();
+};
+
+template < class CharT >
+inline void nsWritingIterator <CharT>::normalize_forward ()
+{
+  mOwningString->GetWritableFragment (mFragment, kNextFragment);
+}
+
+class A {
+public:typedef unsigned short char_type;
+  typedef nsWritingIterator < char_type > iterator;
+};

Added: vendor/elsa/current/elsa/in/d0075.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0075.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0075.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+struct A;
+template<class T> struct B {};
+
+template<class T> void foo (B<T> &);
+template<class T> void foo (A*);
+
+int main() {
+  B<A> s;
+  // this doubling is necessary to reproduce the bug
+  foo(s);
+  foo(s);
+}

Added: vendor/elsa/current/elsa/in/d0079.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0079.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0079.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// /home/ballAruns/tmpfiles/./aspell-0.33.7.1-21/email-MKxI.i:29703:12:
+// Parse error (state 141) at class
+
+struct A {};
+template <class T> class C {};
+template class C<A>;            // explicit template instantiation

Added: vendor/elsa/current/elsa/in/d0080.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0080.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0080.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// aspell-0.33.7.1-21//email-MKxI.i.cpp_out:/home/ballAruns/tmpfiles/./
+// aspell-0.33.7.1-21/email-MKxI.i:29703:12: Parse error (state 141)
+// at class
+
+template <class T> struct E : public T::B {};

Added: vendor/elsa/current/elsa/in/d0084.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0084.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0084.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+//  ./qt2-2.3.1-13/qstring-ht7v.i.cpp_out:/home/ballAruns/tmpfiles/./qt2-2.3.1-13/qstring-ht7v.i:5628:8: error: no viable candidate for function call
+
+// this one involves operator overloading
+
+struct A {
+  A (int s);
+};
+
+A operator+ (char c, A const &a);
+
+struct B {
+  operator char () const;
+};
+
+void f() {
+  B b;
+  b - 1 + 1;
+}

Added: vendor/elsa/current/elsa/in/d0087.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0087.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0087.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// this had stopped working and we hadn't a test to reveal it
+
+struct X {
+  // sm: this is invalid C++!  see 9.2 para 13
+  //ERROR(1): int X;
+
+  int Y;     // ok
+};
+
+
+// another ansi-only rule
+//ERROR(2): int arr[0];

Added: vendor/elsa/current/elsa/in/d0088.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0088.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0088.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// dsw: initializers of members need to be typechecked on the first
+// pass so they can be const-evaled if necessary
+
+struct A {
+   static const int a=64;
+   int b[a];                    // const eval of 'a' here
+};

Added: vendor/elsa/current/elsa/in/d0089.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0089.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0089.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+//  /home/ballA/doxygen-1.2.18-3/png-jmoU.i
+
+// if it had not been previously declared, the size was computed; if
+// it had only been previously declared the size was read from the
+// user; but if it you did both, it didn't work.
+
+extern const int png_pass_start[7];
+const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};

Added: vendor/elsa/current/elsa/in/d0090.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0090.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0090.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+//  ./am-utils-6.0.9-2/fsinfo-S3kd.i
+
+// technically this should only work with this 'extern' here, but gcc
+// allows it without; maybe make a copy in in/gnu that doesn't have
+// the extern.
+
+extern                          // optional in gnu
+char hostname[];
+char hostname[64 + 1];
+int main() {
+  sizeof(hostname);
+}

Added: vendor/elsa/current/elsa/in/d0091.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0091.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0091.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+//  mysql-3.23.54a-11/sql_lex-D6bf.i
+
+// member operators are allowed to be static
+
+typedef unsigned int size_t;
+struct String {
+  static void *operator new(size_t size) throw() { return 0; }
+};

Added: vendor/elsa/current/elsa/in/d0097.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0097.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0097.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+/* ./emacs-21.2-33/ccmdfJJb-l0lu.i.c_out:/home/ballAruns/tmpfiles/./emacs-21.2-33/ccmdfJJb-l0lu.i:4454:7: error: prior declaration of `processed_file' at /home/ballAruns/tmpfiles/./emacs-21.2-33/ccmdfJJb-l0lu.i:4450:13 refers to a different entity, so it conflicts with the one being declared here */
+
+int main() {
+  typedef struct A {
+    int x;
+  } A;
+}

Added: vendor/elsa/current/elsa/in/d0098.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0098.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0098.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// can we find an "explicitly enum" enum in a superclass?
+
+struct A {
+  enum E {
+    EGY,
+    KETTO,
+  };
+};
+
+struct B : A {
+  void f() {
+    enum E a;
+  }
+};

Added: vendor/elsa/current/elsa/in/d0099.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0099.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0099.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+//  /home/ballB/festival-1.4.2-3/EST_Chunk-4Asc.ii
+//  error: function definition of `operator<<' must appear in a namespace that encloses the original declaration
+class X {
+    friend void operator << (int &i, const X &x) { };
+};

Added: vendor/elsa/current/elsa/in/d0100.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0100.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0100.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// operator & can have just one argument, as it isn't just bit-and it
+// is also address-of
+class EST_Chunk {
+    EST_Chunk *operator & ();
+};
+
+EST_Chunk *EST_Chunk::operator & ()
+{
+  return this;
+}

Added: vendor/elsa/current/elsa/in/d0101.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0101.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0101.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// more implicit-int ambiguity problems
+
+// /home/ballB/XFree86-4.2.0-8/LabMnL-1Zss.i:11197:44:
+// WARNING: there is no action to merge nonterm DirectAbstractDeclarator
+double g(double a);
+int f() {
+  float hue;
+  (g (((hue))));
+}
+
+// Scott's example of implicit int causing unnecessary parsing
+// ambiguities.
+int foo (int ((x))) {}

Added: vendor/elsa/current/elsa/in/d0102.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0102.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0102.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// error: there is no type called `Iter'
+
+template<class C> struct A {
+  typedef A<C> Iter;
+};
+
+template<class C> struct B : A<C> {
+  typename A<C>::Iter &operator = (const typename A<C>::Iter &orig) {}
+};

Added: vendor/elsa/current/elsa/in/d0103.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0103.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0103.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// Parse error (state 631) at <
+
+template <class T> struct A {
+  friend bool operator == <>(const A &, const A &);
+};

Added: vendor/elsa/current/elsa/in/d0104.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0104.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0104.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// /home/ballB/ddd-3.3.1-13/Command-qJh2.ii:2579:15:
+// error: reference to `rdbuf' is ambiguous, because it could either
+// refer to strstreambase::rdbuf or ios::rdbuf
+
+// error: reference to `f' is ambiguous, because it could either refer to C::f or A::f
+
+struct A {
+  int *f() {}
+};
+
+struct B:virtual A {};
+
+struct C:virtual A {
+  int *f() {}
+};
+
+
+struct D: C, B {};
+
+void f(D &d)
+{
+  d.f();
+}
+
+               
+// sm: add a variant that has the bases in the opposite order
+struct D2: B, C {};
+
+void f(D2 &d)
+{
+  d.f();
+}

Added: vendor/elsa/current/elsa/in/d0105.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0105.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0105.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// error: there is no type called `A'
+
+template<class V> struct C {
+  typedef struct A0 A;
+};
+
+template<class V> 
+struct D : C<V> {
+  typename C<V>::A x;
+};

Added: vendor/elsa/current/elsa/in/d0106.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0106.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0106.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// error: no template parameter list supplied for `A'
+
+// note that the 'static' is critical for the bug
+
+// sm: This is actually invalid C++, because there should be
+//   template <>
+// before the definition of A<int>::s.  However, gcc-2 accepts
+// it (a bug), as does icc (apparently for compatibility with
+// the gcc bug), though gcc-3 does not.  So, Elsa will probably
+// have to support this too, if icc found it necessary.
+
+// 2005-03-05: screw it; if gcc-3 does not support it, elsa
+// does not have to either
+
+
+template<class T> class A {
+  static int s;
+};
+
+template<>
+int A<int>::s = 0;

Added: vendor/elsa/current/elsa/in/d0107.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0107.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0107.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+//  Assertion failed: MatchTypes: got a type variable on the left, file ../elsa/matchtype.cc line 406
+
+struct A;
+
+template<class T> struct B {};
+
+template<class T> A &operator>> (A &s, B<T> &)
+{
+  T t;
+  s >> t;
+}

Added: vendor/elsa/current/elsa/in/d0108.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0108.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0108.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// error: duplicate member declaration of `ip_opts' in struct ip_opts; previous at
+
+// this was wrapped inside two 'extern "C"'-s actually, but the error
+// is reproducible without them so I took them off.
+
+struct ip_opts
+{
+  char ip_opts[40];
+};
+
+char f()
+{
+  ip_opts i;
+  return i.ip_opts[1];
+}

Added: vendor/elsa/current/elsa/in/d0109.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0109.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0109.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// CoderInfo-ootm.ii:7:3: error: prior declaration of `NoiseType' at CoderInfo-ootm.ii:6:9 refers to a different entity, so it conflicts with the one being declared here
+
+namespace MagickLib {
+  typedef enum {ReadMode, WriteMode, IOMode} NoiseType;
+  //typedef int NoiseType;    // same effect
+}
+
+namespace Magick {
+  using MagickLib::NoiseType;
+  using MagickLib::NoiseType;
+}

Added: vendor/elsa/current/elsa/in/d0110.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0110.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0110.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// CoderInfo-ootm.ii:2:33: error: class specifier name can have template arguments only in a templatized definition
+
+template < class charT > struct string_char_traits {};
+struct string_char_traits <char > {};

Added: vendor/elsa/current/elsa/in/d0111.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0111.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0111.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// CoderInfo-ootm.ii:8:22: error: variable name `D</*ref*/ I0>::P' used as if it were a type
+
+template <int I>
+class D {
+  union P {};
+  static P *L[2];
+  static P *M[2];
+};
+
+template<int I0>
+// the original test case was missing this 'typename' keyword, but
+// it is clearly required by 14.6 para 6; gcc-3 requires it, though
+// gcc-2 and icc do not
+typename
+D<I0>::P *D<I0>::L[2] = {0, 0};
+
+
+// here is the (erroneous) version without 'typename'
+//ERROR(1): template<int I0>
+//ERROR(1): D<I0>::P *D<I0>::M[2] = {0, 0};
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/d0112.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0112.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0112.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// CoderInfo-ootm.ii:5:11: error: dependent template scope name requires 'template' keyword
+
+// this comes from gcc-2 header "stl-alloc.h"; I am going to
+// recognize it and allow it
+
+template < class _Tp, class _Allocator > 
+struct _Alloc_traits
+{
+  typedef typename _Allocator::rebind < _Tp >::other allocator_type;
+};

Added: vendor/elsa/current/elsa/in/d0113.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0113.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0113.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// CoderInfo-ootm.ii:17:3: error: no viable candidate for function call
+
+// yes, gcc 2.96 will compile this.  I don't understand how the
+// function tr::a() can be called when it has never been declared.  I
+// don't understand how 'pos' can be used when it has never been
+// declared
+
+// sm: 10/02/04: The reason gcc accepts this is that it does not
+// instantiate the templates.  The reason Elsa used to fail is that it
+// would attempt operator overloading in uninstantiated template
+// bodies, which fails for a variety of reasons.  I just fixed Elsa to
+// not do that, so it accepts the (invalid; no specialization is
+// possible; no diagnostic required) code for the same reason gcc
+// does, namely that no instantiation occurs.
+
+template<class C> struct S {};
+
+template<bool t, int i> struct D {} ;
+
+template<class C, class tr = S<C> >
+struct B {
+  struct Rep {               
+    // sm: 2005-05-06: I added the following.  I do not know
+    // why gcc and icc do not want it, since "(*p)[pos]" does
+    // not seem to be dependent.
+    int operator[](int);
+  };
+  template<class I> B &f (I j1);
+};
+
+template<class C, class tr>
+  template<class I> B<C, tr> &B<C, tr>::f(I j1)
+{
+  // as Elsa now does non-dependent lookup, this needs to be
+  // declared (in strict mode)
+  int pos;
+
+  Rep *p;
+  (*p)[pos];
+  tr::a((*p)[pos], *j1);
+  // if I replace this with the below elsa seems to also like it but
+  // what the heck is going on?
+//    tr::a();
+}

Added: vendor/elsa/current/elsa/in/d0114.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0114.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0114.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+//  CoderInfo-ootm.ii:10:22: error: variable name `B<T>::S' used as if it were a type
+//  CoderInfo-ootm.ii:10:27: error: the name `B<T>::find' is overloaded, but the type `<error> ()(T */*anon*/, int /*anon*/)' doesn't match any of the 2 declared overloaded instances
+
+template<class T> struct B {
+  typedef int S;
+  S find(T*, int);
+  S find(T*);
+};
+
+// this is invalid code, because 'typename' is required;
+// gcc rejects, icc accepts
+//ERROR(1): template<class T> B<T>::S B<T>::find(T*, int) {}
+
+// this is valid
+template<class T> typename B<T>::S B<T>::find(T*, int) {}

Added: vendor/elsa/current/elsa/in/d0115.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0115.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0115.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// CoderInfo-ootm.ii:9:14: error: cannot find scope name `std'
+// CoderInfo-ootm.ii:9:14: error: there is no type called `std::string'
+
+// sm: This is invalid C++, and is properly rejected by gcc-3 
+// and by icc.
+
+template<class T> class basic_string {};
+
+typedef basic_string<char> string;
+
+class CoderInfo {
+  CoderInfo (std::string &name);
+};

Added: vendor/elsa/current/elsa/in/d0116.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0116.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0116.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// Assertion failed: should not be reachable, file cc_elaborate.cc line 539
+
+struct B {};
+extern B b;
+B b;

Added: vendor/elsa/current/elsa/in/d0117.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0117.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0117.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// operator() was not cloning the type when it set the type of the
+// function variable when replacing the operator with a normal
+// function call
+
+template<class T> struct R {
+  T *get() {}
+};
+
+struct S {
+  int operator() (int *);
+};
+
+int f() {
+  S a;
+  R<int> i;
+  a(i.get());
+}

Added: vendor/elsa/current/elsa/in/d0118.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0118.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0118.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// __builtin_stdarg_start should take a void const \* pointer as its second argument
+
+typedef __builtin_va_list __gnuc_va_list;
+
+typedef __gnuc_va_list va_list;
+
+typedef struct _jmethodID *jmethodID;
+
+void NewObject(jmethodID methodID, ...)
+{
+  va_list args;
+  __builtin_stdarg_start ((args), methodID);
+}

Added: vendor/elsa/current/elsa/in/d0119.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0119.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0119.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+// you can get a const onto an array this way
+typedef char category_t[16];
+const category_t &f();

Added: vendor/elsa/current/elsa/in/d0120.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0120.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0120.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+int f(int code, ...) {
+  __builtin_va_list args;
+  __builtin_stdarg_start (args, code);
+}
+
+int g(char * code, ...) {
+  __builtin_va_list args;
+  __builtin_stdarg_start (args, code);
+}

Added: vendor/elsa/current/elsa/in/d0121.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0121.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0121.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+template < class charT > struct basic_string {
+  basic_string (const charT * s) {}
+};
+
+typedef basic_string <char> string;
+
+struct Geometry {
+  //ERROR(1): Geometry (std::string geometry_);
+  void f();
+};
+
+void Geometry::f() {
+  const char *geometry;
+  
+  // this line used to cause a segfault; now it properly
+  // causes an error message
+  //ERROR(2): *this = std::string (geometry);
+}

Added: vendor/elsa/current/elsa/in/d0123.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0123.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0123.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+struct inode {};
+struct super_block {};
+typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
+extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
+struct inode *iget(struct super_block *sb, unsigned long ino)
+{
+  return iget4(sb, ino, ((void *)0), ((void *)0));
+}

Added: vendor/elsa/current/elsa/in/d0124.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0124.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0124.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// see elsa/in/c/d0124b.c for contrast; string literals are 'char
+// const []' in C++; this only passes because of a special conversion
+// that drops the const on string literals; Scott puts it thus: "See
+// cppstd 4.2 para 2.  There is a special exception for converting a
+// string literal to char*.  This is the reason for the existence of
+// SE_STRINGLIT."
+char *a = "hello";
+char const *b = "hello";

Added: vendor/elsa/current/elsa/in/d0125.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0125.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0125.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+int xprintf(const char * fmt, ...) {}
+char * xgetenv(const char* x) {}
+
+int xvsprintf(char* buf, __builtin_va_list arg)
+{
+  __builtin_va_list arg2;
+  __builtin_va_copy(arg2, arg);
+  buf[0] = * __builtin_va_arg(arg2, char*);
+}
+
+int xsprintf (char* buf, const char * format, ...)
+{
+  __builtin_va_list arg;
+  __builtin_va_start(arg, format);
+
+  xvsprintf(buf, arg);
+
+  __builtin_va_end(arg);
+}
+
+int main()
+{
+  char *s = "";
+  char buf[100];
+  s = xgetenv("HOME");                               
+  xsprintf(buf, "%s", s);
+  xprintf(buf);
+}

Added: vendor/elsa/current/elsa/in/d0126.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0126.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0126.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// #include "stdio.h"
+
+// dsw: I am amazed that this works in both gcc and elsa
+
+typedef void f_t(void);
+
+f_t a;
+
+struct A {
+  f_t b;
+};
+
+void a(void) {
+//   printf("a here\n");
+}
+
+void A::b(void) {
+//   printf("A::b here\n");
+}
+
+int main() {
+  A a2;
+  a();
+  a2.b();
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/d0128.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0128.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0128.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// From Umesh Shankar <ushankar at google.com>
+
+class Bar {
+  Bar(bool (*func)(void *), void *arg);
+
+  template<typename T>
+  Bar(bool (*func)(T *), T *arg);
+
+  template<typename T>
+  Bar(T *object, bool (T::*method)());
+};
+
+template<typename T>
+static bool foo(void *v, bool (Bar::*m)()) {
+  typedef bool (T::*RealMethodType)();
+  T *x = static_cast<T *>(v);
+  RealMethodType rm = reinterpret_cast<RealMethodType>(m);
+  return (x->*rm)();
+}

Added: vendor/elsa/current/elsa/in/d0129.cc
===================================================================
--- vendor/elsa/current/elsa/in/d0129.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/d0129.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// from Taras
+
+struct Foo {
+  void *v;
+  Foo() : v(0) {}
+  Foo(void *v) : v(v) {}
+  Foo(Foo const &other) : v(other.v) {}
+};
+
+bool deep() {
+  return false;
+}
+
+int main() {
+  Foo f = deep() ? Foo() : 0;
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/dk0127.cc
===================================================================
--- vendor/elsa/current/elsa/in/dk0127.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/dk0127.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// this is in class basic_string which is in <string>; found by Karl,
+// it turns out to cause an AST non-tree-ness, namely that the default
+// argument 5 shows up in two different places.
+
+template<typename T>
+struct S1 {
+  struct S2 {
+    void foo(int arg = 5);
+  };
+};
+
+template<typename T>
+void S1<T>::S2::foo(int arg) {
+}
+
+int main()
+{
+  S1<int>::S2 s2;
+  s2.foo();
+}

Added: vendor/elsa/current/elsa/in/gnu/asm01.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/asm01.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/asm01.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// asm01.c
+// testing Asm Labels
+
+// http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Asm-Labels.html
+
+// You can specify the name to be used in the assembler code for a C
+// function or variable by writing the asm (or __asm__) keyword after
+// the declarator as follows:
+
+int foo asm ("myfoo") = 2;
+
+// Where an assembler name for an object or function is specified (see
+// Asm Labels), at present the attribute must follow the asm
+// specification
+
+int foo2 asm ("myfoo2") __attribute__((blah)) = 3;
+
+// this also works for function decls
+
+int foo3(int, float) asm("myfoo3");
+int foo4(int, float) asm("myfoo4") __attribute__((blah));
+

Added: vendor/elsa/current/elsa/in/gnu/attr01.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/attr01.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/attr01.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// attr01.c
+// some elementary properties of attribute specifiers, that
+// is, just the __attribute__((...)) thing itself
+
+// http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Attribute-Syntax.html
+
+// very simple usage
+int x __attribute__ ((    aligned (16)    ));
+
+// now, variations on that designed to test the syntax of
+// what goes inside the (( and ))
+
+// attribute sequence may be empty
+int x __attribute__ ((    /*nothing*/    ));
+
+// attributes themselves may be empty
+int x __attribute__ ((    /*nothing*/, /*nothing*/    ));
+
+// a word, such as an identifier or a reserved word
+int x __attribute__ ((    unused, const    ));
+
+// a word followed by "parameters", which themselves might be
+
+  // an identifier
+  int x __attribute__ ((    func(identifer)    ));
+
+  // an identifier followed by a comma and a non-empty comma-separated
+  // list of expressions
+  int x __attribute__ ((    func(identifer, 1)    ));
+  int x __attribute__ ((    func(identifer, 1, 2)    ));
+  int x __attribute__ ((    func(identifer, 1, 2, 3+4)    ));
+
+  // a possibly empty comma-separated list of expressions, such as
+  // integer or string literals
+  int x __attribute__ ((    func()    ));
+  int x __attribute__ ((    func(1)    ));
+  int x __attribute__ ((    func(1, 2)    ));
+  int x __attribute__ ((    func(1, 2, 3+4)    ));
+  int x __attribute__ ((    func(1, 2, 3+4, "five")    ));
+
+// an attribute specifier list is a sequence of one or more
+// __attribute__ specifiers; every occurrence of __attribute__ appears
+// to be as part of an attribute specifier list, so it should be legal
+// to put lots of these guys together
+int x __attribute__ ((a_word));
+int x __attribute__ ((a_word)) __attribute__ ((another_word));
+int x __attribute__ ((a_word)) __attribute__ ((another_word)) __attribute((yet_another_word));;
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/gnu/attr02.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/attr02.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/attr02.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,189 @@
+// attr02.c
+// these tests focus on the placement of attribute specifier lists,
+// largely ignoring the syntax of what's in the (( and ))
+
+// http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Attribute-Syntax.html
+
+
+// an attribute specifier list may appear af the colon following a label
+void f()
+{
+  label: __attribute__((unused))
+    goto label;
+}
+
+
+// An attribute specifier list may appear as part of a struct, union
+// or enum specifier.
+
+  // It may go either immediately after the struct, union or enum keyword,
+  struct __attribute__((blah)) Struct1 {};
+  union __attribute__((blah)) Union1 {};
+  enum __attribute__((blah)) Enum1 { enum1 };
+
+  // or after the closing brace.
+  struct Struct2 {} __attribute__((blah));
+  struct Struct2a {} __attribute__((blah)) some_declarator;
+  union Union2 {} __attribute__((blah));
+  enum Enum2 { enum2 } __attribute__((blah));
+
+  // subsequent text indicates it is allowed (though ignored) after
+  // the keyword in an elaborated type specifier (no "{}")
+  struct __attribute__((blah)) Struct1 *s1p;
+  union __attribute__((blah)) Union1 *u1p;
+  enum __attribute__((blah)) Enum1 *e1p;
+
+
+// Otherwise, an attribute specifier appears as part of a declaration,
+// counting declarations of unnamed parameters and type names
+// [sm: so, they regard parameters as being "declarations"]
+//
+// Any list of specifiers and qualifiers at the start of a declaration
+// may contain attribute specifiers, whether or not such a list may in
+// that context contain storage class specifiers.
+// [sm: what does "contain" main?  arbitrarily intermixed?  seems so...]
+// 
+// my speculation on the places that a "declaration" can occur:
+//   - toplevel
+//   - function scope
+//   - struct member list
+//   - function parameter list
+            
+
+// toplevel:
+        __attribute__((blah)) int                              x1;
+        __attribute__((blah)) int __attribute__((blah))        x2;
+static  __attribute__((blah)) int __attribute__((blah))        x3;
+        __attribute__((blah)) int __attribute__((blah)) static x4;
+typedef __attribute__((blah)) int __attribute__((blah))        x5;
+
+// function scope:
+void g()
+{
+          __attribute__((blah)) int                              x1;
+          __attribute__((blah)) int __attribute__((blah))        x2;
+  static  __attribute__((blah)) int __attribute__((blah))        x3;
+          __attribute__((blah)) int __attribute__((blah)) static x4;
+  typedef __attribute__((blah)) int __attribute__((blah))        x5;
+}
+
+// struct member list (only in gcc >= 3):
+struct Struct3 {
+  #if defined(__GNUC__) && __GNUC__ >= 3
+          __attribute__((blah)) int                              x1;
+          __attribute__((blah)) int __attribute__((blah))        x2;
+  short   __attribute__((blah)) int __attribute__((blah))        x3;
+  #endif
+          int                              x4   __attribute__((blah)) ;
+};
+
+// function parameter list (declaration declarator)
+int f1(__attribute((blah)) int x);
+int f2(short __attribute((blah)) int x);
+int f3(__attribute((blah)) int x, __attribute((blah)) int y);
+
+// and definition declarators
+int g1(__attribute((blah)) int x) {}
+int g2(short __attribute((blah)) int x) {}
+int g3(__attribute((blah)) int x, __attribute((blah)) int y) {}
+
+
+// In the obsolescent usage where a type of int is implied by the
+// absence of type specifiers, such a list of specifiers and
+// qualifiers may be an attribute specifier list with no other
+// specifiers or qualifiers.
+//
+// I have commented this out because Elsa does not have implicit-int
+// support.
+//         __attribute__((blah)) /*implicit-int*/                   x6;
+
+
+// An attribute specifier list may appear immediately before a
+// declarator (other than the first) in a comma-separated list of
+// declarators in a declaration of more than one identifier using a
+// single list of specifiers and qualifiers.
+int a1, __attribute__((blah)) a2;
+int b1, __attribute__((blah)) *b2;
+int c1, * __attribute__((blah)) c2;     // nested declarators?  guess so...
+int * __attribute__((blah)) d1;         // nested declarator on *first* one
+int ( __attribute__((blah)) e1);        // nested declarator inside paren
+int ( __attribute__((blah)) h1), ( __attribute__((blah)) h2);
+//int ( i1 __attribute__((blah)) );       // end of parenthesized?  NO
+
+// mixed in with cv-qualifiers?  only in gcc >= 3
+int c1c, * const __attribute__((blah)) c2c;
+#if defined(__GNUC__) && __GNUC__ >= 3
+int c1cv, * const __attribute__((blah)) volatile c2cv;
+#endif
+
+// try this in function scope too
+void h()
+{
+  int a1, __attribute__((blah)) a2;
+  int b1, __attribute__((blah)) *b2;
+  int c1, * __attribute__((blah)) c2;     // nested declarator
+  int * __attribute__((blah)) d1;         // nested declarator on *first* one
+  int ( __attribute__((blah)) e1);        // nested declarator inside paren
+  int ( __attribute__((blah)) h1), ( __attribute__((blah)) h2);
+}
+
+// example from the manual; only works in gcc >= 3
+#if defined(__GNUC__) && __GNUC__ >= 3
+__attribute__((noreturn)) void ex_d0 (void),
+         __attribute__((format(printf, 1, 2))) ex_d1 (const char *, ...),
+          ex_d2 (void)   ;   // why was the semicolon missing?
+#endif
+
+
+// An attribute specifier list may appear immediately before the
+// comma, = or semicolon terminating the declaration of an identifier
+// other than a function definition.
+int aa1 __attribute__((blah));
+int bb1 __attribute__((blah)) = 2;
+int cc1 __attribute__((blah)), cc2;
+int dd1 __attribute__((blah)), dd2 __attribute__((blah));
+
+int ee1(int) __attribute__((blah));
+//int ff1(int) __attribute__((blah)) {}    // this one isn't allowed
+
+// example from the manual
+void (****gg1)(void) __attribute__((noreturn));
+
+
+// again, testing attributes *after* declarator, in a number of contexts:
+
+// toplevel:
+        int y1 __attribute__((blah));
+typedef int y2 __attribute__((blah));
+
+// function scope:
+void yg()
+{
+          int y1 __attribute__((blah));
+  typedef int y2 __attribute__((blah));
+}
+
+// struct member list
+struct yStruct3 {
+  int x1 __attribute__((blah)) ;
+  int x2 : 2 __attribute__((blah)) ;
+};
+
+// function parameter list (declaration declarator)
+int yf1(int x __attribute((blah)));
+int yf3(int x __attribute((blah)), int y __attribute((blah)));
+
+// and definition declarators
+int yg1(int x __attribute((blah))) {}
+int yg3(int x __attribute((blah)), int y __attribute((blah))) {}
+
+
+// a few more nested declarator examples from the manual
+void (__attribute__((noreturn)) ****hh1) (void);
+char *__attribute__((aligned(8))) *ii1;
+
+
+// NOTE: I did not test the thing about qualifiers inside [].
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/gnu/bugs/d0106.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/d0106.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/d0106.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// error: no template parameter list supplied for `A'
+
+// note that the 'static' is critical for the bug
+
+// sm: This is actually invalid C++, because there should be
+//   template <>
+// before the definition of A<int>::s.  However, gcc-2 accepts
+// it (a bug), as does icc (apparently for compatibility with
+// the gcc bug), though gcc-3 does not.  So, Elsa will probably
+// have to support this too, if icc found it necessary.
+
+
+template<class T> class A {
+  static int s;
+};
+
+//template<>    <-- this is what is missing
+int A<int>::s = 0;

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0001.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0001.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0001.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// gb0001.c
+// applying cv-flags to a function type via typedef
+
+typedef void voidfn ();
+extern volatile voidfn fatal;

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0002.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0002.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0002.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// gb0002.c
+// applying type specifier keywords to a typedef
+
+// EDG and Elsa both reject this; it's in the regression test
+// directory just to have a name to attach to this bug.
+
+typedef unsigned int uint32_t;
+typedef uint32_t unsigned long;

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0003.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0003.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0003.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// gb0003.cc
+// applying '<' to a function
+
+// See comments in cc_tcheck.cc (search for
+// "cannot apply '<' to a function").  This is not valid C++.
+
+int f();
+
+int g()
+{
+  return f < 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0004.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0004.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0004.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// gb0004.c
+// missing semicolon in structure member declaration
+
+// rejected by icc, so Elsa will continue to reject
+
+struct category {
+  struct cat_item   {
+  }
+};

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0005.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0005.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0005.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// gb0005.cc
+// failure to instantiate, failure to diagnose,
+// though no diagnostic is required...
+
+struct A {};
+
+void f(A *x);
+
+template <typename T>
+struct B {
+  void g(A const *p)
+  {
+    f(p);
+  }
+};
+
+
+// this tests response to an error from overload resol'n
+namespace N {
+  int f(char);
+  int f(short);
+
+  template <class T>
+  struct A {
+    void g(int i)
+    {
+      f(i);
+    }
+  };
+}

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0006.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0006.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0006.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// gb0006.cc
+// another permissive issue
+
+enum State { goodbit };
+
+template <class T>
+void f(State &e)
+{
+  e |= goodbit;
+}

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0007.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0007.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0007.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// gb0007.cc
+// strange friend + qualified ctor name bug
+
+// rejected by ICC
+
+struct A {
+  friend A::A(int);
+};

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0008.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0008.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0008.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// gb0008.cc
+// refer to std::type_info without declaring
+
+// rejected by ICC
+
+std::type_info *p;
+

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0009.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0009.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0009.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// gb0009.cc
+// failure to implement the defn scope must enclose decl scope rule
+// (7.3.1.2p2 and 9.3p2)
+
+// variant with named namespaces; ICC rejects this
+namespace N
+{
+  struct A {
+    void f(int);
+  };
+}
+using namespace N;
+
+namespace M
+{
+  void A::f(int) {}
+}
+
+
+// variant with anonymous namespaces; even ICC does not reject
+namespace
+{
+  struct B {
+    void f(int);
+  };
+}
+
+namespace
+{
+  void B::f(int) {}
+}
+
+

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0010.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0010.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0010.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// gb0010.cc
+// use 'class' when inappropriate
+
+struct A {
+  typedef int INT;
+};
+
+// GCC and ICC reject this
+//ERROR(1): class A::INT x;
+  
+
+template <class T>
+struct B {
+  typedef int INT;
+};
+
+// they also reject this
+//ERROR(2): class B<int>::INT y;
+
+
+template <class T>
+void f(T)
+{
+  // GCC allows this, however
+  class B<T>::INT z;
+}
+
+// even when instantiated
+template void f(int);
+
+

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0011.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0011.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0011.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// gb0011.cc
+// gcc accepts duplicate parameter names in prototypes
+
+int f(int x, int *x);
+
+// it rejects this, at least, though now Elsa does not
+// when it is emulating the GCC bug
+//int f(int x, int *x) { return 1; }
+
+void foo(int *p)
+{
+  f(2,p);
+}
+
+struct A {
+  int f(int x, int x);
+};
+
+//ERROR(1): int A::f(int x) { return 1; }
+
+int A::f(int x, int xx)
+{
+  return 2;
+}

Added: vendor/elsa/current/elsa/in/gnu/bugs/gb0012.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/bugs/gb0012.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/bugs/gb0012.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// gb0012.cc
+// "template <>" not required to specialize a member
+
+template <class T>
+struct A {
+  int f(int);
+  int g(int);
+};
+  
+
+// the standard requires this, but gcc does not
+//template <>
+
+int A<int>::f(int)
+{
+  return 1;
+}
+
+
+// similarly when using a typedef (see also in/t0554.cc, in/t0555.cc)
+typedef A<int> A_int;
+int A_int::g(int)
+{
+  return 2;
+}

Added: vendor/elsa/current/elsa/in/gnu/c0001.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/c0001.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/c0001.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,97 @@
+// c0001.c
+// complicated statement expression from Pine
+
+typedef struct MC {
+  int lockcount;
+  int msgno;
+} MC;
+void *fs_get(int);
+typedef unsigned char __uint8_t;
+
+MC *mail_new_cache_elt (unsigned long msgno)
+{
+  MC *elt = (MC *)
+    (__extension__
+      (__builtin_constant_p ( sizeof (MC) ) && ( sizeof (MC) ) <= 16    ?
+        (( sizeof (MC) ) == 1 ?
+          ({ void *__s = (  fs_get (sizeof (MC))  );
+           *((__uint8_t *) __s) = (__uint8_t)0 ;
+            __s; }) :
+          ({ void *__s = (  fs_get (sizeof (MC))  );
+             union {
+               unsigned int __ui;
+               unsigned short int __usi;
+               unsigned char __uc;
+             } *__u = __s;
+             __uint8_t __c = (__uint8_t) ( 0  );
+             switch ((unsigned int) (   sizeof (MC)  ))      {
+               case 15:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 11:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 7:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 3:
+                 __u->__usi = (unsigned short int) __c * 0x0101;
+                 __u = __extension__ ((void *) __u + 2);
+                 __u->__uc = (unsigned char) __c;
+                 break;
+               case 14:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 10:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 6:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 2:
+                 __u->__usi = (unsigned short int) __c * 0x0101;
+                 break;
+               case 13:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 9:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 5:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 1:
+                 __u->__uc = (unsigned char) __c;
+                 break;
+               case 16:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 12:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 8:
+                 __u->__ui = __c * 0x01010101;
+                 __u = __extension__ ((void *) __u + 4);
+               case 4:
+                 __u->__ui = __c * 0x01010101;
+               case 0:
+                 break;
+             }
+             __s;
+           }) 
+         )     :
+       (__builtin_constant_p ( 0 ) && ( 0 ) == '\0' ? 
+         ({ void *__s = ( fs_get (sizeof (MC)) ); 
+            __builtin_memset ( __s , '\0',    sizeof (MC)  ) ; 
+            __s; })   : 
+         memset ( fs_get (sizeof (MC)) , 0 ,  sizeof (MC) )
+       )
+     )
+   ) ;
+
+  elt->lockcount = 1;
+  elt->msgno = msgno;
+  return elt;
+}
+
+

Added: vendor/elsa/current/elsa/in/gnu/c0002.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/c0002.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/c0002.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// c0002.c
+// enum coverage
+
+enum Blah;
+enum Blah;
+enum Blah {x};
+//ERROR(1): enum Blah {y};
+enum Blah;

Added: vendor/elsa/current/elsa/in/gnu/cil/align1.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/align1.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/align1.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+# 1 "align1.c"
+# 1 "testharness.h" 1
+extern int printf(const char * format, ...);
+#pragma ccuredvararg("printf", printf(1))
+
+extern void exit(int);
+
+ 
+
+
+
+# 1 "align1.c" 2
+
+
+
+struct testalign {
+  int f1;
+} __attribute__((__aligned__(16)));
+
+struct t1 {
+  int f0;
+  struct testalign a;
+};
+
+int main() {
+  int offset;
+
+  offset = &((struct t1*)0)->a.f1;
+  printf("Offset is: %d\n", offset);
+
+  if ((int)&(( struct t1  *)0)->a.f1 & 15) {
+    { printf("Error %d\n",  1 ); exit( 1 ); } ;
+  }
+
+
+  { printf("Success\n"); exit(0); } ;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/align2.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/align2.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/align2.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,347 @@
+//# 1 "align2.c"
+//# 1 "testharness.h" 1
+extern int printf(const char * format, ...);
+//#pragma ccuredvararg("printf", printf(1))
+
+extern void exit(int);
+
+ 
+
+
+
+//# 1 "align2.c" 2
+
+
+typedef unsigned int	__kernel_size_t;
+
+typedef __kernel_size_t		size_t;
+
+typedef unsigned int __u32;
+typedef __u32 kernel_cap_t;
+
+typedef int	pid_t;
+
+typedef unsigned int __kernel_uid32_t;
+typedef unsigned int __kernel_gid32_t;
+
+typedef __kernel_uid32_t uid_t;
+
+typedef __kernel_gid32_t gid_t;
+
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
+struct list_head {
+  struct list_head *next, *prev;
+};
+
+typedef struct { int gcc_is_buggy; } spinlock_t;
+
+struct __wait_queue_head {
+  spinlock_t  lock;
+  struct list_head task_list;
+
+};
+typedef struct __wait_queue_head wait_queue_head_t;
+
+struct timer_list {
+  struct list_head list;
+  unsigned long expires;
+  unsigned long data;
+  void (*function)(unsigned long);
+};
+
+typedef long		clock_t;
+struct tms {
+  clock_t tms_utime;
+  clock_t tms_stime;
+  clock_t tms_cutime;
+  clock_t tms_cstime;
+};
+
+
+typedef struct {
+  unsigned long sig[(64  / 32 ) ];
+} sigset_t;
+
+
+struct i387_fsave_struct {
+  long	cwd;
+  long	swd;
+  long	twd;
+  long	fip;
+  long	fcs;
+  long	foo;
+  long	fos;
+  long	st_space[20];	 
+  long	status;		 
+};
+
+struct i387_fxsave_struct {
+  unsigned short	cwd;
+  unsigned short	swd;
+  unsigned short	twd;
+  unsigned short	fop;
+  long	fip;
+	long	fcs;
+  long	foo;
+  long	fos;
+  long	mxcsr;
+  long	reserved;
+  long	st_space[32];	 
+  long	xmm_space[32];	 
+  long	padding[56];
+} __attribute__ ((aligned (16)));
+
+struct i387_soft_struct {
+  long	cwd;
+  long	swd;
+  long	twd;
+  long	fip;
+  long	fcs;
+  long	foo;
+  long	fos;
+  long	st_space[20];	 
+  unsigned char	ftop, changed, lookahead, no_update, rm, alimit;
+  struct info	*info;
+  unsigned long	entry_eip;
+};
+
+union i387_union {
+  struct i387_fsave_struct	fsave;
+  struct i387_fxsave_struct	fxsave;
+  struct i387_soft_struct soft;
+};
+
+struct thread_struct {
+  unsigned long	esp0;
+  unsigned long	eip;
+  unsigned long	esp;
+  unsigned long	fs;
+  unsigned long	gs;
+  
+  unsigned long	debugreg[8];   
+  
+  unsigned long	cr2, trap_no, error_code;
+  
+  union i387_union	i387;
+  
+  struct vm86_struct	* vm86_info;
+  unsigned long		screen_bitmap;
+  unsigned long		v86flags, v86mask, v86mode, saved_esp0;
+  
+  int		ioperm;
+  unsigned long	io_bitmap[32 +1];
+};
+
+struct rlimit {
+  unsigned long	rlim_cur;
+  unsigned long	rlim_max;
+};
+
+
+
+
+typedef union sigval {
+  int sival_int;
+  void *sival_ptr;
+} sigval_t;
+
+
+
+typedef struct siginfo {
+  int si_signo;
+  int si_errno;
+  int si_code;
+  
+  union {
+    int _pad[((128 /sizeof(int)) - 3) ];
+    
+    
+    struct {
+      pid_t _pid;		 
+      uid_t _uid;		 
+    } _kill;
+    
+    
+    struct {
+      unsigned int _timer1;
+      unsigned int _timer2;
+    } _timer;
+    
+    
+    struct {
+      pid_t _pid;		 
+      uid_t _uid;		 
+      sigval_t _sigval;
+    } _rt;
+    
+    
+    struct {
+      pid_t _pid;		 
+      uid_t _uid;		 
+      int _status;		 
+      clock_t _utime;
+      clock_t _stime;
+    } _sigchld;
+    
+    
+    struct {
+      void *_addr;  
+    } _sigfault;
+    
+    
+    struct {
+      int _band;	 
+      int _fd;
+    } _sigpoll;
+  } _sifields;
+} siginfo_t;
+
+struct sigpending {
+  struct sigqueue *head, **tail;
+  sigset_t signal;
+};
+
+struct sigqueue {
+  struct sigqueue *next;
+  siginfo_t info;
+};
+
+
+
+struct task_struct {
+	 
+
+
+  volatile long state;	 
+  unsigned long flags;	 
+  int sigpending;
+  mm_segment_t addr_limit;	 
+  
+  
+  
+  int   *exec_domain;
+  volatile long need_resched;
+  unsigned long ptrace;
+  
+  int lock_depth;		 
+  
+  long counter;
+  long nice;
+  unsigned long policy;
+  int   *mm;
+  int has_cpu, processor;
+  unsigned long cpus_allowed;
+
+  struct list_head run_list;
+  unsigned long sleep_time;
+  
+  struct task_struct *next_task, *prev_task;
+  int   *active_mm;
+  
+  
+  int   *binfmt;
+  int exit_code, exit_signal;
+  int pdeath_signal;   
+  
+  unsigned long personality;
+  int dumpable:1;
+  int did_exec:1;
+  pid_t pid;
+  pid_t pgrp;
+  pid_t tty_old_pgrp;
+  pid_t session;
+  pid_t tgid;
+  
+  int leader;
+
+  struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+  struct list_head thread_group;
+  
+  
+  struct task_struct *pidhash_next;
+  struct task_struct **pidhash_pprev;
+  
+  wait_queue_head_t wait_chldexit;	 
+  int   *vfork_sem;		 
+  unsigned long rt_priority;
+  unsigned long it_real_value, it_prof_value, it_virt_value;
+  unsigned long it_real_incr, it_prof_incr, it_virt_incr;
+  struct timer_list real_timer;
+  struct tms times;
+  unsigned long start_time;
+  long per_cpu_utime[1 ], per_cpu_stime[1 ];
+  
+  unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
+  int swappable:1;
+  
+  uid_t uid,euid,suid,fsuid;
+  gid_t gid,egid,sgid,fsgid;
+  int ngroups;
+  gid_t	groups[32 ];
+  kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
+  int keep_capabilities:1;
+  int   *user;
+  
+  struct rlimit rlim[11 ];
+  unsigned short used_math;
+  char comm[16];
+  
+  int link_count;
+  int   *tty;  
+  unsigned int locks;  
+  
+  int   *semundo;
+  int   *semsleeping;
+  
+  struct thread_struct thread;
+  
+  int   *fs;
+  
+  int   *files;
+  
+  spinlock_t sigmask_lock;	 
+  int   *sig;
+  
+  sigset_t blocked;
+  struct sigpending pending;
+  
+  unsigned long sas_ss_sp;
+  size_t sas_ss_size;
+  int (*notifier)(void *priv);
+  void *notifier_data;
+  sigset_t *notifier_mask;
+  
+  
+  __u32 parent_exec_id;
+  __u32 self_exec_id;
+  
+  spinlock_t alloc_lock;
+};
+
+
+static void __attribute__ ((__section__ (".text.init")))  check_fpu(void)
+{
+  if (((size_t) &(( struct task_struct  *)0)->  thread.i387.fxsave )  & 15) {
+    extern void __buggy_fxsr_alignment(void);
+    __buggy_fxsr_alignment();
+  }
+
+}
+
+
+int main() {
+  int offset;
+
+  
+  offset = &(( struct task_struct  *)0)->  thread.i387.fxsave;
+  printf("Offset is: %d\n", offset);
+  if (((size_t) &(( struct task_struct  *)0)->  thread.i387.fxsave )  & 15) {
+    check_fpu();
+    { printf("Error %d\n",  1 ); exit( 1 ); } ;
+  }
+
+  { printf("Success\n"); exit(0); } ;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/attr2.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/attr2.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/attr2.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,818 @@
+# 1 "attr2.c"
+# 1 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h" 1
+ 
+
+ 
+
+
+
+
+ 
+
+
+
+
+# 1 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccuredannot.h" 1
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+# 27 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccuredannot.h"
+
+  
+
+
+  
+  
+  
+  
+  
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+   
+  
+   
+  
+   
+  
+   
+  
+   
+  
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+extern int __ccuredAlwaysStopOnError;
+ 
+
+
+
+
+extern int __ccuredUseStrings;
+ 
+
+
+
+extern int __ccuredLogNonPointers;
+ 
+
+
+extern int __ccuredDisableStoreCheck;
+ 
+
+
+extern void* __ccuredStackBottom;
+ 
+
+
+
+extern void __ccuredInit(void);
+
+  #pragma cilnoremove("__ccuredInit")
+
+ 
+
+  void ccured_fail_str(char *str,
+                                    char* file, int line, char *func);
+  void ccured_fail_str_terse(char *str);
+ 
+
+ 
+
+
+
+
+
+
+  void ccured_fail(int msgId, char* file, int line, char *func);
+  void ccured_fail_terse(int msgId);
+ 
+ 
+
+
+
+
+
+
+ 
+
+
+
+  void non_pointer_fail(unsigned long l,
+                                     char* file, int line, char *func);
+  void non_pointer_fail_terse(unsigned long l);
+
+
+
+ 
+
+
+ 
+
+
+void __logScalar(int id, unsigned long l);
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 13 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h" 2
+
+
+
+
+ 
+
+extern void* wrapperAlloc(unsigned int);
+#pragma cilnoremove("wrapperAlloc")
+#pragma ccuredalloc("wrapperAlloc", sizein(1), nozero)
+
+extern void wrapperFree(void *);
+#pragma cilnoremove("wrapperFree")
+#pragma ccuredpoly("wrapperFree")
+
+ 
+extern char* wrapperStrdup(char *);
+#pragma cilnoremove("wrapperStrdup")
+#pragma ccuredpoly("wrapperStrdup")
+
+   
+unsigned __ccured_mult_u32(unsigned x, unsigned y);
+
+
+
+ 
+ 
+ 
+ 
+
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+#pragma ccuredpoly("__ptrof_nocheck")
+#pragma cilnoremove("__ptrof_nocheck")
+void *  __attribute__((safe))     __ptrof_nocheck(void *ptr);
+ 
+ 
+ 
+
+#pragma ccuredpoly("__startof")
+void *  __attribute__((safe))     __startof(void *ptr); 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__endof")
+void *  __attribute__((safe))     __endof(void *ptr);
+ 
+ 
+ 
+ 
+
+ 
+
+
+
+ 
+
+
+
+#pragma ccuredpoly("__ptrof")
+void *  __attribute__((safe))     __ptrof(void *ptr);
+ 
+ 
+ 
+
+#pragma ccuredpoly("__verify_nul")
+void __verify_nul(char const *ptr);
+ 
+ 
+ 
+ 
+
+
+
+#pragma ccuredpoly("__strlen")
+int __strlen(char *ptr);      
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__strlen_n")
+int __strlen_n(char *ptr, int n);
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__stringof")
+char * __stringof(char const *ptr);
+#pragma cilnoremove("__stringof")
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__stringof_ornull")
+char * __stringof_ornull(char const *ptr);
+#pragma cilnoremove("__stringof_ornull")
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__write_at_least")
+void __write_at_least(void *ptr, unsigned int n);  
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__read_at_least")
+void __read_at_least(void *ptr, unsigned int n);  
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__copytags")
+void __copytags(void *dest, void* src, unsigned int n);  
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr")
+#pragma cilnoremove("__mkptr") 
+void * __mkptr(void *  __attribute__((safe))    p, void *phome);
+ 
+   
+   
+   
+
+#pragma ccuredpoly("__mkptr_int")
+void * __mkptr_int(unsigned long p, void *phome);
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr_size")
+#pragma cilnoremove("__mkptr_size")
+void * __mkptr_size(void *  __attribute__((safe))    p, unsigned int len);
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr_string")
+#pragma cilnoremove("__mkptr_string")
+char * __mkptr_string(char *  __attribute__((safe))    p);
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__align_seq")
+#pragma cilnoremove("__align_seq")
+void* __align_seq(void *p, unsigned int size);
+ 
+ 
+ 
+ 
+ 
+
+
+ 
+
+#pragma ccuredpoly("__trusted_cast")
+#pragma cilnoremove("__trusted_cast")
+void * __trusted_cast(void * p);
+
+
+   
+   
+   
+
+
+
+
+
+#pragma ccuredpoly("ccured_hasuniontag")
+int  ccured_hasuniontag(void *);
+
+ 
+ 
+
+
+
+int  __ccured_kind_of(void *);
+#pragma ccuredpoly("__ccured_kind_of")
+ 
+
+   
+   
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+  
+  
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+
+   
+   
+  
+   
+   
+  
+
+
+
+    
+    
+  
+
+char* __ccured_mangling_of(unsigned int);
+#pragma ccuredpoly("__ccured_mangling_of")
+#pragma cilnoremove("__ccured_mangling_of")
+ 
+
+int  __ccured_has_empty_mangling(unsigned int);
+#pragma ccuredpoly("__ccured_has_empty_mangling")
+#pragma cilnoremove("__ccured_has_empty_mangling")
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+#pragma cilnoremove("abort_deepcopy")
+__attribute__((noreturn))  void abort_deepcopy(char * errmsg);
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+      
+
+# 353 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h"
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+# 423 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h"
+
+
+
+ 
+
+
+
+
+
+ 
+#pragma cilnoremove("struct printf_arguments")
+struct printf_arguments {
+  int i;
+  double d;  
+  char *  __attribute__((rostring))    s;
+
+
+
+  long long ll;
+
+};
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "attr2.c" 2
+
+__attribute__ ((regparm(0)))
+     int  printk   (const char * fmt, ...)
+     __attribute__ ((format (printf, 1, 2)));
+
+
+  void do_exit(long error_code)
+	__attribute__((noreturn)) ;
+
+ __attribute__((noreturn))  void do_exit1(long error_code) ;
+
+        
+const char __module_parm_vidmem []	__attribute__((section(".modinfo"))) =	"parm_" "vidmem"   "="   "i"  ;
+
+__attribute__((section(".t1sec"))) char t1[5], t2[6];
+
+
+ 
+void ( * pexit)(int err)  __attribute__((noreturn)) ;
+
+
+
+extern int * functional(void) __attribute__((__const__));
+
+int  (*ptr_printk) (const char * fmt, ...);
+
+struct s{
+  int  (*printfun) (const char * fmt, ...);
+};
+
+int main() {
+  struct s printstruct = {&printk};
+  printk("fooo %s", "bau");
+  ptr_printk = &printk;
+  ptr_printk("fooo %s", "bau");
+  printstruct.printfun("fooo %s", "bau");
+
+  { int k = __module_parm_vidmem[3]; }
+  functional();
+  do_exit(5);
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/attr3.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/attr3.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/attr3.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,809 @@
+# 1 "attr3.c"
+# 1 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h" 1
+ 
+
+ 
+
+
+
+
+ 
+
+
+
+
+# 1 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccuredannot.h" 1
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+# 27 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccuredannot.h"
+
+  
+
+
+  
+  
+  
+  
+  
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+   
+  
+   
+  
+   
+  
+   
+  
+   
+  
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+extern int __ccuredAlwaysStopOnError;
+ 
+
+
+
+
+extern int __ccuredUseStrings;
+ 
+
+
+
+extern int __ccuredLogNonPointers;
+ 
+
+
+extern int __ccuredDisableStoreCheck;
+ 
+
+
+extern void* __ccuredStackBottom;
+ 
+
+
+
+extern void __ccuredInit(void);
+
+  #pragma cilnoremove("__ccuredInit")
+
+ 
+
+  void ccured_fail_str(char *str,
+                                    char* file, int line, char *func);
+  void ccured_fail_str_terse(char *str);
+ 
+
+ 
+
+
+
+
+
+
+  void ccured_fail(int msgId, char* file, int line, char *func);
+  void ccured_fail_terse(int msgId);
+ 
+ 
+
+
+
+
+
+
+ 
+
+
+
+  void non_pointer_fail(unsigned long l,
+                                     char* file, int line, char *func);
+  void non_pointer_fail_terse(unsigned long l);
+
+
+
+ 
+
+
+ 
+
+
+void __logScalar(int id, unsigned long l);
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 13 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h" 2
+
+
+
+
+ 
+
+extern void* wrapperAlloc(unsigned int);
+#pragma cilnoremove("wrapperAlloc")
+#pragma ccuredalloc("wrapperAlloc", sizein(1), nozero)
+
+extern void wrapperFree(void *);
+#pragma cilnoremove("wrapperFree")
+#pragma ccuredpoly("wrapperFree")
+
+ 
+extern char* wrapperStrdup(char *);
+#pragma cilnoremove("wrapperStrdup")
+#pragma ccuredpoly("wrapperStrdup")
+
+   
+unsigned __ccured_mult_u32(unsigned x, unsigned y);
+
+
+
+ 
+ 
+ 
+ 
+
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+#pragma ccuredpoly("__ptrof_nocheck")
+#pragma cilnoremove("__ptrof_nocheck")
+void *  __attribute__((safe))     __ptrof_nocheck(void *ptr);
+ 
+ 
+ 
+
+#pragma ccuredpoly("__startof")
+void *  __attribute__((safe))     __startof(void *ptr); 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__endof")
+void *  __attribute__((safe))     __endof(void *ptr);
+ 
+ 
+ 
+ 
+
+ 
+
+
+
+ 
+
+
+
+#pragma ccuredpoly("__ptrof")
+void *  __attribute__((safe))     __ptrof(void *ptr);
+ 
+ 
+ 
+
+#pragma ccuredpoly("__verify_nul")
+void __verify_nul(char const *ptr);
+ 
+ 
+ 
+ 
+
+
+
+#pragma ccuredpoly("__strlen")
+int __strlen(char *ptr);      
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__strlen_n")
+int __strlen_n(char *ptr, int n);
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__stringof")
+char * __stringof(char const *ptr);
+#pragma cilnoremove("__stringof")
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__stringof_ornull")
+char * __stringof_ornull(char const *ptr);
+#pragma cilnoremove("__stringof_ornull")
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__write_at_least")
+void __write_at_least(void *ptr, unsigned int n);  
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__read_at_least")
+void __read_at_least(void *ptr, unsigned int n);  
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__copytags")
+void __copytags(void *dest, void* src, unsigned int n);  
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr")
+#pragma cilnoremove("__mkptr") 
+void * __mkptr(void *  __attribute__((safe))    p, void *phome);
+ 
+   
+   
+   
+
+#pragma ccuredpoly("__mkptr_int")
+void * __mkptr_int(unsigned long p, void *phome);
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr_size")
+#pragma cilnoremove("__mkptr_size")
+void * __mkptr_size(void *  __attribute__((safe))    p, unsigned int len);
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr_string")
+#pragma cilnoremove("__mkptr_string")
+char * __mkptr_string(char *  __attribute__((safe))    p);
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__align_seq")
+#pragma cilnoremove("__align_seq")
+void* __align_seq(void *p, unsigned int size);
+ 
+ 
+ 
+ 
+ 
+
+
+ 
+
+#pragma ccuredpoly("__trusted_cast")
+#pragma cilnoremove("__trusted_cast")
+void * __trusted_cast(void * p);
+
+
+   
+   
+   
+
+
+
+
+
+#pragma ccuredpoly("ccured_hasuniontag")
+int  ccured_hasuniontag(void *);
+
+ 
+ 
+
+
+
+int  __ccured_kind_of(void *);
+#pragma ccuredpoly("__ccured_kind_of")
+ 
+
+   
+   
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+  
+  
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+
+   
+   
+  
+   
+   
+  
+
+
+
+    
+    
+  
+
+char* __ccured_mangling_of(unsigned int);
+#pragma ccuredpoly("__ccured_mangling_of")
+#pragma cilnoremove("__ccured_mangling_of")
+ 
+
+int  __ccured_has_empty_mangling(unsigned int);
+#pragma ccuredpoly("__ccured_has_empty_mangling")
+#pragma cilnoremove("__ccured_has_empty_mangling")
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+#pragma cilnoremove("abort_deepcopy")
+__attribute__((noreturn))  void abort_deepcopy(char * errmsg);
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+      
+
+# 353 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h"
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+# 423 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h"
+
+
+
+ 
+
+
+
+
+
+ 
+#pragma cilnoremove("struct printf_arguments")
+struct printf_arguments {
+  int i;
+  double d;  
+  char *  __attribute__((rostring))    s;
+
+
+
+  long long ll;
+
+};
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "attr3.c" 2
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+int __attribute__((a( 6 )))   * __attribute__((a( 5 )))   (__attribute__((a( 3 )))   * __attribute__((a( 2 )))   (__attribute__((a( 1 )))   x1)[5])(int __attribute__((a( 4 )))  ) __attribute__((name)) ;
+
+
+ 
+
+extern int __attribute__((a( 7 )))   * __attribute__((a( 6 )))   (__attribute__((a( 4 )))   x2)(float __attribute__((a( 5 )))   x) __attribute__((name)) ;
+
+ 
+
+
+int __attribute__((a( 7 )))   * __attribute__((a( 6 )))   (__attribute__((a( 4 )))   * __attribute__((a( 3 )))   (__attribute__((a( 1 )))   x3)(int __attribute__((a( 2 )))   x))(float __attribute__((a( 5 )))  ) {
+  return & x2;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/attr4.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/attr4.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/attr4.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,825 @@
+# 1 "attr4.c"
+# 1 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h" 1
+ 
+
+ 
+
+
+
+
+ 
+
+
+
+
+# 1 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccuredannot.h" 1
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+# 27 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccuredannot.h"
+
+  
+
+
+  
+  
+  
+  
+  
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+   
+  
+   
+  
+   
+  
+   
+  
+   
+  
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+extern int __ccuredAlwaysStopOnError;
+ 
+
+
+
+
+extern int __ccuredUseStrings;
+ 
+
+
+
+extern int __ccuredLogNonPointers;
+ 
+
+
+extern int __ccuredDisableStoreCheck;
+ 
+
+
+extern void* __ccuredStackBottom;
+ 
+
+
+
+extern void __ccuredInit(void);
+
+  #pragma cilnoremove("__ccuredInit")
+
+ 
+
+  void ccured_fail_str(char *str,
+                                    char* file, int line, char *func);
+  void ccured_fail_str_terse(char *str);
+ 
+
+ 
+
+
+
+
+
+
+  void ccured_fail(int msgId, char* file, int line, char *func);
+  void ccured_fail_terse(int msgId);
+ 
+ 
+
+
+
+
+
+
+ 
+
+
+
+  void non_pointer_fail(unsigned long l,
+                                     char* file, int line, char *func);
+  void non_pointer_fail_terse(unsigned long l);
+
+
+
+ 
+
+
+ 
+
+
+void __logScalar(int id, unsigned long l);
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 13 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h" 2
+
+
+
+
+ 
+
+extern void* wrapperAlloc(unsigned int);
+#pragma cilnoremove("wrapperAlloc")
+#pragma ccuredalloc("wrapperAlloc", sizein(1), nozero)
+
+extern void wrapperFree(void *);
+#pragma cilnoremove("wrapperFree")
+#pragma ccuredpoly("wrapperFree")
+
+ 
+extern char* wrapperStrdup(char *);
+#pragma cilnoremove("wrapperStrdup")
+#pragma ccuredpoly("wrapperStrdup")
+
+   
+unsigned __ccured_mult_u32(unsigned x, unsigned y);
+
+
+
+ 
+ 
+ 
+ 
+
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+#pragma ccuredpoly("__ptrof_nocheck")
+#pragma cilnoremove("__ptrof_nocheck")
+void *  __attribute__((safe))     __ptrof_nocheck(void *ptr);
+ 
+ 
+ 
+
+#pragma ccuredpoly("__startof")
+void *  __attribute__((safe))     __startof(void *ptr); 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__endof")
+void *  __attribute__((safe))     __endof(void *ptr);
+ 
+ 
+ 
+ 
+
+ 
+
+
+
+ 
+
+
+
+#pragma ccuredpoly("__ptrof")
+void *  __attribute__((safe))     __ptrof(void *ptr);
+ 
+ 
+ 
+
+#pragma ccuredpoly("__verify_nul")
+void __verify_nul(char const *ptr);
+ 
+ 
+ 
+ 
+
+
+
+#pragma ccuredpoly("__strlen")
+int __strlen(char *ptr);      
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__strlen_n")
+int __strlen_n(char *ptr, int n);
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__stringof")
+char * __stringof(char const *ptr);
+#pragma cilnoremove("__stringof")
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__stringof_ornull")
+char * __stringof_ornull(char const *ptr);
+#pragma cilnoremove("__stringof_ornull")
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__write_at_least")
+void __write_at_least(void *ptr, unsigned int n);  
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__read_at_least")
+void __read_at_least(void *ptr, unsigned int n);  
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__copytags")
+void __copytags(void *dest, void* src, unsigned int n);  
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr")
+#pragma cilnoremove("__mkptr") 
+void * __mkptr(void *  __attribute__((safe))    p, void *phome);
+ 
+   
+   
+   
+
+#pragma ccuredpoly("__mkptr_int")
+void * __mkptr_int(unsigned long p, void *phome);
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr_size")
+#pragma cilnoremove("__mkptr_size")
+void * __mkptr_size(void *  __attribute__((safe))    p, unsigned int len);
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr_string")
+#pragma cilnoremove("__mkptr_string")
+char * __mkptr_string(char *  __attribute__((safe))    p);
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__align_seq")
+#pragma cilnoremove("__align_seq")
+void* __align_seq(void *p, unsigned int size);
+ 
+ 
+ 
+ 
+ 
+
+
+ 
+
+#pragma ccuredpoly("__trusted_cast")
+#pragma cilnoremove("__trusted_cast")
+void * __trusted_cast(void * p);
+
+
+   
+   
+   
+
+
+
+
+
+#pragma ccuredpoly("ccured_hasuniontag")
+int  ccured_hasuniontag(void *);
+
+ 
+ 
+
+
+
+int  __ccured_kind_of(void *);
+#pragma ccuredpoly("__ccured_kind_of")
+ 
+
+   
+   
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+  
+  
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+
+   
+   
+  
+   
+   
+  
+
+
+
+    
+    
+  
+
+char* __ccured_mangling_of(unsigned int);
+#pragma ccuredpoly("__ccured_mangling_of")
+#pragma cilnoremove("__ccured_mangling_of")
+ 
+
+int  __ccured_has_empty_mangling(unsigned int);
+#pragma ccuredpoly("__ccured_has_empty_mangling")
+#pragma cilnoremove("__ccured_has_empty_mangling")
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+#pragma cilnoremove("abort_deepcopy")
+__attribute__((noreturn))  void abort_deepcopy(char * errmsg);
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+      
+
+# 353 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h"
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+# 423 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h"
+
+
+
+ 
+
+
+
+
+
+ 
+#pragma cilnoremove("struct printf_arguments")
+struct printf_arguments {
+  int i;
+  double d;  
+  char *  __attribute__((rostring))    s;
+
+
+
+  long long ll;
+
+};
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "attr4.c" 2
+# 1 "testharness.h" 1
+extern int printf(const char * format, ...);
+#pragma ccuredvararg("printf", printf(1))
+
+extern void exit(int);
+
+ 
+
+
+
+# 1 "attr4.c" 2
+
+
+typedef struct {
+  int f1;
+  char f1pad;
+  int f2  __attribute__((packed)), f3 __attribute__((packed));
+  char f2pad;
+  int f4, f5 __attribute__((packed));  
+  char f3pad;
+  int __attribute__((packed)) f6, f7;  
+} STR;
+
+
+
+
+
+int main() {
+  printf("Offset 1 = %d\n", ((int)(&((  STR *)(0))-> f1 )) );
+  printf("Offset 2 = %d\n", ((int)(&((  STR *)(0))-> f2 )) );
+  printf("Offset 3 = %d\n", ((int)(&((  STR *)(0))-> f3 )) );
+  printf("Offset 4 = %d\n", ((int)(&((  STR *)(0))-> f4 )) );
+  printf("Offset 5 = %d\n", ((int)(&((  STR *)(0))-> f5 )) );
+  printf("Offset 6 = %d\n", ((int)(&((  STR *)(0))-> f6 )) );
+  printf("Offset 7 = %d\n", ((int)(&((  STR *)(0))-> f7 )) );
+
+  if(((int)(&((  STR *)(0))-> f1 ))  != 0 ||
+     ((int)(&((  STR *)(0))-> f2 ))  != 5 ||
+     ((int)(&((  STR *)(0))-> f3 ))  != 9 ||
+     ((int)(&((  STR *)(0))-> f4 ))  != 16 ||
+     ((int)(&((  STR *)(0))-> f5 ))  != 20 ||
+     ((int)(&((  STR *)(0))-> f6 ))  != 25 ||
+     ((int)(&((  STR *)(0))-> f7 ))  != 29) {
+    return 1;
+  }
+
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/attr5.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/attr5.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/attr5.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+# 1 "attr5.c"
+# 1 "testharness.h" 1
+extern int printf(const char * format, ...);
+#pragma ccuredvararg("printf", printf(1))
+
+extern void exit(int);
+
+ 
+
+
+
+# 1 "attr5.c" 2
+
+
+int x;
+int * myfunc(void) __attribute__((section(".modinfo")));
+int * myfunc(void) {
+  return &x;
+}
+
+int main() {
+  if(&x != myfunc()) { printf("Error %d\n",  1 ); exit( 1 ); } ;
+  
+  { printf("Success\n"); exit(0); } ;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/attr6.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/attr6.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/attr6.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+# 1 "attr6.c"
+ 
+typedef int md5_uint32;
+
+struct md5_ctx
+{
+  md5_uint32 A;
+  md5_uint32 B;
+  md5_uint32 C;
+  md5_uint32 D;
+
+  md5_uint32 total[2];
+  md5_uint32 buflen;
+  char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
+};

Added: vendor/elsa/current/elsa/in/gnu/cil/bind-zero.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/bind-zero.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/bind-zero.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,873 @@
+# 1 "bind-zero.c"
+# 1 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h" 1
+ 
+
+ 
+
+
+
+
+ 
+
+
+
+
+# 1 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccuredannot.h" 1
+ 
+
+ 
+
+
+
+
+
+
+
+
+
+
+# 27 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccuredannot.h"
+
+  
+
+
+  
+  
+  
+  
+  
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+   
+  
+   
+  
+   
+  
+   
+  
+   
+  
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+extern int __ccuredAlwaysStopOnError;
+ 
+
+
+
+
+extern int __ccuredUseStrings;
+ 
+
+
+
+extern int __ccuredLogNonPointers;
+ 
+
+
+extern int __ccuredDisableStoreCheck;
+ 
+
+
+extern void* __ccuredStackBottom;
+ 
+
+
+
+extern void __ccuredInit(void);
+
+  #pragma cilnoremove("__ccuredInit")
+
+ 
+
+  void ccured_fail_str(char *str,
+                                    char* file, int line, char *func);
+  void ccured_fail_str_terse(char *str);
+ 
+
+ 
+
+
+
+
+
+
+  void ccured_fail(int msgId, char* file, int line, char *func);
+  void ccured_fail_terse(int msgId);
+ 
+ 
+
+
+
+
+
+
+ 
+
+
+
+  void non_pointer_fail(unsigned long l,
+                                     char* file, int line, char *func);
+  void non_pointer_fail_terse(unsigned long l);
+
+
+
+ 
+
+
+ 
+
+
+void __logScalar(int id, unsigned long l);
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 13 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h" 2
+
+
+
+
+ 
+
+extern void* wrapperAlloc(unsigned int);
+#pragma cilnoremove("wrapperAlloc")
+#pragma ccuredalloc("wrapperAlloc", sizein(1), nozero)
+
+extern void wrapperFree(void *);
+#pragma cilnoremove("wrapperFree")
+#pragma ccuredpoly("wrapperFree")
+
+ 
+extern char* wrapperStrdup(char *);
+#pragma cilnoremove("wrapperStrdup")
+#pragma ccuredpoly("wrapperStrdup")
+
+   
+unsigned __ccured_mult_u32(unsigned x, unsigned y);
+
+
+
+ 
+ 
+ 
+ 
+
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+#pragma ccuredpoly("__ptrof_nocheck")
+#pragma cilnoremove("__ptrof_nocheck")
+void *  __attribute__((safe))     __ptrof_nocheck(void *ptr);
+ 
+ 
+ 
+
+#pragma ccuredpoly("__startof")
+void *  __attribute__((safe))     __startof(void *ptr); 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__endof")
+void *  __attribute__((safe))     __endof(void *ptr);
+ 
+ 
+ 
+ 
+
+ 
+
+
+
+ 
+
+
+
+#pragma ccuredpoly("__ptrof")
+void *  __attribute__((safe))     __ptrof(void *ptr);
+ 
+ 
+ 
+
+#pragma ccuredpoly("__verify_nul")
+void __verify_nul(char const *ptr);
+ 
+ 
+ 
+ 
+
+
+
+#pragma ccuredpoly("__strlen")
+int __strlen(char *ptr);      
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__strlen_n")
+int __strlen_n(char *ptr, int n);
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__stringof")
+char * __stringof(char const *ptr);
+#pragma cilnoremove("__stringof")
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__stringof_ornull")
+char * __stringof_ornull(char const *ptr);
+#pragma cilnoremove("__stringof_ornull")
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__write_at_least")
+void __write_at_least(void *ptr, unsigned int n);  
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__read_at_least")
+void __read_at_least(void *ptr, unsigned int n);  
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__copytags")
+void __copytags(void *dest, void* src, unsigned int n);  
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr")
+#pragma cilnoremove("__mkptr") 
+void * __mkptr(void *  __attribute__((safe))    p, void *phome);
+ 
+   
+   
+   
+
+#pragma ccuredpoly("__mkptr_int")
+void * __mkptr_int(unsigned long p, void *phome);
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr_size")
+#pragma cilnoremove("__mkptr_size")
+void * __mkptr_size(void *  __attribute__((safe))    p, unsigned int len);
+ 
+ 
+ 
+ 
+ 
+ 
+
+#pragma ccuredpoly("__mkptr_string")
+#pragma cilnoremove("__mkptr_string")
+char * __mkptr_string(char *  __attribute__((safe))    p);
+ 
+ 
+ 
+ 
+
+
+#pragma ccuredpoly("__align_seq")
+#pragma cilnoremove("__align_seq")
+void* __align_seq(void *p, unsigned int size);
+ 
+ 
+ 
+ 
+ 
+
+
+ 
+
+#pragma ccuredpoly("__trusted_cast")
+#pragma cilnoremove("__trusted_cast")
+void * __trusted_cast(void * p);
+
+
+   
+   
+   
+
+
+
+
+
+#pragma ccuredpoly("ccured_hasuniontag")
+int  ccured_hasuniontag(void *);
+
+ 
+ 
+
+
+
+int  __ccured_kind_of(void *);
+#pragma ccuredpoly("__ccured_kind_of")
+ 
+
+   
+   
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+  
+  
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+
+   
+   
+  
+   
+   
+  
+
+
+
+    
+    
+  
+
+char* __ccured_mangling_of(unsigned int);
+#pragma ccuredpoly("__ccured_mangling_of")
+#pragma cilnoremove("__ccured_mangling_of")
+ 
+
+int  __ccured_has_empty_mangling(unsigned int);
+#pragma ccuredpoly("__ccured_has_empty_mangling")
+#pragma cilnoremove("__ccured_has_empty_mangling")
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+#pragma cilnoremove("abort_deepcopy")
+__attribute__((noreturn))  void abort_deepcopy(char * errmsg);
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+
+ 
+
+
+
+      
+
+# 353 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h"
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+# 423 "/slack8/home/scott/wrk/safec/cil-trunk/include/ccured.h"
+
+
+
+ 
+
+
+
+
+
+ 
+#pragma cilnoremove("struct printf_arguments")
+struct printf_arguments {
+  int i;
+  double d;  
+  char *  __attribute__((rostring))    s;
+
+
+
+  long long ll;
+
+};
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "bind-zero.c" 2
+ 
+ 
+ 
+typedef long long __quad_t;
+typedef long __off_t;
+typedef __quad_t __loff_t;
+typedef __loff_t __off64_t;
+typedef struct _IO_FILE FILE;
+typedef void _IO_lock_t;
+struct _IO_FILE
+{
+  int _flags;
+  char *_IO_read_ptr;
+  char *_IO_read_end;
+  char *_IO_read_base;
+  char *_IO_write_base;
+  char *_IO_write_ptr;
+  char *_IO_write_end;
+  char *_IO_buf_base;
+  char *_IO_buf_end;
+  char *_IO_save_base;
+  char *_IO_backup_base;
+  char *_IO_save_end;
+  struct _IO_marker *_markers;
+  struct _IO_FILE *_chain;
+  int _fileno;
+  int _blksize;
+  __off_t _old_offset;
+  unsigned short _cur_column;
+  signed char _vtable_offset;
+  char _shortbuf[1];
+  _IO_lock_t *_lock;
+  __off64_t _offset;
+  void *__pad1;
+  void *__pad2;
+  int _mode;
+  char _unused2[(int) (15U * sizeof (int) - 2U * sizeof (void *))];
+};
+extern void * __attribute__ ((__safe__)) __ptrof_nocheck (void *ptr);
+__inline static char *
+fgets_wrapper (char *buf, int size, FILE * fp)
+{
+  char *res;
+  FILE *tmp;
+  char *tmp___0;
+  char *tmp___1;
+  {
+     
+    tmp = (FILE *) __ptrof_nocheck ((void *) fp);
+
+//    res = fgets ((char *) tmp___0, size, (FILE *) tmp);
+
+    return (tmp___1);
+  }
+}
+char *
+gets_wrapper (char *buffer)
+{
+  char *res;
+  FILE *tmp;
+  void * __attribute__ ((__safe__)) tmp___0;
+  void * __attribute__ ((__safe__)) tmp___1;
+  char *tmp___2;
+  char *tmp___3;
+  {
+//    tmp = get_stdin ();
+     
+    tmp___1 = __ptrof_nocheck ((void *) buffer);
+    tmp___2 =
+      fgets_wrapper (buffer,
+		     (int) ((unsigned int) tmp___0 - (unsigned int) tmp___1),
+		     tmp);
+    res = tmp___2;
+    if ((unsigned long) res != (unsigned long) ((void *) 0))
+      {
+	tmp___3 = res;
+	while (1)
+	  {
+	    if ((int) (*tmp___3) != 10)
+	      {
+		if (!((int) (*tmp___3) != 0))
+		  {
+		    break;
+		  }
+	      }
+	    else
+	      {
+		break;
+	      }
+	    tmp___3++;
+	  }
+	(*tmp___3) = '\0';
+      }
+    return (res);
+  }
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/combine_samefn_1.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/combine_samefn_1.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/combine_samefn_1.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+# 1 "combine_samefn_1.c"
+ 
+ 
+ 
+ 
+                               
+ 
+#pragma ccuredpoly("some_poly_fn")
+
+ 
+int foo(int xxx)
+{
+  int yyy = xxx + 3;     
+  int z = yyy + xxx;     
+  return z + xxx;        
+}
+
+
+int myglobal __attribute__((mayPointToStack)) = 3;
+
+
+ 
+__inline static int func()
+{
+  return 3;
+}
+
+__inline static int func___0();
+__inline static int func___0()
+{
+  return 3;
+}
+
+
+ 
+int otherFunc();
+
+
+int main()
+{
+  int ret = func() + func___0() - 6;     
+  ret += foo(5) - 18 + myglobal - 3;     
+  ret += otherFunc() - 3;                
+  return ret;
+}
+

Added: vendor/elsa/current/elsa/in/gnu/cil/decl1.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/decl1.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/decl1.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+# 1 "decl1.c"
+struct timeval {
+	int	tv_sec;		 
+	int	tv_usec;	 
+};
+
+extern struct timeval xtime;
+
+
+volatile struct timeval xtime __attribute__ ((aligned (16)));
+
+extern void printf(char *, ...);
+
+
+
+int main() {
+  if((int)&xtime & 0xF != 0) { printf("Error %d\n",  1 ); return  1 ; } ;
+
+  printf("Success\n");
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/enumattr.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/enumattr.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/enumattr.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+# 1 "enumattr.c"
+ 
+ 
+
+typedef enum {
+    x = 256
+} __attribute__((__packed__)) large_enum;
+
+large_enum enum_l = x;
+
+int main()
+{
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/globalprob.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/globalprob.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/globalprob.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+# 1 "globalprob.c"
+
+typedef struct {
+	volatile unsigned int lock;
+} spinlock_t;
+
+spinlock_t runqueue_lock __attribute__((__aligned__(32 ),    
+	__section__(".data.cacheline_aligned")))  = (spinlock_t) { 1   } ;
+
+
+int main () {
+ return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/init8.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/init8.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/init8.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+# 1 "init8.c"
+struct pci_device_info {
+	unsigned short device;
+	unsigned short seen;
+	const char *name;
+};
+
+static struct pci_device_info __devices_0000 []
+__attribute__ ((__section__ (".data.init")))  = { };
+

Added: vendor/elsa/current/elsa/in/gnu/cil/invalredef.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/invalredef.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/invalredef.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+# 1 "invalredef.c"
+
+
+extern int wchgat(const void *);
+
+int wchgat(const void *opts __attribute__((unused)) )
+{
+      return 1;
+}
+
+int main () {
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/mode_sizes.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/mode_sizes.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/mode_sizes.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+# 1 "mode_sizes.c"
+ 
+ 
+
+ 
+typedef int int8_t __attribute__ ((__mode__ (  __QI__ ))) ;
+typedef int int16_t __attribute__ ((__mode__ (  __HI__ ))) ;
+typedef int int32_t __attribute__ ((__mode__ (  __SI__ ))) ;
+typedef int int64_t __attribute__ ((__mode__ (  __DI__ ))) ;
+
+typedef unsigned int u_int8_t __attribute__ ((__mode__ (  __QI__ ))) ;
+typedef unsigned int u_int16_t __attribute__ ((__mode__ (  __HI__ ))) ;
+typedef unsigned int u_int32_t __attribute__ ((__mode__ (  __SI__ ))) ;
+typedef unsigned int u_int64_t __attribute__ ((__mode__ (  __DI__ ))) ;
+
+typedef int someInt;       
+
+ 
+someInt printf(char const *fmt, ...);
+
+int main()
+{
+  int ok = 1;
+
+  
+
+
+  printf("size of " "int8_t" " is: %d (should be %d)\n", sizeof( int8_t ),   1 ); ok = ok && (sizeof( int8_t ) ==   1 ) ;
+  printf("size of " "int16_t" " is: %d (should be %d)\n", sizeof( int16_t ),   2 ); ok = ok && (sizeof( int16_t ) ==   2 ) ;
+  printf("size of " "int32_t" " is: %d (should be %d)\n", sizeof( int32_t ),   4 ); ok = ok && (sizeof( int32_t ) ==   4 ) ;
+  printf("size of " "int64_t" " is: %d (should be %d)\n", sizeof( int64_t ),   8 ); ok = ok && (sizeof( int64_t ) ==   8 ) ;
+
+  printf("size of " "u_int8_t" " is: %d (should be %d)\n", sizeof( u_int8_t ),   1 ); ok = ok && (sizeof( u_int8_t ) ==   1 ) ;
+  printf("size of " "u_int16_t" " is: %d (should be %d)\n", sizeof( u_int16_t ),   2 ); ok = ok && (sizeof( u_int16_t ) ==   2 ) ;
+  printf("size of " "u_int32_t" " is: %d (should be %d)\n", sizeof( u_int32_t ),   4 ); ok = ok && (sizeof( u_int32_t ) ==   4 ) ;
+  printf("size of " "u_int64_t" " is: %d (should be %d)\n", sizeof( u_int64_t ),   8 ); ok = ok && (sizeof( u_int64_t ) ==   8 ) ;
+  
+
+  return ok? 0 : 1;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/regparm0.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/regparm0.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/regparm0.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+# 1 "regparm0.c"
+ 
+ 
+
+ 
+ 
+ 
+__attribute__((regparm(0)))  int  do_signal(int *regs, int *oldset)
+   __attribute__((regparm(2))) __attribute__((regparm(3)));
+
+ 
+int main()
+{
+  int r=6, o=5;
+  return do_signal(&o, &r) - 11;
+}
+
+ 
+int do_signal(int *regs, int *oldset)
+{
+  return *regs + *oldset;
+}
+
+
+
+

Added: vendor/elsa/current/elsa/in/gnu/cil/rmtmps-attr.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/rmtmps-attr.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/rmtmps-attr.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+# 1 "rmtmps-attr.c"
+# 1 "testharness.h" 1
+extern int printf(const char * format, ...);
+#pragma ccuredvararg("printf", printf(1))
+
+extern void exit(int);
+
+ 
+
+
+
+# 1 "rmtmps-attr.c" 2
+
+
+int main()
+{
+  int a;
+  int b __attribute__((myattribute(a == a)));
+  b = 5;
+   
+   
+
+   
+   
+  { printf("Success\n"); exit(0); } ; 
+} 

Added: vendor/elsa/current/elsa/in/gnu/cil/rmtmps2.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/rmtmps2.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/rmtmps2.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,49 @@
+# 1 "rmtmps2.c"
+typedef struct { volatile int counter; } atomic_t;
+
+ 
+static __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		""  "decl %0; sete %1"
+		:"=m" (v->counter), "=qm" (c)
+		:"m" (v->counter) : "memory");
+	return c != 0;
+}
+
+struct mm_struct {
+	atomic_t mm_users;			 
+	atomic_t mm_count;			 
+};
+ 
+
+ 
+extern inline void  __mmdrop(struct mm_struct *)  __attribute__((regparm(3))) ;
+static inline void mmdrop(struct mm_struct * mm)
+{
+	if (atomic_dec_and_test(&mm->mm_count))
+		__mmdrop(mm);
+}
+
+
+
+inline void __mmdrop(struct mm_struct *mm)
+{
+  return;
+}
+
+ 
+
+void mmput(struct mm_struct *mm)
+{
+  if (atomic_dec_and_test(&mm->mm_users) ) {
+    mmdrop(mm);
+  }
+}
+
+ 
+int main() {
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/sockaddr.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/sockaddr.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/sockaddr.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,98 @@
+# 1 "sockaddr.c"
+typedef unsigned short int sa_family_t;
+
+typedef signed short int __int16_t;
+
+typedef unsigned char		uint8_t;
+typedef unsigned short int	uint16_t;
+typedef unsigned int		uint32_t;
+
+typedef unsigned int socklen_t;
+
+struct sockaddr
+  {
+    sa_family_t  sa_family ;
+    char sa_data[14];
+  };
+
+
+struct in_addr
+  {
+    uint32_t s_addr;
+  };
+
+struct sockaddr_in
+  {
+    sa_family_t  sin_family ;
+    uint16_t sin_port;
+    struct in_addr sin_addr;
+
+
+    unsigned char sin_zero[sizeof (struct sockaddr) -
+			   (sizeof (unsigned short int))  -
+			   sizeof (uint16_t) -
+			   sizeof (struct in_addr)];
+  };
+
+struct in6_addr
+  {
+    union
+      {
+	uint8_t		u6_addr8[16];
+	uint16_t	u6_addr16[8];
+	uint32_t	u6_addr32[4];
+      } in6_u;
+  };
+
+struct sockaddr_in6
+  {
+    sa_family_t  sin6_family ;
+    uint16_t sin6_port;
+    uint32_t sin6_flowinfo;
+    struct in6_addr sin6_addr;
+  };
+
+
+union sockunion {
+	struct sockinet {
+		sa_family_t  si_family ;
+		uint16_t si_port;
+	} su_si;
+	struct sockaddr_in su_sin;
+	struct sockaddr_in6 su_sin6;
+};
+
+union sockunion server_addr;
+
+typedef union {
+  __const struct  sockaddr  *__sockaddr__;
+   
+   
+   
+   
+  __const struct  sockaddr_in  *__sockaddr_in__;
+  __const struct  sockaddr_in6  *__sockaddr_in6__;
+   
+   
+   
+   
+   
+   
+} __CONST_SOCKADDR_ARG __attribute__ ((__transparent_union__));
+
+extern int bind  (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)    ;
+
+ 
+
+int main()
+{
+  int ctl_sock=0;
+  struct sockaddr *addrptr;
+                           
+  addrptr = (struct sockaddr *)&server_addr;
+  bind(ctl_sock, addrptr, 3);
+            
+
+  return ctl_sock;
+}
+

Added: vendor/elsa/current/elsa/in/gnu/cil/structattr.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/structattr.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/structattr.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,56 @@
+# 1 "structattr.c"
+ 
+ 
+
+struct A {
+  int x;
+} __attribute__((packed));
+struct A a;
+
+struct B {
+  int x;
+} __attribute__((packed)) b;
+
+
+ 
+ 
+ 
+ 
+
+struct __attribute__((packed)) C {
+  int x;
+};
+struct C c;
+
+struct __attribute__((packed)) D {
+  int x;
+} d;
+
+
+ 
+ 
+ 
+ 
+
+ 
+struct __attribute__((__packed__)) {
+    int i;
+    char c;
+} e;
+
+
+typedef unsigned long ULONG;
+typedef int WCHAR;
+typedef struct __attribute__((packed, aligned(4))) _INFORMATION {
+     ULONG FileAttributes;
+     ULONG FileNameLength;
+     WCHAR FileName[1];
+} INFORMATION, *PINFORMATION;
+
+INFORMATION i;
+PINFORMATION pi;
+
+int main()
+{
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/structattr2.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/structattr2.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/structattr2.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+# 1 "structattr2.c"
+ 
+ 
+ 
+
+ 
+const struct c  { int a; } b, e;
+
+ 
+struct c d;
+
+
+ 
+struct c2  { int a; } const b2, e2;
+
+struct c2 d2;
+
+
+ 
+struct c3  { int a; } const;
+struct c3 b3, e3;
+
+const struct c4  { int a; };
+struct c4 b4, e4;
+
+struct __attribute__((packed)) c5 { int a; } b5, e5;
+struct c5 d5;
+
+struct c6 { int a; } __attribute__((packed)) b6, e6;
+struct c6 d6;
+
+struct c7 { int a; } __attribute__((packed));
+struct c7 b7;
+
+int main() { return 0; }
+

Added: vendor/elsa/current/elsa/in/gnu/cil/structattr3.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/structattr3.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/structattr3.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+# 1 "structattr3.c"
+ 
+ 
+
+
+struct S { char a; } __attribute__((aligned(8))) const  x = {1};
+
+struct S y[10] = {1,2,3};
+int z = 5;
+
+int main() { return 0; }

Added: vendor/elsa/current/elsa/in/gnu/cil/transpunion.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/transpunion.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/transpunion.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+# 1 "transpunion.c"
+ 
+
+struct BoxedInt {
+  int x;
+};
+
+typedef union {
+  int *intPtr;
+  struct BoxedInt *boxedPtr;
+} CompatArgUnion __attribute__((__transparent_union__));
+
+extern int compatFunc(int, CompatArgUnion);
+
+int compatFunc(int firstArg, CompatArgUnion secondArg)
+{
+  return firstArg + *(secondArg.intPtr);
+}
+
+
+int main()
+{ 
+  int i = 6;
+  struct BoxedInt b;
+  int ret = 0;
+
+  b.x = 7;
+
+   
+  ret += compatFunc(-6, &i);
+  
+   
+  ret += compatFunc(-7, &b);
+  
+  return ret;
+}
+
+

Added: vendor/elsa/current/elsa/in/gnu/cil/typeof1.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/typeof1.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/typeof1.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,77 @@
+# 1 "typeof1.c"
+ 
+
+extern int printf(const char* fmt, ...);
+
+
+void foo();
+
+
+__typeof(foo) afun;  
+void afun() {}
+
+void bfun(void);  
+extern __typeof(afun) bfun __attribute__ ((alias ("afun")));  
+
+int arr[9];
+
+__typeof(arr) barr = { 0, 1, 2, 3 } ;
+
+
+__typeof("a long string") str;  
+
+
+
+
+typedef int FUN(int);
+
+FUN fptr;  
+
+FUN fptr;  
+
+int fptr(int x);  
+
+int fptr(int x) {  
+  return x - 1;
+}
+
+typedef int ARRAY[8];
+
+ARRAY carr;
+
+int main(void) 
+{
+
+  afun();
+  bfun();
+   
+
+
+
+
+
+
+
+  { char a[] = { [ sizeof(foo) ] = 34 }; printf("sizeof(foo)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( sizeof(foo) )); if( sizeof(foo)  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ sizeof(afun) ] = 34 }; printf("sizeof(afun)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( sizeof(afun) )); if( sizeof(afun)  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ sizeof("a long string") ] = 34 }; printf("sizeof(\"a long string\")" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( sizeof("a long string") )); if( sizeof("a long string")  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ sizeof(str) ] = 34 }; printf("sizeof(str)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( sizeof(str) )); if( sizeof(str)  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ sizeof(arr) ] = 34 }; printf("sizeof(arr)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( sizeof(arr) )); if( sizeof(arr)  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ sizeof(barr) ] = 34 }; printf("sizeof(barr)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( sizeof(barr) )); if( sizeof(barr)  != sizeof(a) - 1) { exit(1); } } ;
+
+  { char a[] = { [ __alignof("a string") ] = 34 }; printf("__alignof(\"a string\")" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( __alignof("a string") )); if( __alignof("a string")  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ __alignof(str) ] = 34 }; printf("__alignof(str)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( __alignof(str) )); if( __alignof(str)  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ __alignof(foo) ] = 34 }; printf("__alignof(foo)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( __alignof(foo) )); if( __alignof(foo)  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ __alignof(afun) ] = 34 }; printf("__alignof(afun)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( __alignof(afun) )); if( __alignof(afun)  != sizeof(a) - 1) { exit(1); } } ;
+  { char a[] = { [ __alignof(arr) ] = 34 }; printf("__alignof(arr)" " = %d (CIL) and %d (Compiler)\n", sizeof(a) - 1, ( __alignof(arr) )); if( __alignof(arr)  != sizeof(a) - 1) { exit(1); } } ;
+
+   
+   
+   
+
+
+  if(sizeof(carr) != sizeof(ARRAY)) {
+    exit(8);
+  }
+  return fptr(1);
+}

Added: vendor/elsa/current/elsa/in/gnu/cil/warnings-noreturn.i
===================================================================
--- vendor/elsa/current/elsa/in/gnu/cil/warnings-noreturn.i	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/cil/warnings-noreturn.i	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+# 1 "warnings-noreturn.c"
+# 1 "testharness.h" 1
+extern int printf(const char * format, ...);
+#pragma ccuredvararg("printf", printf(1))
+
+extern void exit(int);
+
+ 
+
+
+
+# 1 "warnings-noreturn.c" 2
+
+
+
+void croak() __attribute__((noreturn));
+void die() __attribute__((noreturn));
+
+
+void terminate(int) __attribute__((noreturn));
+
+void terminate(int frog)
+{
+  if (frog)
+    croak();
+  else
+    die();
+}
+
+
+int main()
+{
+  { printf("Success\n"); exit(0); } ;
+}

Added: vendor/elsa/current/elsa/in/gnu/d0076.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0076.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0076.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// Test "restrict" which I understand is a C99-ism but right now we
+// only lex "__restrict__" as a gnu extension so I'll put it here with
+// gnu stuff.
+
+int const * const __restrict__ volatile x;

Added: vendor/elsa/current/elsa/in/gnu/d0078.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0078.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0078.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+//  /home/ballAruns/tmpfiles/./Guppi-0.40.3-13/gnan-1Njx.i:3823:64:
+//  error: there is no member called `__d' in union /*anonymous*/
+
+int main() {
+  (
+   (union {int c;}) {c:0}
+  ) .c ;
+
+  (
+   (union {int d;}) {d:0}
+  ) .d ;
+
+  // for now this typechecks the E_compoundLit twice due to the way []
+  // is implemented as lowering and re-typechecking
+  (
+   (union {int i[2];}) {i:{0}}
+  )
+  .i[1];
+}

Added: vendor/elsa/current/elsa/in/gnu/d0081.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0081.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0081.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+// dsw: g++ seems to define a variable __null that my guess is a void*
+// to 0; test that we can typecheck it.
+void *x = __null;

Added: vendor/elsa/current/elsa/in/gnu/d0082.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0082.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0082.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// ./qt2-2.3.1-13/qstring-ht7v.i.cpp_out:/home/ballAruns/tmpfiles/./qt2-2.3.1-13/qstring-ht7v.i:5628:8: error: no viable candidate for function call
+
+typedef __builtin_va_list __gnuc_va_list;
+typedef __gnuc_va_list va_list;
+
+void sprintf( const char* cformat, ... )
+{
+    va_list ap;
+    __builtin_stdarg_start((ap),cformat);
+    int width = __builtin_va_arg( ap, int );
+    __builtin_va_arg(ap, char*);
+    int* n = __builtin_va_arg(ap, int*);
+    double value = __builtin_va_arg(ap, double);
+    void* value2 = __builtin_va_arg(ap, void*);
+    __builtin_va_end( ap );
+}

Added: vendor/elsa/current/elsa/in/gnu/d0083.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0083.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0083.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// ./balsa-2.0.6-1/ab-window-67O9.i.c_out:4:/home/ballAruns/tmpfiles/./balsa-2.0.6-1/ab-window-67O9.i:31990:5:
+// error: there is no type called `LibBalsaMessageFlag'
+
+// looks like you can make a typedef to a enum that doesn't exist yet
+
+typedef enum F0 F;
+
+enum F0 {
+    f1 = 1,
+};
+
+struct S {
+    F flags;
+};

Added: vendor/elsa/current/elsa/in/gnu/d0085.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0085.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0085.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+//  ./compat-db-3.3.11-4/cxx_app-9TN0.i.cpp_out:/home/ballAruns/tmpfiles/./compat-db-3.3.11-4/cxx_app-9TN0.i:561:38:
+//  Parse error (state 275) at asm
+
+// note that the 'asm' comes after the 'throw'
+
+extern void *tmpfile (void) throw () __asm__ ("" "tmpfile64");

Added: vendor/elsa/current/elsa/in/gnu/d0086.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0086.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0086.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+//  ./abiword-1.0.4-2/fl_SectionLayout-aKmk.i.cpp_out:/home/ballAruns/tmpfiles/./abiword-1.0.4-2/fl_SectionLayout-aKmk.i:16896:28: error: there is no variable called `pPair'
+
+// gcc allows a struct to be referred to as a class and vice versa
+
+struct A {
+  public:
+  int x;
+};
+class A a;
+
+class B {
+  public:
+  int y;
+};
+struct B b;
+
+int main() {
+  a.x;
+  b.y;
+}

Added: vendor/elsa/current/elsa/in/gnu/d0089.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0089.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0089.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// /home/ballAruns/tmpfiles/./lftp-2.6.3-3/ftpclass-n5uO.i
+
+int main() {
+  char *pwd=(char*)__builtin_alloca(3);
+}
+
+// quarl 2006-09-07
+//    Do NOT declare __builtin_alloca since it won't be compatible with the
+//    FF_NOPARAM in gnu.cc.  (After builtin-declarations.h is used, this
+//    should be ok.)  I didn't see any real code that does so.
+
+// /home/ballB/gcc-2.96-110/bb-reorder-Zb4y.i
+// extern void *__builtin_alloca (unsigned int);
+
+// try it again
+int f() {
+  char *pwd=(char*)__builtin_alloca(3);
+}

Added: vendor/elsa/current/elsa/in/gnu/d0092.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0092.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0092.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// some builtins that I ran into
+
+// # 441 "/usr/include/bits/mathinline.h"
+__inline double fabs (double __x) throw () { return __builtin_fabs (__x); }
+__inline float fabsf (float __x) throw () { return __builtin_fabsf (__x); }
+__inline long double fabsl (long double __x) throw () { return __builtin_fabsl (__x); }
+__inline long double __fabsl (long double __x) throw () { return __builtin_fabsl (__x); }

Added: vendor/elsa/current/elsa/in/gnu/d0093.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0093.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0093.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1 @@
+typedef int x[];

Added: vendor/elsa/current/elsa/in/gnu/d0094.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0094.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0094.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// /home/ballAruns/tmpfiles/./authconfig-4.3.4-1/dnsclient-Hfb9.i:3562:47:
+// error: reprSize of a sizeless array
+
+// you are allowed to take the size of a dynamically-sized array
+
+typedef unsigned int size_t;
+void f(size_t buf_len)
+{
+  unsigned char label[buf_len];
+  sizeof(label);
+}

Added: vendor/elsa/current/elsa/in/gnu/d0095.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0095.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0095.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+/* nss_ldap-202-5/mp_alloc-WPlt.i */
+
+struct A {
+  int x;
+};
+
+int main(int argc) {
+  struct A *a;
+  /* in C mode gcc seems to allow NULL to merge with another type
+     without affecting it */
+  (argc ? ((void*)0) : a          ) -> x;
+  (argc ? a          : ((void*)0) ) -> x;
+}

Added: vendor/elsa/current/elsa/in/gnu/d0096.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0096.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0096.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// give only a warning when a function that was declared implicitly by
+// a function call is later declared explicitly with a more specific
+// and therefore (likely) inconsistent type; FIX: I don't think this
+// is gnu specific, but is K&R specific
+
+// sm: actually, it's ordinary C89
+
+int main() {
+  int buf[4];
+  int const in[16];
+  MD5_Transform(buf, in);
+}
+
+void MD5_Transform(int buf[4], int const in[16])
+{
+}

Added: vendor/elsa/current/elsa/in/gnu/d0099.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0099.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0099.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// test some of the funkier gcc attribute things:
+// http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC90
+
+// pretty normal
+int x0 __attribute__ ((nocommon));
+int x0b __attribute ((nocommon));
+
+// I don't know what this means but we parse it
+int x1 __attribute__ ((mode (byte)));
+int x2 __attribute__ ((mode (__byte__)));
+int x3 __attribute__ ((mode (word)));
+int x4 __attribute__ ((mode (__word__)));
+int x5 __attribute__ ((mode (pointer)));
+int x6 __attribute__ ((mode (__pointer__)));
+
+int z0 __attribute__ ((model (small)));
+int z1 __attribute__ ((model (medium)));
+int z2 __attribute__ ((model (large)));
+
+int w0 __attribute__ ((aligned (__alignof (int))));
+struct A {} __attribute__ ((aligned (__alignof (int))));
+
+// currently crashes gcc 3.4
+//  struct A {} __attribute__ ((mode (byte)));
+//  struct A {} __attribute__ ((mode (__byte__)));
+//  struct A {} __attribute__ ((mode (word)));
+//  struct A {} __attribute__ ((mode (__word__)));
+//  struct A {} __attribute__ ((mode (pointer)));
+//  struct A {} __attribute__ ((mode (__pointer__)));

Added: vendor/elsa/current/elsa/in/gnu/d0122.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0122.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0122.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+const char __module_parm_desc_aic7xxx[] __attribute__((section(".modinfo"))) =
+  "parm_desc_" "aic7xxx" "=" "period delimited, options string.
+	verbose			Enable verbose/diagnostic logging
+	no_probe		Disable EISA/VLB controller probing
+	no_reset		Supress initial bus resets
+	extended		Enable extended geometry on all controllers
+	periodic_otag		Send an ordered tagged transaction periodically
+				to prevent tag starvation.  This may be
+				required by some older disk drives/RAID arrays. 
+	reverse_scan		Sort PCI devices highest Bus/Slot to lowest
+	tag_info:<tag_str>	Set per-target tag depth
+	seltime:<int>		Selection Timeout(0/256ms,1/128ms,2/64ms,3/32ms)
+
+	Sample /etc/modules.conf line:
+		Enable verbose logging
+		Disable EISA/VLB probing
+		Set tag depth on Controller 2/Target 2 to 10 tags
+		Shorten the selection timeout to 128ms from its default of 256
+
+	options aic7xxx='\"verbose.no_probe.tag_info:{{}.{}.{..10}}.seltime:1\"'
+"
+  ;

Added: vendor/elsa/current/elsa/in/gnu/d0130.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/d0130.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/d0130.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// dsw: from Taras Glek <tglek at mozilla.com>
+class foo {
+    __attribute__ ((visibility ("default"))) __attribute__ ((visibility ("waga")))  foo() ;
+    __attribute__ ((visibility ("default"))) ~foo() ;
+};

Added: vendor/elsa/current/elsa/in/gnu/dC0001.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0001.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0001.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2 @@
+// hex float literal
+float y = (__extension__ 0x1.0p2047);

Added: vendor/elsa/current/elsa/in/gnu/dC0002.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0002.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0002.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// arrays of no size are assumed to have size one in gcc, but not g++
+
+// sm: 2005-03-12: This testcase has been improperly minimized; as
+// noted below, gcc does *not* accept it!  Someone should try to find
+// out what example this came from and minimize it properly.
+
+struct S {
+  int x;
+  //int a[];
+};
+
+int a[];
+int f() {
+  sizeof a;                // though it seems to not tolerate this; whatever
+
+  sizeof(struct S);
+}
+int a[3];
+int g() {
+  sizeof a;
+}
+
+struct Incomplete;
+void h() {
+  //ERROR(1): struct Incomplete inc;
+}
+
+

Added: vendor/elsa/current/elsa/in/gnu/dC0003.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0003.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0003.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+struct A *x;
+struct B {
+  struct A {};
+};
+
+struct A2 *x2;
+struct B2 {
+  struct A2 {} A2;
+};

Added: vendor/elsa/current/elsa/in/gnu/dC0004.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0004.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0004.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// from the kernel
+struct qstr {
+        const unsigned char * name;
+        unsigned int len;
+        unsigned int hash;
+};
+int main() {
+  // in the kernel it is used as a call to a function, not assigned to
+  // a pointer as it is here; I didn't want the extra function call
+  // layer when reading the AST
+  const struct qstr *x =
+    &(const struct qstr) { "bdev:", 5, 0 };
+}

Added: vendor/elsa/current/elsa/in/gnu/dC0005.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0005.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0005.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// from the kernel; see
+// http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Inline.html#Inline
+
+extern __inline__
+void parport_pc_write_data(unsigned char d) {
+  return (d) & (d);
+}
+
+void parport_pc_write_data(unsigned char d) {
+  return (d) & (d);
+}
+
+

Added: vendor/elsa/current/elsa/in/gnu/dC0006.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0006.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0006.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+// from the kernel
+struct board_info static_boards[0]={
+};

Added: vendor/elsa/current/elsa/in/gnu/dC0007.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0007.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0007.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// from the kernel
+static int sstfb_decode_var()
+{
+  int x;
+  switch (x) {
+    case 0 ... 16 :
+      break;
+
+    // gcc-2 allows this      
+    case 17 ... 31 :
+      /* nothing */
+  }
+}

Added: vendor/elsa/current/elsa/in/gnu/dC0008.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0008.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0008.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// this form shows up in the kernel
+int a[] = { [1] /*no = or : here*/ 0, [2] 10, [3] 13,};
+struct A {
+  int x;
+  int y;
+};
+int main() {
+  struct A a = { .y /*no = or : here*/ 3, .x 8 };
+}

Added: vendor/elsa/current/elsa/in/gnu/dC0009.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0009.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0009.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// from the kernel
+
+typedef unsigned char UCHAR8;
+typedef short INT16;
+typedef int INT32;
+
+struct wf_sample_offset
+{
+    INT32 Fraction:4;
+    INT32 Integer:20;
+    INT32 Unused:8;
+};
+
+typedef struct wf_alias {
+    INT16 OriginalSample __attribute__ ((packed));
+
+    struct wf_sample_offset sampleStartOffset __attribute__ ((packed));
+    struct wf_sample_offset loopStartOffset __attribute__ ((packed));
+    struct wf_sample_offset sampleEndOffset __attribute__ ((packed));
+    struct wf_sample_offset loopEndOffset __attribute__ ((packed));
+
+    INT16 FrequencyBias __attribute__ ((packed));
+
+    UCHAR8 SampleResolution:2 __attribute__ ((packed));
+    UCHAR8 Unused1:1 __attribute__ ((packed));
+    UCHAR8 Loop:1 __attribute__ ((packed));
+    UCHAR8 Bidirectional:1 __attribute__ ((packed));
+    UCHAR8 Unused2:1 __attribute__ ((packed));
+    UCHAR8 Reverse:1 __attribute__ ((packed));
+    UCHAR8 Unused3:1 __attribute__ ((packed));
+    UCHAR8 sixteen_bit_padding __attribute__ ((packed));
+} wavefront_alias;

Added: vendor/elsa/current/elsa/in/gnu/dC0014.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0014.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0014.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// dC0014.c
+// combining a typedef-name with a type modifier like "long"
+
+// from the kernel
+
+// sm: this is actually a bug in gcc-2 (and vestiges remain in gcc-3)
+
+typedef unsigned int u32;
+u32 long off;
+typedef u32 long off2;
+
+typedef u32 long;
+typedef u32 unsigned long;
+
+
+// ----------------------------------------
+// copied from (now defunct) in/c/k0001.c
+
+// the input was from e2fsprogs, though e2fsprogs-1.36 does
+// not seem to have this problem anymore
+
+typedef int fooint;
+
+// interestingly, of the three uses of the "feature" in this file,
+// this one is the only one accepted by gcc-3
+typedef fooint long /*omitted declarator*/;
+
+typedef fooint long blah;
+
+

Added: vendor/elsa/current/elsa/in/gnu/dC0015.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0015.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0015.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+void i2o_lan_handle_event()
+{
+  int max_evt_data_size = 3;
+  struct i2o_reply {
+    int data[max_evt_data_size];
+  } *evt;
+}

Added: vendor/elsa/current/elsa/in/gnu/dC0016.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0016.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0016.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// from the kernel
+int __const_udelay_Reae3dfd6(int);
+int __udelay_R9e7d6bd0(int);
+int __bad_udelay();
+int main() {
+  (
+   (__builtin_constant_p(1) && (1)<=5)
+   ? (__builtin_constant_p((1)*1000)
+      ? (((1)*1000) > 20000
+         ? __bad_udelay()
+         : __const_udelay_Reae3dfd6(((1)*1000) * 0x10c6ul))
+      : __udelay_R9e7d6bd0((1)*1000))
+   : ({
+     unsigned long msec=(1);
+     while (msec--)
+       (__builtin_constant_p(1000)
+        ? ((1000) > 20000
+           ? __bad_udelay()
+           : __const_udelay_Reae3dfd6((1000) * 0x10c6ul))
+        : __udelay_R9e7d6bd0(1000));
+   })
+   );
+}

Added: vendor/elsa/current/elsa/in/gnu/dC0017.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/dC0017.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/dC0017.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+int *tableHeader;
+typedef int INT;
+int i;
+void f() {
+  __alignof__(*tableHeader);
+
+  __alignof__(INT /*type*/);
+  __alignof__(i /*expr*/);
+}

Added: vendor/elsa/current/elsa/in/gnu/g0001.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0001.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0001.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// g0001.cc
+// "__restrict__" keyword
+// I think this is a gnu thing
+
+int * __restrict__ x;

Added: vendor/elsa/current/elsa/in/gnu/g0002.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0002.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0002.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// g0002.cc
+// strange extern-template thing (gnu specific?)
+
+//template int x;
+
+// I assume you need a template decl ...
+template <class T>
+class allocator {};
+
+extern template class allocator<char>;

Added: vendor/elsa/current/elsa/in/gnu/g0003.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0003.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0003.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// g0003.cc
+// __builtin_va_list
+
+typedef __builtin_va_list __gnuc_va_list;

Added: vendor/elsa/current/elsa/in/gnu/g0004.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0004.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0004.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// g0004.cc
+// call some GNU __builtins, as gcc's cstream header does
+
+void f()
+{
+  __builtin_strchr("foo", 'f');
+  __builtin_strpbrk("foo", "fo");
+  __builtin_strrchr("foo", 'o');
+  __builtin_strstr("this is the haystack", "hay");
+}

Added: vendor/elsa/current/elsa/in/gnu/g0005.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0005.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0005.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// g0005.cc
+// __builtin_expect
+
+void glorf(int);
+
+void foo(int x)
+{
+  if (__builtin_expect(x == 5, 0)) {
+    glorf(1);
+  }
+  else {
+    glorf(2);
+  }
+}

Added: vendor/elsa/current/elsa/in/gnu/g0006.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0006.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0006.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// g0006.cc
+// simulation of gcc's vararg stuff
+
+
+typedef void *__gnuc_va_list;
+typedef __gnuc_va_list va_list;
+
+int myprintf(char const *format, ...)
+{
+  va_list ap;
+  ( ap  = ((__gnuc_va_list) __builtin_next_arg (  format ))) ;
+  ((void)0) ;
+  return 0;
+}
+

Added: vendor/elsa/current/elsa/in/gnu/g0007.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0007.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0007.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// g0007.cc
+// ambiguity error message
+// -*-c++-*-
+
+typedef void *__gnuc_va_list;
+typedef __gnuc_va_list va_list;
+union my_error_arguments {
+    int i;
+    char *s;
+};
+#pragma boxvararg("my_error",sizeof(union my_error_arguments))
+#pragma boxvararg("__my_error",sizeof(union my_error_arguments))
+void my_error(int severity, ...) {
+    va_list ap;
+    ( ap  = ((__gnuc_va_list) __builtin_next_arg (  severity ))) ;
+}

Added: vendor/elsa/current/elsa/in/gnu/g0008.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0008.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0008.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// g0008.cc
+// test __FUNCTION__ etc. in C++ mode
+
+void f()
+{
+  char const *b = __FUNCTION__;
+  char const *c = __PRETTY_FUNCTION__;
+
+  //ERROR(1):   char const *d = something_else;             // undefined
+  //ERROR(3):   char const *f = "x" __FUNCTION__;           // can't concat
+  //ERROR(4):   char const *g = "x" __PRETTY_FUNCTION__;    // can't concat
+
+  // 2005-08-10: It seems that GCC does allow this in C++,
+  // even though it is a C99 feature.
+  char const *h = __func__;                   // not in (ANSI) C++
+}

Added: vendor/elsa/current/elsa/in/gnu/g0009.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0009.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0009.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// g0009.c
+// test __FUNCTION__ etc. in C mode
+
+void f()
+{
+  char const *a = __func__;
+  char *b = __FUNCTION__;
+  char *c = __PRETTY_FUNCTION__;
+
+  //ERROR(1):   char *d = something_else;             // undefined
+
+  //ERROR(2):   char *d = "x" __func__;               // no concat
+
+  // these *can* concat in gcc <= 3.3
+  char *f = "x" __FUNCTION__;
+  char *g = "x" __PRETTY_FUNCTION__;
+
+  char *f2 = "x" __FUNCTION__ "y";
+  char *g2 = "x" __PRETTY_FUNCTION__ "y";
+}

Added: vendor/elsa/current/elsa/in/gnu/g0010.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0010.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0010.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// g0003.cc
+// from jrvb
+
+int uselocale;
+namespace __gnu_cxx
+{
+  extern "C" __typeof(uselocale) __uselocale;
+}

Added: vendor/elsa/current/elsa/in/gnu/g0011.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0011.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0011.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// g0011.cc
+// __attribute__ in a parameter list
+// from Kevin Millikin
+
+void foo(const int __attribute__ ((__unused__)) x) { return; }

Added: vendor/elsa/current/elsa/in/gnu/g0012.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0012.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0012.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// g0012.cc
+// __attribute__ on a return value
+// from Kevin Millikin
+
+int __attribute__((__cdecl__)) isalnum (int __c);

Added: vendor/elsa/current/elsa/in/gnu/g0013.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0013.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0013.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// g0013.cc
+// compound lit with type defn inside array deref
+// related to d0078.cc
+
+void f()
+{   
+  int *a;
+  a[
+    (
+      (struct Foo { int x; }){ 0 }      // compound lit: {x=0}
+    ).x
+   ];
+}
+
+
+
+
+

Added: vendor/elsa/current/elsa/in/gnu/g0014.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0014.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0014.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// g0014.cc
+// compound lit with unsized array
+
+int f()
+{
+  return (
+           (int[]) {1, 2}
+         )[0];
+}

Added: vendor/elsa/current/elsa/in/gnu/g0015.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0015.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0015.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// t0001.cc
+// hex floating literals
+
+
+void f(float);
+
+void foo()
+{
+  // optional parts:         HEX1 "." HEX2 sign suffix
+  
+  // everything
+  f(0x1aE.2bFp+312f);   //    *    *   *    *     *
+
+  // missing one
+  f(0x.2bFp+312f);      //         *   *    *     *
+  f(0x1aE2bFp+312f);    //    *             *     *
+  f(0x1aE.p+312f);      //    *    *        *     *
+  f(0x1aE.2bFp312f);    //    *    *   *          *
+  f(0x1aE.2bFp+312);    //    *    *   *    *
+
+  // variations
+  f(0X1aE.2bFP-312F);   //    *    *   *    *     *
+  f(0x1aE.2bFP+312l);   //    *    *   *    *     *
+  f(0X1aE.2bFP-312L);   //    *    *   *    *     *
+
+  // missing more
+  f(0x.2bFp312f);       //         *   *          *
+  f(0x.2bFp+312);       //         *   *    *
+  f(0x1aE2bFp312f);     //    *                   *
+  f(0x1aE2bFp+312);     //    *             *
+  f(0x1aE2bFp312);      //    *
+  f(0x1aE.p312f);       //    *    *              *
+  f(0x1aE.p+312);       //    *    *        *     *
+
+  // errors
+  //ERROR(1): f(0x1aE.2bFp);      // need digits after 'p'
+  //ERROR(2): f(0x1aE.2bF);       // must have 'p'
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/gnu/g0016.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0016.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0016.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// g0016.cc
+// gcc allows some nonstandard variations among declarations
+// if the first declarations is in a preprocessing section
+// where the #line header ends with "3" (exactly)
+
+// This input file exists as a record of what I have determined
+// gcc's behavior to be.  Elsa handles the problem in a different
+// way than by emulating gcc.
+
+// this would provoke an error in gcc-3, but gcc-2 accepts it, so I
+// am not going to test the behavior of Elsa on it
+//# 1 "butnot.h"
+//int isatty  ( int )  ;
+
+# 5 "somewhere.h" 3
+
+// an extra intervening #line apparently doesn't change prevailing
+// filename nor flags
+# 19
+
+// this declaration has "throw()" whereas the rest do not; according
+// to cppstd, that is an error
+int isatty (int __fd) throw () ;
+
+# 7 "else.h"
+
+int isatty  ( int )  ;
+
+# 9 "again.h"
+
+int isatty  ( int )  ;

Added: vendor/elsa/current/elsa/in/gnu/g0017.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0017.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0017.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// g0017.cc
+// example of a common header problem that gcc allows
+
+// excerpted from /opt/qt-2.3.2/src/moc/mocgen.cpp (after preprocessing)
+
+extern "C" {
+# 574 "/usr/include/unistd.h" 3
+extern int isatty (int __fd) throw () ;
+}
+extern int isatty  ( int )  ;

Added: vendor/elsa/current/elsa/in/gnu/g0018.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0018.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0018.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// g0018.cc
+// gcc allows 'main' to be declared w/o a type!
+
+main(int argc, char** argv)
+{
+  // whatever
+  return argc - 1;
+}

Added: vendor/elsa/current/elsa/in/gnu/g0019.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0019.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0019.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,103 @@
+// g0019.cc
+// min and max operators
+
+void foo()
+{
+  int i,j,k;
+
+  i = j <? k;
+  i = j >? k;
+
+  double a,b,c;
+
+  a = b <? c;
+  a = b >? c;
+}
+
+
+// little trick to get compiler to tell me the 
+// value of a compile-time constant
+template <int x>
+class A {};
+
+// tell me the value in an error report
+void tellme(int dummy);
+void tellme(int *dummy);
+
+// require the value to be 0
+void zero(int dummy);
+void zero(A<0> a);
+
+// require it to be 1
+void one(int dummy);
+void one(A<1> a);
+
+// 5
+void five(int dummy);
+void five(A<5> a);
+
+
+
+void bar()
+{
+  // what is the precedence?
+
+  // lower than '*'
+  //   if '*' is higher, this is 1     (yes)
+  //   if '<?' is higher, this is 5
+  A<( 5 * 1 <? 1 )> a2;
+  one(a2);
+
+  // lower than '+'
+  //   if '+' is higher, this is 1     (yes)
+  //   if '<?' is higher, this is 6
+  A<( 5 + 1 <? 1 )> a1;
+  one(a1);
+
+  // lower than '<<'
+  //   if '<<' is higher, this is 1    (yes)
+  //   if '<?' is higher, this is 8
+  A<( 4 << 1 <? 1 )> a5;
+  one(a5);
+
+  
+  // it seems that '<?' and '>?' have equal precedence, with
+  // left associativity
+
+  // (      )                 5        (yes)
+  A<( 4 <? 1 >? 5 )> a6;
+  //      (      )            4
+  five(a6);
+
+  //      (      )            4
+  A<( 4 >? 7 <? 1 )> a7;
+  // (      )                 1        (yes)
+  one(a7);
+
+
+  // gcc-3: same precedence as '<' and '>', left associating with them
+  // gcc-2: between "</>" and "<</>>"
+  // Elsa implements the gcc-3 rules ...
+
+  // (      )                 0        (yes)
+  A<( -1 < 1 <? 0 )> a8;
+  //      (      )            1
+  zero(a8);
+
+  // (       )                1        (yes)
+  A<( -1 <? 1 < 0 )> a4;
+  //       (     )           -1        (actually, gcc-2 is here...)
+  one(a4);
+
+
+  // higher than '||'
+  //   if '||' is higher, this is 0
+  //   if '<?' is higher, this is 1    (yes)
+  A<( 5 || 0 <? 0 )> a3;
+  one(a3);
+  
+  
+  // wrong types
+  //ERROR(1): 3 <? a3;
+  //ERROR(2): a3 >? 3;
+}

Added: vendor/elsa/current/elsa/in/gnu/g0020.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0020.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0020.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// g0020.cc
+// gcc-2 accepts this code, despite the mismatch between argument
+// and parameter type for the second argument to 'signal'; Elsa
+// and gcc-3 do not accept it, but I'm creating this testcase just
+// in case I want Elsa to accept it at some point
+
+typedef void (*SignalProc)(... );
+
+extern "C" {
+
+typedef void (*__sighandler_t) (int);
+extern __sighandler_t xxxsignal (int __sig, __sighandler_t __handler) throw () ;
+
+}
+
+void foo()
+{
+  SignalProc s;
+  xxxsignal(1, s);
+}

Added: vendor/elsa/current/elsa/in/gnu/g0021.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0021.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0021.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// g0021.cc
+// coverage: arrays
+
+extern int sizeLess[];
+
+void f(int s)
+{
+  int dynSize[s];       // legal in GNU mode
+  int fixedSize[5];
+
+  sizeof(fixedSize);
+  sizeof(dynSize);      // also legal in GNU mode
+  //ERROR(1): sizeof(sizeLess);
+}
+
+

Added: vendor/elsa/current/elsa/in/gnu/g0022.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0022.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0022.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// addresses of labels and computed goto
+
+// originally found in package procps
+
+// error: Parse error (state 499) at &&
+
+// ERR-MATCH: Parse error .*at &&
+
+int main()
+{
+    void *a = &&x;
+    goto *a;
+x:
+
+    int i;
+    //ERROR(1): goto *i;     // 'i' is not a pointer
+
+    return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/g0023.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0023.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0023.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// g0023.cc
+// g++-2 lets code refer to bad_alloc w/o std:: prefix
+
+namespace std {
+  class bad_alloc {};
+}
+
+int *foo()
+{
+  try {
+    return new int;
+  }
+  catch (std::bad_alloc) {      // standard
+    return 0;
+  }
+}
+
+int *foo2()
+{
+  try {
+    return new int;
+  }
+  catch (bad_alloc) {           // nonstandard
+    return 0;
+  }
+}
+
+int *foo3()
+{
+  try {
+    return new int;
+  }
+  catch (class bad_alloc) {     // nonstandard, with elaborated type spec
+    return 0;
+  }
+}

Added: vendor/elsa/current/elsa/in/gnu/g0024.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0024.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0024.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// g0024.cc                               
+// excerpt from gcc-2 header "stl_alloc.h" that contains invalid code
+// but I need to allow if I want to handle code preprocessed with
+// gcc-2
+
+template <bool __threads, int __inst>
+class __default_alloc_template {
+  typedef int _Obj;
+  static _Obj * volatile _S_free_list[16];
+};
+
+template <bool __threads, int __inst>
+__default_alloc_template<__threads, __inst>::_Obj* volatile
+__default_alloc_template<__threads, __inst> ::_S_free_list[
+    16
+] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };

Added: vendor/elsa/current/elsa/in/gnu/g0025.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0025.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0025.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// g0025.cc
+// explicit class spec w/o "template <>"
+// allowed by gcc-2 bug
+
+template <class T>
+class string_char_traits {};
+
+/* should say "template <>" here */
+class string_char_traits<char> {};

Added: vendor/elsa/current/elsa/in/gnu/g0026.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0026.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0026.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// g0026.cc
+// gcc-2 header bugs from bastring.cc
+
+template <class charT, class traits,
+          class Allocator>
+class basic_string
+{
+private:
+  struct Rep {
+    inline static Rep* create (unsigned);
+  };
+
+  typedef unsigned size_type;
+  size_type copy (charT* s, size_type n, size_type pos = 0) const;
+};
+
+template <class charT, class traits, class Allocator>
+inline /* should say "typename" here */
+basic_string <charT, traits, Allocator>::Rep *
+basic_string <charT, traits, Allocator>::Rep::
+create (unsigned extra)
+{
+  // ...
+}
+
+template <class charT, class traits, class Allocator>
+/* should say "typename" here */
+basic_string <charT, traits, Allocator>::size_type
+basic_string <charT, traits, Allocator>::
+copy (charT* s, size_type n, size_type pos) const
+{
+  // ...
+  return n;
+}

Added: vendor/elsa/current/elsa/in/gnu/g0027.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0027.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0027.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// g0027.cc
+// valid client code interacts with buggy gcc-2 headers
+
+// these should be in namespace std, but are not
+class string {};
+void getline(string s);      // this prototype is bogus
+
+// clients then expect them to be in std
+void foo()
+{
+  std::string s;
+  std::getline(s);
+}
+

Added: vendor/elsa/current/elsa/in/gnu/g0028.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0028.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0028.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// g0028.cc
+// from gcc-3.4.3 <limits> header
+
+static float infinity1() throw()
+{ return __builtin_huge_valf (); }
+
+static double infinity2() throw()
+{ return __builtin_huge_val(); }
+
+static long double infinity3() throw()
+{ return __builtin_huge_vall (); }
+
+static double quiet_NaN() throw()
+{ return __builtin_nan (""); }

Added: vendor/elsa/current/elsa/in/gnu/g0029.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0029.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0029.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// g0029.cc
+// __complex__
+// from gcc-3.4.3 <complex> header
+
+typedef __complex__ float _ComplexT;
+
+//ERROR(1): typedef __complex__ /*missing*/ something;
+
+void f()
+{
+  _ComplexT c1, c2;
+  float f1, f2;
+
+  // read parts
+  f1 = __real__ c1;
+  f1 = __imag__ c1;
+  
+  //ERROR(2): __real__ f1;
+               
+  // write parts
+  __real__ c1 = f1;
+  __imag__ c1 = f1;
+                
+  // read+write
+  __real__ c1 += f1;
+
+  // arith on complex
+  c1 = c2;
+  c1 = c1 + c2;
+                     
+  // mixed arith
+  c1 = c1 * f1;
+  c1 *= f1;
+
+  c1 = c1 / f1;
+  c2 /= f1;
+}
+
+

Added: vendor/elsa/current/elsa/in/gnu/g0030.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0030.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0030.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// g0030.cc
+// testing "extern template"
+
+template <class T>
+struct A {
+  int foo()
+  {
+    // This code is not valid when T = int, but I will not
+    // notice because I won't actually instantiate it.
+    typename T::Foo f;
+    return f;
+  }
+};
+
+extern template class A<int>;

Added: vendor/elsa/current/elsa/in/gnu/g0031.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0031.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0031.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,80 @@
+// g0031.cc
+// using __attribute__ mode to select data type
+
+// The page
+//   http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Variable-Attributes.html
+// documents the notion of __attribute__ __mode__, however I cannot
+// find anything that specifies what the modes themselves mean.  So
+// I will simply infer their meaning from how they are used in the
+// glibc headers.
+
+// /usr/include/sys/types.h, around line 177, after macro expansion
+typedef int int8_t __attribute__ ((__mode__ (  __QI__ ))) ;
+typedef int int16_t __attribute__ ((__mode__ (  __HI__ ))) ;
+typedef int int32_t __attribute__ ((__mode__ (  __SI__ ))) ;
+typedef int int64_t __attribute__ ((__mode__ (  __DI__ ))) ;
+
+typedef unsigned int u_int8_t __attribute__ ((__mode__ (  __QI__ ))) ;
+typedef unsigned int u_int16_t __attribute__ ((__mode__ (  __HI__ ))) ;
+typedef unsigned int u_int32_t __attribute__ ((__mode__ (  __SI__ ))) ;
+typedef unsigned int u_int64_t __attribute__ ((__mode__ (  __DI__ ))) ;
+
+
+// way to test at compile-time that two types are equal; template
+// argument deduction will fail if the args are not equal; Elsa has
+// __elsa_checkType, but other compilers don't, and I especially want to
+// test against GCC
+template <class T>
+void equalTypes(T,T);
+
+// test 'equalTypes'
+void foo()
+{
+  int i;
+  char c;
+
+  equalTypes(i,i);
+  //ERROR(1): equalTypes(i,c);
+  equalTypes(c,c);
+}
+
+
+// compare the __mode__ types above
+void bar()
+{
+  int8_t  i8;
+  int16_t i16;
+  int32_t i32;
+  int64_t i64;
+
+  u_int8_t  ui8;
+  u_int16_t ui16;
+  u_int32_t ui32;
+  u_int64_t ui64;
+  
+  signed char sc;
+  unsigned char uc;
+  
+  signed short ss;
+  unsigned short us;
+  
+  signed int si;
+  unsigned int ui;
+  
+  signed long long sll;
+  unsigned long long ull;
+  
+  equalTypes(i8,  sc);
+  equalTypes(i16, ss);
+  equalTypes(i32, si);
+  equalTypes(i64, sll);
+
+  equalTypes(ui8,  uc);
+  equalTypes(ui16, us);
+  equalTypes(ui32, ui);
+  equalTypes(ui64, ull);
+}
+
+
+
+

Added: vendor/elsa/current/elsa/in/gnu/g0032.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0032.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0032.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// g0032.cc
+// using '$' in identifiers
+
+struct A {
+  int identifier_$_has_dollar;
+
+  // this one conflicts with cqual's syntax...
+  int $starts_with_dollar;
+  
+  int ends_with_dollar$;
+  
+  int two_$_dollars_$_here;
+  
+  int adjacent_$$_dollars;
+};

Added: vendor/elsa/current/elsa/in/gnu/g0033.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/g0033.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/g0033.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// g0033.cc
+// does typeof applied to an array type incorporate knowledge
+// of a later-added size?
+        
+
+extern int a[];                 // initially, no size specified
+
+extern typeof(a) b;             // int b[];
+
+void f1()
+{
+  //ERROR(1): sizeof(a);        // invalid, size unknown
+  //ERROR(2): sizeof(b);        // same
+}
+
+int a[5];
+
+void f2()
+{
+  sizeof(a);                    // valid, size now known
+  //ERROR(3): sizeof(b);        // valid? NO
+}
+
+int b[10];                      // give 'b' a different size
+
+void f3()
+{
+  sizeof(b);                    // now ok
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/gnu/k0001.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0001.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0001.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// empty compound-statement expression
+
+// originally found in package opencdk
+
+// error: `({ ... })' cannot be empty
+
+int main() {
+    ({});
+}

Added: vendor/elsa/current/elsa/in/gnu/k0002.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0002.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0002.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+
+// example program using __builtin_va_* functions
+
+// ERR-MATCH: __builtin_va
+
+int printf(const char*, ...);
+
+int foo(int count, ...) {
+    __builtin_va_list v;
+
+    __builtin_va_start(v, count);
+
+    while (count--) {
+        const char* p = __builtin_va_arg(v, const char*);
+        printf("%s ", p);
+    }
+
+    __builtin_va_list v2;
+    __builtin_va_copy(v2, v);                       // C99 has va_copy
+
+    __builtin_va_end(v2);
+}
+
+int main()
+{
+    foo(4, "a", "b", "c", "d");
+}

Added: vendor/elsa/current/elsa/in/gnu/k0003.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0003.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0003.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,256 @@
+// gcc 3.4 __builtin_* math functions
+
+// http://gcc.gnu.org/onlinedocs/gcc-3.4.3/gcc/Other-Builtins.html
+// though that page does not document "modff" ...
+
+// ERR-MATCH: __builtin_f
+
+inline double
+abs(double __x)
+{ return __builtin_fabs(__x); }
+
+inline float
+abs(float __x)
+{ return __builtin_fabsf(__x); }
+
+inline long double
+abs(long double __x)
+{ return __builtin_fabsl(__x); }
+
+
+inline float
+acos(float __x)
+{ return __builtin_acosf(__x); }
+
+inline long double
+acos(long double __x)
+{ return __builtin_acosl(__x); }
+
+inline double acos(double __x)
+{
+    return __builtin_acos(__x);
+}
+
+inline float
+asin(float __x)
+{ return __builtin_asinf(__x); }
+
+inline long double
+asin(long double __x)
+{ return __builtin_asinl(__x); }
+
+inline double asin(double __x)
+{ return __builtin_asin(__x); }
+
+inline float
+atan(float __x)
+{ return __builtin_atanf(__x); }
+
+inline long double
+atan(long double __x)
+{ return __builtin_atanl(__x); }
+
+inline double atan(double __x)
+{ return __builtin_atan(__x); }
+
+inline float
+atan2(float __y, float __x)
+{ return __builtin_atan2f(__y, __x); }
+
+inline long double
+atan2(long double __y, long double __x)
+{ return __builtin_atan2l(__y, __x); }
+
+inline double
+atan2(double __y, double __x)
+{ return __builtin_atan2(__y, __x); }
+
+inline float
+ceil(float __x)
+{ return __builtin_ceilf(__x); }
+
+inline long double
+ceil(long double __x)
+{ return __builtin_ceill(__x); }
+
+inline double ceil(double __x)
+{ return __builtin_ceil(__x); }
+
+inline float
+cos(float __x)
+{ return __builtin_cosf(__x); }
+
+inline long double
+cos(long double __x)
+{ return __builtin_cosl(__x); }
+
+inline double cos(double __x)
+{ return __builtin_cos(__x); }
+
+inline float
+cosh(float __x)
+{ return __builtin_coshf(__x); }
+
+inline long double
+cosh(long double __x)
+{ return __builtin_coshl(__x); }
+
+inline double cosh(double __x)
+{ return __builtin_cosh(__x); }
+
+inline float
+exp(float __x)
+{ return __builtin_expf(__x); }
+
+inline long double
+exp(long double __x)
+{ return __builtin_expl(__x); }
+
+inline double exp(double __x)
+{ return __builtin_exp(__x); }
+
+inline float
+fabs(float __x)
+{ return __builtin_fabsf(__x); }
+
+inline long double
+fabs(long double __x)
+{ return __builtin_fabsl(__x); }
+
+inline double fabs(double __x)
+{ return __builtin_fabs(__x); }
+
+inline float
+floor(float __x)
+{ return __builtin_floorf(__x); }
+
+inline long double
+floor(long double __x)
+{ return __builtin_floorl(__x); }
+
+inline double floor(double __x)
+{ return __builtin_floor(__x); }
+
+inline float
+fmod(float __x, float __y)
+{ return __builtin_fmodf(__x, __y); }
+
+inline long double
+fmod(long double __x, long double __y)
+{ return __builtin_fmodl(__x, __y); }
+
+inline float
+frexp(float __x, int* __exp)
+{ return __builtin_frexpf(__x, __exp); }
+
+inline long double
+frexp(long double __x, int* __exp)
+{ return __builtin_frexpl(__x, __exp); }
+
+inline double frexp(double __x, int* __exp)
+{ return __builtin_frexp(__x, __exp); }
+
+inline float
+ldexp(float __x, int __exp)
+{ return __builtin_ldexpf(__x, __exp); }
+
+inline long double
+ldexp(long double __x, int __exp)
+{ return __builtin_ldexpl(__x, __exp); }
+
+inline double ldexp(double __x, int __exp)
+{ return __builtin_ldexp(__x, __exp); }
+
+inline float
+log(float __x)
+{ return __builtin_logf(__x); }
+
+inline long double
+log(long double __x)
+{ return __builtin_logl(__x); }
+
+inline double log(double __x)
+{ return __builtin_log(__x); }
+
+inline float
+log10(float __x)
+{ return __builtin_log10f(__x); }
+
+inline long double
+log10(long double __x)
+{ return __builtin_log10l(__x); }
+
+inline double log10(double __x)
+{ return __builtin_log10(__x); }
+
+inline float
+modf(float __x, float* __iptr)
+{ return __builtin_modff(__x, __iptr); }
+
+inline long double
+modf(long double __x, long double* __iptr)
+{ return __builtin_modfl(__x, __iptr); }
+
+inline float
+pow(float __x, float __y)
+{ return __builtin_powf(__x, __y); }
+
+inline long double
+pow(long double __x, long double __y)
+{ return __builtin_powl(__x, __y); }
+
+inline float
+sin(float __x)
+{ return __builtin_sinf(__x); }
+
+inline long double
+sin(long double __x)
+{ return __builtin_sinl(__x); }
+
+inline double sin(double __x)
+{ return __builtin_sin(__x); }
+
+inline float
+sinh(float __x)
+{ return __builtin_sinhf(__x); }
+
+inline long double
+sinh(long double __x)
+{ return __builtin_sinhl(__x); }
+
+inline double sinh(double __x)
+{ return __builtin_sinh(__x); }
+
+inline float
+sqrt(float __x)
+{ return __builtin_sqrtf(__x); }
+
+inline long double
+sqrt(long double __x)
+{ return __builtin_sqrtl(__x); }
+
+inline double sqrt(double __x)
+{ return __builtin_sqrt(__x); }
+
+inline float
+tan(float __x)
+{ return __builtin_tanf(__x); }
+
+inline long double
+tan(long double __x)
+{ return __builtin_tanl(__x); }
+
+inline double tan(double __x)
+{ return __builtin_tan(__x); }
+
+inline float
+tanh(float __x)
+{ return __builtin_tanhf(__x); }
+
+inline long double
+tanh(long double __x)
+{ return __builtin_tanhl(__x); }
+
+inline double tanh(double __x)
+{ return __builtin_tanh(__x); }
+

Added: vendor/elsa/current/elsa/in/gnu/k0004.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0004.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0004.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// operator <?
+
+// originally found in package gambit
+
+// a.ii:4:24: Parse error (state 102) at <?
+
+// ERR-MATCH: Parse error.*at <[?]$
+
+struct S1 {
+    friend S1 operator <? (const S1& x, const S1& y)
+    {
+        return y;
+    }
+};
+
+
+S1 operator >? (const S1& x, const S1& y) {
+    return x;
+}
+
+int main()
+{
+  S1 a,b;
+  
+  a <? b;
+  a >? b;
+  
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/k0005.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0005.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0005.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// comparing long long to enum value
+
+// originally found in package d4x
+
+// k0005.cc:14:5: error: no viable candidate for function call; arguments:
+//   0: long long int &
+//   1: enum /*anonymous*/ &
+//  original candidates:
+//   <init>:1:1: bool ::operator==(<prom_arith> x, <prom_arith> y)
+
+// ERR-MATCH: error: no viable candidate for function call
+
+enum{
+    someEnumValue = 42
+};
+
+int main()
+{
+    long long longVar = 42;
+    return longVar == someEnumValue;
+}
+
+

Added: vendor/elsa/current/elsa/in/gnu/k0006.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0006.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0006.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// __offsetof__
+
+// http://gcc.gnu.org/ml/gcc-patches/2003-12/msg01317.html
+
+//      @smallexample
+//        __offsetof__ (expression)
+//      @end smallexample
+//
+//      is equivalent to the parenthesized expression, except that the
+//      expression is considered an integral constant expression even if it
+//      contains certain operators that are not normally permitted in an
+//      integral constant expression.  Users should never use
+//      @code{__offsetof__} directly; the only valid use of
+//      @code{__offsetof__} is to implement the @code{offsetof} macro in
+//      @code{<stddef.h>}.
+
+// originally found in package ddd
+
+// k0006.cc:35:12: error: there is no function called `__offsetof__'
+// typechecking results:
+//   errors:   1
+//   warnings: 0
+
+// ERR-MATCH: error: there is no function called `__offsetof__'
+
+struct S {
+    int x;
+    int y;
+};
+
+int main()
+{
+    struct S s;
+    return __offsetof__((static_cast<S*> (0))->y);
+}
+
+int foo()
+{
+  // make sure it's a compile-time constant
+  int static_assertion[ (4 == __offsetof__((static_cast<S*> (0))->y)) ? 1 : -1 ];
+}

Added: vendor/elsa/current/elsa/in/gnu/k0006a.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0006a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0006a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// __builtin_offsetof
+
+// #include <stddef.h>
+
+struct S {
+  int xxx;
+  int yyy;
+};
+
+// int a = offsetof(S, yyy);
+
+// gcc-4.0, gcc-4.1
+int static_assertion1[ __builtin_offsetof(S,yyy) == 4 ? 1 : -1 ];
+
+// gcc-3.4
+int static_assertion2[ __offsetof__(((int) &((S *)0)->yyy)) == 4 ? 1: -1 ];
+
+// gcc-3.3
+int static_assertion3[ (((int) &((S *)0)->yyy) == 4) ? 1 : -1 ];
+
+// int AAAAA = (int) &((S *)0)->yyy;

Added: vendor/elsa/current/elsa/in/gnu/k0007.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0007.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0007.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// __builtin_frame_address
+
+// originally found in package 'aleph_0.9.0-2'
+
+// a.ii:5:14: error: there is no function called `__builtin_frame_address'
+
+// ERR-MATCH: there is no function called `__builtin_frame_address'
+
+int main()
+{
+  void * p;
+  p = __builtin_frame_address(0);
+  p = __builtin_return_address(0);
+}

Added: vendor/elsa/current/elsa/in/gnu/k0008.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0008.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0008.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// gcc accepts this in C, but not C++
+
+extern int foo();
+
+extern inline int foo()
+{
+}
+
+int foo()
+{
+}

Added: vendor/elsa/current/elsa/in/gnu/k0009.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0009.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0009.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// "namespace attribute strong"
+
+// from /usr/include/c++/3.4/i486-linux-gnu/bits/c++config.h
+
+// In state 706, I expected one of these tokens:
+//   ;,
+// k0009.cc:9:21: Parse error (state 706) at __attribute__
+
+// ERR-MATCH: a86c8a1e-2cd7-41bd-8a23-f9049358c166
+
+namespace g
+{
+}
+
+namespace std
+{
+  using namespace g __attribute__ ((strong));
+}

Added: vendor/elsa/current/elsa/in/gnu/k0010.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/k0010.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/k0010.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// nested K&R function
+
+// Assertion failed: unimplemented: nested K&R function definition
+// (d00aa531-ca12-4d72-9caf-ca9db9941179), file gnu.gr line 144
+
+// ERR-MATCH: d00aa531-ca12-4d72-9caf-ca9db9941179
+
+void foo (void) {
+  void bar (x) int x;
+  {
+  }
+}

Added: vendor/elsa/current/elsa/in/gnu/t0124.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0124.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0124.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0124.cc
+// statement expressions
+
+int main() {
+  int x;
+  x = ({int y=1; int z=2; y+z;});
+}

Added: vendor/elsa/current/elsa/in/gnu/t0125.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0125.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0125.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,85 @@
+// dsw: from cqual/tests/linux/rtc.i; I think these are from the real
+// linux kernel
+
+typedef struct { volatile int counter; } atomic_t;
+static __inline__ void atomic_add(int i, volatile atomic_t *v)
+{
+  __asm__ __volatile__("lock ; "  "addl %1,%0"
+                       // two colons here
+                       :"=m" ((*(volatile struct { int a[100]; } *) v ) )
+                       :"ir" (i), "m" ((*(volatile struct { int a[100]; } *) v ) ));
+}
+
+typedef struct {
+  volatile unsigned int lock;
+} rwlock_t;
+extern inline void read_lock(rwlock_t *rw)
+{
+  do {
+    if (true) // don't have this: (__builtin_constant_p( rw ))
+      asm volatile
+        ("lock ; "
+         "subl $1,%0\n\t"
+         "js 2f\n"
+         "1:\n"
+         ".section .text.lock,\"ax\"\n"
+         "2:\tpushl %%eax\n\t"
+         "leal %0,%%eax\n\t"
+         "call "
+         "__read_lock_failed"
+         "\n\t"
+         "popl %%eax\n\t"
+         "jmp 1b\n"
+         ".previous"
+         :"=m" ((*(__dummy_lock_t *)(   rw   )) ) // only one colon here
+         ) ;
+    else
+      asm volatile
+        ("lock ; "
+         "subl $1,(%0)\n\t"
+         "js 2f\n"
+         "1:\n"
+         ".section .text.lock,\"ax\"\n"
+         "2:\tcall "
+         "__read_lock_failed"
+         "\n\t"
+         "jmp 1b\n"
+         ".previous"
+         :
+         :"a" (  rw  )
+         : "memory"             // three colons here
+         ) ;
+  } while (0) ;
+}
+
+// this is another copy but retaining the double colon, which is a
+// single token in C++
+extern inline void read_lock2(rwlock_t *rw)
+{
+	do {
+          if (true)//__builtin_constant_p( rw ))
+            asm volatile("lock ; "  "subl $1,%0\n\t" "js 2f\n" "1:\n" ".section .text.lock,\"ax\"\n" "2:\tpushl %%eax\n\t" "leal %0,%%eax\n\t" "call "     "__read_lock_failed"   "\n\t" "popl %%eax\n\t" "jmp 1b\n" ".previous" :"=m" ((*(__dummy_lock_t *)(   rw   )) )) ; else asm volatile("lock ; "  "subl $1,(%0)\n\t" "js 2f\n" "1:\n" ".section .text.lock,\"ax\"\n" "2:\tcall "     "__read_lock_failed"   "\n\t" "jmp 1b\n" ".previous"
+  ::"a" (  rw  )                // NOTE double colon!
+  : "memory") ; 
+        } while (0) ;
+}
+
+void triple() {
+  // three-colons now works also!
+  asm ("asdfasd" ::: "a"(rw) );
+  // and four
+  asm ("asdfasd" :::: "a"(rw) );
+}
+
+//  /home/dsw/oink_extra/ballAruns/tmpfiles/./arts-1.1-7/gsldatahandle-mad-04hG.i:2145:107: Parse error (state 222) at <string literal>: "fpatan"
+
+typedef unsigned int guint32;
+typedef guint32 CORBA_unsigned_long;
+typedef unsigned char guchar;
+void f() {
+  guchar *_ORBIT_curptr;
+        __asm__ __const__       // "const" is also legal after an asm
+          ("rorw $8, %w0\n\t" "rorl $16, %0\n\t" "rorw $8, %w0": "=r" (__v):"0"
+           ((guint32)
+            (*((guint32 *) _ORBIT_curptr))));
+}

Added: vendor/elsa/current/elsa/in/gnu/t0126.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0126.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0126.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,324 @@
+// dsw: pieces presumably from the linux kernel
+// (cqual/tests/linux/rtc.i) containing __attribute__-s
+
+/* check C comments ***** ***/
+/* check C comments ***** oink*/
+/* check C comments ***** oink*/
+// check C++ comments /* /*
+// */
+
+// these should still show up
+/* __attribute__((blah)) */
+// __attribute__((blah))
+int boink() {
+  char *x = "__attribute__((rah))"; // should show up
+  __attribute__/*a comment*/(// another comment
+                             (oink
+                              )// another comment
+                             )// another comment
+    int y;
+}
+
+typedef unsigned short umode_t;
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+typedef signed char s8;
+typedef unsigned char u8;
+typedef signed short s16;
+typedef unsigned short u16;
+typedef signed int s32;
+typedef unsigned int u32;
+typedef signed long long s64;
+typedef unsigned long long u64;
+typedef u32 dma_addr_t;
+
+typedef unsigned char		u_char;
+typedef unsigned short		u_short;
+typedef unsigned int		u_int;
+typedef unsigned long		u_long;
+typedef unsigned char		unchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+typedef		__u8		u_int8_t;
+typedef		__s8		int8_t;
+typedef		__u16		u_int16_t;
+typedef		__s16		int16_t;
+typedef		__u32		u_int32_t;
+typedef		__s32		int32_t;
+typedef		__u8		uint8_t;
+typedef		__u16		uint16_t;
+typedef		__u32		uint32_t;
+typedef		__u64		uint64_t;
+typedef		__u64		u_int64_t;
+typedef		__s64		int64_t;
+
+typedef struct { volatile int counter; } atomic_t;
+extern int printk(const char * fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+static const char __module_kernel_version[] __attribute__((section(".modinfo"))) =
+"kernel_version=" "2.4.0-test4" ;
+  void panic(const char * fmt, ...)
+	__attribute__ ((noreturn,  format (printf, 1, 2)));
+  void do_exit(long error_code)
+	__attribute__((noreturn)) ;
+  __attribute__((regparm(0)))  int printk(const char * fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+struct i387_fxsave_struct {
+	unsigned short	cwd;
+	unsigned short	swd;
+	unsigned short	twd;
+	unsigned short	fop;
+	long	fip;
+	long	fcs;
+	long	foo;
+	long	fos;
+	long	mxcsr;
+	long	reserved;
+	long	st_space[32];	 
+	long	xmm_space[32];	 
+	long	padding[56];
+} __attribute__ ((aligned (16)));
+extern void  __switch_to(struct task_struct *prev, struct task_struct *next)  __attribute__((regparm(3))) ;
+  __attribute__((regparm(0)))  void __down_failed(void  );
+  __attribute__((regparm(0)))  int  __down_failed_interruptible(void   );
+  __attribute__((regparm(0)))  int  __down_failed_trylock(void   );
+  __attribute__((regparm(0)))  void __up_wakeup(void  );
+  __attribute__((regparm(0)))  void __down(struct semaphore * sem);
+  __attribute__((regparm(0)))  int  __down_interruptible(struct semaphore * sem);
+  __attribute__((regparm(0)))  int  __down_trylock(struct semaphore * sem);
+  __attribute__((regparm(0)))  void __up(struct semaphore * sem);
+extern struct rw_semaphore *  __down_read_failed(struct rw_semaphore *sem)  __attribute__((regparm(3))) ;
+struct semaphore {};
+struct ncp_inode_info {
+	__u32	dirEntNum __attribute__((packed));
+	__u32	DosDirNum __attribute__((packed));
+	__u32	volNumber __attribute__((packed));
+	__u32	nwattr;
+	struct semaphore open_sem;
+	atomic_t	opened;
+	int	access;
+	__u32	server_file_handle __attribute__((packed));
+	__u8	open_create_action __attribute__((packed));
+	__u8	file_handle[6] __attribute__((packed));
+};
+extern void ext2_error (struct super_block *, const char *, const char *, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern   void ext2_panic (struct super_block *, const char *,
+				   const char *, ...)
+	__attribute__ ((noreturn,  format (printf, 3, 4)));
+  __attribute__((regparm(0)))  long sys_open(const char *, int, int);
+  __attribute__((regparm(0)))  long sys_close(unsigned int);	 
+  __attribute__((regparm(0)))  long sys_personality(unsigned long personality);
+struct local_apic {
+ 	struct { unsigned int  __reserved[4]; } __reserved_01;
+ 	struct { unsigned int  __reserved[4]; } __reserved_02;
+ 	struct {  
+		unsigned int    __reserved_1	: 24,
+			phys_apic_id	:  4,
+			__reserved_2	:  4;
+		unsigned int  __reserved[3];
+	} id;
+ 	const
+	struct {  
+		unsigned int    version		:  8,
+			__reserved_1	:  8,
+			max_lvt		:  8,
+			__reserved_2	:  8;
+		unsigned int  __reserved[3];
+	} version;
+ 	struct { unsigned int  __reserved[4]; } __reserved_03;
+ 	struct { unsigned int  __reserved[4]; } __reserved_04;
+ 	struct { unsigned int  __reserved[4]; } __reserved_05;
+ 	struct { unsigned int  __reserved[4]; } __reserved_06;
+ 	struct {  
+		unsigned int    priority	:  8,
+			__reserved_1	: 24;
+		unsigned int  __reserved_2[3];
+	} tpr;
+ 	const
+	struct {  
+		unsigned int    priority	:  8,
+			__reserved_1	: 24;
+		unsigned int  __reserved_2[3];
+	} apr;
+ 	const
+	struct {  
+		unsigned int    priority	:  8,
+			__reserved_1	: 24;
+		unsigned int  __reserved_2[3];
+	} ppr;
+ 	struct {  
+		unsigned int    eoi;
+		unsigned int  __reserved[3];
+	} eoi;
+ 	struct { unsigned int  __reserved[4]; } __reserved_07;
+ 	struct {  
+		unsigned int    __reserved_1	: 24,
+			logical_dest	:  8;
+		unsigned int  __reserved_2[3];
+	} ldr;
+ 	struct {  
+		unsigned int    __reserved_1	: 28,
+			model		:  4;
+		unsigned int  __reserved_2[3];
+	} dfr;
+ 	struct {  
+		unsigned int 	spurious_vector	:  8,
+			apic_enabled	:  1,
+			focus_cpu	:  1,
+			__reserved_2	: 22;
+		unsigned int  __reserved_3[3];
+	} svr;
+ 	struct {  
+ 		unsigned int  bitfield;
+		unsigned int  __reserved[3];
+	} isr [8];
+ 	struct {  
+ 		unsigned int  bitfield;
+		unsigned int  __reserved[3];
+	} tmr [8];
+ 	struct {  
+ 		unsigned int  bitfield;
+		unsigned int  __reserved[3];
+	} irr [8];
+ 	union {  
+		struct {
+			unsigned int    send_cs_error			:  1,
+				receive_cs_error		:  1,
+				send_accept_error		:  1,
+				receive_accept_error		:  1,
+				__reserved_1			:  1,
+				send_illegal_vector		:  1,
+				receive_illegal_vector		:  1,
+				illegal_register_address	:  1,
+				__reserved_2			: 24;
+			unsigned int  __reserved_3[3];
+		} error_bits;
+		struct {
+			unsigned int  errors;
+			unsigned int  __reserved_3[3];
+		} all_errors;
+	} esr;
+ 	struct { unsigned int  __reserved[4]; } __reserved_08;
+ 	struct { unsigned int  __reserved[4]; } __reserved_09;
+ 	struct { unsigned int  __reserved[4]; } __reserved_10;
+ 	struct { unsigned int  __reserved[4]; } __reserved_11;
+ 	struct { unsigned int  __reserved[4]; } __reserved_12;
+ 	struct { unsigned int  __reserved[4]; } __reserved_13;
+ 	struct { unsigned int  __reserved[4]; } __reserved_14;
+ 	struct {  
+		unsigned int    vector			:  8,
+			delivery_mode		:  3,
+			destination_mode	:  1,
+			delivery_status		:  1,
+			__reserved_1		:  1,
+			level			:  1,
+			trigger			:  1,
+			__reserved_2		:  2,
+			shorthand		:  2,
+			__reserved_3		:  12;
+		unsigned int  __reserved_4[3];
+	} icr1;
+ 	struct {  
+		union {
+			unsigned int    __reserved_1	: 24,
+				phys_dest	:  4,
+				__reserved_2	:  4;
+			unsigned int    __reserved_3	: 24,
+				logical_dest	:  8;
+		} dest;
+		unsigned int  __reserved_4[3];
+	} icr2;
+ 	struct {  
+		unsigned int    vector		:  8,
+			__reserved_1	:  4,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			timer_mode	:  1,
+			__reserved_3	: 14;
+		unsigned int  __reserved_4[3];
+	} lvt_timer;
+ 	struct { unsigned int  __reserved[4]; } __reserved_15;
+ 	struct {  
+		unsigned int    vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		unsigned int  __reserved_4[3];
+	} lvt_pc;
+ 	struct {  
+		unsigned int    vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			polarity	:  1,
+			remote_irr	:  1,
+			trigger		:  1,
+			mask		:  1,
+			__reserved_2	: 15;
+		unsigned int  __reserved_3[3];
+	} lvt_lint0;
+ 	struct {  
+		unsigned int    vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			polarity	:  1,
+			remote_irr	:  1,
+			trigger		:  1,
+			mask		:  1,
+			__reserved_2	: 15;
+		unsigned int  __reserved_3[3];
+	} lvt_lint1;
+ 	struct {  
+		unsigned int    vector		:  8,
+			__reserved_1	:  4,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		unsigned int  __reserved_4[3];
+	} lvt_error;
+ 	struct {  
+		unsigned int    initial_count;
+		unsigned int  __reserved_2[3];
+	} timer_icr;
+ 	const
+	struct {  
+		unsigned int    curr_count;
+		unsigned int  __reserved_2[3];
+	} timer_ccr;
+ 	struct { unsigned int  __reserved[4]; } __reserved_16;
+ 	struct { unsigned int  __reserved[4]; } __reserved_17;
+ 	struct { unsigned int  __reserved[4]; } __reserved_18;
+ 	struct { unsigned int  __reserved[4]; } __reserved_19;
+ 	struct {  
+		unsigned int    divisor		:  4,
+			__reserved_1	: 28;
+		unsigned int  __reserved_2[3];
+	} timer_dcr;
+ 	struct { unsigned int  __reserved[4]; } __reserved_20;
+} __attribute__ ((packed));
+
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+
+// dsw: doctored from the real thing
+static int   rtc_init(void)
+{ return 0; }
+static void   rtc_exit (void)
+{ return 0; }
+
+int init_module(void) __attribute__((alias("rtc_init"))); extern inline __init_module_func_t __init_module_inline(void) { return  rtc_init ; } ;
+void cleanup_module(void) __attribute__((alias("rtc_exit"))); extern inline __cleanup_module_func_t __cleanup_module_inline(void) { return  rtc_exit ; } ;

Added: vendor/elsa/current/elsa/in/gnu/t0126.c.da_cor
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0126.c.da_cor	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0126.c.da_cor	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,323 @@
+// dsw: pieces presumably from the linux kernel
+// (cqual/tests/linux/rtc.i) containing __attribute__-s
+
+/* check C comments ***** ***/
+/* check C comments ***** oink*/
+/* check C comments ***** oink*/
+// check C++ comments /* /*
+// */
+
+// these should still show up
+/* __attribute__((blah)) */
+// __attribute__((blah))
+int boink() {
+  char *x = "__attribute__((rah))"; // should show up
+                                               
+                                  
+                                                 
+                              // another comment
+    int y;
+}
+
+typedef unsigned short umode_t;
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+typedef signed char s8;
+typedef unsigned char u8;
+typedef signed short s16;
+typedef unsigned short u16;
+typedef signed int s32;
+typedef unsigned int u32;
+typedef signed long long s64;
+typedef unsigned long long u64;
+typedef u32 dma_addr_t;
+
+typedef unsigned char		u_char;
+typedef unsigned short		u_short;
+typedef unsigned int		u_int;
+typedef unsigned long		u_long;
+typedef unsigned char		unchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+typedef		__u8		u_int8_t;
+typedef		__s8		int8_t;
+typedef		__u16		u_int16_t;
+typedef		__s16		int16_t;
+typedef		__u32		u_int32_t;
+typedef		__s32		int32_t;
+typedef		__u8		uint8_t;
+typedef		__u16		uint16_t;
+typedef		__u32		uint32_t;
+typedef		__u64		uint64_t;
+typedef		__u64		u_int64_t;
+typedef		__s64		int64_t;
+
+typedef struct { volatile int counter; } atomic_t;
+extern int printk(const char * fmt, ...)
+	                                       ;
+static const char __module_kernel_version[]                                      =
+"kernel_version=" "2.4.0-test4" ;
+  void panic(const char * fmt, ...)
+	                                                  ;
+  void do_exit(long error_code)
+	                          ;
+                               int printk(const char * fmt, ...)
+	                                       ;
+struct i387_fxsave_struct {
+	unsigned short	cwd;
+	unsigned short	swd;
+	unsigned short	twd;
+	unsigned short	fop;
+	long	fip;
+	long	fcs;
+	long	foo;
+	long	fos;
+	long	mxcsr;
+	long	reserved;
+	long	st_space[32];	 
+	long	xmm_space[32];	 
+	long	padding[56];
+}                               ;
+extern void  __switch_to(struct task_struct *prev, struct task_struct *next)                              ;
+                               void __down_failed(void  );
+                               int  __down_failed_interruptible(void   );
+                               int  __down_failed_trylock(void   );
+                               void __up_wakeup(void  );
+                               void __down(struct semaphore * sem);
+                               int  __down_interruptible(struct semaphore * sem);
+                               int  __down_trylock(struct semaphore * sem);
+                               void __up(struct semaphore * sem);
+extern struct rw_semaphore *  __down_read_failed(struct rw_semaphore *sem)                              ;
+struct ncp_inode_info {
+	__u32	dirEntNum                        ;
+	__u32	DosDirNum                        ;
+	__u32	volNumber                        ;
+	__u32	nwattr;
+	struct semaphore open_sem;
+	atomic_t	opened;
+	int	access;
+	__u32	server_file_handle                        ;
+	__u8	open_create_action                        ;
+	__u8	file_handle[6]                        ;
+};
+extern void ext2_error (struct super_block *, const char *, const char *, ...)
+	                                       ;
+extern   void ext2_panic (struct super_block *, const char *,
+				   const char *, ...)
+	                                                  ;
+                               long sys_open(const char *, int, int);
+                               long sys_close(unsigned int);	 
+                               long sys_personality(unsigned long personality);
+struct local_apic {
+ 	struct { unsigned int  __reserved[4]; } __reserved_01;
+ 	struct { unsigned int  __reserved[4]; } __reserved_02;
+ 	struct {  
+		unsigned int    __reserved_1	: 24,
+			phys_apic_id	:  4,
+			__reserved_2	:  4;
+		unsigned int  __reserved[3];
+	} id;
+ 	const
+	struct {  
+		unsigned int    version		:  8,
+			__reserved_1	:  8,
+			max_lvt		:  8,
+			__reserved_2	:  8;
+		unsigned int  __reserved[3];
+	} version;
+ 	struct { unsigned int  __reserved[4]; } __reserved_03;
+ 	struct { unsigned int  __reserved[4]; } __reserved_04;
+ 	struct { unsigned int  __reserved[4]; } __reserved_05;
+ 	struct { unsigned int  __reserved[4]; } __reserved_06;
+ 	struct {  
+		unsigned int    priority	:  8,
+			__reserved_1	: 24;
+		unsigned int  __reserved_2[3];
+	} tpr;
+ 	const
+	struct {  
+		unsigned int    priority	:  8,
+			__reserved_1	: 24;
+		unsigned int  __reserved_2[3];
+	} apr;
+ 	const
+	struct {  
+		unsigned int    priority	:  8,
+			__reserved_1	: 24;
+		unsigned int  __reserved_2[3];
+	} ppr;
+ 	struct {  
+		unsigned int    eoi;
+		unsigned int  __reserved[3];
+	} eoi;
+ 	struct { unsigned int  __reserved[4]; } __reserved_07;
+ 	struct {  
+		unsigned int    __reserved_1	: 24,
+			logical_dest	:  8;
+		unsigned int  __reserved_2[3];
+	} ldr;
+ 	struct {  
+		unsigned int    __reserved_1	: 28,
+			model		:  4;
+		unsigned int  __reserved_2[3];
+	} dfr;
+ 	struct {  
+		unsigned int 	spurious_vector	:  8,
+			apic_enabled	:  1,
+			focus_cpu	:  1,
+			__reserved_2	: 22;
+		unsigned int  __reserved_3[3];
+	} svr;
+ 	struct {  
+ 		unsigned int  bitfield;
+		unsigned int  __reserved[3];
+	} isr [8];
+ 	struct {  
+ 		unsigned int  bitfield;
+		unsigned int  __reserved[3];
+	} tmr [8];
+ 	struct {  
+ 		unsigned int  bitfield;
+		unsigned int  __reserved[3];
+	} irr [8];
+ 	union {  
+		struct {
+			unsigned int    send_cs_error			:  1,
+				receive_cs_error		:  1,
+				send_accept_error		:  1,
+				receive_accept_error		:  1,
+				__reserved_1			:  1,
+				send_illegal_vector		:  1,
+				receive_illegal_vector		:  1,
+				illegal_register_address	:  1,
+				__reserved_2			: 24;
+			unsigned int  __reserved_3[3];
+		} error_bits;
+		struct {
+			unsigned int  errors;
+			unsigned int  __reserved_3[3];
+		} all_errors;
+	} esr;
+ 	struct { unsigned int  __reserved[4]; } __reserved_08;
+ 	struct { unsigned int  __reserved[4]; } __reserved_09;
+ 	struct { unsigned int  __reserved[4]; } __reserved_10;
+ 	struct { unsigned int  __reserved[4]; } __reserved_11;
+ 	struct { unsigned int  __reserved[4]; } __reserved_12;
+ 	struct { unsigned int  __reserved[4]; } __reserved_13;
+ 	struct { unsigned int  __reserved[4]; } __reserved_14;
+ 	struct {  
+		unsigned int    vector			:  8,
+			delivery_mode		:  3,
+			destination_mode	:  1,
+			delivery_status		:  1,
+			__reserved_1		:  1,
+			level			:  1,
+			trigger			:  1,
+			__reserved_2		:  2,
+			shorthand		:  2,
+			__reserved_3		:  12;
+		unsigned int  __reserved_4[3];
+	} icr1;
+ 	struct {  
+		union {
+			unsigned int    __reserved_1	: 24,
+				phys_dest	:  4,
+				__reserved_2	:  4;
+			unsigned int    __reserved_3	: 24,
+				logical_dest	:  8;
+		} dest;
+		unsigned int  __reserved_4[3];
+	} icr2;
+ 	struct {  
+		unsigned int    vector		:  8,
+			__reserved_1	:  4,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			timer_mode	:  1,
+			__reserved_3	: 14;
+		unsigned int  __reserved_4[3];
+	} lvt_timer;
+ 	struct { unsigned int  __reserved[4]; } __reserved_15;
+ 	struct {  
+		unsigned int    vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		unsigned int  __reserved_4[3];
+	} lvt_pc;
+ 	struct {  
+		unsigned int    vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			polarity	:  1,
+			remote_irr	:  1,
+			trigger		:  1,
+			mask		:  1,
+			__reserved_2	: 15;
+		unsigned int  __reserved_3[3];
+	} lvt_lint0;
+ 	struct {  
+		unsigned int    vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			polarity	:  1,
+			remote_irr	:  1,
+			trigger		:  1,
+			mask		:  1,
+			__reserved_2	: 15;
+		unsigned int  __reserved_3[3];
+	} lvt_lint1;
+ 	struct {  
+		unsigned int    vector		:  8,
+			__reserved_1	:  4,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		unsigned int  __reserved_4[3];
+	} lvt_error;
+ 	struct {  
+		unsigned int    initial_count;
+		unsigned int  __reserved_2[3];
+	} timer_icr;
+ 	const
+	struct {  
+		unsigned int    curr_count;
+		unsigned int  __reserved_2[3];
+	} timer_ccr;
+ 	struct { unsigned int  __reserved[4]; } __reserved_16;
+ 	struct { unsigned int  __reserved[4]; } __reserved_17;
+ 	struct { unsigned int  __reserved[4]; } __reserved_18;
+ 	struct { unsigned int  __reserved[4]; } __reserved_19;
+ 	struct {  
+		unsigned int    divisor		:  4,
+			__reserved_1	: 28;
+		unsigned int  __reserved_2[3];
+	} timer_dcr;
+ 	struct { unsigned int  __reserved[4]; } __reserved_20;
+}                         ;
+
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+
+// dsw: doctored from the real thing
+static int   rtc_init(void)
+{ return 0; }
+static void   rtc_exit (void)
+{ return 0; }
+
+int init_module(void)                                   ; extern inline __init_module_func_t __init_module_inline(void) { return  rtc_init ; } ;
+void cleanup_module(void)                                   ; extern inline __cleanup_module_func_t __cleanup_module_inline(void) { return  rtc_exit ; } ;

Added: vendor/elsa/current/elsa/in/gnu/t0127.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0127.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0127.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// test typeof
+typedef unsigned int size_t;
+void *malloc(size_t size);
+int main() {
+  // a typical use of typeof
+  int sz = 16;
+  char *a = (typeof(a)) malloc(sz * sizeof *a);
+
+  // weird use
+  typeof(*a) x = 'c';
+
+  // typeof also applies to types; that is, it is idempotent
+  typeof(int) y = 5;
+  typeof(typeof(y)) z = 6;
+
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/t0128.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0128.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0128.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// test that a label can end a block, in particular that a case can
+// end a switch statement
+int main() {
+  switch(1) {
+  default:
+  case 1:
+  case 2:
+  }
+  {
+  gronk:
+  blonk:
+  }
+}

Added: vendor/elsa/current/elsa/in/gnu/t0129.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0129.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0129.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// test compound literals
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Compound-Literals.html#Compound%20Literals
+int main() {
+  int q = 7;
+  struct foo {
+    int x;
+    int y;
+  } f;
+  f = (struct foo) {q, 4};
+}

Added: vendor/elsa/current/elsa/in/gnu/t0130.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0130.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0130.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// test combo designated initializers and compound literals
+// Designated Initializers:
+// http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Designated-Inits.html#Designated%20Inits
+int main() {
+  struct foo {
+    int x;
+    double y;
+  };
+  struct foo f = (struct foo) {1, 2.3};
+  struct goo {
+    int x;
+    double y;
+  } g = {x:1, y:2.3};
+  struct boo {
+    int x;
+    double y;
+  };
+  struct boo b = (struct boo) {x:1, y:2.3};
+  struct oink {
+    struct boo b;
+    int i;
+  };
+  struct oink o = (struct oink) {i:7, b:{x:8, y:9.8}};
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/gnu/t0131.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0131.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0131.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// test __builtin_constant_p
+typedef struct {
+	volatile unsigned int lock;
+} rwlock_t;
+extern inline void read_lock(rwlock_t *rw)
+{
+  if (__builtin_constant_p( rw )) {
+  }
+}

Added: vendor/elsa/current/elsa/in/gnu/t0132.cc
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0132.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0132.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// check __alignof__
+int main() {
+  struct foo {int x; int y;};
+  int x = __alignof__(struct foo);
+};

Added: vendor/elsa/current/elsa/in/gnu/t0133.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0133.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0133.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,56 @@
+// gnu/t0133.c
+// transparent union
+
+typedef struct S {
+  int blah;
+} S;
+
+typedef struct T {
+  int gorf;
+} T;
+
+typedef union W {
+  T *t;
+} W;  // __attribute__((transparent_union));
+
+typedef union U {
+  W w;
+  int *i;
+  S *s;
+} U __attribute__((transparent_union));
+
+int f(U u)
+{
+  return *u.i;
+}
+
+int pass_int(int *p)
+{
+  return f(p /*implicitly initializes U.i*/);
+}
+
+// normalizes to:
+int pass_int_normalized(int *p)
+{
+  return f( (U){ .i = p } );
+}
+
+int pass_S(S *s)
+{
+  return f(s /*implicitly initializes U.s*/);
+}
+
+int pass_S_normalized(S *s)
+{
+  return f( (U){ .s = s } );
+}
+
+// This is *not* accepted by gcc-3.4.3, even if we
+// mark W as being a transparent union also.
+#if 0
+int pass_T(T *t)
+{
+  return f(t /*implicitly initializes U.w.t*/);
+}
+#endif // 0
+

Added: vendor/elsa/current/elsa/in/gnu/t0134.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0134.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0134.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0134.c
+// the exact example for transparent unions from the GCC manual:
+// http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Type-Attributes.html
+
+// prelude declarations
+
+union wait {
+  int blah;
+};
+
+typedef int pid_t;
+
+pid_t waitpid(pid_t pid, int *status, int options);
+
+// actual example
+
+typedef union
+  {
+    int *__ip;
+    union wait *__up;
+  } wait_status_ptr_t __attribute__ ((__transparent_union__));
+
+pid_t wait (wait_status_ptr_t);
+
+int w1 () { int w; return wait (&w); }
+int w2 () { union wait w; return wait (&w); }
+
+pid_t wait (wait_status_ptr_t p)
+{
+  return waitpid (-1, p.__ip, 0);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/gnu/t0135.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0135.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0135.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// gnu/t0135.c
+// transparent union, with the attribute directly on the union
+
+typedef struct S {
+  int blah;
+} S;
+
+union U {
+  int *i;
+  S *s;
+} __attribute__((transparent_union));
+
+int f(union U u)
+{
+  return *u.i;
+}
+
+int pass_int(int *p)
+{
+  return f(p /*implicitly initializes U.i*/);
+}

Added: vendor/elsa/current/elsa/in/gnu/t0136.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0136.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0136.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// gnu/t0136.c
+// transparent union, with the attribute directly on the union
+
+typedef struct S {
+  int blah;
+} S;
+
+union __attribute__((transparent_union)) U {
+  int *i;
+  S *s;
+};
+
+int f(union U u)
+{
+  return *u.i;
+}
+
+int pass_int(int *p)
+{
+  return f(p /*implicitly initializes U.i*/);
+}

Added: vendor/elsa/current/elsa/in/gnu/t0137.c
===================================================================
--- vendor/elsa/current/elsa/in/gnu/t0137.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/gnu/t0137.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// gnu/t0137.c
+// transparent union: does the transparency flow down to the union
+// itself when applied to a typedef?  no
+//
+// fuck that.  it will in Elsa anyway.
+
+union U {
+  int *i;
+};
+
+typedef union U U2 __attribute__((transparent_union));
+
+int f(union U u)
+{
+  return *u.i;
+}
+
+void pass_int(int *p)
+{
+  // not accepted by GCC
+  //ERROR(1): f(p /*implicitly initializes U.i*/);
+}

Added: vendor/elsa/current/elsa/in/k0001.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0001.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0001.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// invoking a pointer to member function of a template class
+
+// originally found in package apt
+
+// error: left side of .* must be a class or reference to a class
+
+// ERR-MATCH: left side of [.][*] must be a class
+
+template <class T> void foo() {
+    T t;
+    int (T::*bar)() = &T::barfunc;
+    t.*bar;     // useless reference to the name
+    (t.*bar)();
+
+    T *p = &t;
+    (p->*bar)();
+
+    //ERROR(1): int (T::*bar2)() = &T::barfuncqqq;   // does not exist
+}
+
+struct A {
+  int barfunc();
+};
+
+void f()
+{
+  foo<A>();
+}

Added: vendor/elsa/current/elsa/in/k0002.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0002.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0002.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// template function declared in another class (as a friend)
+
+// originally found in package apt
+
+// ---- BEGIN: messages from an ambiguity ----
+// there is no variable called `foo'
+// `T' used as a variable, but it's actually a type
+// ---- SEPARATOR: messages from an ambiguity ----
+// explicit template arguments were provided after `foo', but that is not the name of a template function
+// there is no function called `foo'
+// ---- SEPARATOR: messages from an ambiguity ----
+// there is no type called `foo<T>'
+// ---- END: messages from an ambiguity ----
+
+// ERR-MATCH: used as a variable, but it's actually a type
+
+struct S {
+    template<typename F> friend const F& foo(int);
+};
+
+template<typename T> T bar() {
+    return foo<T>(0);
+}

Added: vendor/elsa/current/elsa/in/k0003.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0003.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0003.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// template argument from static const member of template class
+
+// originally found in package apt
+
+// error: ` (A<T1, T2>::foo)' must lookup to a variable with a value for it to
+// be a variable template reference argument
+
+template<typename T1, typename T2> struct A {
+    static const bool foo = false;
+};
+
+template<bool f> struct B {};
+
+template<typename T1, typename T2> struct C :
+        public B<A<T1, T2>::foo> {};
+
+C<int,float> c;

Added: vendor/elsa/current/elsa/in/k0004.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0004.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0004.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// non-typename template argument
+
+// error: dependent name `A<T1>::foo' used as a type, but the 'typename'
+// keyword was not suppliedk0004.cc:11:28: error: `f' is a non-type parameter,
+// but `<error>' is a type argument (inst from k0004.cc:11:28)
+
+// error: `f' is a non-type parameter, but `<error>' is a type argument (inst
+// from k0004.cc:11:28)
+
+// ERR-MATCH: dependent name.*used as a type, but the 'typename'
+
+template<typename T1> struct A {
+    static const bool foo = false;
+};
+
+template<bool f> struct B {};
+
+template<typename T1> struct C :
+        public B<A<T1>::foo> {};
+
+C<int> c;

Added: vendor/elsa/current/elsa/in/k0005.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0005.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0005.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// declaring a constructor with class name
+
+// originally found in package groff
+// template version originally found in package aime
+
+// error: undeclared identifier `S::S'
+
+// error: the name `S::S' is overloaded, but the type `()(int x)' doesn't
+// match any of the 2 declar
+
+// ERR-MATCH: undeclared identifier .*::
+
+struct S1 {
+    S1::S1(int x) {}
+};
+
+
+struct S2 {
+    S2::S2(int x);
+};
+S2::S2(int x) {}
+
+
+template<class T> struct S3 {
+    S3<T>::S3() {}
+};
+
+S3<int> s3;

Added: vendor/elsa/current/elsa/in/k0005a.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0005a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0005a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+// declaring variables and member functions with class name
+
+// originally found in package bombermaze
+// template version originally found in package buffy
+
+// for non-templatized structs:
+//   error: undeclared identifier `S1::varName'
+
+// for inherited templated version:
+//   Assertion failed: kind() == PQ_NAME, file cc.ast.gen.cc line 552
+
+// ERR-MATCH: Assertion failed: kind.. == PQ_NAME
+
+struct S1 {
+    int S1::varName;
+};
+
+struct S2 {
+    int S2::funcName() {}
+};
+
+struct otherS { int funcName(); };
+
+struct S3 {
+    // sm: my workaround for qualified member declarators is to
+    // simply ignore the qualifier, so I do not detect this as
+    // an error
+    //nerfed-ERROR(1): int otherS::funcName() {}
+};
+
+template <typename T>
+struct S4 {
+    int S4<T>::varName;
+};
+
+
+template <typename T>
+struct S5 {
+    int S5<T>::funcName() {}
+};
+
+template <typename T>
+struct S6 : S5<T> {
+    S6<T> (S5<T> &) {}
+};

Added: vendor/elsa/current/elsa/in/k0006.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0006.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0006.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// error: E_alignofType is not constEval'able
+
+// originally found in package gettext
+
+// ERR-MATCH: E_alignofType is not constEval
+
+enum E {
+    a = __alignof__(int)
+};

Added: vendor/elsa/current/elsa/in/k0007.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0007.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0007.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// error: E_floatLit is not constEval'able
+
+// originally found in package coreutils
+
+enum E {
+    a = (0.5 == 0)
+};

Added: vendor/elsa/current/elsa/in/k0008.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0008.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0008.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// template parameterized by function pointer
+
+// originally found in package 'aptitude'
+
+// b.ii:4:1: error: cannot convert `bool (**)(int )' to `bool (*)(int )': different type constructors (inst from b.ii:7:24) (from template; would be suppressed in permissive mode)
+
+// ERR-MATCH: cannot convert `.*?' to `.*?': different type constructors [(]inst from .*?[)] [(]from template; would be suppressed in permissive mode[)]
+
+typedef bool (*mfunc)(int);
+template<mfunc f> struct S
+{
+  int foo() {
+    S<f> * s = new S<f>;
+  }
+};

Added: vendor/elsa/current/elsa/in/k0009.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0009.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0009.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// clash between function and instantiated template parameter member
+
+// originally found in package netkit-telnet
+
+// error: during argument-dependent lookup of `foo', found non-function of
+// type `int' in class B at 0x82258b8
+
+// ERR-MATCH: during argument-dependent
+
+class B { int foo; };
+template <class T> class A { };
+typedef A<B> C;
+
+int foo(C *);
+
+void bar() {
+    C* c;
+    foo(c);
+}

Added: vendor/elsa/current/elsa/in/k0010.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0010.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0010.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,83 @@
+// type sizes used in compile-time assertions
+
+// originally found in package lzo
+
+typedef unsigned int size_t;
+typedef int ptrdiff_t;
+typedef unsigned int lzo_uint32;
+typedef int lzo_int32;
+typedef unsigned int lzo_uint;
+typedef int lzo_int;
+typedef int lzo_bool;
+typedef ptrdiff_t lzo_ptrdiff_t;
+typedef unsigned long lzo_ptr_t;
+typedef long lzo_sptr_t;
+
+
+int foo() {
+    { typedef int F[1 - 2 * !(8 == 8)]; };
+    { typedef int F[1 - 2 * !(sizeof(char) == 1)]; };
+    { typedef int F[1 - 2 * !(sizeof(short) >= 2)]; };
+    { typedef int F[1 - 2 * !(sizeof(long) >= 4)]; };
+    { typedef int F[1 - 2 * !(sizeof(int) >= sizeof(short))]; };
+    { typedef int F[1 - 2 * !(sizeof(long) >= sizeof(int))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_uint) == sizeof(lzo_int))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_uint32) == sizeof(lzo_int32))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_uint32) >= 4)]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_uint32) >= sizeof(unsigned))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_uint) >= 4)]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_uint) >= sizeof(unsigned))]; };
+    { typedef int F[1 - 2 * !(sizeof(short) == 2)]; };
+    { typedef int F[1 - 2 * !(sizeof(int) == 4)]; };
+    { typedef int F[1 - 2 * !(sizeof(long) == 4)]; };
+    { typedef int F[1 - 2 * !(4 == sizeof(unsigned))]; };
+    { typedef int F[1 - 2 * !(4 == sizeof(unsigned long))]; };
+    { typedef int F[1 - 2 * !(2 == sizeof(unsigned short))]; };
+    { typedef int F[1 - 2 * !(4 == sizeof(size_t))]; };
+    { typedef int F[1 - 2 * !((((unsigned char) (-1)) > ((unsigned char) 0)))]; };
+    { typedef int F[1 - 2 * !((((unsigned short) (-1)) > ((unsigned short) 0)))]; };
+    { typedef int F[1 - 2 * !((((unsigned) (-1)) > ((unsigned) 0)))]; };
+    { typedef int F[1 - 2 * !((((unsigned long) (-1)) > ((unsigned long) 0)))]; };
+    { typedef int F[1 - 2 * !((((short) (-1)) < ((short) 0)))]; };
+    { typedef int F[1 - 2 * !((((int) (-1)) < ((int) 0)))]; };
+    { typedef int F[1 - 2 * !((((long) (-1)) < ((long) 0)))]; };
+    { typedef int F[1 - 2 * !((((lzo_uint32) (-1)) > ((lzo_uint32) 0)))]; };
+    { typedef int F[1 - 2 * !((((lzo_uint) (-1)) > ((lzo_uint) 0)))]; };
+    { typedef int F[1 - 2 * !((((lzo_int32) (-1)) < ((lzo_int32) 0)))]; };
+    { typedef int F[1 - 2 * !((((lzo_int) (-1)) < ((lzo_int) 0)))]; };
+    { typedef int F[1 - 2 * !(2147483647 == (((1l << (8*(sizeof(int))-2)) - 1l) + (1l << (8*(sizeof(int))-2))))]; };
+    { typedef int F[1 - 2 * !((2147483647 * 2U + 1U) == (((1ul << (8*(sizeof(unsigned))-1)) - 1ul) + (1ul << (8*(sizeof(unsigned))-1))))]; };
+    { typedef int F[1 - 2 * !(2147483647L == (((1l << (8*(sizeof(long))-2)) - 1l) + (1l << (8*(sizeof(long))-2))))]; };
+    { typedef int F[1 - 2 * !((2147483647L * 2UL + 1UL) == (((1ul << (8*(sizeof(unsigned long))-1)) - 1ul) + (1ul << (8*(sizeof(unsigned long))-1))))]; };
+    { typedef int F[1 - 2 * !(32767 == (((1l << (8*(sizeof(short))-2)) - 1l) + (1l << (8*(sizeof(short))-2))))]; };
+    { typedef int F[1 - 2 * !((32767 * 2 + 1) == (((1ul << (8*(sizeof(unsigned short))-1)) - 1ul) + (1ul << (8*(sizeof(unsigned short))-1))))]; };
+    { typedef int F[1 - 2 * !((2147483647 * 2U + 1U) == (((1ul << (8*(sizeof(lzo_uint32))-1)) - 1ul) + (1ul << (8*(sizeof(lzo_uint32))-1))))]; };
+    { typedef int F[1 - 2 * !((2147483647 * 2U + 1U) == (((1ul << (8*(sizeof(lzo_uint))-1)) - 1ul) + (1ul << (8*(sizeof(lzo_uint))-1))))]; };
+    { typedef int F[1 - 2 * !((((1ul << (8*(4)-1)) - 1ul) + (1ul << (8*(4)-1))) == (((1ul << (8*(sizeof(size_t))-1)) - 1ul) + (1ul << (8*(sizeof(size_t))-1))))]; };
+    { typedef int F[1 - 2 * !(sizeof(char *) >= sizeof(int))]; };
+    { typedef int F[1 - 2 * !(sizeof(unsigned char *) >= sizeof(char *))]; };
+    { typedef int F[1 - 2 * !(sizeof(void *) == sizeof(unsigned char *))]; };
+    { typedef int F[1 - 2 * !(sizeof(void *) == sizeof(void * *))]; };
+    { typedef int F[1 - 2 * !(sizeof(void *) == sizeof(unsigned char * *))]; };
+    { typedef int F[1 - 2 * !(sizeof(void *) >= sizeof(lzo_uint))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_ptr_t) == sizeof(void *))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_ptr_t) == sizeof(lzo_sptr_t))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_ptr_t) >= sizeof(lzo_uint))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_ptrdiff_t) >= 4)]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_ptrdiff_t) >= sizeof(ptrdiff_t))]; };
+    { typedef int F[1 - 2 * !(sizeof(ptrdiff_t) >= sizeof(size_t))]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_ptrdiff_t) >= sizeof(lzo_uint))]; };
+    { typedef int F[1 - 2 * !(4 == sizeof(char *))]; };
+    { typedef int F[1 - 2 * !(4 == sizeof(ptrdiff_t))]; };
+    { typedef int F[1 - 2 * !((((ptrdiff_t) (-1)) < ((ptrdiff_t) 0)))]; };
+    { typedef int F[1 - 2 * !((((size_t) (-1)) > ((size_t) 0)))]; };
+    { typedef int F[1 - 2 * !((((lzo_ptrdiff_t) (-1)) < ((lzo_ptrdiff_t) 0)))]; };
+    { typedef int F[1 - 2 * !((((lzo_sptr_t) (-1)) < ((lzo_sptr_t) 0)))]; };
+    { typedef int F[1 - 2 * !((((lzo_ptr_t) (-1)) > ((lzo_ptr_t) 0)))]; };
+    { typedef int F[1 - 2 * !((((lzo_uint) (-1)) > ((lzo_uint) 0)))]; };
+    { typedef int F[1 - 2 * !((int) ((unsigned char) ((signed char) -1)) == 255)]; };
+    { typedef int F[1 - 2 * !((((unsigned char)128) << (int)(8*sizeof(int)-8)) < 0)]; };
+    { typedef int F[1 - 2 * !(sizeof(short) == 2)]; };
+    { typedef int F[1 - 2 * !(sizeof(lzo_uint32) == 4)]; };
+    { typedef int F[1 - 2 * !(sizeof(unsigned char *) == sizeof(const unsigned char *))]; };
+}

Added: vendor/elsa/current/elsa/in/k0010a.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0010a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0010a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// compile-time type size checking - long long
+
+// originally found in package 'ucl'
+
+// k0010a.cc:5:12: error: array size must be nonnegative (it is -1)
+// k0010a.cc:6:12: error: array size must be nonnegative (it is -1)
+// k0010a.cc:7:12: error: array size must be nonnegative (it is -1)
+// k0010a.cc:8:12: error: array size must be nonnegative (it is -1)
+// k0010a.cc:9:12: error: array size must be nonnegative (it is -1)
+
+// ERR-MATCH: array size must be nonnegative
+
+extern int x[1-2*!(9223372036854775807LL > 0)];
+extern int x[1-2*!(-9223372036854775807LL - 1 < 0)];
+extern int x[1-2*!(9223372036854775807LL % 2147483629l == 721)];
+extern int x[1-2*!(9223372036854775807LL % 2147483647l == 1)];
+extern int x[1-2*!(9223372036854775807ULL % 2147483629ul == 721)];

Added: vendor/elsa/current/elsa/in/k0011.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0011.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0011.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// error: more than one ambiguous alternative succeeds
+
+// originally found in package bzip2
+
+struct S{ int z; } *s;
+
+int foo() {
+    int x, y;
+
+    s->z < 1 || 2 > (3);
+    s->z < 1 && 2 > (3);
+
+    x < 1 || y > (3);
+    x < 1 && y > (3);
+
+    x < 1 || 2 > (3);
+    x < 1 && y > (3);
+}

Added: vendor/elsa/current/elsa/in/k0012.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0012.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0012.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// there is no action to merge nonterm ConditionalExpression
+
+// originally found in package coreutils
+
+int foo() {
+    int x;
+    x < 1 ? 2 : 3 > (4);
+}

Added: vendor/elsa/current/elsa/in/k0013.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0013.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0013.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,76 @@
+
+// error: cannot convert argument type `float (*)[4]' to parameter 1 type
+// `float const (*)[4]'
+
+// originally found in package xfree86.
+
+
+// ----------------
+// ERR-MATCH: cannot convert.*\Q(*)[4]\E
+
+void bar(const float M[4][4]);
+void bar2(const float (*M)[4]);
+
+void foo() {
+    float (*m)[4] = 0;
+
+    bar((float (*)[4]) m);
+    bar(m);
+
+    bar2((float (*)[4]) m);
+    bar2(m);
+}
+
+
+// ----------------
+typedef int *ptr_to_int;
+typedef ptr_to_int array4_of_ptr_to_int[4];
+typedef array4_of_ptr_to_int *ptr_to_array4_of_ptr_to_int;
+
+typedef int const *ptr_to_cint;
+typedef ptr_to_cint array4_of_ptr_to_cint[4];
+typedef array4_of_ptr_to_cint *ptr_to_array4_of_ptr_to_cint;
+
+
+void callee(ptr_to_array4_of_ptr_to_cint param);
+
+void caller()
+{
+  // EDG accepts with warning, GCC rejects, my understanding
+  // of cppstd is it is not allowed, even though it would be
+  // const-safe
+  //ERROR(1): callee((ptr_to_array4_of_ptr_to_int)0);
+}
+
+
+// ----------------
+typedef int array4_of_int[4];
+typedef array4_of_int array5_of_array4_of_int[5];
+typedef array5_of_array4_of_int *ptr_to_array5_of_array4_of_int;
+
+typedef int const array4_of_cint[4];
+typedef array4_of_cint array5_of_array4_of_cint[5];
+typedef array5_of_array4_of_cint *ptr_to_array5_of_array4_of_cint;
+
+void callee2(ptr_to_array5_of_array4_of_cint param);
+
+void caller2()
+{
+  // ok to have an arbitrary number of array nestings
+  callee2((ptr_to_array5_of_array4_of_int)0);
+}
+
+
+void callee3(array5_of_array4_of_cint param);
+
+void caller3()
+{
+  array5_of_array4_of_int a;
+
+  // both argument and parameter have their outermost level
+  // of arrayness converted to pointers
+  callee3(a);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/k0014.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0014.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0014.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// ambiguous lookup of base class constructor with constructor of same class
+// with different template argument
+
+// Assertion failed: !ambiguity, file cc.ast.gen.cc line 2726
+
+// originally found in package aspell
+
+struct B {};
+
+template <typename T> struct C : B {
+    C() {}
+    C(C<int> & other) : B(other)
+    {
+        foo();
+    }
+
+    void foo() {}
+};
+
+
+int main() {
+    C<int> c1;
+    C<long> c2(c1);
+}

Added: vendor/elsa/current/elsa/in/k0015.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0015.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0015.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// catch namespace_qualified::class_name
+
+// WARNING: there is no action to merge nonterm HandlerParameter
+
+// originally found in package aiksaurus
+
+// ERR-MATCH: merge nonterm HandlerParameter
+
+namespace N {
+    struct exception {
+    };
+}
+
+int main() {
+    try {
+    }
+    catch(N::exception) {
+    }
+}
+

Added: vendor/elsa/current/elsa/in/k0016.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0016.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0016.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// error: no template parameter list supplied for `S'
+
+// explicit instantiation of template member function
+
+// originally found in package aspell
+
+// ERR-MATCH: no template parameter list supplied
+
+template <typename T> struct S {
+    void foo() {  
+      // the following line of code contains an error that
+      // is only found if S<int>::foo is instantiated; this
+      // ensures the instantiation request below is not simply
+      // being ignored
+      //ERROR(1): typename T::foo x;
+    }
+};
+template void S<int>::foo();

Added: vendor/elsa/current/elsa/in/k0017.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0017.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0017.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// 'using namespace std' before 'namespace std'
+
+//  [ This may be a gcc extension, though gcc -pedantic accepts it. --Karl ]
+
+// originally found in package amsynth
+
+// ERR-MATCH: could not find namespace `(?:\::)?std'
+
+using namespace std;
+
+using namespace ::std;
+
+//ERROR(1): using namespace BogusNamespace;

Added: vendor/elsa/current/elsa/in/k0018.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0018.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0018.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// member function taking an array argument with default value __null
+
+// Assertion failed: isArrayType(), file cc_type.cc line 870
+
+// originally found in package anjuta
+
+// ERR-MATCH: Assertion failed: isArrayType
+
+struct S {
+    // sm: __null is a GNU thing, and the test was failing due to the
+    // presence of an initializer (rather than anything having to do
+    // with the specific value of that initializer), so I changed it
+    // to "0"
+    void f(int a[] = 0 /*__null*/);
+};

Added: vendor/elsa/current/elsa/in/k0019.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0019.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0019.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// template parameters named for ctor/dtor
+
+// originally found in package apollon
+
+// ERR-MATCH: Parse error.*at <$
+
+template <typename T>
+struct S1 {
+    S1<T>() {}
+    ~S1<T>() {}
+
+    //ERROR(1): int blargh<T>() {}
+    //ERROR(1): S1<U>() {}
+};
+
+template <typename T, typename U>
+struct S2 {
+    S2<T, U>(T t) {}
+    virtual ~S2<T, U>() {}
+};

Added: vendor/elsa/current/elsa/in/k0020.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0020.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0020.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// deleting pointers of template-type
+
+// error: can only delete pointers, not `T'
+
+// originally found in package qt-x11-free
+
+// ERR-MATCH: can only delete pointers
+
+template <class T> struct S1 {
+    static void foo() {
+        void * x = 0;
+        delete (T)x;
+    }
+};
+
+void f()
+{
+  S1<int*>::foo();
+}
+

Added: vendor/elsa/current/elsa/in/k0021.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0021.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0021.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// calling a templated function pointer
+
+// error: you can't use an expression of type `funcType &' as a function
+
+// originally found in package aprsd
+
+// ERR-MATCH: you can't use an expression of type `.*?' as a function
+
+template<typename funcType>
+void generate(funcType func) {
+    func();
+}

Added: vendor/elsa/current/elsa/in/k0022.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0022.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0022.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,61 @@
+// explicit instantiation of template loses original template parameter names
+
+// error: there is no type called `K1' (inst from a.ii:13:13)
+
+// originally found in package kdelibs
+
+// ERR-MATCH: there is no type called
+
+
+// ---- defn then decl ----
+
+template <class K1> struct S1 {
+};
+
+// defn
+template<class K1> struct S2 {
+    typedef S1< K1 > S1;
+};
+
+// decl
+template <class K2> struct S2;
+
+int foo() {
+    S2<int> m;
+}
+
+
+
+
+// ---- decl then defn ----
+// decl
+template <class T1>
+struct A;
+
+// defn
+template <class T2>
+struct A {
+  T2 *p;
+};
+
+A<int> a;
+
+
+
+
+// ---- defn then decl for func ----
+template <class T1>
+int bar(T1 t)
+{
+  T1 *p = 0;
+  return 0;
+}
+
+template <class T2>
+int bar(T2 t);
+
+int b()
+{
+  int x;
+  return bar(x);
+}

Added: vendor/elsa/current/elsa/in/k0023.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0023.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0023.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// typedef pointer to member function in template
+
+// originally seen in package aqsis
+
+// ERR-MATCH: Assertion failed: inClassNAT->isCompoundType
+
+template<class T> struct S1 {
+    typedef void * (S1<T>::*funcType)();
+};

Added: vendor/elsa/current/elsa/in/k0024.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0024.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0024.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// overloaded function resolution in an array
+
+// originally found in package fltk
+
+// error: failed to resolve address-of of overloaded function `foo' assigned
+// to type `struct Anon_struct_1 []'
+
+// error: failed to resolve address-of of overloaded function `foo' assigned
+// to type `void (*[])(int /*anon*/, long int /*anon*/)'
+
+// ERR-MATCH: resolve address-of of overloaded function
+
+typedef void (*funcType)(int, long);
+
+void foo(int x);
+
+void foo(int x, long y);
+
+funcType array1[] = {foo};
+
+struct S {
+    funcType f;
+    //ERROR(1): int x;     // would assign 'foo' to 'int', not ok
+    funcType g;
+} array2[] = { {foo, foo} };
+
+// these provoke errors because of the failure to resolve 'foo',
+// rather than because of having too many initializers, because
+// the latter is just a weak error right now
+//ERROR(2): funcType array3[2] = {foo, foo, foo};
+//ERROR(3): S s = {foo, foo, foo};
+
+S array4[2] = {
+  foo,foo,
+  foo,foo,
+};
+
+

Added: vendor/elsa/current/elsa/in/k0025.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0025.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0025.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// fully-namespace-qualified base class initialization
+
+// originally found in package centericq
+
+// ERR-MATCH: Parse error.* at ::$
+
+namespace N {
+    struct S1 {
+        S1() {}
+    };
+
+    struct S2 : public ::N::S1 {
+        S2() : ::N::S1() {
+        };
+    };
+
+    struct T1 {
+        struct S3 : public ::N::S1 {
+            S3() : ::N::S1() {
+            };
+        };
+    };
+
+    // even if S1 is the same name, but in an enclosing scope
+    struct T2 {
+        struct S1 : public ::N::S1 {
+            S1() : ::N::S1() {
+            };
+        };
+    };
+
+}

Added: vendor/elsa/current/elsa/in/k0026.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0026.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0026.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// template argument default value from another template class
+
+// originally found in package buffy
+
+// Assertion failed: newHead->next == NULL, file ../ast/fakelist.h line 81
+
+// ERR-MATCH: Assertion failed: newHead->next
+
+template <typename T> struct B {
+    static const int value = true;
+};
+
+struct T1 {
+};
+
+template <class U, int v = B<T1>::value>
+struct S {
+};
+
+struct U{};
+S<U> x;

Added: vendor/elsa/current/elsa/in/k0027.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0027.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0027.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// reprSize of a sizeless array
+
+// originally found in package krb5
+
+// ERR-MATCH: reprSize of a sizeless array
+
+typedef int S[1];
+const S array[2] = {};
+
+int foo()
+{
+    int size = sizeof(array);
+}

Added: vendor/elsa/current/elsa/in/k0028.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0028.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0028.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// definition of member function declared in another namespace
+
+// originally found in package kdelibs
+
+// error: function definition of `S::foo' must appear in a namespace that
+// encloses the original declaration
+
+// sm: This is invalid C++.
+
+// ERR-MATCH: must appear in a namespace
+
+namespace NS1 {
+    struct S {
+        int foo();
+    };
+}
+
+using namespace NS1;
+
+namespace NS2 {
+    int S::foo() { return 0; }
+}
+
+
+
+// ---- variant without the 'using' directive ----
+namespace NS3 {
+    struct S {
+        int foo();
+    };
+}
+
+namespace NS4 {
+    int NS3::S::foo() { return 0; }
+}

Added: vendor/elsa/current/elsa/in/k0029.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0029.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0029.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// ambiguous overload "char* const*" vs "char const* const*"
+
+// originally found in package aconnectgui
+
+// ERR-MATCH: ambiguous overload
+
+struct S1
+{
+    S1(char * const * D)
+    {
+    }
+    S1(char const * const * D)
+    {
+    }
+};
+
+int func(char * const * D)
+{
+}
+int func(char const * const * D)
+{
+}
+
+char **strings;
+
+int main() {
+    func(strings);
+
+    S1 s1(strings);
+}

Added: vendor/elsa/current/elsa/in/k0030.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0030.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0030.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// "and" and "or" keywords
+
+// originally found in package battleball
+
+//  Parse error (state 910) at <name>: and
+
+// ERR-MATCH: Parse error.*at.* and$
+
+int main()
+{
+    return (true and false) or (false and true);
+}
+
+// use all the alternative tokens
+void f(int x, int y, int *p)
+<%                   // {
+
+  x = p <: 3 :>;     //   x = p[3];
+
+  // skipping %: and %:%: because they are "#" and "##", for cpp only
+
+  x and y;           //   x && y;
+  x bitor y;         //   x | y;
+  x or y;            //   x || y;
+  x xor y;           //   x ^ y;
+  compl x;           //   ~ x;
+  x bitand y;        //   x & y;
+  x and_eq y;        //   x &= y;
+  x or_eq y;         //   x |= y;
+  x xor_eq y;        //   x ^= y;
+  not x;             //   ! x;
+  x not_eq y;        //   x != y;
+
+%>                   // }
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/k0031.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0031.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0031.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// weird function typedefs used in a class
+
+// originally found in package aplus-fsf
+
+// Assertion failed: dt.funcSyntax, file cc_tcheck.cc line 2228
+
+// ERR-MATCH: Assertion failed: dt.funcSyntax
+
+typedef int funcType1(int);
+typedef int *funcType2(int);
+typedef int (*funcType3)(int);
+
+struct S1 {
+    funcType1 f1;
+    funcType2 f2;
+    funcType3 f3;
+};

Added: vendor/elsa/current/elsa/in/k0032.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0032.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0032.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// converting <integral>& to integral
+
+// originally found in package fltk
+
+// error: cannot convert argument type `<integral> &' to parameter 1 type
+// `int'
+
+// ERR-MATCH: cannot convert argument type `<integral> &'
+
+enum {
+    FOO = 1
+};
+
+void intFunc (int f) {}
+
+int main() {
+    int c;
+
+    intFunc(c |= FOO);
+}
+

Added: vendor/elsa/current/elsa/in/k0033.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0033.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0033.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// casting function pointer with throw() to/from no throw
+
+// allowed by 8.3.5p4
+
+// originally found in package abiword
+
+// error: cannot convert argument type `int (*&)() throw()' to parameter 1
+// type `int (*)()'
+
+// ERR-MATCH: cannot convert argument type `.*throw\(\)'
+
+int bar1 (int (*func) ());
+int bar2 (int (*func) () throw());
+
+int foo1 ();
+int foo2 () throw ();
+
+int main() {
+    // bar(foo);
+
+    int (*func1) ()           = 0;
+    int (*func2) () throw()   = 0;
+
+    func1 = func2;        // ok, func2 has fewer behaviors
+    func2 = func1;        // questionable, but legal (8.3.5p4)
+
+    bar1(func1);
+    bar1(func2);          // ok, func2 has fewer behaviors
+
+    bar2(func1);          // questionable
+    bar2(func2);
+
+    bar1(foo1);
+    bar1(foo2);           // ok, foo2 has fewer behaviors
+
+    bar2(foo1);           // questionable
+    bar2(foo2);
+}

Added: vendor/elsa/current/elsa/in/k0034.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0034.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0034.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// undefined instanceless unions repeating members
+
+// originally found in package buildtool
+
+// error: duplicate definition for `i' of type `int'
+
+// ERR-MATCH: duplicate definition
+
+int main()
+{
+    union {int i;};
+    union {int i;};
+}

Added: vendor/elsa/current/elsa/in/k0035.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0035.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0035.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// ambiguous int+sizeof(struct{})
+
+// originally found in package buildtool
+
+// Assertion failed: env.disambiguationNestingLevel == 0, file cc_tcheck.cc
+// line 1836
+
+// ERR-MATCH: env.disambiguationNestingLevel == 0
+
+int main() {
+    int n;
+    
+    // actually, this is invalid, and is rejected by gcc-3.4.3
+    //ERROR(1): (n) + (sizeof(struct {}));
+}

Added: vendor/elsa/current/elsa/in/k0036.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0036.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0036.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,47 @@
+// taking the address of a string (?!)
+
+// originally found in package psys
+
+// error: cannot take address of non-lvalue `char [5]'
+
+// ERR-MATCH: address of non-lvalue `char
+
+void f1(int *);     
+void g1(int [5]);
+void f2(int (*)[5]);
+
+void f3(char const *);
+void f4(char const (*)[5]);
+
+template <class T>
+void f(T);
+
+template <class T>
+void g(T (&)[5]);
+
+int main()
+{
+  int a[5];
+  &a;
+
+  f1(a);
+  g1(a);
+  f2(&a);
+
+  //ERROR(1): f1(&a);
+  //ERROR(2): f2(a);
+
+  f3("blah");
+  f4(&"blah");
+
+  //ERROR(3): f3(&"blah");
+  //ERROR(4): f4("blah");
+
+  f(a);
+  f(&a);
+  f("blah");
+  f(&"blah");
+  
+  g(a);
+  g("blah");
+}

Added: vendor/elsa/current/elsa/in/k0037.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0037.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0037.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// new array of pointers
+
+// originally found in package achilles
+
+// Parse error (state 253) at [
+
+// ERR-MATCH: Parse error.*at \[$
+
+int main() {
+    // correct syntax #1: new of array of pointers to int
+    int ** pointer_array = new (int *[42]);
+
+    // correct syntax #2: new[] of pointers to int
+    int ** pointer_array2 = new int *[42];
+
+    // invalid, rejected by gcc-3.4.3
+    //ERROR(1): int ** pointer_array3 = new (int*)[42];
+}

Added: vendor/elsa/current/elsa/in/k0038.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0038.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0038.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// templatized struct as template parameter to function
+
+// from gcc-3.3 <locale> header
+
+// error: `S1' used as a variable, but it's actually a type
+// error: `T' used as a variable, but it's actually a type
+
+// ERR-MATCH: used as a variable, but it's actually a type
+
+template<typename T>
+T foo(int) {}
+
+template<typename T>
+struct S1
+{
+};
+
+template<typename T>
+void bar(T dummy) {
+    foo<S1<T> >(42);
+}
+
+int main()
+{
+    int x;
+    bar(x);
+}

Added: vendor/elsa/current/elsa/in/k0039.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0039.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0039.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// funky namespace resolution after 'using namespace'
+
+// originally found in package dcmtk_3.5.3-1
+
+// Assertion failed: (!!v) == set.isNotEmpty(), file cc_scope.cc line 773
+
+// ERR-MATCH: \QAssertion failed: (!!v) == set.isNotEmpty\E
+
+namespace NS {
+}
+using namespace NS;
+
+typedef int fooint;
+namespace NS {
+    using ::fooint;
+}

Added: vendor/elsa/current/elsa/in/k0040.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0040.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0040.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// instantiating a template with unnamed template parameter
+
+// originally found in package akregator_1.0-beta8-2
+
+// Assertion failed: key != NULL, file vptrmap.cc line 58
+
+// ERR-MATCH: \QAssertion failed: key != NULL, file vptrmap\E
+
+template <class> struct S1;
+
+typedef S1<int> s1;
+

Added: vendor/elsa/current/elsa/in/k0041.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0041.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0041.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// inner struct defined inline in an inner struct not defined inline
+
+// originally found in package kdelibs_4:3.3.1-4
+
+// Assertion failed: (unsigned)i < (unsigned)sz, file ../smbase/array.h line 66
+
+// ERR-MATCH: \QAssertion failed: (unsigned)i < (unsigned)sz\E
+
+struct S1 {
+    struct S2;
+};
+
+struct S1::S2 {
+    struct S3 {
+    };
+};
+
+S1 s1;

Added: vendor/elsa/current/elsa/in/k0042.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0042.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0042.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// computed array size expression as an assignment
+
+// originally found in package centericq_4.13.0-2
+
+// (expected-token info not available due to nondeterministic mode)
+// a.ii:5:15: Parse error (state -1) at =
+
+// ERR-MATCH: Parse error.*at =$
+
+int main() {
+    int i;
+    char str[i=4];
+    
+    // does gcc/icc allow commas too?
+    //
+    // interesting; gcc does *not*, while icc *does*!
+    //
+    // I will reject
+    //ERROR(1): char str2[4/*ignored*/, 6];
+    
+    // what about throw?  they both parse it but then reject
+    // for tcheck reasons; I will do the same (since it is the
+    // behavior that naturally falls out of my implementation)
+    //
+    // er, I guess my tchecker isn't strict enough
+    //char str3[throw 4];
+
+    return 0;
+}

Added: vendor/elsa/current/elsa/in/k0043.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0043.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0043.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// voiding the result of a member call
+
+// originally found in package amule_1.2.6+rc7-2
+
+// c.ii:9:12: Parse error (state 676) at .
+
+// ERR-MATCH: Parse error.*at ([.]|->)$
+
+struct S1 {
+    int foo() { return 0; }
+} s1, *ps2;
+
+int main()
+{
+    void(s1.foo());
+    void(ps2->foo());
+
+    return 0;
+}

Added: vendor/elsa/current/elsa/in/k0044.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0044.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0044.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// template super class member variable
+
+// originally found in <vector>
+
+// vx.ii:9:9: error: there is no variable called `var'
+
+// ERR-MATCH: there is no variable
+
+template<typename T>
+struct B {
+    int var;
+};
+
+template<typename T>
+struct C : B<T> {
+    C() {
+        var = 0;
+    }
+};
+
+int main()
+{
+    C<int> b;
+    return 0;
+}

Added: vendor/elsa/current/elsa/in/k0045.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0045.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0045.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// 'operator delete' redeclared without throw()
+
+// originally found in package drscheme_1:208-1
+
+// a.ii:3:6: error: prior declaration of `operator delete' at <init>:1:1 had
+// type `void ()(void *p) throw()', but this one uses `void ()(void
+// */*anon*/)'
+
+// ERR-MATCH: prior declaration of `operator delete'
+  
+// this would make both gcc and icc reject
+//ERROR(1): void operator delete(void *) throw();
+
+void operator delete(void *) {
+}
+
+
+// something else
+extern int x;
+//ERROR(2): typedef int x;
+
+typedef int y;
+//ERROR(3): extern int y;
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/k0046.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0046.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0046.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// anonymous inline struct fields
+
+// originally found in package elinks_0.9.3-1
+
+// a.i:4:62: error: field `dummy2' is not a class member
+
+// ERR-MATCH: is not a class member
+
+int main () {
+    // invalid, rejected by gcc-3.4.3
+    //ERROR(1): int x = (int) &((struct {int dummy1; int dummy2;} *) 0)->dummy2;
+    
+    
+    // all these are invalid
+    //ERROR(2): (struct { int x; }*)0;
+    //ERROR(3): const_cast<struct { int x; }*>(0);
+    //ERROR(4): static_cast<struct { int x; }*>(0);
+    //ERROR(5): dynamic_cast<struct { int x; }*>(0);
+    //ERROR(6): reinterpret_cast<struct { int x; }*>(0);
+}

Added: vendor/elsa/current/elsa/in/k0046a.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0046a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0046a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// anonymous struct fields in a union
+
+// originally found in package libselinux
+
+// k0046a.cc:14:24: error: there is no member called `foo2' in union U1
+
+// ERR-MATCH: there is no member called.*in union
+
+union U1 {
+    struct {
+        int foo1;
+        int foo2;
+    };
+};
+
+void f()
+{
+  U1 u;
+  u.foo1;
+}
+
+int x =  ((int) &((U1 *)0)->foo2);

Added: vendor/elsa/current/elsa/in/k0046b.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0046b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0046b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// k0046b.cc
+// test for ANSI mode
+
+union U1 {
+    struct {
+        int foo1;
+        int foo2;
+    };
+};
+
+void f()
+{
+  U1 u;
+
+  // the anon struct is useless, so this is illegal
+  //ERROR(1): u.foo1;
+}

Added: vendor/elsa/current/elsa/in/k0047.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0047.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0047.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// template<T> operator T*
+
+// originally found in package djvulibre_3.5.14-2
+
+// k0047.cc:14:36: error: there is no type called `T'
+
+// ERR-MATCH: there is no type called
+
+template <class T> struct S1 {
+    operator T*();
+};
+
+template <class T> S1<T>::operator T*()
+{
+    T *p = new T;
+    return p;
+}
+
+void f()
+{
+  S1<int> s;
+  s.operator int*();
+}

Added: vendor/elsa/current/elsa/in/k0048.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0048.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0048.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// re-declaration of template base-class member
+
+// originally found in package jade_1.2.1-43
+
+// a.ii:10:8: error: class `A' isn't a template (inst from a.ii:14:12)
+
+// ERR-MATCH: class `.*?' isn't a template
+
+template<class T> struct A {
+protected:
+    int foo() { return 42; }
+};
+
+template<class T> struct B : A<T> {
+public:
+    A<T>::foo;
+};
+
+int main() {
+    B<int> b;
+    return b.foo();
+}

Added: vendor/elsa/current/elsa/in/k0049.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0049.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0049.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// 'restrict' as name
+
+// originally found in package crawl_1:4.0.0beta26-4
+
+// a.ii:3:8: Parse error (state 138) at restrict
+
+// ERR-MATCH: Parse error.*?at restrict
+
+struct restrict {
+};
+
+int main() {
+    int restrict = 1;
+    return restrict == 1;
+}

Added: vendor/elsa/current/elsa/in/k0050.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0050.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0050.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// definition of a function without 'const' on a basic type
+
+// originally found in package audacity_1.2.3-1
+
+// a.ii:7:1: error: the name `S1::S1' is overloaded, but the type `()(int const number)' doesn't match any of the 2 declared overloaded instances
+
+// ERR-MATCH: the name `.*?' is overloaded, but the type `.*?' doesn't match
+
+struct S1 {
+S1(int number);
+};
+
+S1::S1(int const number) {
+}
+
+
+struct S2 {
+  void f(int number);
+  void f();
+};
+
+void S2::f(int const number) {
+}

Added: vendor/elsa/current/elsa/in/k0051.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0051.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0051.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// defining static-member array without array size
+
+// originally found in package fam_2.7.0-6
+
+// a.ii:7:4: error: attempt to create an object of incomplete type `struct S1
+// []'
+
+// ERR-MATCH: attempt to create an object of incomplete type
+
+struct S1 {
+    static S1 foo[1];
+};
+
+S1 S1::foo[];

Added: vendor/elsa/current/elsa/in/k0052.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0052.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0052.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// operator& returning other pointer type
+
+// originally found in package tetex-bin_2.0.2-25
+
+// a.ii:13:5: error: cannot convert argument type `struct S2 *' to parameter 1 type `struct S1 *'
+
+// ERR-MATCH: cannot convert argument type `.*?[*]' to .*? type `.*?[*]'
+
+struct S1 {};
+
+int foo(S1* obj) { return 42; }
+
+struct S2 {
+    S1* operator&() { return 0; }
+};
+
+int main() {
+    S2 s2;
+    return foo(&s2);
+}

Added: vendor/elsa/current/elsa/in/k0053.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0053.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0053.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// calling a function with a pointer to an undefined template class
+
+// originally found in package ace_5.4.2.1-1
+
+// a.ii:9:9: error: attempt to instantiate `::S1<int>', but no definition has
+// been provided for `::S1<T>'
+
+// ERR-MATCH: attempt to instantiate `.*?', but no definition has been provided
+
+template <typename T> 
+struct S1;
+
+void foo(S1<int> *);
+
+void f()
+{
+    S1<int>* ptr;
+    
+    // this is ok; if we *could* instantiate 'S1<int>', then we
+    // could consider base class conversions, but not being able
+    // to instantiate it is not fatal
+    foo(ptr);
+
+    return 0;
+}
+
+// now suppose we see a defn
+template <typename T>
+struct S1 {
+  T x;
+};
+
+// and a legitimate need to instantiate
+void g()
+{
+  S1<int> s1;
+  s1.x = 5;
+  //ERROR(1): s1.y = 6;    // no such member
+}
+
+

Added: vendor/elsa/current/elsa/in/k0054.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0054.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0054.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// constructor member initialization without namespace qualifier
+
+// originally found in package omniorb4_4.0.5-1
+
+// a.ii:9:5: error: `S1' does not denote any class
+
+// ERR-MATCH: `.*?' does not denote any class
+
+namespace NS {
+    struct B {
+    };
+}
+
+struct D : NS::B {
+    D() : B() {
+    }
+};

Added: vendor/elsa/current/elsa/in/k0055.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0055.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0055.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// using 'class' instead of 'typename' for template-class typedefs
+
+// [dunno if this is a gcc-bug false positive -- Karl]
+
+// originally found in package
+
+// a.ii:13:9: error: there is no variable called `var1'
+// a.ii:14:9: error: there is no variable called `var2'
+// a.ii:18:15: error: `V<int>::foo_t' is a typedef-name, so cannot be used after 'struct' (inst from a.ii:25:13)
+// a.ii:19:14: error: `V<int>::foo_t' is a typedef-name, so cannot be used after 'class' (inst from a.ii:25:13)
+// a.ii:13:9: error: there is no variable called `var1' (inst from a.ii:26:5)
+// a.ii:14:9: error: there is no variable called `var2' (inst from a.ii:26:5)
+
+// ERR-MATCH: there is no variable called `.*?'
+
+struct A {};
+
+template<class T> struct V {
+    typedef A foo_t;
+};
+
+template<class T> struct S2 {
+    int foo() {
+        //ERROR(1): var1;
+        //ERROR(2): var2;
+        var3;
+        return 42;
+    }
+    //ERROR(1): struct V<T>::foo_t var1;
+    //ERROR(2): class V<T>::foo_t var2;
+    typename V<T>::foo_t var3;
+};
+
+int main()
+{
+    S2<int> s2;
+    return s2.foo();
+}
+

Added: vendor/elsa/current/elsa/in/k0056.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0056.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0056.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// template friend function
+
+// originally found in package arts
+
+// Assertion failed: !destVar->funcDefn, file template.cc line 3073
+
+// ERR-MATCH: Assertion failed: !destVar->funcDefn
+
+template <typename T>
+struct S1 {
+    template <typename T1> friend int foo();
+};
+
+template <typename T1> int foo() {
+    return 42;
+}
+
+int main()
+{
+    S1<long> s1;
+}

Added: vendor/elsa/current/elsa/in/k0057.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0057.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0057.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// template friend function (2)
+
+// originally found in package arts
+
+// Assertion failed: ct->parameterizingScope == this, file cc_scope.cc line 53
+
+// ERR-MATCH: Assertion failed: ct->parameterizingScope == this
+
+template <typename T>
+struct S1 {
+    template <typename T1> friend int foo();
+};
+
+template <typename T1> int foo() {
+    return 42;
+}
+
+template <typename T>
+struct S2 {
+    S1<long> s1;
+};
+
+int main()
+{
+    S2<int> x;
+    return foo<int>();
+}

Added: vendor/elsa/current/elsa/in/k0058.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0058.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0058.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// converting to types from parameter templates
+
+// originally found in <string>
+
+// a.ii:17:9: error: cannot convert argument type `int' to parameter 1 type `A::A_int'
+// a.ii:17:9: error: cannot convert argument type `int' to parameter 1 type `A::A_int'
+// a.ii:20:9: error: cannot convert argument type `int &' to parameter 1 type `A::A_int'
+
+// ERR-MATCH: cannot convert argument type `int' to parameter 1 type `.*?::.*?'
+
+struct SA {
+    typedef int A_int;
+};
+
+template<typename A>
+struct S1 {
+    typedef typename A::A_int my_int;
+    int func0(typename A::A_int p) {
+        return p;
+    }
+    int func1(my_int p) {
+        return p;
+    }
+    int func2() {
+        return func0(6) * func1(7);
+    }
+    int func3(int i) {
+        return func0(i);
+    }
+};
+
+int main() {
+    S1<SA> s1;
+    s1.func3(3);
+    return s1.func2();
+}

Added: vendor/elsa/current/elsa/in/k0059.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0059.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0059.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// implicit type conversion in operator delete
+
+// originally found in qt-x11-free
+
+// k0059.cc:15:3: error: can only delete pointers, not `struct QGuardedPtr'
+// typechecking results:
+//   errors:   1
+//   warnings: 0
+
+// ERR-MATCH: can only delete pointers, not `.*'
+
+struct QGuardedPtr
+{
+  operator int*() const {}
+};
+
+int main()
+{
+  QGuardedPtr p;
+  delete p;
+}

Added: vendor/elsa/current/elsa/in/k0060.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0060.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0060.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// disambiguated from multiple base class subobjects
+
+// originally found in package kdelibs
+
+// k0060.cc:21:5: error: field `C1::x' ambiguously refers to elements of multiple base class subobjects
+// typechecking results:
+//   errors:   1
+//   warnings: 0
+
+// ERR-MATCH: error: field `.*' ambiguously refers to elements of multiple base class subobjects
+
+struct B {
+  int x;
+};
+
+struct C1: B {
+};
+struct C2: B {
+};
+
+struct T : C1, C2 {
+};
+
+int main() {
+  T t;
+  t.C1::x = 0;
+}

Added: vendor/elsa/current/elsa/in/k0061.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0061.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0061.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// multiple base classes instantiated from the same template class
+
+// originally found in package kdelibs
+
+// k0061.cc:19:12: error: reference to `S' is ambiguous, because it could either refer to S::S or S::S
+// typechecking results:
+//   errors:   1
+//   warnings: 0
+
+// ERR-MATCH: error: reference to `.*' is ambiguous, because it could either refer to
+
+template <class T>
+struct S {
+  void bar() {}
+};
+
+struct C : S<int>, S<float> {
+  void foo() {
+    S<float>::bar();
+  }
+};

Added: vendor/elsa/current/elsa/in/k0062.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0062.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0062.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// template class with subclass whose member function with default argument is
+// defined outside class.
+
+// from <string>.
+// originally found in package 'aptitude'.
+
+// Assertion failed: !wasVisitedAST(obj), file cc.ast.gen.cc line 6948
+
+// ERR-MATCH: Assertion failed:.* file cc.ast.gen.cc line 6948
+
+template<typename T> struct S {
+  struct Rep {
+    void foo(int = 0);
+  };
+};
+
+template<typename T> void S<T>::Rep:: foo(int x) {}
+
+int main()
+{
+  S<int>::Rep r;
+  r.foo();
+}

Added: vendor/elsa/current/elsa/in/k0063.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0063.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0063.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// class friend main
+
+// originally found in package 'bibletime'.
+
+// Assertion failed: prior->hasFlag(DF_EXTERN_C), file cc_env.cc line 3505
+// Failure probably related to code near k0063.cc:10:14
+// current location stack:
+//   k0063.cc:10:14
+//   k0063.cc:9:1
+
+// ERR-MATCH: c524f127-19cb-44eb-a829-f49faf2185a4
+// ERR-MATCH: Assertion failed: prior->hasFlag.DF_EXTERN_C.
+
+struct S {
+  friend int main(int argc, char* argv[]);
+};
+

Added: vendor/elsa/current/elsa/in/k0064.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0064.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0064.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// functions overloaded by number of template parameters
+
+// originally found in kde/kmainwindow.h
+
+// k0064.cc:9:5: error: duplicate definition for `foo' of type `int ()()'; previous at k0064.cc:6:5 (from template; would be suppressed in permissive mode)
+// typechecking results:
+//   errors:   1
+//   warnings: 0
+
+// ERR-MATCH: error: duplicate definition for.*from template
+
+template <class T1>
+int foo() {}
+
+template <class T1, class T2>
+int foo() {}
+
+int main()
+{
+  foo<int>();
+  foo<int,int>();
+}

Added: vendor/elsa/current/elsa/in/k0065.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0065.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0065.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// using incomplete class as default template argument
+
+// originally found in package 'monotone' (Boost headers)
+
+// k0065.cc:13:31: error: attempt to create an object of incomplete class `Foo_'
+// typechecking results:
+//   errors:   1
+//   warnings: 0
+
+// ERR-MATCH: error: attempt to create an object of incomplete class
+
+struct Foo_;
+template< typename Tag = Foo_ > struct T;

Added: vendor/elsa/current/elsa/in/k0066.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0066.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0066.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// nested template class
+
+// originally found in package 'monotone' (Boost headers)
+
+// In state 159, I expected one of these tokens:
+//   <name>,
+// k0066.cc:12:19: Parse error (state 159) at <
+
+// ERR-MATCH: Parse error .state (157|159). at <
+
+template< template< typename T1 > class F >
+struct S;

Added: vendor/elsa/current/elsa/in/k0067.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0067.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0067.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// constructor using volatile reference
+
+// originally found in package 'bidwatcher'
+
+// Assertion failed: fullyQualifiedName called on scope that doesn't terminate in the global scope, file cc_scope.cc line 1176
+// Failure probably related to code near k0067.cc:14:12
+// current location stack:
+//   k0067.cc:14:12
+//   k0067.cc:9:12
+//   k0067.cc:9:6
+
+// ERR-MATCH: fullyQualifiedName called on scope that doesn't terminate in the global scope
+
+volatile bool x;
+
+void foo() {
+  struct AutoFlag {
+    volatile bool &b;
+    AutoFlag(volatile bool & b0): b(b0) {}
+  };
+  AutoFlag a(x);
+}

Added: vendor/elsa/current/elsa/in/k0068.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0068.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0068.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// explicitly named constructor
+
+// k0068.cc:9:3: error: there is no variable called `C::C'
+// typechecking results:
+//   errors:   1
+//   warnings: 0
+
+// ERR-MATCH: error: there is no variable called `([A-Za-z0-9_]+)::\1'
+
+struct C {
+  C (int x) {}
+};
+
+int main()
+{
+  C::C(42);
+}

Added: vendor/elsa/current/elsa/in/k0069.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0069.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0069.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// friend class as template parameter
+
+// originally found in package 'zipios'
+
+// typechecking results:
+//   errors:   0
+//   warnings: 0
+// error: k0069.cc:15:12: internal error: found dependent type `Friend' in non-template
+
+// ERR-MATCH: internal error: found dependent type `([^(]|[(][^d]|[(][d][^e]).*?' in non-template
+
+template< class Type > struct T {
+  friend struct Friend ;
+};
+
+struct Friend;
+
+typedef T< Friend > T1 ;

Added: vendor/elsa/current/elsa/in/k0070.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0070.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0070.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// scoping via template instantiation with all parameters defaulted
+
+// originally found in package 'libcrypto++'
+
+// In state 646, I expected one of these tokens:
+//   asm, try, (, ), [, ], ->, ::, ., +, -, ++, --, &, *, .*, ->*, /, %, <<, >>, <, <=, >, >=, ==, !=, ^, |, &&, ||, ?, :, =, *=, /=, %=, +=, -=, &=, ^=, |=, <<=, >>=, ,, ..., ;, {, }, __attribute__, <?, >?,
+// a.ii:11:11: Parse error (state 646) at <name>: s
+
+// ERR-MATCH: In state (646|658), I expected one of these tokens
+
+template <typename T = int>
+struct S
+{
+  struct S2 {};
+};
+
+int foo()
+{
+  S<>::S2 s;
+}

Added: vendor/elsa/current/elsa/in/k0071.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0071.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0071.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// compound initializer for struct which was earlier forward-declared as class
+
+// originally found in package 'kdelibs'
+
+// a.ii:8:3: error: cannot convert initializer type `int' to type `struct S'
+
+// ERR-MATCH: cannot convert initializer type `.*?' to type `struct .*?'
+
+class S;
+struct S {
+  int foo, bar;
+};
+
+S s = { 42, 84 };

Added: vendor/elsa/current/elsa/in/k0072.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0072.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0072.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// template <class T> void foo(S1<T> s1, const typename T::T2 t2) {}
+
+// originally found in package 'aspell'
+
+// ERR-MATCH: Assertion failed: .*ceae1527-94a7-480d-9134-5dbd8cbfb2aa
+
+template <class T> struct S1 {};
+
+template <class T> void foo(S1<T> s1, const typename T::T2 t2) {}

Added: vendor/elsa/current/elsa/in/k0073.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0073.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0073.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// compound initializer for instantiated template struct
+
+// originally found in package 'speech-tools_1:1.2.3-8'
+
+// a.ii:5:15: error: can't initialize memberless aggregate S<int /*anon*/>
+
+// ERR-MATCH: can't initialize memberless aggregate
+
+template<class T> struct S { int foo; };
+
+static S<int> estfile_names[] = { { 42 } };

Added: vendor/elsa/current/elsa/in/k0074.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0074.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0074.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// template unions
+
+// originally found in package 'monotone_0.18-1'
+
+// a.ii:3:18: error: template unions are not allowed
+
+// ERR-MATCH: template unions are not allowed
+
+template <int N> union U {};

Added: vendor/elsa/current/elsa/in/k0075.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0075.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0075.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// overloaded function involving function pointer in presence of template
+
+// originally found in package 'digikam_0.7.2-2'
+
+// Assertion failed: argType != NULL && "52291632-1792-4e5c-b5b8-9e6240b75a91", file template.cc line 1305
+// Failure probably related to code near a.ii:18:3
+// current location stack:
+//   a.ii:18:3
+//   a.ii:15:1
+//   a.ii:14:5
+
+// ERR-MATCH: Assertion failed:.*52291632-1792-4e5c-b5b8-9e6240b75a91
+
+struct S1 {};
+struct S2 {};
+
+int operator<<(S1, S1 (*f)(S1)) {}
+
+inline S1 foo(S1 s) {}
+inline S2 foo(S2 s) {}
+
+template <typename T1> struct SB;
+template <class T1> inline char operator<<(char, const SB<T1>& p) {}
+
+int main()
+{
+  S1 s;
+  int i;
+  s << foo;
+}

Added: vendor/elsa/current/elsa/in/k0076.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0076.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0076.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// attribute unused on struct parameter
+
+// originally found in package 'rbldnsd_0.994b'
+
+// Assertion failed: e != NULL && "388cba6d-895c-4acb-ac25-c28fc1c4c2cb", file cc.gr line 1234
+
+// ERR-MATCH: 388cba6d-895c-4acb-ac25-c28fc1c4c2cb
+
+struct S1 {};
+int foo(struct S1 __attribute__((unused)) *x)
+{
+}

Added: vendor/elsa/current/elsa/in/k0077.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0077.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0077.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// template constructor instantiated using function type
+
+// originally found in package 'wvstreams_4.0.2-4'
+
+// Assertion failed: var0inst != NULL && "f1c15444-8783-4296-981f-e3908d7cb1b4", file overload.cc line 351
+// Failure probably related to code near a.ii:10:12
+// current location stack:
+//   a.ii:10:12
+//   a.ii:9:12
+//   a.ii:9:5
+
+// ERR-MATCH: Assertion failed:.*f1c15444-8783-4296-981f-e3908d7cb1b4
+
+struct Callback {
+  template<typename Functor>  Callback(const Functor& func) {}
+};
+
+void foo(int x) {}
+
+int main() {
+  Callback cb(foo);
+}

Added: vendor/elsa/current/elsa/in/k0078.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0078.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0078.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// array of function pointers initialized with template functions
+
+// originally found in package 'monotone_0.18-1'
+
+// Assertion failed: list != NULL && "8706f04b-0a31-407e-b31b-40607d31edf9", file cc.gr line 1437
+
+// ERR-MATCH: Assertion failed:.*8706f04b-0a31-407e-b31b-40607d31edf9
+
+template <class T1, class T2>
+struct S {
+  static bool foo();
+};
+
+typedef bool (*FuncType)();
+
+template <class T1, class T2>
+void bar() {
+  FuncType funcs[] = {
+    0,
+    &S<T1,T2>::foo
+  };
+}

Added: vendor/elsa/current/elsa/in/k0078a.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0078a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0078a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// array of function pointers initialized with template functions
+
+// originally found in package 'monotone_0.18-1'
+
+// d.ii:13:5: error: there is no action to merge nonterm InitializerList
+
+// ERR-MATCH: error: there is no action to merge nonterm InitializerList
+
+template <class T1, class T2>
+struct S {
+  static bool foo();
+};
+
+typedef bool (*FuncType)();
+
+template <class T1, class T2>
+void bar() {
+  FuncType funcs[] = {
+    &S<T1,T2>::foo
+  };
+}

Added: vendor/elsa/current/elsa/in/k0079.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0079.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0079.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// reference to reference used in inner class of template class
+
+// I think this is correctly typechecked as error; allow with permissive mode
+// and/or indicate this is allowed by gcc bug?
+
+// originally found in package 'wvstreams_4.0.2-4'
+
+// b.ii:9:18: error: cannot create a reference to a reference (inst from b.ii:13:10)
+
+// ERR-MATCH: cannot create a reference to a reference
+
+template<typename T1>
+struct S1 {
+  struct S2 {
+    void foo (T1 &t1) {}
+  };
+};
+
+S1<int&> s1;
+

Added: vendor/elsa/current/elsa/in/k0080.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0080.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0080.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// already implicitly instantiated
+
+// originally found in package 'aspell_0.60.2+20050121-2'
+
+// b.ii:13:27: error: S2<void /*anon*/> has already been implicitly instantiated, so it's too late to provide an explicit specialization
+
+// ERR-MATCH: has already been implicitly instantiated
+
+struct S1 {};
+
+template <typename T1> struct S2 : S1 {
+  int foo(S1 const &);
+
+  int bar(S2<void> const & other) {
+    foo(other);
+  }
+};
+
+template <> struct S2<void> : S1 {};

Added: vendor/elsa/current/elsa/in/k0081.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0081.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0081.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// template instantiated through inferred type instantiating another template
+// with default parameter depending on first template parameter
+
+// originally found in package 'lostirc_0.4.4-1'
+
+// a.ii:16:8: error: could not evaluate default argument `S1<T2 /*anon*/>::MyType': attempt to extract member `MyType' from non-class `S1<T2 /*anon*/>' (from template; would be suppressed in permissive mode)
+// a.ii:16:8: error: no argument supplied for template parameter `T3' (from template; would be suppressed in permissive mode)
+
+// ERR-MATCH: could not evaluate default argument .*?: attempt to extract member .*? from non-class .*?
+
+template <typename T1> struct S1 {
+  typedef int MyType;
+};
+
+template <class T2, class T3 = typename S1<T2>::MyType>
+struct S2
+{
+  S2(T2) {}
+};
+
+template <class T2> int foo(T2 a)
+{
+  S2<T2> s2(a);
+}
+
+int main()
+{
+  foo(42);
+}

Added: vendor/elsa/current/elsa/in/k0082.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0082.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0082.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// const register function parameter
+
+// originally found in package 'tripwire_2.3.1.2.0-4'
+
+// In state 896, I expected one of these tokens:
+//   <name>, bool, char, class, const, double, enum, float, int, long, operator, short, signed, struct, typename, union, unsigned, void, volatile, wchar_t, ::, __attribute__, __typeof__, restrict, _Complex, _Imaginary,
+// a.ii:3:16: Parse error (state 896) at register
+
+// ERR-MATCH: Parse error .state 896. at register
+
+void foo(const register int c)
+{
+}
+
+int main()
+{
+  foo(42);
+}

Added: vendor/elsa/current/elsa/in/k0083.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0083.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0083.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// friend template class declaration
+
+// originally found in package 'lyx_1.3.4-2'
+
+// a.ii:6:32: error: wrong # of template param lists in declaration of S1 (from template; would be suppressed in permissive mode)
+
+// ERR-MATCH: wrong # of template param lists in declaration
+
+template<typename T1> struct S1 {};
+
+template<typename T1> struct S2 {
+  template<typename T2> friend struct S1;
+  int foo() {
+    S1<bool> x;
+  }
+};
+
+int main()
+{
+  S2<int> p;
+  p.foo();
+}

Added: vendor/elsa/current/elsa/in/k0084.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0084.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0084.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// complex literals
+
+// originally found in package 'snd_7.8-1'
+
+// a.ii:6:7: error: two adjacent nonseparating tokens
+// In state 4, I expected one of these tokens:
+//   (, ), [, ], ->, ., +, -, ++, --, &, *, .*, ->*, /, %, <<, >>, <, <=, >, >=, ==, !=, ^, |, &&, ||, ?, :, =, *=, /=, %=, +=, -=, &=, ^=, |=, <<=, >>=, ,, ..., ;, }, __attribute__, <?, >?,
+// a.ii:6:9: Parse error (state 4) at <name>: i
+
+// ERR-MATCH: two adjacent nonseparating tokens
+
+int main()
+{
+  _Complex double d;
+  d = 42i;
+  d = 42.0i;
+  d = 42.0fi;
+}

Added: vendor/elsa/current/elsa/in/k0085.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0085.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0085.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// complex double * int
+
+// originally found in package 'snd_7.8-1'
+
+// b.ii:7:19: error: invalid complex arithmetic operand types `double _Complex &' and `int &'
+
+// ERR-MATCH: invalid complex arithmetic operand types
+
+int main()
+{
+  _Complex double a;
+  int b;
+  _Complex double c = a * b;
+  _Complex double d = b * a;
+}

Added: vendor/elsa/current/elsa/in/k0086.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0086.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0086.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// enable_if: template argument expressions
+
+// originally found in package 'cimg_1.0.7-1'
+
+// in code near a.ii:14:3:
+// unimplemented: template.cc:3961: applyArgumentMap: dep-expr is not E_variable
+
+// ERR-MATCH: unimplemented: .* applyArgumentMap: dep-expr is not E_variable
+
+double atan2(double y, double x) {}
+
+template<typename, bool> struct enable_if {};
+
+template<typename _Tp> struct is_integer {};
+
+template<typename _Tp, typename _Up>
+enable_if<double, is_integer<_Tp>::_M_type && false>
+atan2(_Tp y, _Up) {}
+
+int main() {
+  atan2(0,0);
+}
+

Added: vendor/elsa/current/elsa/in/k0087.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0087.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0087.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// implicit conversion to "bool const &" via "bool" via "operator bool"
+
+// originally found in package 'config-manager_0.1p83-1'
+
+// c.ii:13:3: error: no viable candidate for function call; arguments:
+//   1: struct MyBool &
+//  original candidates:
+//   c.ii:3:6: void foo(bool const &)
+//   c.ii:4:6: void foo()
+
+// ERR-MATCH: no viable candidate for function call; arguments
+
+void foo(bool const &);
+void foo();
+
+struct MyBool {
+  operator bool () const{}
+};
+
+int main()
+{
+  MyBool b;
+  foo(b);
+}

Added: vendor/elsa/current/elsa/in/k0088.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0088.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0088.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// inferring const member function template parameter type
+
+// see also simplified version: t0590.cc
+
+// originally found in package 'fluxbox_0.9.11-1sarge0'
+
+// b.ii:18:3: error: ambiguous overload; arguments:
+//   1: int  (S::*)(/*m: struct S const & */ ) const
+//  candidates:
+//   b.ii:7:22: mem_fun_t<int /*anon*/, struct S const /*anon*/> mem_fun<int /*anon*/, struct S const /*anon*/>(int  (S::*__f)(/*m: struct S const & */ ) const)
+//   b.ii:10:28: const_mem_fun_t<int /*anon*/, struct S /*anon*/> mem_fun<int /*anon*/, struct S /*anon*/>(int  (S::*__f)(/*m: struct S const & */ ) const)
+
+// ERR-MATCH: ambiguous overload; arguments
+
+template <class _Ret, class _Tp> class mem_fun_t {};
+template <class _Ret, class _Tp> class const_mem_fun_t {};
+
+template <class _Ret, class _Tp>
+mem_fun_t<_Ret, _Tp> mem_fun(_Ret (_Tp::*__f)()) {}
+
+template <class _Ret, class _Tp>
+const_mem_fun_t<_Ret, _Tp> mem_fun(_Ret (_Tp::*__f)() const) {};
+
+struct S {
+  int foo() const {}
+};
+
+int main()
+{
+  mem_fun(&S::foo);
+}

Added: vendor/elsa/current/elsa/in/k0089.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0089.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0089.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// specialization of template function member
+
+// originally found in package 'fluxbox_0.9.11-1sarge0'
+
+// Assertion failed: vfd == this, file cc_tcheck.cc line 694
+// Failure probably related to code near a.ii:7:24
+// current location stack:
+//   a.ii:7:24
+//   a.ii:7:1
+
+// ERR-MATCH: Assertion failed: vfd == this
+
+template <typename T> struct S1 {
+  void foo() {}
+};
+
+template <> void S1<int>::foo() {}

Added: vendor/elsa/current/elsa/in/k0090.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0090.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0090.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// template specialization of array
+
+// originally found in package 'shaketracker_0.4.6-4'
+
+// a.ii:6:7: error: RHS of . or -> must be of the form "~ identifier" if the LHS is not a class; the LHS is `int const [2]' (inst from a.ii:19:13) (inst from a.ii:26:10)
+
+// ERR-MATCH: RHS of . or -> must be of the form
+
+template <class T>
+struct Traits {
+  static void get_data(const T& t) {
+    t.dont_use_me();
+  }
+};
+
+template <class T, int N>
+struct Traits<T[N]>  {
+  static void get_data(const T* t) {
+  }
+};
+
+struct SArray {
+  template <class T> SArray(const T& t)
+  {
+    Traits<T>::get_data(t);
+  }
+};
+
+int main()
+{
+  int items[] = { 0, 0 };
+  SArray a(items);
+}

Added: vendor/elsa/current/elsa/in/k0090a.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0090a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0090a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// template specialization of array
+
+// originally found in package 'shaketracker_0.4.6-4'
+
+// k0090a.cc:21:13: error: during partial specialization parameter `N' not bound in inferred bindings (inst from k0090a.cc:28:10)
+// k0090a.cc:28:10: error: confused by earlier errors, bailing out
+
+// ERR-MATCH: during partial specialization parameter .*? not bound in inferred bindings
+
+template <class T>
+struct Traits {
+  static void get_data(const T& t) {
+    t.dont_use_me();
+  }
+};
+
+template <class T, int N>
+struct Traits<T[N]>  {
+  static void get_data(const T* t) {
+  }
+};
+
+struct SArray {
+  template <class T> SArray(const T& t)
+  {
+    Traits<T>::get_data(t);
+  }
+};
+
+int main()
+{
+  int items[] = { 0 };
+  SArray a(items);
+}

Added: vendor/elsa/current/elsa/in/k0091.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0091.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0091.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// template specialization with all default parameters
+
+// originally found in package 'kdissert_0.3.8-1'
+
+// Assertion failed: arguments.isNotEmpty(), file template.cc line 396
+// Failure probably related to code near a.ii:5:12
+// current location stack:
+//   a.ii:5:12
+//   a.ii:5:12
+//   a.ii:5:1
+
+// ERR-MATCH: Assertion failed: arguments.isNotEmpty
+
+template<typename T1 = int> struct S1{};
+
+template<> struct S1<> {};

Added: vendor/elsa/current/elsa/in/k0092.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0092.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0092.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// template-parameter-instantiated template class without 'typename' in
+// constructor initializer
+
+// originally found in package 'gnomemeeting_1.2.1-1'
+
+// a.ii:14:17: error: `S1<T1 /*anon*/>::C1' does not denote any class (from template; would be suppressed in permissive mode)
+
+// ERR-MATCH: `.*?<.*?>::.*?' does not denote any class
+
+template <class T1>
+struct S1
+{
+  struct C1 {};
+};
+
+template <class T1>
+struct S2 : S1<T1>
+{
+  struct C2 : S1<T1>::C1
+  {
+    C2() : S1<T1>::C1()
+    {
+      typename S1<T1>::C1 c1;
+    }
+  };
+};
+
+int main()
+{
+  S2<int> s2;
+}

Added: vendor/elsa/current/elsa/in/k0093.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0093.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0093.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// tertiary operator implicitly casting one pointer operand to bool
+
+// originally found in package 'vdr'
+
+// a.ii:5:8: error: incompatible ?: argument types `struct S1 *' and `bool'
+
+// ERR-MATCH: incompatible [?]: argument types
+
+int main() {
+  struct S1 * x;
+  bool b = true ? x : false;
+}

Added: vendor/elsa/current/elsa/in/k0094.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0094.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0094.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+
+//ERROR(1): int foo();   //declared non-static, cannot re-declare as static
+
+static int foo() {
+}

Added: vendor/elsa/current/elsa/in/k0095.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0095.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0095.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// templatized enum parameter
+
+// originally found in package 'gtkmathview'
+
+// b.ii:10:9: error: cannot convert `int' to `enum MyEnum': incompatible atomic types (inst from b.ii:7:14) (inst from b.ii:10:9)
+
+// ERR-MATCH: cannot convert `int' to `enum.*': incompatible atomic types
+
+enum MyEnum { e1 };
+
+template <MyEnum e>
+void foo() { foo<e>(); }
+
+int main() {
+  foo<e1>();
+}
+

Added: vendor/elsa/current/elsa/in/k0096.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0096.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0096.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// ERR-MATCH: 39ce4334-0ca1-4e19-aaf9-7f27f335a629
+
+struct S1 { int foo; char bar; };
+
+struct S1 func () {
+  struct S1 v;
+
+  ({ return v; });
+}
+
+int main() {}

Added: vendor/elsa/current/elsa/in/k0097.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0097.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0097.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// ERR-MATCH: ed1f952c-dbf5-41bf-9778-d5b0c0bda5af
+
+float foo(float);
+
+template <float (*func)(float)>
+struct S1 {
+};
+
+int main() {
+  S1<foo> s1;
+}

Added: vendor/elsa/current/elsa/in/k0098.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0098.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0098.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// ERR-MATCH: 25f0c1af-5aea-4528-b994-ccaac0b3a8f1
+
+// Assertion failed: IC_AMBIGUOUS -- what does this mean here?
+// (25f0c1af-5aea-4528-b994-ccaac0b3a8f1), file cc_tcheck.cc line 5894
+
+void Foo(const void *p);
+
+struct S {
+  operator int *() {};
+  operator void *() {};
+};
+
+int main() {
+  S s;
+  Foo(s);
+}

Added: vendor/elsa/current/elsa/in/k0099.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0099.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0099.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// ERR-MATCH: 60a04156-a119-4c6c-8c04-bca58e69dee1
+
+// Assertion failed: primaryTI->isPrimary() &&
+// "60a04156-a119-4c6c-8c04-bca58e69dee1", file template.cc line 2635
+
+template<class T>
+struct S {
+};
+
+template<>
+struct S<int> {
+  static int foo();
+};
+
+template<class T>
+struct S<T*> {
+  int bar() {
+    S<int>::foo();
+  }
+};
+
+int main()
+{
+  S<int*> s;
+  s.bar();
+}

Added: vendor/elsa/current/elsa/in/k0100.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0100.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0100.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// templatized template parameter list
+
+// ERR-MATCH: 25eb7000-851c-4028-b762-4e365a5b10bf
+
+// from boost, originally seen in package 'monotone'
+
+// Assertion failed: unimplemented: templatized template parameter list
+// (25eb7000-851c-4028-b762-4e365a5b10bf), file cc.gr line 2395
+
+template< template< typename T1, typename T2, typename T3 > class F, typename Tag >
+struct quote3;

Added: vendor/elsa/current/elsa/in/k0101.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0101.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0101.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// typename ParameterDeclaration in TemplateParameterList
+
+// ERR-MATCH: 5fb56c83-4701-421f-9f6a-f9333f0aef56
+
+// from boost, originally seen in package 'lyx'
+
+// Assertion failed: unimplemented: typename ParameterDeclaration in
+// TemplateParameterList (5fb56c83-4701-421f-9f6a-f9333f0aef56), file cc.gr
+// line 2383
+
+namespace boost {
+  struct A
+  {
+    typedef int fast;
+  };
+}
+
+struct A2
+{
+  typedef int fast;
+};
+
+template < typename ::boost::A::fast foo = 0u >
+struct S {};
+
+template < typename A2::fast foo >
+struct S2 {};

Added: vendor/elsa/current/elsa/in/k0102.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0102.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0102.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// template parameter template-instantiated on another template paramter
+
+// ERR-MATCH: 64103c40-efae-4068-b4b1-5492a549b00c
+
+// from boost
+
+// Assertion failed: ret.hasValue() && "64103c40-efae-4068-b4b1-5492a549b00c",
+// file template.cc line 4038
+
+template< int N > struct A {
+  typedef int fast;
+};
+
+template < int N, typename A<N>::fast foo > struct S {
+};
+
+int main() {
+  S<1, 2> s;
+}

Added: vendor/elsa/current/elsa/in/k0103.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0103.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0103.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// 'duplicate definition' from 'using' declaration
+
+// ERR-MATCH: duplicate definition for
+
+// c.ii:9:1: error: duplicate definition for `Foo' of type `double ()(double
+// x)'; previous at c.ii:2:8 c.ii.7
+
+double Foo (double x) {
+}
+
+namespace N {
+  using ::Foo;
+}
+
+using N::Foo;

Added: vendor/elsa/current/elsa/in/k0104.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0104.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0104.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// restrict reference
+
+// ERR-MATCH: Parse error .state 399. at restrict
+
+// first seen in package 'cppunit'
+
+void foo(int & __restrict x) {}

Added: vendor/elsa/current/elsa/in/k0105.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0105.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0105.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// function pointer dependent type
+
+// ERR-MATCH: found dependent type `[(]dependent[)]' in non-template
+
+// // ERR-MATCH: (0a257264-c6ec-4983-95d0-fcd6aa48a6ce|ee42ebc5-7154-4ace-be35-c2090a2821c5)
+
+// error: a.ii:11:3: internal error: found dependent type `(dependent)' in
+// non-template (0a257264-c6ec-4983-95d0-fcd6aa48a6ce)
+
+// NOTE: "cout << endl" hits this bug.
+
+template <typename T>
+struct S {
+  void bar(void (*pf)(S<T>&)) {}
+};
+
+template<typename T>
+void foo(S<T>& s) {}
+
+int main() {
+  S<char> s;
+  s.bar(foo);
+}

Added: vendor/elsa/current/elsa/in/k0105a.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0105a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0105a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+template<typename C> struct basic_ostream {
+  basic_ostream<C>& operator<<(basic_ostream<C>& (*f)(basic_ostream<C>&));
+};
+
+template<typename C> basic_ostream<C>& endl(basic_ostream<C>& os) {
+}
+
+basic_ostream<char> cout;
+
+int main() {
+  cout << endl;
+}

Added: vendor/elsa/current/elsa/in/k0106.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0106.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0106.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// anonymous struct in anonymous union
+
+// ERR-MATCH: there is no member called `.*' in struct
+
+// a.i:12:3: error: there is no member called `a' in struct S
+// a.i.13
+
+struct S {
+  union {
+    struct {
+      int a;
+    };
+  };
+};
+
+int main() {
+  struct S s;
+  int a;
+  a = s.a;
+}

Added: vendor/elsa/current/elsa/in/k0107.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0107.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0107.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// inline explicit instantiations
+
+// ERR-MATCH: c24a5f9c-edbd-4945-a56a-ed73a1d6a0fa
+
+// In state 161, I expected one of these tokens:
+//   <name>,
+// k0107.cc:5:17: Parse error (state 161) at class
+
+template <class C>
+struct T {};
+
+inline template class T<int>;

Added: vendor/elsa/current/elsa/in/k0108.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0108.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0108.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// explicit instantiation of constructor
+
+template <class C>
+struct A {
+    A() {}
+};
+
+template A<char>::A();
+
+typedef A<int> Aint;
+template Aint::A();

Added: vendor/elsa/current/elsa/in/k0109.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0109.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0109.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// "instantiating template member function"
+
+// a.ii:6:15: error: type `void ()(int )' does not match any template function
+// `S::foo'
+
+// seen in gcc-3.4/libstdc++
+
+struct S {
+    template<typename T> void foo(T) {}
+};
+
+template void S::foo(int);
+

Added: vendor/elsa/current/elsa/in/k0110.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0110.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0110.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// "calling template dtor with template arguments"
+
+// from gcc-3.4 ios_init.cc
+
+// a.ii:9:8: error: call site name lookup failed to yield any candidates; last
+// candidate was removed because: non-template given template arguments
+
+//ERR-MATCH: last candidate was removed because: non-template given template arguments
+
+template<typename T>
+struct S {
+};
+
+int main()
+{
+    S<char> s1;
+    s1.~S<char>();
+}

Added: vendor/elsa/current/elsa/in/k0111.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0111.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0111.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// "duplicate template specialization/definition of static data"
+
+// a.cc:8:24: error: duplicate definition for `foo' of type `char const *';
+// previous at a.cc:6:23 (from template; would be suppressed in permissive
+// mode)
+
+// from gcc-3.4 locale_facets.cc
+
+//ERR-MATCH: duplicate definition.*from template
+
+template <class T>
+struct S {
+    static const char *foo;
+};
+
+template<> const char *S<char>::foo;
+
+template<> const char *S<char>::foo = "foo";
+

Added: vendor/elsa/current/elsa/in/k0112.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0112.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0112.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// template instantiation with all default args
+
+// In state 664, I expected one of these tokens:
+//   asm, try, (, ), [, ], ->, ::, ., +, -, ++, --, &, *, .*, ->*, /, %, <<, >>, <, <=, >, >=, ==, !=, ^, |, &&, ||, ?, :, =, *=, /=, %=, +=, -=, &=, ^=, |=, <<=, >>=, ,, ..., ;, {, }, __attribute__, <?, >?,
+// a.ii:17:26: Parse error (state 664) at <name>: myint1
+
+// from sigc++ deduce_result_type.h
+
+template <class T=int>
+struct S1 {
+    typedef int myint;
+};
+
+struct S2 {
+    template <class T=int>
+    struct S2a {
+        typedef int myint;
+    };
+};
+
+template <class T>
+struct S7 {
+    typename S1<>::myint myint1;
+
+    typename T::template S2a<>::myint myint2;
+};
+
+int main()
+{
+    S1<>::myint myint1;
+
+    S2::S2a<>::myint myint2;
+
+    S7<S2> s7;
+}
+

Added: vendor/elsa/current/elsa/in/k0113.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0113.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0113.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// calling templatized operator-overloaded function
+
+// In state 161, I expected one of these tokens:
+//   <name>,
+// b.ii:15:22: Parse error (state 161) at operator
+
+// from sigc++-2.0/sigc++/functors/slot.h
+
+//ERR-MATCH: fc042c37-50e2-4596-8460-c095e7ac892b
+
+template <class T>
+struct S1 {
+    template <class T2>
+    void operator()() {}
+
+    template <class T2>
+    void foo() {}
+};
+
+template <class T>
+struct S2 {
+    void foo() {
+        S1<T> *s1;
+        s1->template operator()<int> ();
+    }
+};
+
+int main()
+{
+    S1<int> s1;
+    s1.foo<int>();
+    s1.operator()<int>();
+
+    S2<int> s2;
+    s2.foo();
+}

Added: vendor/elsa/current/elsa/in/k0114.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0114.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0114.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// template parameterized on function (not function pointer)
+
+// ERR-MATCH: 6ccc991e-bd8a-47d8-8f5c-e75d7065a29d
+
+// Assertion failed: origSrc && "6ccc991e-bd8a-47d8-8f5c-e75d7065a29d", file
+// template.cc line 3778 a.ii.16
+
+// first seen in gwenview/gvimageutils.cpp.50e0d6a9383e1f3a615b9b5350d2597b.ii
+
+int foo( int x1, int x2 ) {
+}
+
+typedef int (Function_t)( int, int );
+
+template< Function_t function >
+int bar() {
+}
+
+int main()
+{
+  bar< foo > ();
+}

Added: vendor/elsa/current/elsa/in/k0115.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0115.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0115.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// using own member function
+
+// i/xalan_1.8-4/ElemApplyTemplates.cpp.8c892e8b0da809df12dd69739b9228a7.ii:28377:2:
+// error: duplicate member declaration of `transformChild' in class
+// xalanc_1_8::ElemApplyTemplates; previous at
+// i/xalan_1.8-4/ElemApplyTemplates.cpp.8c892e8b0da809df12dd69739b9228a7.ii:28370:2
+
+// ERR-MATCH: duplicate member declaration of `.*?' in class
+
+struct S {
+  void foo( );
+  using S::foo;
+};

Added: vendor/elsa/current/elsa/in/k0116.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0116.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0116.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// template parameter default instantiating template class
+
+// Assertion failed: !parameterizedEntity && "4d621e9b-fdc9-4646-918c-76bd950d191c" , file cc_scope.cc line 1217
+
+// scim_1.0.2-3/scim_slot.cpp.313b4664519cb00a19e4d377049f0f0a.ii
+
+// ERR-MATCH: 4d621e9b-fdc9-4646-918c-76bd950d191c
+
+template <class T0>
+struct S1 {
+};
+
+template <class T1 = class S1<int> >
+struct S2 {
+};
+
+int main()
+{
+  S2<> s2;
+}

Added: vendor/elsa/current/elsa/in/k0117.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0117.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0117.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// class templatized on int, copy constructor
+
+// pstoedit_3.33-15/pstoedit.cpp.438c7efbc0cced5ef0b70ed3c5068ee8.ii:32656:40:
+// error: more than one ambiguous alternative succeeds (from template; would
+// be suppressed in permissive mode)
+
+// ERR-MATCH: more than one ambiguous alternative succeeds
+
+template <int e>
+struct S {
+  // S<e>(S<e> const &) {}
+
+  void foo() {
+    new S<e>(*this);
+  }
+};

Added: vendor/elsa/current/elsa/in/k0118.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0118.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0118.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+typedef struct {
+  int a;
+} s0;
+
+typedef struct {
+  int a;
+} *s1;
+
+typedef struct {
+  int a;
+} volatile * const & s2;
+
+int foo(s0) {}

Added: vendor/elsa/current/elsa/in/k0119.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0119.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0119.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// Umesh says this dies during oinkx serialization on a 64-bit machine,
+// although I (Karl) can't reproduce it (on IA-64).
+
+typedef unsigned long long uint64;
+uint64 htonll(uint64 x) {
+   return (__extension__ ({
+       union {
+           unsigned long int __l[2];
+       } __w;
+   }
+  ));
+}

Added: vendor/elsa/current/elsa/in/k0120.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0120.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0120.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// confusion between function template decl and return type
+
+// reported by Evan Driscoll <driscoll at cs.wisc.edu>
+
+// a.cc:6:1: error: prior declaration of class C at a.cc:1:1 was not
+// templatized, but this one is, with parameters template <class T>
+
+class C
+{
+};
+
+// parse error goes away if "class" removed
+template <class T>
+class C foo(T t)
+{
+    C c;
+    return c;
+}
+
+int main()
+{
+    C c = foo<int>(5);
+}

Added: vendor/elsa/current/elsa/in/k0121.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0121.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0121.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// For testing nested template delimiter pretty printing.  From Evan Driscoll.
+
+// http://www.cubewano.org/oink/ticket/123
+
+template <class T>
+class C {};
+
+template <class T1, class T2 = C<T1> >
+class basic_string;

Added: vendor/elsa/current/elsa/in/k0122.cc
===================================================================
--- vendor/elsa/current/elsa/in/k0122.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/k0122.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// test file for pretty printing (can't just print fully-qualified name of the
+// second E1)
+
+namespace {
+  enum E1 { };
+
+  struct S1 {
+    enum E1 { };
+
+    S1(E1) {}
+  };
+}

Added: vendor/elsa/current/elsa/in/kandr/t0001.c
===================================================================
--- vendor/elsa/current/elsa/in/kandr/t0001.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/kandr/t0001.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0001.c
+// K&R function definition
+
+int foo(a,b,c)
+  int a;
+  float b;
+  int *c;
+{
+  return a + (int)b + *c;
+}

Added: vendor/elsa/current/elsa/in/kandr/t0002.c
===================================================================
--- vendor/elsa/current/elsa/in/kandr/t0002.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/kandr/t0002.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0002.c
+// implicit int
+
+a;
+
+int foo(register a)
+{  
+  return a;
+}
+

Added: vendor/elsa/current/elsa/in/kandr/t0003.c
===================================================================
--- vendor/elsa/current/elsa/in/kandr/t0003.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/kandr/t0003.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0003.c
+// static and implicit int
+
+static /*implicit-int*/ tinfoclose()
+{
+    return(0);
+}

Added: vendor/elsa/current/elsa/in/kandr/t0004.c
===================================================================
--- vendor/elsa/current/elsa/in/kandr/t0004.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/kandr/t0004.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0004.c
+// "static" with implicit int in a definition that has
+// a K&R parameter list
+
+static /*implicit-int*/ tinfomove(row, col)
+  register int row, col;
+{
+    return(0);
+}

Added: vendor/elsa/current/elsa/in/msvc/m0001.cc
===================================================================
--- vendor/elsa/current/elsa/in/msvc/m0001.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/msvc/m0001.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// m0001.cc
+// report from Kevin Millikin about MSVC bug
+
+class Integer {
+public:
+  // this is fine
+  int operator<(int);
+  
+  // this is illegal, but allowed by MSVC
+  operator==(const Integer&) const { return 0; }
+};

Added: vendor/elsa/current/elsa/in/sg0001.cc
===================================================================
--- vendor/elsa/current/elsa/in/sg0001.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/sg0001.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+class A {};
+int main() {
+  const A *val = 0;
+  val->~A ();
+}

Added: vendor/elsa/current/elsa/in/std/12.3.2c.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/12.3.2c.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/12.3.2c.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// 12.3.2c.cc
+// potential ambiguity between conversion-type-id and expressions
+
+struct A {
+  operator int * ();
+};
+
+void f()
+{
+  A ac;
+  int i;
+  
+  // example is this line:
+  //ERROR(1): &ac.operator int*i;    // parse error
+  
+}

Added: vendor/elsa/current/elsa/in/std/12.6.2.2a.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/12.6.2.2a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/12.6.2.2a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// 12.6.2 para 2, first example
+
+struct A { A(); };
+typedef A global_A;
+struct B {};
+struct C: public A, public B { C(); };
+C::C(): global_A() {}    // mem-initializer for base A

Added: vendor/elsa/current/elsa/in/std/12.6.2.2b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/12.6.2.2b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/12.6.2.2b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// 12.6.2 para 2, second example
+
+struct A { A(); };
+struct B: public virtual A {};
+struct C: public A, public B { C(); };
+//ERROR1: C::C(): A() {}           // ill-formed: which A?
+

Added: vendor/elsa/current/elsa/in/std/13.1a.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.1a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.1a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// 13.1a.cc
+
+class X {
+    static void f();
+    //ERROR(1): void f();                      // ill-formed
+    //ERROR(2): void f() const;                // ill-formed
+    //ERROR(3): void f() const volatile;       // ill-formed
+    void g();                   
+    void g() const;                // OK: no static g
+    void g() const volatile;       // OK: no static g
+};
+

Added: vendor/elsa/current/elsa/in/std/13.1b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.1b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.1b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// 13.1b.cc
+
+typedef int Int;
+
+void f(int i);
+void f(Int i);                    // OK: declaration of f(int)
+void f(int i) { /* ... */ }       
+//ERROR(1): void f(Int i) { /* ... */ }    // error: redefinition of f(int)
+

Added: vendor/elsa/current/elsa/in/std/13.1c.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.1c.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.1c.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// 13.1c.cc
+
+enum E { a };
+
+void f(int i) { /* ... */ }
+void f(E i)   { /* ... */ }

Added: vendor/elsa/current/elsa/in/std/13.1d.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.1d.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.1d.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// 13.1d.cc
+
+int f(char*);
+int f(char[]);            // same as f(char*)
+int f(char[7]);           // same as f(char*)
+int f(char[9]);           // same as f(char*)
+
+int g(char(*)[10]);       
+int g(char[5][10]);       // same as g(char(*)[10]);
+int g(char[7][10]);       // same as g(char(*)[10]);
+int g(char(*)[20]);       // different from as g(char(*)[10]);

Added: vendor/elsa/current/elsa/in/std/13.1e.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.1e.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.1e.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// 13.1e.cc
+
+void h(int());
+void h(int (*)());           // redeclaration of h(int())
+void h(int x()) { }          // definition of h(int())
+//ERROR(1): void h(int (*x)()) { }       // ill-formed: redefinition of h(int())

Added: vendor/elsa/current/elsa/in/std/13.1f.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.1f.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.1f.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// 13.1f.cc
+
+typedef const int cInt;
+
+int f (int);
+int f (const int);             // redeclaration of f(int)
+int f (int) { /*...*/ }        // definition of f(int)
+//ERROR(1): int f (cInt) { /*...*/ }       // error: redefinition of f(int)

Added: vendor/elsa/current/elsa/in/std/13.1g.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.1g.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.1g.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// 13.1g.cc
+
+void f (int i, int j);
+void f (int i, int j = 99);          // OK: redeclaration of f(int, int)
+void f (int i = 88, int j);          // OK: redeclaration of f(int, int)
+void f ();                           // OK: overloaded declaration of f
+
+void prog ()
+{
+    f (1, 2);                        // OK: call f(int, int)
+
+    // TODO: I fail to properly handle the next two calls because
+    // I don't properly cascade the default arguments.  I am not
+    // sure now I want to implement it, because I could either
+    // go back and modify the params which originally didn't
+    // have default arguments, or I could make a new type that
+    // has the union of all the defaults seen so far ...
+    //f (1);                           // OK: call f(int, int)
+    //f ();                            // Error: f(int, int) or f()?
+}

Added: vendor/elsa/current/elsa/in/std/13.2a.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.2a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.2a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// 13.2a.cc
+
+class B {
+public:
+    int f(int);
+};
+
+class D : public B {
+public:
+    int f(char*);
+};
+
+// Here D::f(char*) hides B::f(int) rather than overloading it.
+
+void h(D *pd)
+{
+    //ERROR(1): pd->f(1);               // error:
+                                        // D::f(char*) hides B::f(int)
+    pd->B::f(1);                        // OK
+    pd->f("Ben");                       // OK, calls D::f
+}
+
+

Added: vendor/elsa/current/elsa/in/std/13.3.1.1.2.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.3.1.1.2.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.3.1.1.2.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// 13.3.1.1.2.cc
+
+int f1(int);
+int f2(float);
+typedef int (*fp1)(int);
+typedef int (*fp2)(float);
+struct A {
+    operator fp1() { return f1; }
+    operator fp2() { return f2; }
+} a;
+
+// TODO: this does not work because I don't try implicit conversions
+// in this context
+//int i = a(1);                        // Calls f1 via pointer returned from
+                                     // conversion function

Added: vendor/elsa/current/elsa/in/std/13.3.3.1.4.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.3.3.1.4.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.3.3.1.4.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// 13.3.3.1.4.cc
+
+struct A {};
+struct B : public A {} b;
+int f(A&);                         // line 5
+int f(B&);                         // line 6
+
+int i = __testOverload(f(b), 6);   // Calls f(B&), an exact match, rather than
+                                   // f(A&), a conversion

Added: vendor/elsa/current/elsa/in/std/13.3.3.2a.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.3.3.2a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.3.3.2a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// 13.3.3.2a.cc
+
+int f(const int *);                       // line 3
+int f(int *);                             // line 4
+int i;
+int j = __testOverload(f(&i), 4);         // Calls f(int *)

Added: vendor/elsa/current/elsa/in/std/13.3.3.2b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.3.3.2b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.3.3.2b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// 13.3.3.2b.cc
+
+int f(const int &);                // line 3
+int f(int &);                      // line 4
+int g(const int &);                // line 5
+int g(int);                        // line 6
+
+int i;
+int j = __testOverload(f(i), 4);   // Calls f(int &)
+//ERROR(1): int k = g(i);                      // ambiguous
+
+class X {
+public:
+    void f() const;                // line 14
+    void f();                      // line 15
+};
+void g(const X& a, X b)
+{
+    // TODO: these aren't checked because I'm not currently
+    // doing overload resolution on member function calls
+    a.f();                         // Calls X::f() const
+    b.f();                         // Calls X::f()
+}

Added: vendor/elsa/current/elsa/in/std/13.3.3.2d.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.3.3.2d.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.3.3.2d.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// 13.3.3.2d.cc
+
+struct A {};
+struct B : public A {};
+struct C : public B {};
+C *pc;
+int f(A *);                         // line 7
+int f(B *);                         // line 8
+int i = __testOverload(f(pc), 8);   // Calls f(B*)

Added: vendor/elsa/current/elsa/in/std/13.3.3b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.3.3b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.3.3b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// 13.3.3b.cc
+
+void Fcn(const int*,  short);        // line 3
+void Fcn(int*, int);                 // line 4
+
+int i;
+short s = 0;
+
+void f() {                           // line 9
+  // turn on overload resolution
+  __testOverload(f(), 9);
+
+  //ERROR(1): Fcn(&i, s);            // is ambiguous because
+                                     // &i->int* is better than &i->const int*
+                                     // but s->short is also better than s->int
+
+  __testOverload(Fcn(&i, 1L), 4);    // calls Fcn(int*, int), because
+                                     // &i->int* is better than &i->const int*
+                                     // and 1L->short and 1L->int are indistinguishable
+
+  __testOverload(Fcn(&i,'c'), 4);    // calls Fcn(int*, int), because
+                                     // &i->int* is better than &i->const int*
+                                     // and c->int is better than c->short
+}

Added: vendor/elsa/current/elsa/in/std/13.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/13.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/13.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// 13.cc
+
+double abs(double);        // line 3
+int abs(int);              // line 4
+
+void f()
+{
+  __testOverload(abs(1), 4);       // calls abs(int);
+  __testOverload(abs(1.0), 3);     // calls abs(double);
+}
+

Added: vendor/elsa/current/elsa/in/std/3.4.3a.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/3.4.3a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/3.4.3a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// section 3.4.3 example #1
+
+class A {
+public: 
+  static int n; 
+}; 
+int main() 
+{ 
+  // the example includes this line
+  //   int A;
+  // but my current implementation can't handle it..
+
+  A::n = 42;          // OK    
+  //ERROR1: A b;                // ill-formed: A does not name a type
+}
+

Added: vendor/elsa/current/elsa/in/std/3.4.5.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/3.4.5.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/3.4.5.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// 3.4.5.cc
+// example showing qualified field access
+
+struct A {
+  int a;
+};
+struct B : virtual A {};
+struct C : B {};
+struct D : B {};
+struct E : public C, public D {};
+struct F : public A{};
+
+void f()
+{
+  E e;
+  e.B::a = 0;        // OK, only one A::a in E
+
+  F f;
+  f.A::a = 1;        // OK, A::a is a member of F
+}

Added: vendor/elsa/current/elsa/in/std/7.1.3b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.1.3b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.1.3b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// duplicate typedefs
+
+typedef struct s { /* ... */ } s;
+typedef int I;
+typedef int I;
+typedef I I;
+
+// this isn't part of the official example, but it lets
+// me verify that "I" maps to "int"
+I x;
+

Added: vendor/elsa/current/elsa/in/std/7.3.1.2b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.1.2b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.1.2b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// 7.3.1.2b.cc
+
+namespace Q {
+  namespace V {
+    void f();
+  }
+  void V::f() { /*...*/ }                 // OK
+  //ERROR(1): void V::g() { /*...*/ }     // error: g() is not yet a member of V
+  namespace V {
+    void g();
+  }
+}
+
+namespace R {
+  //ERROR(2): void Q::V::g() { /*...*/ }  // error: R doesn't enclose Q
+}

Added: vendor/elsa/current/elsa/in/std/7.3.1.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.1.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.1.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// 7.3.1.cc
+
+asm("collectLookupResults i=6 i=9");
+
+namespace Outer {
+  int i;                  // line 6
+  namespace Inner {
+    void f() { i++; }     // Outer::i
+    int i;                // line 9
+    void g() { i++; }     // Inner::i
+  }
+}
+

Added: vendor/elsa/current/elsa/in/std/7.3.2.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.2.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.2.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// 7.3.2.cc
+
+namespace Company_with_very_long_name { /*...*/ }
+namespace CWVLN = Company_with_very_long_name;
+namespace CWVLN = Company_with_very_long_name;      // OK: duplicate
+namespace CWVLN = CWVLN;

Added: vendor/elsa/current/elsa/in/std/7.3.3a.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// 7.3.3a.cc
+
+struct B {
+  void f(char);
+  void g(char);
+  enum E { e };
+  union { int x; };
+};
+
+struct D : B {
+  using B::f;
+  void f(int) { f('c'); }        // calls B::f(char)
+  void g(int) { g('c'); }        // recursively calls D::g(int)
+};

Added: vendor/elsa/current/elsa/in/std/7.3.3b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// 7.3.3b.cc
+
+// implied prerequisite; actual example doesn't include B
+struct B {
+  void f(char);
+  void g(char);
+  enum E { e };
+  union { int x; };
+};
+
+class C {
+  int g();
+};
+
+class D2 : public B {
+  using B::f;              // OK: B is a base of D2
+  using B::e;              // OK: e is an enumerator of base B
+  using B::x;              // OK: x is a union member of base B
+  //ERROR(1): using C::g;              // error: C isn't a base of D2
+};

Added: vendor/elsa/current/elsa/in/std/7.3.3c.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3c.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3c.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// 7.3.3c.cc
+
+// this one does not work since member templates are not
+// implemented at all--they don't even parse!
+
+//  class A {
+//  public:
+//    template <class T> void f(T);
+//    template <class T> struct X { };
+//  };
+
+//  class B : public A {
+//  public:
+//    using A::f<double>;     // ill-formed
+//    using A::X<int>;        // ill-formed
+//  };

Added: vendor/elsa/current/elsa/in/std/7.3.3d.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3d.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3d.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// 7.3.3d.cc
+
+struct X {
+  int i;
+  static int s;
+};
+
+void f()
+{
+  //ERROR(1): using X::i;       // error: X::i is a class member
+                                // and this is not a member declaration.
+  //ERROR(2): using X::s;       // error: X::s is a class member
+                                // and this is not a member declaration.
+}

Added: vendor/elsa/current/elsa/in/std/7.3.3e.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3e.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3e.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// 7.3.3e.cc
+
+asm("collectLookupResults f=5 g=8");
+
+void f();            // line 5
+
+namespace A {
+  void g();          // line 8
+}
+
+namespace X {
+  using ::f;         // global f
+  using A::g;        // A's g
+}
+
+void h()
+{
+  X::f();            // calls ::f
+  X::g();            // calls A::g
+}

Added: vendor/elsa/current/elsa/in/std/7.3.3f.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3f.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3f.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// 7.3.3f.cc
+
+namespace A {
+  int i;
+}
+
+namespace A1 {
+  using A::i;
+  using A::i;                     // OK: double declaration
+}
+
+void f()
+{
+  using A::i;
+  //ERROR(1): using A::i;         // error: double declaration
+}
+
+class B {
+public:
+  int i;
+};
+
+class X : public B {
+  using B::i;
+  //ERROR(2): using B::i;         // error: double member declaration
+};

Added: vendor/elsa/current/elsa/in/std/7.3.3g.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3g.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3g.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// 7.3.3g.cc
+
+// turn on overloading
+int dummy();             // line 4
+void ddummy() { __testOverload(dummy(), 4); }
+
+asm("collectLookupResults f=10 f=16");
+
+namespace A {
+  void f(int);          // line 10
+}
+
+using A::f;             // f is a synonym for A::f;
+                        // that is, for A::f(int).
+namespace A {
+  void f(char);         // line 16
+}
+
+void foo()
+{
+  f('a');               // calls f(int),
+}                       // even though f(char) exists.
+
+void bar()
+{
+  using A::f;           // f is a synonym for A::f;
+                        // that is, for A::f(int) and A::f(char).
+  f('a');               // calls f(char)
+}

Added: vendor/elsa/current/elsa/in/std/7.3.3h.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3h.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3h.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// 7.3.3h.cc
+
+// turn on overloading
+int dummy();             // line 4
+void ddummy() { __testOverload(dummy(), 4); }
+
+asm("collectLookupResults f=18 g=19 x=10");
+
+namespace A {
+  int x;                        // line 10
+}
+
+namespace B {
+  int i;
+  struct g { };
+  struct x { };
+  void f(int);
+  void f(double);               // line 18
+  void g(char);                 // OK: hides struct g   (line 19)
+}
+
+void func()
+{
+  int i;
+  //ERROR(1): using B::i;       // error: i declared twice
+  void f(char);
+  using B::f;                   // OK: each f is a function
+  f(3.5);                       // calls B::f(double)
+  using B::g;
+  g('a');                       // calls B::g(char)
+  struct g g1;                  // g1 has class type B::g
+  using B::x;
+  using A::x;                   // OK: hides struct B::x
+  x = 99;                       // assigns to A::x
+  struct x x1;                  // x1 has class type B::x
+}
+

Added: vendor/elsa/current/elsa/in/std/7.3.3i.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3i.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3i.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// 7.3.3i.cc
+
+// turn on overloading
+int dummy();             // line 4
+void ddummy() { __testOverload(dummy(), 4); }
+
+asm("collectLookupResults f=16");
+
+namespace B {
+  void f(int);
+  void f(double);
+}
+namespace C {
+  void f(int);
+  void f(double);
+  void f(char);               // line 16
+}
+
+void h()
+{
+  using B::f;                 // B::f(int) and B::f(double)
+  using C::f;                 // C::f(int), C::f(double), and C::f(char)
+  f('h');                     // calls C::f(char)
+  //ERROR(1): f(1);           // error: ambiguous: B::f(int) or C::f(int)?
+  //ERROR(2): void f(int);    // error:
+                              // f(int) conflicts with C::f(int) and B::f(int)
+}

Added: vendor/elsa/current/elsa/in/std/7.3.3j.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3j.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3j.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// 7.3.3j.cc
+
+// turn on overloading
+int dummy();             // line 4
+void ddummy() { __testOverload(dummy(), 4); }
+
+asm("collectLookupResults f=18 p=27 f=11 p=27 g=12 p=27 g=21 p=27");
+
+struct B {
+  virtual void f(int);
+  virtual void f(char);  // 11:16
+  void g(int);           // 12:8
+  void h(int);
+};
+
+struct D : B {
+  using B::f;
+  void f(int);           // OK: D::f(int) overrides B::f(int); (18:8)
+
+  using B::g;
+  void g(char);          // OK (21:8)
+
+  using B::h;
+  void h(int);           // OK: D::h(int) hides B::h(int)
+};
+
+void k(D* p /*27:11*/)
+{
+  p->f(1);               // calls D::f(int)
+  p->f('a');             // calls B::f(char)
+  p->g(1);               // calls B::g(int)
+  p->g('a');             // calls D::g(char)
+}

Added: vendor/elsa/current/elsa/in/std/7.3.3k.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.3k.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.3k.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// 7.3.3k.cc
+
+// I'm supposed to find the call below ambiguous, but I do not,
+// and it's not at all clear how to modify things so I do.
+//
+// 9/23/04: Elsa now rejects this code, but with an error that
+// may or may not be "right"...
+
+struct A { int x(); };
+struct B : A { };
+struct C : A {
+  using A::x;
+  int x(int);
+};
+
+struct D : B, C {
+  using C::x;
+  int x(double);
+};
+int f(D* d) {
+  //ERROR(1): return d->x();            // ambiguous: B::x or C::x
+}

Added: vendor/elsa/current/elsa/in/std/7.3.4a.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.4a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.4a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// 7.3.4a.cc
+
+asm("collectLookupResults i=9 i=6");
+
+namespace A {
+  int i;                      // line 6
+  namespace B {
+    namespace C {
+      int i;                  // line 9
+    }
+    using namespace A::B::C;
+    void f1() {
+      i = 5;                  // OK, C::i visible in B and hides A::i
+    }
+  }
+  namespace D {
+    using namespace B;
+    using namespace C;
+    void f2() {
+      //ERROR(1): i = 5;      // ambiguous, B::C::i or A::i?
+    }
+  }
+  void f3() {
+    i = 5;                    // uses A::i
+  }
+}
+void f4() {
+  //ERROR(2): i = 5;          // ill-formed; neither i is visible
+}
+

Added: vendor/elsa/current/elsa/in/std/7.3.4b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.4b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.4b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// 7.3.4b.cc
+
+namespace M {
+  int i;
+}
+
+namespace N {
+  int i;
+  using namespace M;
+}
+
+void f()
+{
+  using namespace N;
+  //ERROR(1):   i = 7;           // error: both M::i and N::i are visible
+}

Added: vendor/elsa/current/elsa/in/std/7.3.4c.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.4c.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.4c.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// 7.3.4c.cc
+
+asm("collectLookupResults i=9 i=9 j=14");
+
+namespace A {
+  int i;                         // line 6
+}
+namespace B {
+  int i;                         // line 9
+  int j;                         // line 10
+  namespace C {
+    namespace D {
+      using namespace A;
+      int j;                     // line 14
+      int k;                     // line 15
+      int a = i;                 // B::i hides A::i
+    }
+    using namespace D;
+    int k = 89;                  // no problem yet              line 19
+    //ERROR(1): int l = k;       // ambiguous: C::k or D::k     line 20
+    int m = i;                   // B::i hides A::i             line 21
+    int n = j;                   // D::j hides B::j             line 22
+  }
+}

Added: vendor/elsa/current/elsa/in/std/7.3.4d.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.4d.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.4d.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// 7.3.4d.cc
+
+namespace A {
+  class X { };
+  extern "C"   int g();
+  extern "C++" int h();
+}
+namespace B {
+  void X(int);
+  extern "C"   int g();
+  extern "C++" int h();
+}
+using namespace A;
+using namespace B;
+
+void f() {
+  //ERROR(1): X(1);    // error: name X found in two namespaces
+  g();                 // okay: name g refers to the same entity
+  //ERROR(2): h();     // error: name h found in two namespaces
+}

Added: vendor/elsa/current/elsa/in/std/7.3.4e.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/7.3.4e.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/7.3.4e.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// 7.3.4e.cc
+
+namespace D {
+  int d1;
+  void f(char);
+}
+using namespace D;
+
+int d1;                  // OK: no conflict with D::d1
+
+namespace E {
+  int e;
+  void f(int);
+}
+
+namespace D {            // namespace extension
+  int d2;
+  using namespace E;
+  void f(int);
+}
+
+void f()
+{
+  //ERROR(1): d1++;      // error: ambiguous ::d1 or D::d1?
+  ::d1++;                // OK
+  D::d1++;               // OK
+  d2++;                  // OK: D::d2
+  e++;                   // OK: E::e
+  
+  // I don't get these right because my lookup interfaces are
+  // not capable of returning sets of declarations
+  //f(1);                  // error: ambiguous: D::f(int) or E::f(int)?
+  //f('a');                // OK: D::f(char)
+}

Added: vendor/elsa/current/elsa/in/std/8.2.1.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/8.2.1.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/8.2.1.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// 8.2.cc
+
+struct S {
+  S(int);
+};
+
+void foo(double a)
+{
+  S w(int(a));   // function declaration
+  S x(int());    // function declaration
+  S y((int)a);   // object declaration
+  S z = int(a);  // object declaration
+}

Added: vendor/elsa/current/elsa/in/std/8.2.7a.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/8.2.7a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/8.2.7a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// 8.2.7a.cc
+
+class C {};
+void f(int (C)) {}           // void f(int (*fp)(C c)) {}
+                             // not: void f(int C);
+
+int g(C);
+
+void foo() {
+  //ERROR(1): f(1);          // error: cannot convert 1 to function pointer
+  f(g);                      // OK
+}
+

Added: vendor/elsa/current/elsa/in/std/8.2.7b.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/8.2.7b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/8.2.7b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// 8.2.7b.cc
+
+class C {};
+void h(int *(C[10]));

Added: vendor/elsa/current/elsa/in/std/8.3.3.2.cc
===================================================================
--- vendor/elsa/current/elsa/in/std/8.3.3.2.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/std/8.3.3.2.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// 8.3.3.2.cc
+// pointers to members
+
+class X {
+public:
+  void f(int);
+  int a;
+};
+class Y;
+
+int X::* pmi = &X::a;
+void (X::* pmf)(int) = &X::f;
+double X::* pmd;
+char Y::* pmc;
+
+void foo()
+{
+  X obj;
+
+  obj.*pmi = 7;        // assign 7 to an integer
+                       // member of obj
+  (obj.*pmf)(7);       // call a function member of obj
+                       // with the argument 7
+}

Added: vendor/elsa/current/elsa/in/t0001.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0001.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0001.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,3 @@
+// very simple
+
+int x;

Added: vendor/elsa/current/elsa/in/t0002.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0002.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0002.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+
+typedef int x;
+
+x y;
+

Added: vendor/elsa/current/elsa/in/t0003.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0003.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0003.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+
+typedef int x;
+
+int main()
+{
+  x (y);    // this is a declaration according to cppstd sec. 6.8
+  
+  return y;
+}
+
+

Added: vendor/elsa/current/elsa/in/t0004.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0004.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0004.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// cc.in4
+// testcase for some sharing
+
+typedef int x;
+int z;
+typedef int t;
+
+int main()
+{
+  x *y = (t*)z;
+  
+  // left side: multiplication or declaration
+  // right side: unambiguous cast
+  // goal: share the "cast" node on the RHS, not merely the typeid and expr
+}

Added: vendor/elsa/current/elsa/in/t0005.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0005.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0005.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// cc.in5
+// some tricky ambiguous syntax examples
+
+enum MyEnum { e8, e4=4, e5 };
+
+int f(int, int);
+int a, b, c, y, p;
+void x(int);
+typedef int q;
+
+int main()
+{
+  +f(a,2);                // unambiguous call
+
+  f( (a)&(b), c );        // ambiguous call
+
+  {
+    x(y);
+    3;
+  }
+
+  (q)(p);
+  
+  3+4*5;
+}

Added: vendor/elsa/current/elsa/in/t0006.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0006.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0006.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,60 @@
+// cc.in6
+// one example of each statement (no ambiguity)
+
+int something, a, whatever, something_else, x;
+typedef int X;
+
+int main()
+{
+  3+4;
+mylabel:
+  switch (something) {
+    case 5:
+      { 6; 7; }
+      break;
+
+    default:
+      ;
+  }
+
+  if (a) 8; else 9;
+  if (a) 10;
+
+  // precedence should make this unambiguous too
+  {
+    if (a) 11;
+    if (a) 12; else 13;
+  }
+
+  while (whatever) 14;
+
+  // variant which declares a variable in the condition
+  while (bool cond = whatever) 15;
+
+  do 16; while (something_else);
+
+  // no decl in the initializer
+  int i;
+  for (i=0; i<4; i++) 17;
+
+  // decl in init
+  for (int j=9; j>0; j--) 18;
+
+  // both variants of 'return'
+  if (a) return; else return x;
+
+  goto mylabel;
+
+  try {
+    19;
+  }
+  catch (X &x) {
+    throw 20;
+  }
+  catch (...) {
+    21;
+    throw;
+  }
+
+  4;   // dummy for 'try' CFG targets
+}

Added: vendor/elsa/current/elsa/in/t0007.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0007.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0007.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// cc.in7
+// problem with "x;" .. ?
+
+// this is actually a valid ambiguity.. in syntax like
+//   class Foo {
+//     ...
+//   };
+// the declarator is missing, and it thinks of "x;" the 
+// same way potentially..
+
+int const c;
+
+// With the 'typedef', the code is illegal; gcc says
+// "declaration does not declare anything".  It's messing
+// up the idempotency test so I'm just going to fix it.
+/*typedef*/ int x;
+
+int main()
+{
+  x;        // is this illegal?
+}
+
+int strcmp(char const *s1, char const *s2);

Added: vendor/elsa/current/elsa/in/t0008.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0008.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0008.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// cc.in8
+// really simple disambiguation example
+
+int main()
+{
+  int a;
+  int b;
+  
+  (a) & (b);
+}

Added: vendor/elsa/current/elsa/in/t0009.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0009.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0009.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// cc.in9
+// stuff with structs, etc.
+
+struct Foo {
+  int x;
+  int y;
+};
+
+int main()
+{
+  Foo f;
+  return f.x;
+}

Added: vendor/elsa/current/elsa/in/t0010.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0010.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0010.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// expressions
+
+//typedef struct page { int x; } page;
+
+typedef struct pte_t { int y; } pte_t;
+
+// this is not ambiguous because "()" is not
+// a valid ctor-initializer (there must be arguments there)
+int get_pte_fast();
+
+int foo ( )
+{
+  pte_t * page = (pte_t *) get_pte_fast();
+}

Added: vendor/elsa/current/elsa/in/t0011.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0011.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0011.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// cc.in11
+// experimenting with one definition rule
+
+
+extern int x;
+int x;
+
+int y;
+extern int y;
+
+extern int x;
+//ERROR(1): int x;
+
+int foo();
+int foo();
+
+int foo()
+{
+  return 4;
+}
+
+
+int foo();
+
+
+//ERROR(2): int foo() { return 4; }
+
+
+int foo2(int q);
+
+// definition uses different param name than prototype
+int foo2(int z)
+{
+  return z;
+}

Added: vendor/elsa/current/elsa/in/t0012.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0012.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0012.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// cc.in12
+// experiments with qualifiers
+
+class Foo {
+public:
+  static int x;
+  int y;
+  
+  int func();
+  int func2();
+  int func3() const;
+};
+
+// qualifiers on a declarator, so it refers to
+// something which has already been declared
+int Foo::x = 5;
+
+// violation of ODR
+//ERROR(1): int Foo::x = 5;
+
+// can't define nonstatic data members
+//ERROR(2): int Foo::y = 7;
+
+
+int main()
+{
+  // qualifiers on an E_variable
+  return Foo::x;
+}
+
+
+int Foo::func()
+{
+  return x;    // requires that scope includes Foo's variables
+}
+
+//ERROR(3): int Foo::func() {  return 18; }
+
+//ERROR(4): void Foo::func2() {}
+
+
+// I think this doesn't work during printing..
+int foo(Foo * const ths);
+
+// what about this?
+Foo * const arf;

Added: vendor/elsa/current/elsa/in/t0013.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0013.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0013.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// cc.in13
+// inline member functions
+
+class Foo {
+public:
+  int func()
+  {
+    //ERROR(1): return y;
+    return x;
+  }
+
+  //ERROR(3): int func();
+  
+  //ERROR(4): int func() { return 5; }
+
+  int bar();
+  //ERROR(2): int bar();
+
+  int x;
+};
+
+int main()
+{
+  Foo x;
+  x.func();
+}

Added: vendor/elsa/current/elsa/in/t0014.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0014.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0014.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// cc.in14
+// a few of the obscure expression kinds
+
+// this would normally come from the <typeinfo> header
+namespace std {
+  class type_info {
+  public:
+    char const *name() const;
+  };
+}
+
+typedef char y;
+
+int main()
+{
+  int x, *p, *pp;
+
+  // E_constructor
+  x = int(6);
+
+  // E_new
+  p = new int;
+  
+  // E_new of an array with non-const size
+  p = new int[x];
+
+  // E_new of an array of an array; this allocates
+  // an array of objects, where each object has type
+  // "int[5]", and 'x' objects are allocated
+  pp = new int[x][5];
+
+  // E_delete
+  delete p;
+
+  // E_keywordCast
+  x = const_cast<int>(x);
+  x = dynamic_cast<int>(x);
+  x = static_cast<int>(x);
+  x = reinterpret_cast<int>(x);
+
+  // E_typeidExpr
+  typeid(x);
+  
+  // E_typeidType
+  typeid(y);
+}

Added: vendor/elsa/current/elsa/in/t0014a.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0014a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0014a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+int main()
+{
+  int x, *p;
+  x = int(6);
+  p = new int[x];
+}

Added: vendor/elsa/current/elsa/in/t0015.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0015.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0015.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,43 @@
+// cc.in15
+// ctors and dtors
+
+class Foo {
+public:
+  // member with 'const' qualifier
+  //int f() const;
+
+  // constructor
+  Foo();
+
+  // constructor with arguments
+  //Foo(int x);
+
+  // and inline definition
+  ///*explicit*/ Foo(int x) { x+5; }
+
+  // destructor
+  ~Foo();
+
+};
+
+
+// out-of-line ctor
+Foo::Foo()
+{
+  5;
+}
+
+
+// out-of-line dtor
+Foo::~Foo()
+{
+  8;
+}
+
+
+void f()
+{
+  Foo f;
+  
+  //ERROR(1): Foo g(3);  // error
+}

Added: vendor/elsa/current/elsa/in/t0016.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0016.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0016.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// cc.in16
+// overloading
+
+int f(int);
+
+int f(double);
+
+
+class Foo {
+public:
+  int g(int);
+  int g(double);
+  //ERROR(1): int g(int);
+  //ERROR(2): char g(int);
+};

Added: vendor/elsa/current/elsa/in/t0017.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0017.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0017.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// cc.in17
+// some constructors with member-init and try-block
+
+
+class Foo {
+public:
+  int x, y;
+  
+  Foo() : x(3), y(4) {}
+  Foo(int z);
+  Foo(double d);
+};
+
+Foo::Foo(int z) : x( (z) & (z) ), y(4) {}
+
+//ERROR(1): Foo::Foo(Foo *f) {}
+
+Foo::Foo(double d)
+try
+{
+  x;
+}
+catch (int &x)
+{
+  6;
+  throw;
+}

Added: vendor/elsa/current/elsa/in/t0018.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0018.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0018.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// cc.in18
+// class forward decls
+
+class Foo;
+
+int main()
+{
+  Foo *x;
+  
+  //ERROR(1): x->y;   // incomplete type
+
+}
+
+void f(Foo *) {}
+
+class Foo {
+public:
+  int x;
+};
+
+// this is ok because it's an overloading
+void f(Foo *, int) {}
+
+// since Foo from above is same Foo as here, we'll
+// get an error about duplicate definitions
+//ERROR(2): void f(Foo *) {}     // duplicate definition
+
+

Added: vendor/elsa/current/elsa/in/t0019.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0019.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0019.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// cc.in19
+// base classes
+
+class B {
+public:
+  int x;
+};
+
+class C {
+public:
+  int z;
+  //ERROR(1): int x;     // ambiguous
+  
+  C() : z(9) {}
+};
+
+class D : public B, public C {
+public:
+  int y;
+
+  int f1() { return y; }    // D's member
+  int f2() { return x; }    // B's member
+  int f3() { return z; }    // C's member
+  
+  D() : C() { 18; }
+};
+
+
+class E : virtual public B {};
+
+class F : virtual public B, public E {
+public:
+  int f4() { return x; }
+};
+
+class G : public B, public E {
+public:
+  // this one won't work because the virtual is missing along one path
+  //ERROR(2): int f4() { return x; }    // ambiguous
+};

Added: vendor/elsa/current/elsa/in/t0020.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0020.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0020.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+// cc.in20
+// operators..
+
+
+class B {
+public:
+  operator char ();
+  operator int ();
+
+  int f(char);
+};
+
+
+class Bar {};
+
+class Foo : public B {
+public:
+  Foo operator- (Foo &f);
+
+  // no reason to do this
+  //static Foo operator/ (Foo &f1, Foo &f2);
+
+  // instead do this
+  friend Foo operator/ (Foo &f1, Foo &f2);
+
+  operator int ();
+  operator short ();
+  //operator Bar ();
+
+  int f(short);
+  int f(int);
+  //ERROR(1): int f(int);    // duplicate definition
+};
+
+Foo Foo::operator- (Foo &f)
+{
+  return f;
+}
+
+// static would look like
+//Foo Foo::operator/ (Foo &f1, Foo &f2) {}
+
+// this is the friend
+Foo operator/ (Foo &f1, Foo &f2) {}
+
+
+Foo operator+ (Foo &f1, Foo &f2);
+
+Bar operator+ (Bar &f1, Bar &f2);
+  
+// these can never be nonmembers
+//operator int (Foo &f);
+
+
+int main()
+{
+  Foo x, y;
+  x + y;    // 2
+  x - y;
+  
+  int q;
+  q = x;    // could use "operator int (Foo &)"
+  
+  x.f(9);
+}

Added: vendor/elsa/current/elsa/in/t0021.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0021.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0021.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// cc.in21
+// demonstrate variable vs. class namespace
+
+class Gronk {
+};
+
+//typedef class Gronk Gronk;    // implicit
+
+// this isn't an error..
+//typedef class Whammy Gronk;    // implicit
+
+int main()
+{
+  int Gronk;
+
+  class Gronk *g;      // -> type
+  return Gronk;        // -> int
+}
+
+
+typedef int x;
+
+// it turns out this isn't actually an error in C++
+typedef int x;
+
+//ERROR(2): typedef double x;
+

Added: vendor/elsa/current/elsa/in/t0022.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0022.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0022.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// cc.in22
+// bitfields
+
+struct BF {
+  int x : 2;
+  unsigned y : 4;
+  int /*anon*/ : 7;
+  //ERROR(1):  /*anon*/ : 7;  // missing type--parse error
+};

Added: vendor/elsa/current/elsa/in/t0023.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0023.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0023.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// cc.in23
+// exception specs on functions
+
+int foo() throw();
+
+int foo() throw()
+{
+  return 3;
+}
+
+
+// 15.4 para 1: this must be a complete type
+class Exc {};
+
+void bar() throw(Exc);
+
+//ERROR(1): void bar();    // conflicting declaration
+

Added: vendor/elsa/current/elsa/in/t0024.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0024.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0024.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// cc.in24
+// typedef'd class members
+
+class Foo {
+public:
+  typedef int Int;
+  
+  void f()
+  {
+    Int x;
+  }
+};

Added: vendor/elsa/current/elsa/in/t0025.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0025.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0025.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// cc.in25
+// inner classes
+
+class A {
+public:
+  class B {
+  public:
+    static int x;
+    int y;
+    int f();
+    double g();
+  };
+
+  int func(B &b);
+};
+
+// verify that declarators can see the class scope
+int A::func(B &b)
+{
+  return 6;
+}
+
+
+int main()
+{
+  int d;
+  d = A::B::x;
+
+  A::B b;
+  d = b.y;
+}
+
+int A::B::f()
+{
+  return 6;
+}
+
+//ERROR(1): int A::B::h() {   return 66; }   // undeclared
+
+double x;
+
+double A::B::g()
+{
+  return ::x;
+}
+

Added: vendor/elsa/current/elsa/in/t0026.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0026.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0026.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0026.cc
+// template functions
+
+template <class T>
+int f(T t)
+{
+  T(z);    // ambiguous, but I can disambiguate!
+
+  int q = T(z);    // ctor call
+
+  // this error is correct:
+  // non-compound `int' doesn't have fields to access
+//    int y = t.x;
+}
+
+template <class T>
+void g(T t, int);
+
+int main()
+{
+  f(9);
+
+  f<int>(8);
+
+  //ERROR(1): f(1,2);        // too many arguments
+  //ERROR(2): f();           // not all template arguments bound
+  //ERROR(3): g(1);          // too few arguments (but all template args bound)
+
+  // I get the wrong answer for this one..
+  //f<int()>(8);
+}

Added: vendor/elsa/current/elsa/in/t0027.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0027.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0027.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// cc.in27
+// template classes
+
+// forward decl
+template <class T> class Foo;
+
+// a redudant forward decl
+template <class T> class Foo;
+
+//ERROR(1): template <class TT, class YY> class Foo;     // inconsistent
+
+template <class T>
+class Foo {
+public:
+  T x;
+
+  T put();
+  T get();
+};
+
+//ERROR(2): template <class TT> class Foo {};   // already defined
+
+template <class T>
+T Foo<T>::put()
+{
+  //return 3;
+  return x;     // require Foo<T>::x to be in scope
+}
+
+//ERROR(3): template <class T> T Foo::get() { return 3; }   // needs template args
+
+int main()
+{
+  Foo<int> h;
+  h.x;
+  //ERROR(4): h.y;   // no field
+  
+  Foo<int*> g;
+  *( g.x );        // will complain that 'typename T' isn't a pointer..
+  
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0028.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0028.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0028.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,93 @@
+// cc.in28
+// smbase/arraymap.h, with one small tweak to make it self-contained
+
+
+// map: int -> T
+template <class T>
+class ArrayMap {
+private:     // data
+  T **map;               // array[0,nextId-1] of owner ptr
+  int nextId;            // next id to assign
+  int mapSize;           // allocated size of 'map'
+
+private:     // funcs
+  void make();
+  void del();
+  void validate(int index) const;
+
+public:      // data
+  ArrayMap() { make(); }
+  ~ArrayMap() { del(); }
+
+  // # of elements defined
+  int count() const { return nextId; }
+
+  // insert a new element and yield its assigned id
+  int insert(T * /*owner*/ t);
+
+  // retrieve by id
+  T const *lookupC(int id) const;
+  T *lookup(int id) { return const_cast<T*>(lookupC(id)); }
+  T *&lookupRef(int id) { validate(id); return map[id]; }
+
+  // throw everything away
+  void empty() { del(); make(); }
+};
+
+template <class T>
+void ArrayMap<T>::make()
+{
+  mapSize = 100;
+  nextId = 0;
+  map = new T* [mapSize];
+}
+
+template <class T>
+void ArrayMap<T>::del()
+{
+  for (int i=0; i<nextId; i++) {
+    delete map[i];
+  }
+  delete[] map;
+}
+
+template <class T>
+int ArrayMap<T>::insert(T *t)
+{
+  if (nextId == mapSize) {
+    // make it bigger
+    int newMapSize = mapSize * 2;
+    T **newMap = new T* [newMapSize];
+
+    // copy the old contents to the new map
+    for (int i=0; i<mapSize; i++) {
+      newMap[i] = map[i];
+    }
+    mapSize = newMapSize;
+
+    // blow away the old map
+    delete[] map;
+
+    // grab the new map
+    map = newMap;
+  }
+
+  int ret = nextId++;
+  map[ret] = t;
+  return ret;
+}
+
+void xassert(int c);
+
+template <class T>
+void ArrayMap<T>::validate(int id) const
+{
+  xassert(0 <= id && id < nextId);
+}
+
+template <class T>
+T const *ArrayMap<T>::lookupC(int id) const
+{
+  validate(id);
+  return map[id];
+}

Added: vendor/elsa/current/elsa/in/t0029.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0029.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0029.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// cc.in29
+// linkage specifications
+
+extern "C" int exit(int code);
+
+extern "C" {
+  int printf(char const *fmt, ...);
+  int rand();
+}

Added: vendor/elsa/current/elsa/in/t0030.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0030.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0030.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,123 @@
+// cc.in30
+// misc
+
+int f(int x = 3);
+
+// parameter is unnamed
+int f2(int = 5);
+
+class Foo {
+public:
+  // this doesn't work right now..
+  //int g(int x = y);    // refers to static member Foo::y
+  //static int y;
+
+  int h(int j=9);
+  
+  // ctor with "inline"
+  inline Foo(int *x);
+};
+
+// anonymous class
+class {
+  int x;
+} xx;
+
+// anonymous enum
+enum { whazza, whozza, howza } futza;
+
+// array size that's not a simple literal integer
+typedef struct
+  {
+    unsigned long int __val[(1024 / (8 * sizeof (unsigned long int))) ];
+  } __sigset_t;
+
+// enum where one value is used to initialize another
+enum Blah { A, B, C=B, D };
+  
+
+
+// struct with same name as function
+struct stat {
+  int x;
+};
+
+extern int stat (const  char *   __file,
+		 struct stat *   __buf)  ;
+
+  
+// struct with same name as variable
+struct timezone
+  {
+    int tz_minuteswest;
+    int tz_dsttime;
+  };
+
+extern long int timezone;
+
+
+// enumerators with values calculated from prior enumerators
+enum { skipws= 01 ,
+       left= 02 , right= 04 , internal= 010 ,
+       dec= 020 , oct= 040 , hex= 0100 ,
+       showbase= 0200 , showpoint= 0400 ,
+       uppercase= 01000 , showpos= 02000 ,
+       scientific= 04000 , fixed= 010000 ,
+       unitbuf= 020000 , stdio= 040000
+       };
+enum {
+    basefield=dec+oct+hex,
+    floatfield = scientific+fixed,
+    adjustfield = left+right+internal
+};
+
+
+
+class ios {
+    // overloading on constness of 'this'
+    void*& pword(int);
+    void* pword(int) const;
+    long& iword(int);
+    long iword(int) const;
+
+    // defining a typedef of an enum
+    enum seek_dir { beg, cur, end};
+    typedef enum seek_dir seekdir;
+
+};
+
+// and then typedef'ing that outside the class scope
+typedef ios::seek_dir _seek_dir;
+
+
+class streammarker {
+    streammarker(int *sb);
+    ~streammarker();
+
+    // doesn't think 'streammarker' is a type name here?
+    // I see, it was getting confused by the constructor name
+    // hiding the type name itself.  now that's fixed.
+    int delta(streammarker&);
+    int delta();
+};
+
+
+// apparently the keyword clash is ok
+class streambuf;
+struct streambuf { int foo; };
+
+
+// call to delete[] using unusual syntax
+void call_delete()
+{
+  int *x;
+  operator delete[] (x);
+}
+
+
+class ostream {
+    // problems with "this"?
+    ostream& operator<<(unsigned char c) { return (*this) << (char)c; }
+};
+
+

Added: vendor/elsa/current/elsa/in/t0030a.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0030a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0030a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// cc.in30; cut down to show only anonymous stuff.
+class {
+  int x;
+} xx;
+// anonymous enum
+enum { whazza, whozza, howza } futza;

Added: vendor/elsa/current/elsa/in/t0030b.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0030b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0030b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+enum GRNK0 { whazza0, whozza0, howza0 } waga0;
+enum GRNK2 { whazza2, whozza2, howza2 };
+enum GRNK2 waga2;
+enum { whazza, whozza, howza } futza;

Added: vendor/elsa/current/elsa/in/t0031.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0031.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0031.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// cc.in31
+// explicit calls to some builtins
+
+class Foo {
+  void operator delete[]();
+};
+
+int main()
+{
+  void *x;
+  
+  operator delete (x);
+  operator delete[] (x);
+}

Added: vendor/elsa/current/elsa/in/t0032.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0032.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0032.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// cc.in32
+// anonymous unions
+
+int main()
+{
+  union {
+    unsigned ret;
+    char c[4];
+  };
+
+  c[3] = 4;
+  return ret;
+}
+
+
+int foo()
+{
+  // better not still be able to see 'ret' ..
+  //ERROR(1): return ret;     // undeclared
+}
+
+
+struct nsStr {
+  union {
+    char*         mStr;
+    short*        mUStr;
+  };
+};
+
+void someFunc()
+{
+  nsStr s;
+  s.mUStr;
+}
+
+
+char *anotherFunc()
+{     
+  //ERROR(2): return mStr;
+}
+
+

Added: vendor/elsa/current/elsa/in/t0033.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0033.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0033.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// cc.in33
+// calling constructors
+
+class Foo {
+public:
+  Foo(int x);
+};
+
+typedef class Foo FILE;
+
+int main()
+{
+  Foo f(3);
+
+  int x,y;
+  Foo g(x*y);
+
+  int exit(int);
+
+  // this one looks ambiguous at first blush
+  int fileno(FILE *f);
+}

Added: vendor/elsa/current/elsa/in/t0034.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0034.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0034.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// cc.in34
+// difficulty making connection with forward-declared
+// template class
+
+template <class T> class OwnerHashTableIter;
+
+template <class T>
+class OwnerHashTable {
+public:
+  friend class OwnerHashTableIter<T>;
+};

Added: vendor/elsa/current/elsa/in/t0035.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0035.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0035.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// cc.in35
+// problem with recognizing that different instantiations
+// of a template class are different types
+
+template <class num>
+class TPoint {
+public:
+  num x, y;
+};
+
+
+
+class stringBuilder;
+typedef TPoint<int> point;
+typedef TPoint<double> fpoint;
+
+
+
+stringBuilder& operator<< (stringBuilder &sb, point const &pt)
+{   
+  // would require adding operators for stringBuilder, but
+  // that is not what this file is intended to test
+  //return sb << "(" << pt.x << ", " << pt.y << ")";
+  return sb;
+}
+
+stringBuilder& operator<< (stringBuilder &sb, fpoint const &pt)
+{
+  //return sb << "(" << pt.x << ", " << pt.y << ")";
+  return sb;
+}
+
+
+ 
+ 
+ 

Added: vendor/elsa/current/elsa/in/t0036.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0036.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0036.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// cc.in36
+// testing template implemenation some more
+  
+template <class T>
+class Baz {
+public:
+  int b(T *p);
+};
+
+
+int func()
+{
+  Baz<int> b;
+  return (int)3;
+}
+
+
+
+template <class T>
+class Foo {
+  T *x;
+  Baz<T> *b;
+
+  T *f() {
+    int q;
+    q = b->b(x);
+    return x;
+  }
+};
+
+int func2()
+{
+  Foo<float> f;
+  return *(f.x);    // should be type 'float'
+}
+

Added: vendor/elsa/current/elsa/in/t0037.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0037.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0037.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// cc.in37
+// publishing superclass members
+
+class Super {
+public:
+  int x;
+};
+
+class Sub : private Super {
+public:    
+  // publish 'x' despite private inheritance
+  Super::x;                                 
+  
+  //ERROR(1): y;     // missing superclass
+};

Added: vendor/elsa/current/elsa/in/t0038.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0038.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0038.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// cc.in38
+// problem with order of processing inner class inline members
+
+int f(int x);
+
+class StringDict {
+  class Iter {
+  public:
+    Iter(StringDict &dict) { dict.getIter(); }
+
+    // ambiguous, so I need to check the bodies..
+    int foo() { return f(3); }
+  };
+  Iter getIter();
+};
+     

Added: vendor/elsa/current/elsa/in/t0039.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0039.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0039.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// cc.in39
+// problem with fwd decls inside classes
+
+class Foo {
+  class Bar;
+};
+
+class Bar {
+  int x;
+};

Added: vendor/elsa/current/elsa/in/t0040.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0040.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0040.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// cc.in40
+// provoke exprlist->next double-set
+
+char *strtok(char *str, char *delim);
+
+int main()
+{
+  int tok;
+  char *delim;
+  tok = strtok(((char *)0) , delim);
+}

Added: vendor/elsa/current/elsa/in/t0041.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0041.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0041.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// cc.in41
+// operator[] overloading
+
+class Foo {
+public:
+  int operator[] (int index);
+};
+
+int main()
+{
+  Foo f;
+  return f[4];
+}

Added: vendor/elsa/current/elsa/in/t0042.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0042.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0042.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// cc.in42
+// need to merge ForInitStatement
+ 
+typedef int Node;
+
+int main()
+{
+  int *top;
+  for (Node *n = top; 3; 4) ;
+}
+

Added: vendor/elsa/current/elsa/in/t0043.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0043.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0043.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// cc.in43
+// anonymous class following a deviously-named non-anon
+      
+// not anonymous, but looks like a name I'd construct
+class Anon_class_1 {
+  int x;
+};
+
+class {
+  int y;
+} z;

Added: vendor/elsa/current/elsa/in/t0044.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0044.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0044.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// cc.in44
+// problem with inline definition of virtual destructor
+
+class Foo
+{
+  virtual ~Foo() {}
+};

Added: vendor/elsa/current/elsa/in/t0045.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0045.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0045.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// cc.in45
+// inheritance with several keywords
+
+class B
+{};
+
+class D1 : public virtual B
+{};
+
+class D2 : virtual public B
+{};
+
+class D3 : public B
+{};
+
+class D4 : virtual B
+{};
+
+class D5 : B
+{};
+

Added: vendor/elsa/current/elsa/in/t0046.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0046.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0046.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// cc.in46
+// point of declaration for template parameters
+
+template <class T>
+class Foo : public T
+{};
+
+
+// TODO: allow T-typed non-type template arguments
+// TODO: allow T to be the default argument for a type template argument

Added: vendor/elsa/current/elsa/in/t0047.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0047.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0047.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// cc.in47
+// undefined function name in a template definition
+
+unsigned int getRandom(int low, int high);
+
+template <class T>
+void Shuffle(T *array, unsigned int size)
+{
+  // the function 'swap' isn't declared
+  while (--size) {
+    swap(array[size], array[getRandom(0, size)]);
+  }
+}

Added: vendor/elsa/current/elsa/in/t0048.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0048.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0048.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+// cc.in48
+// experimenting with declarator notation printing
+
+// essentially, declarators have three kinds of type
+// constructors:
+//   pointer    *       prefix
+//   function   (...)   postfix
+//   array      [n]     postfix
+// parsing ambiguity arises because of the combination of
+// prefix and postfix syntax, and is resolved by always
+// considering the postfix syntax to bind more tightly
+
+int a;
+
+int *b;
+
+int **c;
+
+int d[2];
+
+// array of 2 pointers to ints
+int *e[2];
+int *(f[2]);
+
+// pointer to an array of 2 ints
+int (*g)[2];
+
+int h();
+
+// function returning pointer to int
+int *i();
+int *(j());
+
+// pointer to function returning int
+int (*k)();
+
+// function accepting an integer
+int f1(int n);
+class S;
+int f2(int S);
+
+// function accepting a pointer to a function which returns int
+int l(int (*)());
+int m(int (*n)());
+
+// function accepting a function which returns int
+int p(int (q)());
+int f3(int (S));        // ambiguous..
+
+// function accepting a function which returns a function (!)
+// dsw: nope
+//  int q(int (S)());       // ayyyeeee!!
+//  int r(int ()());
+
+

Added: vendor/elsa/current/elsa/in/t0049.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0049.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0049.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// cc.in49
+// friend decls
+
+class Foo {
+  typedef int Integer;
+  friend int f(Integer i);
+};
+
+int main()
+{
+  return f(3);
+}

Added: vendor/elsa/current/elsa/in/t0050.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0050.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0050.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// cc.in50
+// this caused a segfault when the GLR core failed to dup()
+// terminal svals yielded more than once directly from
+// the LexerInterface
+
+void f(double d);
+
+int main()
+{
+  f(2.0);
+}

Added: vendor/elsa/current/elsa/in/t0051.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0051.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0051.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// cc.in51
+// accessing object fields with qualified names
+
+class A {
+public:
+  void f();
+};
+
+class B {
+public:
+  void f();
+};
+
+class C : public A, public B {};
+
+int main()
+{
+  C c;
+
+  //ERROR(1):*/ c.f();      // ambiguous
+
+  c.A::f();   // ok
+  c.B::f();   // ok
+
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0052.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0052.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0052.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// cc.in52
+// variant of 3.4.5.cc
+
+struct A {
+  int a;
+  int x;
+};
+struct B : /*NOT virtual*/ A {};
+struct C : B { int q; int x; };
+struct D : B { int q; };
+struct E : public C, public D {};
+struct F : public A{};
+
+void f()
+{
+  // in these cases, the field being accessed is A::a; the qualifiers
+  // cannot be used to specify the base class subobject
+  E e;
+  //ERROR(1): e.a = 0;                    // ambiguous
+  //ERROR(2): e.B::a = 0;                 // ambiguous
+  //ERROR(3): e.C::B::a = 0;              // ambiguous
+
+  //ERROR(4): e.q;
+  //ERROR(5): e.E::q;
+  
+  //ERROR(6): e.x;    // ambiguous because A is not inherited virtually
+
+  F f;
+  f.A::a = 1;        // OK, A::a is a member of F
+}

Added: vendor/elsa/current/elsa/in/t0053.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0053.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0053.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// cc.in53
+// problem with names of enums from within context of an inner class
+
+namespace N {
+  class Foo {
+  public:
+    enum Enum1 { E1_VAL = 3 };
+
+    class Another {
+    public:
+      enum Enum2 { E2_VAL = 4 };
+    };
+
+    class Bar {
+    public:
+      int f();
+      int g();
+    };
+
+  };
+
+  int Foo::Bar::f()
+  {
+    int x;
+
+    x = E1_VAL;      // ok
+    //ERROR(1): x = E2_VAL;      // can't look into Foo::Another without qualifier
+
+    return x;
+  }
+}
+
+// three levels deep nesting of qualifiers; this in essence
+// tests that the ArrayStackEmbed stuff works (deep in my
+// implementation) even when we have to put some of the
+// scope pointers on the heap
+int N::Foo::Bar::g()
+{
+  return E1_VAL;
+}

Added: vendor/elsa/current/elsa/in/t0054.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0054.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0054.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0054.cc
+// explicit template class specialization
+
+// primary template
+template <class T>
+class A {
+  //T f();    // not declared!
+};
+
+// explicit specialization
+template <>
+class A<char> {
+  // something new in the specialization
+  char f() { return 'f'; }
+};
+
+int main()
+{
+  A<char> a;
+
+  // now that specialization matching is implemented, this call to 'f'
+  // will be looked up in the proper specialization
+  a.f();
+
+  A<int> b;
+  // ERROR(1): b.f();     // doesn't work since base doesn't have 'f'
+
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0055.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0055.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0055.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0055.cc
+// member initializer where member is a templatized base class
+      
+template <class T>
+class A {
+public:
+  int f();
+  A(T t);
+  int g();
+};
+
+class B : A<int> {
+public:
+  B() : A<int>(5) {}
+};
+
+
+// variant using an explicit specialization
+template <>
+class A<float> {};
+
+struct D : A<float> {
+  D() : A<float>() {}
+
+  void f()
+  {
+    A<float> a;
+  }
+};

Added: vendor/elsa/current/elsa/in/t0056.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0056.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0056.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// cc.in56
+// using "typename" to dig down into a template argument to
+// retrieve a type
+
+class A {
+public:
+  typedef int diff_type;
+};
+
+template <class T>
+class Foo {
+public:
+  // class T is expected to contain a nested (or typedef'd) type
+  // called 'diff_type', and here we're digging down to retrieve
+  // it, and give it a nicer alias in this scope
+  typedef typename T::diff_type diff_type;
+
+  // use the retrieved type
+  diff_type d;
+};
+
+// example usage
+int main()
+{
+  Foo<A> f;
+  int x = f.d;     // 'f.d' has type 'int'
+  return x;
+}

Added: vendor/elsa/current/elsa/in/t0057.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0057.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0057.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,49 @@
+// t0057.cc
+// problem with template-id as a qualifier
+
+// this testcase demonstrates the need to fully implement
+// template specialization matching in order to properly
+// disambiguate C++ syntax
+
+template <class T>
+class Foo {
+public:
+  // the absence of this declaration in the primary template
+  // is what makes the access of 'x' appear to fail, below
+  //  static int x();
+
+  static int y(int q);
+  typedef int z;
+};
+
+// specialization
+template <>
+class Foo<int> {
+public:
+  static int x();
+  typedef int y;
+  static int z(int);
+};
+
+int j,k;
+
+int main()
+{
+  int i;
+
+  // for this one, I pretend 'x' is a variable of type ST_ERROR
+  // to suppress the error and make it appear unambiguous
+  i = Foo<int>::x();
+  
+  // correct interpretation: declaration
+  // my interpretation: function call
+  Foo<int>::y(j);
+
+  // correct interpretation: function call
+  // my interpretation: declaration
+  Foo<int>::z(k);
+  
+  // UPDATE 9/05/03: I now have a very restricted form of specialization
+  // implemented, and some of the above may now actually work right.
+}
+

Added: vendor/elsa/current/elsa/in/t0058.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0058.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0058.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// cc.in58
+// use a typedef as a qualifier
+
+class A {
+public:
+  static int x;
+};
+
+typedef A B;
+
+int main()
+{
+  return B::x;
+}

Added: vendor/elsa/current/elsa/in/t0059.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0059.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0059.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// cc.in59
+// ambiguous expression from mozilla
+
+//template <class CharT>
+struct nsReadableFragment
+  {
+    const void*   mFragmentIdentifier;
+
+    unsigned long
+    GetIDAsInt() const
+      {
+        typedef char* char_ptr;
+        typedef unsigned long ulong;
+        
+        // this line caused a problem because it is two ambiguities
+        // nested inside another ambiguity, and while checking the
+        // first toplevel ambiguitiy I set the 'type' field of one
+        // of the lower ones (to ST_ERROR), and then the next time
+        // I checked it I didn't generate an error message because
+        // 'type' was already set
+        return ulong(char_ptr(mFragmentIdentifier)-char_ptr(0));
+      }
+  };

Added: vendor/elsa/current/elsa/in/t0060.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0060.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0060.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// cc.in60
+// invoke via operator()
+
+class Foo {
+public:
+  int operator() ();
+};
+
+int main()
+{
+  Foo f;
+  return f();
+}

Added: vendor/elsa/current/elsa/in/t0061.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0061.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0061.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// cc.in61
+// simulation of gcc's vararg stuff
+
+
+typedef void *__gnuc_va_list;
+typedef __gnuc_va_list va_list;
+
+int myprintf(char const *format, ...)
+{
+  va_list ap;
+  
+  // sm: nerfed this and moved into in/gnu/g0006.cc
+  // since it is gnu-specific
+  //
+  // update: then I put it back since the mozilla tests refer
+  // to __builtin_next_arg and I want to use them in non-gnu
+  // mode too... so this symbol is defined even in non-gnu mode now
+  ( ap  = ((__gnuc_va_list) __builtin_next_arg (  format ))) ;
+
+  ((void)0) ;
+  return 0;
+}
+

Added: vendor/elsa/current/elsa/in/t0062.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0062.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0062.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// cc.in62
+// ambiguity from nsLDAPProtocolModule.i
+
+typedef unsigned short u_short;
+
+class Foo2 {};
+
+class Foo {
+public:
+  // ambiguous, but resolution is to consider it a ctor decl
+  Foo( u_short );
+
+  // gcc issues an unusual warning, but appears to accept this as a
+  // declaration of member "u_short"
+  //Foo2( u_short );
+
+  // make sure this works
+  Foo *p1;
+  Foo *p2, *p3;
+
+  // unambiguous
+  Foo(u_short, u_short);
+
+  // parse error now
+  //*ERROR(1):*/ Foo x;
+
+  // should (eventually) provoke error about incomplete type
+  //Foo *y, z;
+
+  // but this has to still work!
+  typedef Foo my_type;
+
+  // so must this
+  static Foo an_instance;
+
+  // what about this?  parsed as a declaration of a static variable,
+  // because "static" isn't among the modifiers allowed to preceed
+  // a ctor declaration
+  static Foo(u_short);
+};

Added: vendor/elsa/current/elsa/in/t0063.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0063.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0063.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// cc.in63
+// some lexical tests
+
+float f = 0.0;
+float g = 0.0f;
+
+char const *s = "hello";
+wchar_t const *t = L"hello";
+
+char c = 'c';
+wchar_t d = L'c';
+                      
+char c_oct = '\033';
+char c_hex = '\xAB';
+
+int i = 4;
+unsigned j = 4U;
+
+long m = 50L;
+unsigned long n = 50UL;
+unsigned long o = 50LU;

Added: vendor/elsa/current/elsa/in/t0064.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0064.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0064.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// cc.in64
+// problem with (void) parameter lists
+
+class Foo {
+public:
+  int f(void);
+};
+
+int Foo::f()
+{}
+
+
+// no!
+//ERROR(1): int g(void x);
+
+// no!
+//ERROR(2): int h(void, int);
+
+// no!
+//ERROR(3): int i(void = 4);
+

Added: vendor/elsa/current/elsa/in/t0065.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0065.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0065.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// cc.in65
+// some tricky const-eval expressions
+
+const int five = 5;
+int array[five];
+
+typedef int PRInt32;
+const   PRInt32 kDefaultStringSize = 64;
+enum  eCharSize {eOneByte=0,eTwoByte=1};
+char mBuffer[kDefaultStringSize<<eTwoByte];

Added: vendor/elsa/current/elsa/in/t0066.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0066.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0066.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// cc.in66
+// problem with friends
+
+class Foo {
+public:
+  friend class Bar;
+  int f();
+};
+
+class Bar {
+public:
+  int x;
+};
+
+int Foo::f()
+{
+  Bar *b;
+  return b->x;
+}

Added: vendor/elsa/current/elsa/in/t0067.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0067.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0067.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// cc.in67
+// deref/overload problem
+
+class Foo {
+public:
+  void f(int, int);
+  int *f(int);     
+};
+
+int main()
+{
+  Foo foo;
+  return *(foo.f(4));
+}

Added: vendor/elsa/current/elsa/in/t0068.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0068.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0068.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// cc.in68
+// explicit dtor call w/o qualifier
+
+class A {
+public:
+  //~A();
+  void destroy(A &aref)
+  {
+    this->~A();
+    aref.~A();
+  }
+};
+
+int main()
+{
+  A *a1;
+  a1->~A();
+
+  A &a2;
+  a2.~A();
+
+  return 0;
+}
+

Added: vendor/elsa/current/elsa/in/t0069.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0069.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0069.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// cc.in69
+// odd behavior of forward decls inside other constructs
+
+// -----------------------
+class Foo {
+public:
+  class Bar *b;    // functions as fwd decl (?)
+  int f();
+};
+
+class Bar {
+public:
+  int x;
+};
+
+int Foo::f()
+{
+  return b->x;
+}
+
+
+// -----------------------
+void g(class Baz *b);     // this should also introduce the name
+
+Baz *z;
+
+
+// but this won't work because it's captured by the paramter scope
+void h(struct Frozz { int y; } *q);
+
+//ERROR(1): Frozz *qq;
+

Added: vendor/elsa/current/elsa/in/t0070.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0070.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0070.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// cc.in70
+// inherit from a typedef'd name!
+
+class Foo {};
+
+typedef Foo Bar;
+
+class Baz : public Bar {
+  //...
+};
+

Added: vendor/elsa/current/elsa/in/t0071.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0071.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0071.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// cc.in71
+// duplicate typedef at class scope
+
+class Foo {
+public:
+  typedef int x;
+  typedef int x;
+  
+  typedef enum E { a,b,c } E;
+};

Added: vendor/elsa/current/elsa/in/t0072.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0072.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0072.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0072.cc
+// declmodifiers after type specifier word
+
+const static int x = 4;
+
+//ERROR(1): const const int q;    // duplicate 'const'
+
+unsigned int r;
+
+
+// some more hairy examples
+long unsigned y;
+const unsigned volatile long static int z;
+
+long long LL;    // support this because my libc headers use it..
+
+// may as well get the literal notation too
+void foo()
+{
+  LL = 12LL;
+  LL = -1LL;
+}
+
+
+//ERROR(3): long float g;    // malformed type
+                       
+// too many!
+//ERROR(4): long long long LLL;
+//ERROR(5): long long long long LLLL;
+//ERROR(6): long long long long long LLLL;
+

Added: vendor/elsa/current/elsa/in/t0073.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0073.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0073.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// cc.in73
+// inheriting from a typedef'd class and trying to call
+// the superclass dtor in the member init
+
+class txList {};
+typedef txList List;
+
+class Stack : private List {
+  Stack();
+};
+
+Stack::Stack() : List()
+{}

Added: vendor/elsa/current/elsa/in/t0074.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0074.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0074.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// cc.in74
+// need global operator new defined
+
+int foo()
+{
+  return operator new(3);
+}
+
+int foo2()
+{
+  return ::operator new(4);
+}

Added: vendor/elsa/current/elsa/in/t0075.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0075.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0075.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// cc.in75
+// need to relax checking between decl and defn for array types
+
+extern int arr[];
+
+int arr[3] = {1,2,3};
+
+
+extern int blah[][4];
+
+int blah[5][4] = { 0 };
+
+
+extern int borg[3];
+//ERROR(1): int borg[4] = { 7 };   // mismatch
+
+class Foo {
+public:
+  int f(int arr2[]);
+};
+
+int Foo::f(int arr2[5])
+{
+  return 6;
+}

Added: vendor/elsa/current/elsa/in/t0076.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0076.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0076.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// cc.in76
+// use 'extern "C"' as synonym for 'extern'
+
+extern "C" int x;
+
+int x;

Added: vendor/elsa/current/elsa/in/t0077.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0077.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0077.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// cc.in77
+// problem with div by zero?
+
+static const char *gScheme[] = {"chrome", "file", "http", "jar", "resource"};
+
+int mWeakHandler[(sizeof( gScheme )/sizeof(* gScheme )) ];

Added: vendor/elsa/current/elsa/in/t0078.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0078.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0078.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// cc.in78
+// clash between implicit typedef and class member
+
+class Foo {
+  struct hash {
+    int x;
+  } hash;
+};
+
+void func()
+{
+  Foo f; 
+  int i;
+  
+  i = f.hash.x;    // make sure 'hash' is a variable, not a type
+}
+

Added: vendor/elsa/current/elsa/in/t0079.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0079.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0079.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// in/t0079.cc
+// problem with templatized forward decl?
+// no, was a problem with templatized prototypes
+
+class istream;
+
+template<class TP> class smanip;
+//template<class TP> class smanip {};
+
+template<class TP>
+inline istream& operator>>(istream& i, const smanip<TP>& m);
+//int foo(smanip<TP> &m);
+
+typedef smanip<int> smanip_int;
+
+template<class TP> class smanip {
+public:
+  smanip *whatever;
+  smanip<TP> *whatever2;
+};
+
+void f()
+{
+  smanip_int s;
+  s.whatever;
+}
+

Added: vendor/elsa/current/elsa/in/t0080.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0080.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0080.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// cc.in80
+// reproduce ASTTypeId ambiguity
+
+int f(int);
+int g(int);
+
+int func(int param)
+{
+  // unambiguous
+  //int y(f(param));
+  
+  // ambiguous
+  int x(f(g(param)));
+}
+
+
+// different way of seeing it
+typedef int x;
+typedef int y;
+typedef int z;
+
+int h(int /*anon*/(x /*anon*/(y /*anon*/)));
+    

Added: vendor/elsa/current/elsa/in/t0081.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0081.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0081.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// cc.in81
+// 'register' in a parameter list
+
+int f(register int a)
+{
+  return a;
+}

Added: vendor/elsa/current/elsa/in/t0082.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0082.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0082.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// cc.in82
+// ambiguity with angle brackets
+
+template <int n> class C { /*...*/ };
+
+int main()
+{
+  int x;
+  C<  3+4  > a;      // ok; same as C<7> a;
+  C<  3<4  > b;      // ok; same as C<1> b;
+  //ERROR(1): C<  3>4  > c;      // no!
+  C< 3&&4  > c;      // ok; same as C<1> c;
+  C< (3>4) > d;      // ok; same as C<0> d;
+
+  new C< 3 > +4 > +5;
+}

Added: vendor/elsa/current/elsa/in/t0083.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0083.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0083.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// cc.in83
+// this was a problem when I had a bug in the code which maintains the
+// ambiguity lists
+
+template <class num>
+class TPoint {
+  int f()
+    { return TPoint<num>(3,3); }
+};

Added: vendor/elsa/current/elsa/in/t0084.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0084.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0084.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+template <class T> class C {};
+typedef int x;
+
+int f(C<x> *y);

Added: vendor/elsa/current/elsa/in/t0085.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0085.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0085.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// cc.in85
+// demonstrate inability to simply separate qual_tcheck into
+// two whole-AST passes to deal with scoping
+
+class Foo {
+public:
+  int f()
+  {
+    x y;            // y's qvar needs x's qtype
+    return y;
+  }
+
+  typedef int x;    // this is what sets x's qtype
+};

Added: vendor/elsa/current/elsa/in/t0086.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0086.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0086.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0086.cc
+// test #line directive processing
+
+#line 1 "foo.cc"
+int x;
+int y;
+
+#line 6 "bar.cc"
+int z;

Added: vendor/elsa/current/elsa/in/t0087.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0087.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0087.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,61 @@
+// t0087.cc
+// experimenting with ptr-to-member
+
+class A {
+public:
+  int x;
+};
+class B {};
+                            
+// just let me inherit from A in a way that all subobjects
+// can still be unambiguously named; g++ has a warning for this,
+// "warning: direct base `A' inaccessible in `D' due to ambiguity"
+class A_prime : public A {};
+
+class C : public A {};
+class D : public C, public A_prime {};
+
+class E : virtual public A {};
+class F : public E, virtual public A {};
+class G : public E, public A_prime {};
+
+void foo()
+{
+  int A::*p = &A::x;
+
+  // experiments with .*
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+  F f;
+  G g;
+
+  a.*p = 7;                 // ok, obviously
+  //ERROR(1): b.*p = 7;     // not derived
+  c.*p = 7;                 // ok, A is a base of C
+  //ERROR(2): d.*p = 7;     // ambiguous derivation
+  e.*p = 7;                 // ok, A is a virtual base of E
+  f.*p = 7;                 // ok, A is a virtual base twice (E and F)
+  //ERROR(3): g.*p = 7;     // ambiguous derivation
+
+  // same things with ->*
+  A *ap;
+  B *bp;
+  C *cp;
+  D *dp;
+  E *ep;
+  F *fp;
+  G *gp;
+
+  ap->*p = 7;               // ok, obviously
+  //ERROR(4): bp->*p = 7;   // not derived
+  cp->*p = 7;               // ok, A is a base of C
+  //ERROR(5): dp->*p = 7;   // ambiguous derivation
+  ep->*p = 7;               // ok, A is a virtual base of E
+  fp->*p = 7;               // ok, A is a virtual base twice (E and F)
+  //ERROR(6): gp->*p = 7;   // ambiguous derivation
+}
+
+

Added: vendor/elsa/current/elsa/in/t0088.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0088.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0088.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0088.cc
+// excerpt from /home/scott/bld/mozilla-1.0/extensions/inspector/base/src/inDOMUtils.i
+// dealing with pointer to member
+
+struct nsStyleStruct {};
+struct nsCSSStruct {};
+class nsIStyleContext;
+typedef int PRBool;
+
+class nsRuleNode {
+  enum RuleDetail {
+    eRuleNone,
+    // etc.
+  };
+
+  typedef const nsStyleStruct*
+  (nsRuleNode::*ComputeStyleDataFn)(nsStyleStruct* aStartStruct,
+                                    const nsCSSStruct& aStartData,
+                                    nsIStyleContext* aContext,
+                                    nsRuleNode* aHighestNode,
+                                    const RuleDetail& aRuleDetail,
+                                    PRBool aInherited);
+};

Added: vendor/elsa/current/elsa/in/t0089.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0089.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0089.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0089.cc
+// replicate problem with reported decl/defn mismatch with static funcs
+
+class A {
+  static int foo();
+};
+
+int A::foo()
+{}

Added: vendor/elsa/current/elsa/in/t0090.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0090.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0090.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0090.cc
+// more problems with static member defns
+
+class A {
+  static int foo(int);
+  static int foo(int, int);
+};
+
+int A::foo(int)
+{}

Added: vendor/elsa/current/elsa/in/t0091.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0091.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0091.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// t0091.cc
+// problem with explicit dtor call
+
+class morkNode {
+  ~morkNode();
+  void foo();
+};
+
+void morkNode::foo()
+{
+  this->~morkNode();
+  this->morkNode::~morkNode();
+  this->morkNode::foo();
+}
+
+
+
+class forkNode {
+  void foo();
+};
+
+void forkNode::foo()
+{
+  this->~forkNode();
+  this->forkNode::~forkNode();
+}
+
+
+typedef unsigned uint;
+
+void f()
+{
+  uint x;
+  x.~uint();    // legal
+  
+  //ERROR(1): x.~uint(1);   // not legal
+}
+
+
+typedef unsigned uintArr[3];
+
+void g()
+{
+  uintArr x;
+  x.~uintArr();
+}

Added: vendor/elsa/current/elsa/in/t0092.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0092.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0092.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// t0092.cc
+// adjacent string literals
+
+// apparently this is legal; cppstd is unclear IMO
+char *s = "foo""bar";

Added: vendor/elsa/current/elsa/in/t0093.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0093.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0093.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0093.cc
+// asm
+
+asm("whassup");
+
+int foo()
+{
+  asm("oof");
+}

Added: vendor/elsa/current/elsa/in/t0094.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0094.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0094.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,129 @@
+// t0094.cc
+// nasty excerpt from gcc-2.95.3's iomanip.h
+
+// ouch, not sure what to do.  the line marked "/* !!! */" 
+// has some angle brackets which the Standard grammar does
+// not allow.  I'm not entirely sure what the goal of the
+// author was.  for now I'm just going to comment-out the
+// place that mozilla #includes iomanip.h, since I don't
+// appear to actually need it to parse their file.
+
+// 2005-02-20: Now elsa accepts this!  (After adding a couple of
+// needed forward declarations.)  Maybe I was wrong about the grammar?
+// icc and gcc-3 both like it too.
+
+// 2005-02-27: I just figured this out.  The problematic syntax is
+// *not* allowed by the grannar of ISO/IEC 14882:1998(E), but *is*
+// allowed by the grammar of ISO/IEC 14882:2003(E).  My original
+// conclusion that the syntax was invalid was itself based on a
+// faulty grammar.  So now things are correct, I believe.
+
+
+class ios;
+class istream;
+class ostream;
+
+
+template<class TP> class smanip;
+
+template<class TP> class sapp {
+    ios& (*_f)(ios&, TP);
+public:
+    sapp(ios& (*f)(ios&, TP)) : _f(f) {}
+
+    smanip<TP> operator()(TP a)
+      { return smanip<TP>(_f, a); }
+};
+
+template<class TP>
+inline istream& operator>>(istream& i, const smanip<TP>& m);
+template<class TP>
+inline ostream& operator<<(ostream& o, const smanip<TP>& m);
+
+template <class TP> class smanip {
+    ios& (*_f)(ios&, TP);
+    TP _a;
+public:
+    smanip(ios& (*f)(ios&, TP), TP a) : _f(f), _a(a) {}
+
+    friend
+      istream& operator>> <>(istream& i, const smanip<TP>& m);  /* !!! */
+    friend
+      ostream& operator<< <>(ostream& o, const smanip<TP>& m);
+};
+
+
+
+
+
+
+template<class TP>
+inline istream& operator>>(istream& i, const smanip<TP>& m)
+{ (*m._f)(i, m._a); return i; }
+
+template<class TP>
+inline ostream& operator<<(ostream& o, const smanip<TP>& m)
+{ (*m._f)(o, m._a); return o;}
+
+
+
+
+template<class TP> class imanip;
+
+template<class TP> class iapp {
+    istream& (*_f)(istream&, TP);
+public:
+    iapp(istream& (*f)(istream&,TP)) : _f(f) {}
+
+    imanip<TP> operator()(TP a)
+       { return imanip<TP>(_f, a); }
+};
+
+template <class TP>
+inline istream& operator>>(istream&, const imanip<TP>&);
+
+template <class TP> class imanip {
+    istream& (*_f)(istream&, TP);
+    TP _a;
+public:
+    imanip(istream& (*f)(istream&, TP), TP a) : _f(f), _a(a) {}
+     
+    friend
+      istream& operator>> <>(istream& i, const imanip<TP>& m);
+};
+
+template <class TP>
+inline istream& operator>>(istream& i, const imanip<TP>& m)
+{ return (*m._f)( i, m._a); }
+
+ 
+ 
+ 
+ 
+template<class TP> class omanip; 
+
+template<class TP> class oapp {
+    ostream& (*_f)(ostream&, TP);
+public: 
+    oapp(ostream& (*f)(ostream&,TP)) : _f(f) {}
+     
+    omanip<TP> operator()(TP a)
+      { return omanip<TP>(_f, a); }
+};
+
+template <class TP>
+inline ostream& operator<<(ostream&, const omanip<TP>&);
+
+template <class TP> class omanip {
+    ostream& (*_f)(ostream&, TP);
+    TP _a;
+public:
+    omanip(ostream& (*f)(ostream&, TP), TP a) : _f(f), _a(a) {}
+     
+    friend
+      ostream& operator<< <>(ostream& o, const omanip<TP>& m);
+};
+
+template <class TP>
+inline ostream& operator<<(ostream& o, const omanip<TP>& m)
+{ return (*m._f)(o, m._a); }

Added: vendor/elsa/current/elsa/in/t0095.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0095.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0095.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0095.cc
+// unions with member functions
+
+union F {
+  F(){}
+  int foo();
+};

Added: vendor/elsa/current/elsa/in/t0096.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0096.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0096.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0096.cc
+// E_constructor as a constant
+
+typedef int PRInt32;
+enum { eHTMLTag_text=5 };
+class nsVoidArray;
+
+nsVoidArray* mObservers[PRInt32(eHTMLTag_text - 1)  + 1];

Added: vendor/elsa/current/elsa/in/t0097.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0097.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0097.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0097.cc
+// mismatch provoked by confusing qualification?
+        
+class nsFrameUtil {
+  //struct Node;
+  struct Tag;
+  struct Node {
+    static Node* Read(Tag* aTag);
+  };
+  struct Tag {};
+};
+
+nsFrameUtil::Node*
+nsFrameUtil::Node::Read(Tag* tag)
+{
+}
+

Added: vendor/elsa/current/elsa/in/t0098.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0098.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0098.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0098.cc
+// overloaded fn, one is virtual another is static
+
+class A {
+  virtual int foo(int);
+  static int foo(int,int);
+};
+
+int A::foo(int,int)
+{}

Added: vendor/elsa/current/elsa/in/t0099.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0099.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0099.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0099.cc
+// I claim something is ambiguous...
+// excerpt from gcc-2.95.3's ststream.h
+
+class streambuf;
+typedef int __ssize_t;
+
+struct _ios_fields
+{  
+    streambuf *_strbuf;
+};
+
+class ios : public _ios_fields {
+};
+
+class ostream : virtual public ios
+{
+};
+
+class strstreambuf {
+  int pcount();
+};
+
+class strstreambase : virtual public ios {
+};
+
+class ostrstream : public strstreambase, public ostream {
+    __ssize_t   pcount() { return ((strstreambuf*)_strbuf)->pcount(); }
+};

Added: vendor/elsa/current/elsa/in/t0100.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0100.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0100.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+class X {
+  int y;
+  void foo() {
+    X::y++;
+  }
+};

Added: vendor/elsa/current/elsa/in/t0101.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0101.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0101.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+struct Anon_struct_10 {
+  long int __pos;
+};
+extern int fsetpos(struct Anon_struct_10 const * __pos);

Added: vendor/elsa/current/elsa/in/t0102.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0102.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0102.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+typedef int *(*intpa3p_t)[3];
+typedef int *intpa3_t[3];
+
+int main() {
+  int x = 3;
+  intpa3_t f = {&x, &x, &x,};
+  intpa3p_t g = &f;
+  int y = *(*g)[1];
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0103.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0103.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0103.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+//-*-c++-*-
+//  extern "C++" {
+template <class _FLT> class complex;
+template <class _FLT> complex<_FLT>& __doapl (complex<_FLT>* ths, const complex<_FLT>& r);
+//  }

Added: vendor/elsa/current/elsa/in/t0104.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0104.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0104.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// ambiguity error message
+// -*-c++-*-
+
+typedef void *__gnuc_va_list;
+typedef __gnuc_va_list va_list;
+union my_error_arguments {
+    int i;
+    char *s;
+};
+void *foo(int);
+#pragma boxvararg("my_error",sizeof(union my_error_arguments))
+#pragma boxvararg("__my_error",sizeof(union my_error_arguments))
+void my_error(int severity, ...) {
+    va_list ap;
+    ( ap  = ((__gnuc_va_list) /*__builtin_next_arg*/foo (  severity ))) ;
+}

Added: vendor/elsa/current/elsa/in/t0105.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0105.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0105.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// demonstrates that stack-allocation constructors with multiple
+// arguments don't render correctly.
+class Goo {
+    public:
+    int a;
+};
+
+class RefBox {
+    public:
+    int x;                       
+    int &yref;                   
+    Goo &z;                      
+
+    RefBox(int x0, int &yref0, Goo &z0) : x(x0), yref(yref0), z(z0) {}
+};
+
+int main() {
+    Goo g;
+    g.a = 3;
+    int b = 4;
+    RefBox r(5, b, g);
+}

Added: vendor/elsa/current/elsa/in/t0106.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0106.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0106.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// demonstrates that you can't use the bool cond ( (whatever)) syntax
+// for constructing a variable inside a while condition
+int main() {
+  int whatever = 3;
+  int whoever(7);
+  int whichever[] = {1, 2, 3};
+  while (whatever) 14;
+  while (bool cond = whatever) 15;
+}

Added: vendor/elsa/current/elsa/in/t0107.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0107.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0107.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0107.cc
+// really evil ambiguity..
+
+template <class T>
+class Foo {
+  Foo& get();
+};
+
+template <class T>
+Foo<T> & Foo<T>::get()
+{}
+
+
+// bad interpretation, ruled out by unparenthesized greater-than
+//Foo<   T > &Foo < T   >::get()

Added: vendor/elsa/current/elsa/in/t0108.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0108.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0108.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0108.cc
+// simple template argument tests
+// needed for ostream.h, __default_alloc_template::reallocate
+
+template <int n>
+class Foo {
+public:
+  int x;
+  Foo() { x=n; }    // assign from template argument
+  int f();
+  int g();
+};
+
+template <int n>
+int Foo<n>::f()
+{
+  return n;
+}
+
+// should be legal to change parameter name, I think
+template <int m>
+int Foo<m>::g()
+{
+  return m;
+}
+
+int main()
+{
+  Foo<3> f;
+  f.f();
+  f.x;
+  
+  return f.g();
+}

Added: vendor/elsa/current/elsa/in/t0108b.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0108b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0108b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,43 @@
+// t0108.cc
+// simple template argument tests
+
+// this is a version of t0108.cc that doesn't attempt to change the
+// template parameter names between the declaration and definition of
+// the member function
+
+template <int n>
+class Foo {
+  public:
+  int x;
+  Foo() { x=n; }    // assign from template argument
+  int f();
+  int g();
+};
+
+template <int n>
+int Foo<n>::f()
+{
+  return n;
+}
+
+// NOTE: this name-change feature is not tested here; see t0108.cc
+// should be legal to change parameter name, I think
+//  template <int m>
+//  int Foo<m>::g()
+//  {
+//    return m;
+//  }
+template <int n>
+int Foo<n>::g()
+{
+  return n;
+}
+
+int main()
+{
+  Foo<3> f;
+  f.f();
+  f.x;
+  
+  return f.g();
+}

Added: vendor/elsa/current/elsa/in/t0109.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0109.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0109.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0109.cc
+// more template tests
+
+template <int n
+  //ERROR(1): , int n     // duplicate param
+  >
+class Foo {};
+
+class Bar {};
+
+class Zoo;     // incomplete class
+
+void f()
+{
+  // <3> is a template argument
+  new Foo< 3 > +4 > +5;
+
+  // <3> is not a template argument
+  new Bar< 3 > +4 > +5;
+  
+  // should be an error b/c Zoo is incomplete
+  //ERROR(2): new Zoo;
+}

Added: vendor/elsa/current/elsa/in/t0110.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0110.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0110.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0110.cc
+// more with templates; testing the clone impl
+
+typedef double A;
+
+template <class T>
+class Foo {
+public:
+  T x;
+  A d;    // should be double
+  
+  Foo<T> *fooptr;
+  Foo *fooptr2;
+};
+
+void f()
+{
+  typedef char *A;     // *not* seen by template definition
+
+  Foo<int> y;
+  Foo<int> z;
+
+  y.x + z.x;
+
+  y.d;                 // should be seen as having 'double' type
+  y.fooptr;            // type: Foo<int>*
+  y.fooptr2;           // type: Foo<int>*
+}
+

Added: vendor/elsa/current/elsa/in/t0111.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0111.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0111.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0111.cc
+// some nontype template arguments
+          
+template <int n>
+class Foo {
+public:
+  int arr[n];
+};
+
+void f()
+{
+  Foo<3> x;
+  Foo<1+2> y;   // same type!
+  Foo<2+2> z;   // different type!
+  x.arr;
+  y.arr;
+  z.arr;
+  
+  //ERROR(1): Foo<-5> w;    // negative array size not allowed
+}
+
+
+template <class T>
+class A {                    
+  // will be error if it thinks it knows the size of T
+  int arr[sizeof(T) - 10];
+};
+
+void g()
+{
+  typedef int blah[30];
+  A<blah> a;
+}

Added: vendor/elsa/current/elsa/in/t0112.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0112.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0112.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,51 @@
+// t0112.cc
+// some random problem..   
+
+
+template <class CharT>
+class SomeBase {};
+
+template <class CharT>
+class nsSharedBufferHandle : SomeBase<CharT>
+  {
+      void
+      AcquireReference() const
+        {
+          nsSharedBufferHandle<CharT>* mutable_this = 
+            const_cast<  nsSharedBufferHandle<CharT>*  >(  this ) ;
+          mutable_this->set_refcount( get_refcount()+1 );
+        }
+
+      void ReleaseReference() const;
+
+      bool
+      IsReferenced() const
+        {
+          return get_refcount() != 0;
+        }
+
+      void StorageLength( int aNewStorageLength )
+        {
+        }
+
+      int
+      StorageLength() const
+        {
+        }
+
+    protected:
+      int  mFlags;
+      int mStorageLength;
+
+      int
+      get_refcount() const
+        {
+          return 1;
+        }
+
+      int
+      set_refcount( int aNewRefCount )
+        {
+          return 1;
+        }
+  };

Added: vendor/elsa/current/elsa/in/t0113.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0113.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0113.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0113.cc
+// disambiguate dependent scope qual
+
+template <class T>
+class C {};
+
+template <class T>
+int f()
+{
+  typedef C<T> CT;
+  return CT::func1(T::func2(), T::func3());   // ambiguous: func or constructor
+}
+

Added: vendor/elsa/current/elsa/in/t0114.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0114.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0114.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0114.cc
+// overloaded decls in template classes
+
+// non-template class, as an initial control
+class Foo {
+      void addr(int &r) const;
+      void addr(int const &r) const;
+};
+
+// template class
+template <class T>
+class Bar
+{
+    public:
+      typedef T*         pointer;
+      typedef const T*   const_pointer;
+
+      typedef T&         reference;
+      typedef const T&   const_reference;
+
+
+      pointer
+      address( reference r ) const;
+
+      const_pointer
+      address( const_reference r ) const;
+      
+      void addr(int &r) const;
+      void addr(int const &r) const;
+};
+
+// force instantiation
+typedef Bar<unsigned short> blah;

Added: vendor/elsa/current/elsa/in/t0115.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0115.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0115.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0115.cc
+// stuff with template functions
+
+template <class T>
+void foo(T t)
+{
+  t;
+}
+
+void f()
+{
+  foo(3);
+  foo(3.4);
+}

Added: vendor/elsa/current/elsa/in/t0116.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0116.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0116.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0116.c
+// experimenting with overloading; be careful with line numbers!
+
+int foo(int i)    // line 4
+{
+  return i;
+}
+
+float foo(float f)  // line 9
+{
+  return f;
+}
+
+void notOverloaded() {}     // line 14
+
+void bar()
+{
+  __testOverload(notOverloaded(), 14);    // turn on overload resolution
+
+  __testOverload(foo(3), 4);
+  __testOverload(foo(3.4f), 9);
+}
+

Added: vendor/elsa/current/elsa/in/t0117.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0117.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0117.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,201 @@
+// t0117.cc
+// test 'getStandardConversion' in stdconv.cc
+
+// copied from stdconv.h
+enum StandardConversion {
+  SC_IDENTITY        = 0x00,  // types are identical
+
+  // conversion group 1 (comes first)
+  SC_LVAL_TO_RVAL    = 0x01,  // 4.1: int& -> int
+  SC_ARRAY_TO_PTR    = 0x02,  // 4.2: char[] -> char*
+  SC_FUNC_TO_PTR     = 0x03,  // 4.3: int ()(int) -> int (*)(int)
+  SC_GROUP_1_MASK    = 0x03,
+
+  // conversion group 3 (comes last conceptually)
+  SC_QUAL_CONV       = 0x04,  // 4.4: int* -> int const*
+  SC_GROUP_3_MASK    = 0x04,
+
+  // conversion group 2 (goes in the middle)
+  SC_INT_PROM        = 0x10,  // 4.5: int... -> int..., no info loss possible
+  SC_FLOAT_PROM      = 0x20,  // 4.6: float -> double, no info loss possible
+  SC_INT_CONV        = 0x30,  // 4.7: int... -> int..., info loss possible
+  SC_FLOAT_CONV      = 0x40,  // 4.8: float... -> float..., info loss possible
+  SC_FLOAT_INT_CONV  = 0x50,  // 4.9: int... <-> float..., info loss possible
+  SC_PTR_CONV        = 0x60,  // 4.10: 0 -> Foo*, Child* -> Parent*
+  SC_PTR_MEMB_CONV   = 0x70,  // 4.11: int Child::* -> int Parent::*
+  SC_BOOL_CONV       = 0x80,  // 4.12: various types <-> bool
+  SC_GROUP_2_MASK    = 0xF0,
+
+  SC_ERROR           = 0xFF,  // cannot convert
+};
+
+class Foo {};
+class Incomplete;
+enum Enum {};
+enum Enum2 {};
+
+class Base {};
+class Ambiguous {};
+class Amb1 : public Ambiguous {};     // workaround for inherent ambiguity
+class Amb2 : public Ambiguous {};     // of directly inheriting same class twice
+class Virtual {};
+class Derived : public Base, public Amb1, public Amb2,
+                virtual public Virtual {};
+
+void f()
+{
+  // identity
+  __getStandardConversion((int)0, (int)0, SC_IDENTITY);
+  __getStandardConversion((Foo)0, (Foo)0, SC_IDENTITY);
+  __getStandardConversion((Foo &)0, (Foo &)0, SC_IDENTITY);
+
+  // lval to rval
+  __getStandardConversion((int &)0, (int)0, SC_LVAL_TO_RVAL);
+  __getStandardConversion((int const &)0, (int)0, SC_LVAL_TO_RVAL);
+  __getStandardConversion((Foo &)0, (Foo)0, SC_LVAL_TO_RVAL);
+  __getStandardConversion((Foo const &)0, (Foo const)0, SC_LVAL_TO_RVAL);
+
+  // I can't tell if this is really supposed to be an error.. and
+  // for now my implementation doesn't classify it as such
+  //__getStandardConversion((Foo const &)0, (Foo)0, SC_ERROR);
+
+  // this now fails with a different error mode than SC_ERROR
+  //ERROR(1): __getStandardConversion((Incomplete &)0, (Incomplete)0, SC_ERROR);
+
+  // binding to references
+  __getStandardConversion((int)0, (int const &)0, SC_IDENTITY);
+  __getStandardConversion((int*)0, (int * const &)0, SC_IDENTITY);
+  __getStandardConversion((Foo)0, (Foo const &)0, SC_IDENTITY);
+  __getStandardConversion((Foo &)0, (Foo const &)0, SC_IDENTITY);
+  __getStandardConversion((Derived)0, (Derived const &)0, SC_IDENTITY);
+  __getStandardConversion((Derived)0, (Base const &)0, SC_PTR_CONV);
+                                                            
+  // binding an rvalue to a non-const reference
+  __getStandardConversion((Derived)0, (Derived &)0, SC_ERROR);
+  __getStandardConversion((Derived)0, (Base &)0, SC_ERROR);
+
+  // I'm inferring the following from the second example in
+  // section 13.3.3.2 para 3
+  __getStandardConversion((int&)0, (int const&)0, SC_IDENTITY);  // not SC_QUAL_CONV!
+  __getStandardConversion((int const&)0, (int&)0, SC_ERROR);
+  __getStandardConversion((int const&)0, (int const&)0, SC_IDENTITY);
+  __getStandardConversion((int &)0, (int &)0, SC_IDENTITY);
+
+  // array to pointer
+  extern int intArr[];
+  extern int const intArrC[];
+  __getStandardConversion((int [3])0, (int*)0, SC_ARRAY_TO_PTR);
+  __getStandardConversion(intArr, (int*)0, SC_ARRAY_TO_PTR);
+  __getStandardConversion("abc", (char const*)0, SC_ARRAY_TO_PTR);
+  __getStandardConversion(L"abc", (wchar_t const*)0, SC_ARRAY_TO_PTR);
+  __getStandardConversion("abc", (char*)0, SC_ARRAY_TO_PTR|SC_QUAL_CONV);
+
+  __getStandardConversion(intArrC, (int*)0, SC_ERROR);
+  __getStandardConversion((int (&)[])0, (int*)0, SC_ARRAY_TO_PTR);
+
+  // function to pointer
+  typedef int func(int*);
+  __getStandardConversion((func)0, (int (*)(int*))0, SC_FUNC_TO_PTR);
+  __getStandardConversion((func)0, (int (*)(int const*))0, SC_ERROR);
+
+  // qualification conversions
+  __getStandardConversion((int *)0, (int const *)0, SC_QUAL_CONV);
+  __getStandardConversion((int **)0, (int const * const *)0, SC_QUAL_CONV);
+  __getStandardConversion((int * const *)0, (int const * const *)0, SC_QUAL_CONV);
+  __getStandardConversion((int const **)0, (int const * const *)0, SC_QUAL_CONV);
+
+  __getStandardConversion((int **)0, (int const **)0, SC_ERROR);
+  __getStandardConversion((int const * const *)0, (int const **)0, SC_ERROR);
+  __getStandardConversion((int const * const *)0, (int * const *)0, SC_ERROR);
+  __getStandardConversion((int const * const *)0, (int **)0, SC_ERROR);
+
+  __getStandardConversion((int Foo::*)0, (int const Foo::*)0, SC_QUAL_CONV);
+  __getStandardConversion((int Foo::* *)0, (int const Foo::* const *)0, SC_QUAL_CONV);
+  __getStandardConversion((int * Foo::*)0, (int const * const Foo::*)0, SC_QUAL_CONV);
+  __getStandardConversion((int * Foo::*)0, (int const * Foo::*)0, SC_ERROR);
+
+  // integral promotions
+  __getStandardConversion((char)0, (int)0, SC_INT_PROM);
+  __getStandardConversion((signed char)0, (int)0, SC_INT_PROM);
+  __getStandardConversion((unsigned char)0, (int)0, SC_INT_PROM);
+  __getStandardConversion((short)0, (int)0, SC_INT_PROM);
+  __getStandardConversion((unsigned short)0, (int)0, SC_INT_PROM);
+  __getStandardConversion((wchar_t)0, (int)0, SC_INT_PROM);
+  __getStandardConversion((Enum)0, (int)0, SC_INT_PROM);
+  __getStandardConversion((bool)0, (int)0, SC_INT_PROM);
+
+  __getStandardConversion((int)0, (Enum)0, SC_ERROR);
+  __getStandardConversion((Enum2)0, (Enum)0, SC_ERROR);
+  __getStandardConversion((Enum)0, (Enum)0, SC_IDENTITY);
+
+  // TODO: test bitfields once they're implemented as distinct types
+
+  // floating point promotion
+  __getStandardConversion((float)0, (double)0, SC_FLOAT_PROM);
+
+  // integral conversions
+  __getStandardConversion((short)0, (unsigned)0, SC_INT_CONV);
+  __getStandardConversion((short)0, (long)0, SC_INT_CONV);
+  __getStandardConversion((long)0, (int)0, SC_INT_CONV);
+  __getStandardConversion((short)0, (char)0, SC_INT_CONV);
+  __getStandardConversion((short)0, (unsigned short)0, SC_INT_CONV);
+  __getStandardConversion((char)0, (signed char)0, SC_INT_CONV);
+  __getStandardConversion((bool)0, (char)0, SC_INT_CONV);
+
+  // floating point conversions
+  __getStandardConversion((float)0, (long double)0, SC_FLOAT_CONV);
+  __getStandardConversion((double)0, (float)0, SC_FLOAT_CONV);
+
+  // floating-integral conversions
+  __getStandardConversion((short)0, (float)0, SC_FLOAT_INT_CONV);
+  __getStandardConversion((float)0, (short)0, SC_FLOAT_INT_CONV);
+  __getStandardConversion((bool)0, (float)0, SC_FLOAT_INT_CONV);
+
+  // pointer conversions
+  __getStandardConversion(0, (int *)0, SC_PTR_CONV);
+  __getStandardConversion(0, (int const *)0, SC_PTR_CONV);
+  __getStandardConversion(0, (Foo *)0, SC_PTR_CONV);
+  __getStandardConversion(0, (Foo const * const *)0, SC_PTR_CONV);
+  __getStandardConversion(1, (int *)0, SC_ERROR);
+
+  __getStandardConversion((int *)0, (void *)0, SC_PTR_CONV);
+  __getStandardConversion((int const *)0, (void const *)0, SC_PTR_CONV);
+  __getStandardConversion((Foo *)0, (void *)0, SC_PTR_CONV);
+  __getStandardConversion((Foo const *)0, (void const *)0, SC_PTR_CONV);
+
+  __getStandardConversion((int const *)0, (void *)0, SC_ERROR);
+  __getStandardConversion((void *)0, (int *)0, SC_ERROR);
+  __getStandardConversion((Foo *)0, (int *)0, SC_ERROR);
+  __getStandardConversion((float *)0, (int *)0, SC_ERROR);
+
+  __getStandardConversion((Derived *)0, (Base *)0, SC_PTR_CONV);
+  __getStandardConversion((Derived const *)0, (Base const *)0, SC_PTR_CONV);
+  __getStandardConversion((Derived *)0, (Base const *)0, SC_PTR_CONV|SC_QUAL_CONV);
+  __getStandardConversion((Derived *)0, (Virtual *)0, SC_PTR_CONV);
+
+  __getStandardConversion((Base *)0, (Derived *)0, SC_ERROR);
+  __getStandardConversion((Derived *)0, (Ambiguous *)0, SC_ERROR);
+
+  // pointer to member conversions
+  __getStandardConversion(0, (int Foo::*)0, SC_PTR_MEMB_CONV);
+  __getStandardConversion(0, (int const Foo::*)0, SC_PTR_MEMB_CONV);
+
+  __getStandardConversion((int Base::*)0, (int Derived::*)0, SC_PTR_MEMB_CONV);
+  __getStandardConversion((int Base::*)0, (int const Derived::*)0, SC_PTR_MEMB_CONV|SC_QUAL_CONV);
+
+  __getStandardConversion((int Base::* *)0, (int Derived::* *)0, SC_ERROR);
+  __getStandardConversion((int Base::*)0, (float Derived::*)0, SC_ERROR);
+  __getStandardConversion((int Derived::*)0, (int Base::*)0, SC_ERROR);
+  __getStandardConversion((int Ambiguous::*)0, (int Derived::*)0, SC_ERROR);
+  __getStandardConversion((int Virtual::*)0, (int Derived::*)0, SC_ERROR);
+
+  // boolean conversions
+  __getStandardConversion((int)0, (bool)0, SC_BOOL_CONV);
+  __getStandardConversion((float)0, (bool)0, SC_BOOL_CONV);
+  __getStandardConversion((Enum)0, (bool)0, SC_BOOL_CONV);
+  __getStandardConversion((int *)0, (bool)0, SC_BOOL_CONV);
+  __getStandardConversion((int Foo::*)0, (bool)0, SC_BOOL_CONV);
+
+  __getStandardConversion((Foo)0, (bool)0, SC_ERROR);
+
+}

Added: vendor/elsa/current/elsa/in/t0118.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0118.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0118.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,220 @@
+// t0118.cc
+// test getImplicitConversion
+
+// copied from stdconv.h
+enum StandardConversion {
+  SC_IDENTITY        = 0x00,  // types are identical
+
+  // conversion group 1 (comes first)
+  SC_LVAL_TO_RVAL    = 0x01,  // 4.1: int& -> int
+  SC_ARRAY_TO_PTR    = 0x02,  // 4.2: char[] -> char*
+  SC_FUNC_TO_PTR     = 0x03,  // 4.3: int ()(int) -> int (*)(int)
+  SC_GROUP_1_MASK    = 0x03,
+
+  // conversion group 3 (comes last conceptually)
+  SC_QUAL_CONV       = 0x04,  // 4.4: int* -> int const*
+  SC_GROUP_3_MASK    = 0x04,
+
+  // conversion group 2 (goes in the middle)
+  SC_INT_PROM        = 0x10,  // 4.5: int... -> int..., no info loss possible
+  SC_FLOAT_PROM      = 0x20,  // 4.6: float -> double, no info loss possible
+  SC_INT_CONV        = 0x30,  // 4.7: int... -> int..., info loss possible
+  SC_FLOAT_CONV      = 0x40,  // 4.8: float... -> float..., info loss possible
+  SC_FLOAT_INT_CONV  = 0x50,  // 4.9: int... <-> float..., info loss possible
+  SC_PTR_CONV        = 0x60,  // 4.10: 0 -> Foo*, Child* -> Parent*
+  SC_PTR_MEMB_CONV   = 0x70,  // 4.11: int Child::* -> int Parent::*
+  SC_BOOL_CONV       = 0x80,  // 4.12: various types <-> bool
+  SC_GROUP_2_MASK    = 0xF0,
+
+  SC_ERROR           = 0xFF,  // cannot convert
+};
+
+// copied from implconv.h
+enum Kind {
+  IC_NONE,             // no conversion possible
+  IC_STANDARD,         // 13.3.3.1.1: standard conversion sequence
+  IC_USER_DEFINED,     // 13.3.3.1.2: user-defined conversion sequence
+  IC_ELLIPSIS,         // 13.3.3.1.3: ellipsis conversion sequence
+  IC_AMBIGUOUS,        // 13.3.3.1 para 10
+  NUM_KINDS
+} kind;
+
+
+struct A {
+};
+
+struct B {
+  B(A const &);                    // line 47
+};
+
+struct C : A {   operator int();   // line 50
+};
+
+
+struct D {
+  operator int();      // line 55
+  operator float();    // line 56
+};
+
+struct E {
+  operator char();     // line 60
+  operator float();    // line 61
+};
+
+struct F {
+  operator bool ();               // line 65
+  operator char ();               // line 66
+  operator signed char ();        // line 67
+  operator unsigned char ();      // line 68
+  operator short ();              // line 69
+  operator unsigned short ();     // line 70
+  operator int ();                // line 71
+  operator unsigned int ();       // line 72
+  operator long ();               // line 73
+  operator unsigned long ();      // line 74
+  operator float ();              // line 75
+  operator double ();             // line 76
+  operator long double ();        // line 77
+};
+
+class G {
+  operator A* ();                 // line 81
+  operator C* ();                 // line 82
+};
+
+class H {
+  operator A* ();                 // line 86
+  operator B* ();                 // line 87
+};
+
+class I {
+  operator int ();                // line 91
+  operator int& ();               // line 92
+}; 
+
+class J {
+  J(int);                         // line 96
+  J(long);                        // line 97
+};
+
+class L;
+class K {
+  K(L const &);                   // line 102
+};
+
+class L {
+  operator K ();                  // line 106
+};
+
+class L2;
+class K2 {
+  K2(L2 const &);                 // line 111
+};
+
+class L2 {
+  operator K2 ();                 // line 115
+  operator K2& ();                // line 116
+};
+
+// __getImplicitConversion(
+//   <expression with source type>,
+//   <expression with destination type>,
+//   <implicit conversion kind>,
+//   <standard conversion 1>,
+//   <line number of user-defined conversion, or 0 if none>,
+//   <standard conversion 2, or 0 if none>
+// )
+
+
+void f()
+{
+  // elementary conversions
+  __getImplicitConversion((int)0, (int)0,
+                          IC_STANDARD, SC_IDENTITY, 0, 0);
+  __getImplicitConversion((int)0, (int const &)0,
+                          IC_STANDARD, SC_IDENTITY,0,0);
+
+  // constructor conversions
+  A a;
+  B b(a);
+  C c;
+  __getImplicitConversion((A)a, (B)b,
+                          IC_USER_DEFINED, SC_IDENTITY, 47, SC_IDENTITY);
+  __getImplicitConversion((A&)a, (B)b,
+                          IC_USER_DEFINED, SC_IDENTITY, 47, SC_IDENTITY);
+  __getImplicitConversion((C&)c, (B)b,
+                          IC_USER_DEFINED, SC_PTR_CONV, 47, SC_IDENTITY);
+  __getImplicitConversion(c, (int)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 50, SC_IDENTITY);
+
+  // operator conversions
+  D d;
+  __getImplicitConversion(d, (int)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 55, SC_IDENTITY);
+  __getImplicitConversion(d, (float)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 56, SC_IDENTITY);
+
+  // int->char and float->char are both conversions, therefore it's ambiguous
+  __getImplicitConversion(d, (char)0,
+                          IC_AMBIGUOUS, 0,0,0);
+
+  E e;
+  // char->int is a promotion, therefore preferred
+  __getImplicitConversion(e, (int)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 60, SC_INT_PROM);
+  // float->double also a promotion
+  __getImplicitConversion(e, (double)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 61, SC_FLOAT_PROM);
+
+  F f;
+  __getImplicitConversion(f, (bool)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 65, SC_IDENTITY);
+  __getImplicitConversion(f, (unsigned short)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 70, SC_IDENTITY);
+  __getImplicitConversion(f, (double)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 76, SC_IDENTITY);
+                          
+  G g;
+  __getImplicitConversion(g, (A*)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 81, SC_IDENTITY);
+  __getImplicitConversion(g, (B*)0,
+                          IC_NONE, 0,0,0);
+  __getImplicitConversion(g, (C*)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 82, SC_IDENTITY);
+  __getImplicitConversion(g, (void*)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 81, SC_PTR_CONV);
+
+  H h;
+  __getImplicitConversion(h, (A*)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 86, SC_IDENTITY);
+  __getImplicitConversion(h, (B*)0,
+                          IC_USER_DEFINED, SC_IDENTITY, 87, SC_IDENTITY);
+  __getImplicitConversion(h, (void*)0,
+                          IC_AMBIGUOUS, 0,0,0);
+
+  I i;
+  int anInt;
+  __getImplicitConversion(i, anInt /*int&*/,
+                          IC_USER_DEFINED, SC_IDENTITY, 92, SC_IDENTITY);
+
+  J j(1);
+  __getImplicitConversion((int)0, (J)j,
+                          IC_USER_DEFINED, SC_IDENTITY, 96, SC_IDENTITY);
+  __getImplicitConversion((long)0, (J)j,
+                          IC_USER_DEFINED, SC_IDENTITY, 97, SC_IDENTITY);
+  __getImplicitConversion((float)0, (J)j,
+                          IC_AMBIGUOUS, 0,0,0);
+
+  // ambiguity between conversion operator and conversion constructor
+  L ell;
+  K k(ell);
+  __getImplicitConversion(ell, (K)k,
+                          IC_AMBIGUOUS, 0,0,0);
+
+  // ambiguity among 3: ambiguous conversion operator, and conversion constructor
+  L2 ell2;
+  K2 k2(ell2);
+  __getImplicitConversion(ell2, (K2)k2,
+                          IC_AMBIGUOUS, 0,0,0);
+
+}

Added: vendor/elsa/current/elsa/in/t0119.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0119.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0119.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0119.cc
+// check deep signature normalization
+
+int f(int (*)(int)) {}
+//ERROR(1): int f(int (*)(const int)) {}      // illegal redefinition
+
+
+int f(int (*)(int *)) {}
+int f(int (*)(const int *)) {}    // different

Added: vendor/elsa/current/elsa/in/t0120.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0120.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0120.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,83 @@
+// t0120.cc
+// trying to test overload.cc; be careful with line numbers!
+
+int f1();                                 // line 4
+int f1(int);                              // line 5
+
+int x1a = __testOverload(f1(), 4);
+int x1b = __testOverload(f1(2), 5);
+//ERROR(1): int x1c = f1(1,2);            // "no viable candidate"
+int x1d = __testOverload(f1(2.5), 5);
+
+int f1(short);                            // line 12
+
+//ERROR(2): int x1e = f1(2.5);            // "ambiguous"
+
+
+enum E1 { e1 };
+enum E2 { e2 };
+enum E3 { e3 };
+enum E4 { e4 };
+enum E5 { e5 };
+enum E6 { e6 };
+
+int f2(E1);                               // line 24
+int f2(E2);                               // line 25
+int f2(E3);                               // line 26
+int f2(E4);                               // line 27
+int f2(E5);                               // line 28
+int f2(E6);                               // line 29
+
+// this is intended to test the tournament algorithm
+int x2a = __testOverload(f2(e1), 24);
+int x2b = __testOverload(f2(e2), 25);
+int x2c = __testOverload(f2(e3), 26);
+int x2d = __testOverload(f2(e4), 27);
+int x2e = __testOverload(f2(e5), 28);
+int x2f = __testOverload(f2(e6), 29);
+
+
+int f3(int);                              // line 40
+int f3(...);                              // line 41
+
+// test ellipsis vs others
+int x3a = __testOverload(f3(), 41);
+int x3b = __testOverload(f3(2), 40);
+int x3c = __testOverload(f3(2.3), 40);
+int x3d = __testOverload(f3(2, 3), 41);
+
+
+int f4(int x = 5);                        // line 50
+int f4(float);                            // line 51
+
+int x4a = __testOverload(f4(), 50);
+int x4b = __testOverload(f4(3), 50);
+int x4c = __testOverload(f4(3.5f), 51);
+//ERROR(3): int x4d = f4(2,3);            // "no viable"
+
+
+class Src { public: Src(int); };
+struct Dest {
+  Dest(Src const &);                      // line 61
+  Dest(E1);                               // line 62 
+};
+
+int f5(int);                              // line 65
+int f5(Dest);                             // line 66
+int f5(E1);                               // line 67
+
+int x5a = __testOverload(f5(2), 65);          // no ctor is viable
+int x5b = __testOverload(f5(Dest(e1)), 66);   // SC_IDENTITY
+int x5c = __testOverload(f5(Src(2)), 66);     // convert via ctor
+int x5d = __testOverload(f5(e1), 67);         // ctor is viable, but not best
+
+
+
+
+
+
+
+
+
+
+// eof

Added: vendor/elsa/current/elsa/in/t0121.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0121.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0121.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0121.cc
+// based on 13.1a.cc
+
+class X {
+  static void f();
+  //ERROR(1): void f();                      // ill-formed
+  //ERROR(2): void f() const;                // ill-formed
+  //ERROR(3): void f() const volatile;       // ill-formed
+  void f(int);
+
+  void g();
+  void g() const;                // OK: no static g
+  void g() const volatile;       // OK: no static g
+  //ERROR(4): void g() const volatile;       // duplicate definition
+  //ERROR(5): void g() const;                // duplicate definition
+  //ERROR(6): void g();                      // duplicate definition
+};
+
+
+void X::f() {              // static
+  //ERROR(10): this;
+}
+void X::f(int) { this; }   // nonstatic
+
+void X::g() { this; }
+void X::g() const { this; }
+void X::g() const volatile { this; }
+
+//ERROR(7): void X::g() {}                   // redefinition
+//ERROR(8): void X::g() const {}             // redefinition
+//ERROR(9): void X::g() const volatile {}    // redefinition

Added: vendor/elsa/current/elsa/in/t0122.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0122.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0122.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// t0122.cc
+// member/non-member tests
+
+int f();
+
+//ERROR(1): int g() const;
+
+class X {
+  int h();
+  int h2() const;
+  int h3() volatile;
+
+  int (*i)();
+
+  int j(int k());
+
+  static int L();
+  friend int m();
+  
+  X();
+};
+
+
+int X::h() { this; }
+int X::h2() const { this; }
+//ERROR(2): int X::h3() {}    // type mismatch
+
+int X::L() {
+  //ERROR(3): this;      // not a nonstatic member
+}
+
+//ERROR(4): int X::m() {}    // does not exist
+
+X::X() {
+  // does not have a 'this' parameter, but there *is*
+  // a local variable called 'this'
+  this;
+}
+
+

Added: vendor/elsa/current/elsa/in/t0123.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0123.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0123.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// dsw: check pointer arithmetic
+
+// copied from stdconv.h
+enum StandardConversion {
+  SC_IDENTITY        = 0x00,  // types are identical
+
+  // conversion group 1 (comes first)
+  SC_LVAL_TO_RVAL    = 0x01,  // 4.1: int& -> int
+  SC_ARRAY_TO_PTR    = 0x02,  // 4.2: char[] -> char*
+  SC_FUNC_TO_PTR     = 0x03,  // 4.3: int ()(int) -> int (*)(int)
+  SC_GROUP_1_MASK    = 0x03,
+
+  // conversion group 3 (comes last conceptually)
+  SC_QUAL_CONV       = 0x04,  // 4.4: int* -> int const*
+  SC_GROUP_3_MASK    = 0x04,
+
+  // conversion group 2 (goes in the middle)
+  SC_INT_PROM        = 0x10,  // 4.5: int... -> int..., no info loss possible
+  SC_FLOAT_PROM      = 0x20,  // 4.6: float -> double, no info loss possible
+  SC_INT_CONV        = 0x30,  // 4.7: int... -> int..., info loss possible
+  SC_FLOAT_CONV      = 0x40,  // 4.8: float... -> float..., info loss possible
+  SC_FLOAT_INT_CONV  = 0x50,  // 4.9: int... <-> float..., info loss possible
+  SC_PTR_CONV        = 0x60,  // 4.10: 0 -> Foo*, Child* -> Parent*
+  SC_PTR_MEMB_CONV   = 0x70,  // 4.11: int Child::* -> int Parent::*
+  SC_BOOL_CONV       = 0x80,  // 4.12: various types <-> bool
+  SC_GROUP_2_MASK    = 0xF0,
+
+  SC_ERROR           = 0xFF,  // cannot convert
+};
+
+int main() {
+  int *p;
+  int *q;
+//    int *r = p + 1;
+  __getStandardConversion((int*)0, p + 1, SC_IDENTITY);
+//    int *s = 1 + p;
+  __getStandardConversion((int*)0, 1 + p, SC_IDENTITY);
+//    int i = p - q;
+  __getStandardConversion((int)0, p - q, SC_IDENTITY);
+}

Added: vendor/elsa/current/elsa/in/t0124.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0124.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0124.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0124.cc
+// some more tests of pointer-to-member
+
+class A {
+public:
+  int q(int);
+  int qc(int) const;
+  static int sq(int);
+};
+
+
+void f()
+{
+  int (A::*quint)(int);
+  int (A::*quintc)(int) const;
+  int (*squint)(int);
+
+  quint = &A::q;
+  //ERROR(1): quint = &(A::q);
+  quintc = &A::qc;
+  squint = &A::sq;
+  squint = &(A::sq);   // ok
+}

Added: vendor/elsa/current/elsa/in/t0125.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0125.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0125.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0125.cc
+// operator elaboration
+
+struct A {
+  int operator * ();
+};
+
+A a;
+
+void f()
+{
+  // un-elaborated
+  *a;
+
+  // elaborated
+  a.operator *();
+}

Added: vendor/elsa/current/elsa/in/t0126.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0126.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0126.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0126.cc
+// test overload resolution of member functions
+
+asm("collectLookupResults f=7 a=13 f=8 a=13");
+
+struct A {
+  int f();        // line 7
+  int f(int);     // line 8
+};
+
+void func()
+{
+  A a;            // line 13
+  a.f();
+  a.f(3);
+}

Added: vendor/elsa/current/elsa/in/t0127.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0127.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0127.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,107 @@
+// t0127.cc
+// some operator overload resolution tests
+
+class A {};
+
+class B : public A {
+public:
+  void operator+(A &a);             // 8
+};
+
+void operator+(A &a, A &b);         // 11
+void operator+(B &a, B &b);         // 12
+
+void some_random_crap();            // 14
+
+// the built-in operators are all non-functions, and 0 is my code for that
+enum { BUILTIN=0 };
+
+class C {
+public:
+  operator int ();                  // 21
+};
+
+class D {
+public:
+  operator int* ();                 // 26
+};
+
+class E {
+public:
+  operator int ();                  // 31
+  operator int* ();                 // 32
+  void operator-(A &a);             // 33
+};
+
+class F {
+public:
+  void operator* (F const &);       // 38
+  void operator/ (F const &);       // 39
+  void operator+ (F const &);       // 40
+  void operator- (F const &);       // 41
+  void operator< (F const &);       // 42
+  void operator> (F const &);       // 43
+  void operator<=(F const &);       // 44
+  void operator>=(F const &);       // 45
+  void operator==(F const &);       // 46
+  void operator!=(F const &);       // 47
+};
+
+void f()
+{
+  A a1,a2;
+  B b1,b2;
+  C c;
+  D d;
+  E e;
+  F f1,f2;
+
+
+  // turn on overload resolution
+  __testOverload(some_random_crap(), 14);
+
+  __testOverload(a1+a2, 11);
+
+  __testOverload(b1+b2, 12);
+
+  __testOverload(b1+a1, 8);
+
+  __testOverload(c+1, BUILTIN);
+  __testOverload(c+(char)1, BUILTIN);
+
+  __testOverload(d+1, BUILTIN);
+  __testOverload(1+d, BUILTIN);
+
+  //ERROR(1): __testOverload(e+1, BUILTIN);    // ambiguous
+
+  // BIN_MINUS
+  __testOverload(e-a1, 33);
+  __testOverload(c-1, BUILTIN);
+  __testOverload(d-1, BUILTIN);
+  __testOverload(d-d, BUILTIN);
+  //ERROR(2): __testOverload(1-d, BUILTIN);    // no viable
+
+  // these resolve to member functions
+  __testOverload(f1* f2, 38);
+  __testOverload(f1/ f2, 39);
+  __testOverload(f1+ f2, 40);
+  __testOverload(f1- f2, 41);
+  __testOverload(f1< f2, 42);
+  __testOverload(f1> f2, 43);
+  __testOverload(f1<=f2, 44);
+  __testOverload(f1>=f2, 45);
+  __testOverload(f1==f2, 46);
+  __testOverload(f1!=f2, 47);
+
+  // these resolve to the built-ins of 13.6 para 12
+  __testOverload(c* c, BUILTIN);
+  __testOverload(c/ c, BUILTIN);
+  __testOverload(c+ c, BUILTIN);
+  __testOverload(c- c, BUILTIN);
+  __testOverload(c< c, BUILTIN);
+  __testOverload(c> c, BUILTIN);
+  __testOverload(c<=c, BUILTIN);
+  __testOverload(c>=c, BUILTIN);
+  __testOverload(c==c, BUILTIN);
+  __testOverload(c!=c, BUILTIN);
+}

Added: vendor/elsa/current/elsa/in/t0128.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0128.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0128.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0128.cc
+// bind a 'C' to a 'A const &'
+// isolated by dsw
+
+struct A {};
+struct C : A {};
+C g();
+void f (const A & x);
+void f ();
+int main () {
+  f (g ());
+}

Added: vendor/elsa/current/elsa/in/t0129.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0129.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0129.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0129.cc
+// exercise the C comment pattern
+
+// strategy: intersperse the comments with numbers to add,
+// and then test at the end to see if we saw them all
+
+enum { x =
+
+/**/        1+
+/***/       2+
+/****/      3+
+/*****/     4+
+/******/    5+
+            6+
+/*
+*/
+            7+
+/**
+*/
+            8+
+/*
+**/
+            9+
+/**
+**/
+            10+
+
+//ERROR(1): 100+        // would make the wrong size
+
+0 };
+
+
+// the constant-evaluator knows how to deal with ?:, and the array
+// type checker knows that sizes must be non-negative, so if we miss
+// one then the size will be -1 and we'll get an error
+int arr[x==55? 1 : -1];

Added: vendor/elsa/current/elsa/in/t0130.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0130.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0130.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// t0130.cc
+// some specific cases where we want to allow 0-length arrays,
+// despite cppstd 8.3.4 para 1
+
+// dsw: I turned the 0-length ones off since I now allow them to get
+// the kernel through.  See in/gnu/dC0006.c
+
+// no
+// dsw: this failure is OFF: ERROR(1): int arr[0];
+// dsw: the negative version is tested below
+
+// ok
+int array[1];
+
+// no
+//ERROR(4): int negGlobalArr[-1];
+
+struct F {
+  // yes
+  int fieldArr[0];
+
+  // no
+  //ERROR(3): int negLengthArr[-1];
+};
+
+void f()
+{
+  // no
+  // dsw: this failure is OFF: ERROR(2): int localArr[0];
+  // dsw: might as well test the negative version though
+  //ERROR(2): int localArr[-1];
+  
+  // yes
+  int okLocalArr[1];
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0131.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0131.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0131.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0131.cc
+// experiment for structural delta..
+
+int q;
+
+struct Foo {
+  int x;
+  int y;
+  void f();
+};
+
+void Foo::f()
+{
+  x = 6;
+  y = x;
+}
+
+int g(Foo *f)
+{
+  f->x = 7;
+  f->f();
+  if (f->y)
+    q = 78;
+  return f->y;
+}
+
+void h()
+{
+  while (1) {
+    q = 8;
+    q = 9;
+  }
+}

Added: vendor/elsa/current/elsa/in/t0132.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0132.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0132.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,348 @@
+// t0132.cc
+// looking more closely at 13.6 para 14
+
+// For every T, where T is a pointer to object type, there exist
+// candidate operator functions of the form
+//
+//   ptrdiff_t operator-(T, T);
+
+
+struct Int {
+  operator int* ();        // line 11
+};
+
+struct Float {
+  operator float* ();      // line 15
+};
+
+// the built-in operators are all non-functions, and 0 is my code for that
+enum { BUILTIN=0 };
+void jekyl() { __testOverload(jekyl(), 20); }     // turn on operator overloading
+
+void f()                   // line 22
+{
+  Int i;
+  Float f;
+
+  // there is no candidate for this, since int* and float* do not convert
+  //ERROR(1): i-f;
+}
+
+
+
+
+
+
+
+struct Parent {};
+struct Child : Parent {};
+
+struct A {
+  operator Parent* ();        // line 41
+  operator Child* ();         // line 42
+};
+
+struct B {
+  operator Child* ();         // line 46
+};
+
+void g()
+{
+  A a;
+  B b;
+
+  // candidate operator-(Parent*,Parent*):                              
+  //   arg0: A -> Parent* is better than A -> Child* by 13.3.3 para 1
+  //         final bullet(SC_IDENTITY)
+  //   arg1: B -> Child* which can be converted to Parent* (SC_PTR_CONV)
+  //
+  // candidate operator-(Child*,Child*):
+  //   arg0: A -> Child* is only possibility (SC_IDENTITY)
+  //   arg1: B -> Child* (SC_IDENTITY)
+  //
+  // candidate operator-(Foo*,Foo*):
+  //   arg0: no viable conversion candidates
+  //   not viable
+  //
+  // arg0 comparison is indistinguishable, since they use different
+  // user-defined conversion operators
+  //
+  // arg1 comparison favors second candidate, because it's the same
+  // user-defined conversion operator, but the final standard
+  // conversion is better
+  //
+  // therefore the winner is
+  //   operator-(Child*,Child*)
+  a-b;
+}
+
+
+
+
+        
+
+
+
+
+
+
+struct C {
+  operator Parent* ();        // line 90
+};
+
+struct D {
+  operator Child* ();         // line 94
+};
+
+void h()
+{
+  C c;
+  D d;
+
+  // candidate operator-(Parent*,Parent*):
+  //   arg0: C -> Parent* (SC_IDENTITY);
+  //   arg1: B -> Child* which can be converted to Parent* (SC_PTR_CONV)
+  //
+  // candidate operator-(Child*,Child*):
+  //   arg0: no viable conversion
+  //   not viable
+  //
+  // candidate operator-(Foo*,Foo*):
+  //   not viable
+  //
+  // winner:
+  //   candidate operator-(Parent*,Parent*):
+  c-d;
+}
+
+
+
+
+
+
+
+
+class Child2 : public Parent {};
+
+struct E {
+  operator Child* ();         // line 128
+};
+
+struct F {
+  operator Child2* ();        // line 132
+};
+
+void i()
+{
+  E e;
+  F f;
+
+  // candidate operator-(Parent*,Parent*):
+  //   arg0: E -> Child* -> Parent* (SC_PTR_CONV)
+  //   arg1: F -> Child2* -> Parent* (SC_PTR_CONV)
+  //
+  // candidate operator-(Child*,Child*):
+  //   arg0: E -> Child* (SC_IDENTITY)
+  //   arg1: no viable conversion
+  //   not viable
+  //
+  // candidate operator-(Foo*,Foo*):
+  //   not viable
+  //
+  // winner:
+  //   candidate operator-(Parent*,Parent*):
+  //
+  // NOTE: gcc claims there is no candidate
+  e-f;
+}
+
+
+
+
+
+
+struct G {
+  operator int const * ();     // line 165
+};
+
+struct H {
+  operator int volatile * ();  // line 169
+};
+
+void j()
+{
+  G g;
+  H h;
+
+  // candidate operator-(int*,int*):
+  //   arg0: not viable
+  //   not viable
+  //
+  // candidate operator-(int const *, int const *):
+  //   arg0: SC_IDENTITY
+  //   arg1: not viable
+  //   not viable
+  //
+  // candidate operator-(int const volatile *, int const volatile *):
+  //   arg0: SC_QUAL_CONV
+  //   arg1: SC_QUAL_CONV
+  //
+  // winner:
+  //   candidate operator-(int const volatile *, int const volatile *):
+  //
+  // again, gcc thinks not
+  g-h;
+}
+
+
+
+
+
+struct I {
+  operator int const ** ();     // line 202
+};
+
+struct J {
+  operator int volatile ** ();  // line 206  
+};
+
+void k()
+{
+  I i;
+  J j;
+
+  // candidate operator-(int*,int*):
+  //   arg0: not viable
+  //   not viable
+  //
+  // candidate operator-(int**,int**):
+  //   arg0: not viable
+  //   not viable
+  //
+  // candidate operator-(int const **, int const **):
+  //   arg0: SC_IDENTITY
+  //   arg1: not viable
+  //   not viable
+  //
+  // candidate operator-(int const volatile **, int const volatile **):
+  //   arg0: not viable
+  //   not viable
+  //
+  // candidate operator-(int const volatile * const *, int const volatile * const *):
+  //   arg0: SC_QUAL_CONV
+  //   arg1: SC_QUAL_CONV
+  //
+  // winner:
+  //   candidate operator-(int const volatile * const *, int const volatile * const *)
+  i-j;
+}
+
+
+
+
+
+
+struct I2 {
+  operator int const * const * ();     // line 246
+};
+
+struct J2 {
+  operator int volatile * const * ();  // line 250
+};
+
+void k2()
+{
+  I2 i;
+  J2 j;
+
+  // candidate operator-(int const * const *, int const * const *):
+  //   arg0: SC_IDENTITY
+  //   arg1: not viable
+  //   not viable
+  //
+  // candidate operator-(int const volatile * const *, int const volatile * const *):
+  //   arg0: SC_QUAL_CONV
+  //   arg1: SC_QUAL_CONV
+  //
+  // winner:
+  //   candidate operator-(int const volatile * const *, int const volatile * const *):
+  //
+  // again, gcc thinks not
+  i-j;
+}
+
+
+
+// demonstration that gcc *does* have the right conversion rule
+void foo(int const volatile * const *);
+
+void goo()
+{
+  int const **p = 0;
+  foo(p);
+}
+
+
+
+
+
+
+struct K {
+  operator A* ();     // line 291
+};
+
+struct L {
+  operator B* ();     // line 295
+};
+
+void jjj()
+{
+  K k;
+  L l;
+
+  // LUB is void*, but that is not a pointer-to-object type
+  //ERROR(2): k-l;
+}
+
+
+
+
+typedef int (*funcPtr)();
+
+struct M {
+  operator funcPtr ();
+};
+
+struct N {
+  operator funcPtr ();
+};
+
+void mn()
+{
+  M m;
+  N n;
+
+  // LUB is a function pointer type, which is not pointer-to-object
+  //ERROR(3): m-n;
+}
+
+
+
+
+// example from my notes on the convertibility relation
+struct AA {
+  operator int* ();
+  operator float* ();
+};
+
+struct BB {
+  operator float* ();
+  operator char* ();
+};
+
+int ff()
+{
+  AA a;
+  BB b;
+  return a-b;     // overloaded operator call
+};

Added: vendor/elsa/current/elsa/in/t0133.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0133.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0133.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0133.cc
+// d0011.cc but with no templates
+
+struct A {};
+struct B {};
+struct C {
+  operator void **();
+};
+C f(B&);
+struct D {
+  static void g(A &, void **);
+  static void g(char *, void **);
+};
+int main () {
+  B x;
+  A y;
+  D::g(y, f(x));
+}

Added: vendor/elsa/current/elsa/in/t0134.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0134.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0134.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,112 @@
+// t0134.cc
+// test 'computeLUB'
+
+// codes from overload.h
+enum {
+  BAD=0,
+  OK=1,
+  AMBIG=2
+};
+
+//         A          .
+//        / \         .
+//       B   C        .
+//        \ / \       .
+//         E   D      .
+struct A {};
+struct B : A {};
+struct C : A {};
+struct E : B, C {};
+struct D : C {};
+
+//        F     G     .
+//        | \ / |     .
+//        | / \ |     .
+//        H     I     .
+//         \   /      .
+//          \ /       .
+//           J        .
+struct F {};
+struct G {};
+struct H : F, G {};
+struct I : F, G {};   
+struct J : H, I {};
+
+enum Enum1 {};
+enum Enum2 {};
+
+void f()
+{
+  // straightforward cv
+  __computeLUB((int*)0, (int*)0, (int*)0, OK);
+  __computeLUB((int*)0, (float*)0, 0, BAD);
+  __computeLUB((int*)0, (int const*)0, (int const*)0, OK);
+  __computeLUB((int volatile*)0, (int const*)0, (int volatile const*)0, OK);
+
+  // tricky cv
+  __computeLUB((int volatile **)0,
+               (int const **)0,
+               (int volatile const * const *)0, OK);
+
+  __computeLUB((int volatile * const *)0,
+               (int const * const *)0,
+               (int volatile const * const *)0, OK);
+
+  __computeLUB((int volatile **)0,
+               (int const * volatile *)0,
+               (int volatile const * const volatile *)0, OK);
+
+  // put some pointer-to-member into the cv mix
+  __computeLUB((int A::*)0, (int A::*)0, (int A::*)0, OK);
+  __computeLUB((int const A::*)0, (int A::*)0, (int const A::*)0, OK);
+  __computeLUB((int A::**)0, (int A::**)0, (int A::**)0, OK);
+
+  __computeLUB((int const A::**)0,
+               (int volatile A::**)0,
+               (int const volatile A::* const *)0, OK);
+
+  __computeLUB((int const A::* B::*)0,
+               (int volatile A::* B::*)0,
+               (int const volatile A::* const B::*)0, OK);
+
+  __computeLUB((int const C::* B::*)0,
+               (int volatile A::* B::*)0,
+               0, BAD);
+               
+  // this should actually yield 'int E::*', but I don't implement
+  // it properly
+  __computeLUB((int B::*)0, (int C::*)0, 0, BAD);
+
+  // basic inheritance stuff
+  __computeLUB((A*)0, (B*)0, (A*)0, OK);
+  __computeLUB((C*)0, (B*)0, (A*)0, OK);
+  __computeLUB((E*)0, (D*)0, (C*)0, OK);
+  __computeLUB((E*)0, (A*)0, (A*)0, OK);
+  __computeLUB((B*)0, (D*)0, (A*)0, OK);
+
+  // same, but play some games with cv qualification
+  __computeLUB((A const *)0, (B*)0, (A const *)0, OK);
+  __computeLUB((C*)0, (B volatile *)0, (A volatile *)0, OK);
+  __computeLUB((E const *)0, (D const *)0, (C const *)0, OK);
+  __computeLUB((B const *)0, (D volatile *)0, (A const volatile *)0, OK);
+
+  // with ambiguity
+  __computeLUB((H*)0, (G*)0, (G*)0, OK);
+  __computeLUB((H*)0, (I*)0, 0, AMBIG);
+  __computeLUB((F*)0, (J*)0, (F*)0, OK);
+  __computeLUB((J*)0, (I*)0, (I*)0, OK);
+
+  // across disconnected hierarchies
+  __computeLUB((F*)0, (A*)0, (void*)0, OK);
+  __computeLUB((H const *)0, (D volatile *)0, (void const volatile *)0, OK);
+  
+  // with enums
+  __computeLUB((Enum1)0, (Enum1)0, (Enum1)0, OK);
+  __computeLUB((Enum2)0, (Enum1)0, 0, BAD);
+  __computeLUB((void*)0, (Enum1)0, 0, BAD);
+  
+  // according to my spec for computeLUB, it's only relevant that
+  // this does *not* yield Enum1; if at some point it changes to
+  // yield int, that's ok (just change the test to match)
+  __computeLUB((int)0, (Enum1)0, 0, BAD);
+}

Added: vendor/elsa/current/elsa/in/t0135.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0135.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0135.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,54 @@
+// t0135.cc
+// experiments with operator<
+          
+enum E {};
+
+struct A {
+  operator short ();
+  operator E ();
+};
+
+void operator+ (E,E);
+
+void f()
+{
+  A a;
+  E e;
+
+  // candidate: operator<(int,int)
+  //   arg1: IC_AMBIGUOUS: can't decide between A->short->int and A->E->int
+  //   arg2: SC_INT_PROM
+  //
+  // candidate: operator<(E,E)
+  //   arg1: IC_USER_DEFINED: A->E
+  //   arg2: SC_IDENTITY
+  //
+  // winner by virtue of arg2:
+  //   candidate: operator<(E,E)
+  a + e;
+}
+
+
+
+struct B {
+  operator E();
+};
+
+void g()
+{
+  A a;
+  B b;
+
+  // candidate: operator<(int,int)
+  //   arg1: IC_AMBIGUOUS: can't decide between A->short->int and A->E->int
+  //   arg2: IC_USER_DEFINED: B->E->int
+  //
+  // candidate: operator<(E,E)
+  //   arg1: IC_USER_DEFINED: A->E
+  //   arg2: IC_USER_DEFINED: B->E
+  //
+  // winner by virtue of arg2:
+  //   candidate: operator<(E,E)
+  a + b;
+}
+

Added: vendor/elsa/current/elsa/in/t0136.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0136.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0136.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0136.cc
+// test op overloading with some enums
+
+enum E1 {};
+enum E2 {};
+enum E3 {};
+enum E4 {};
+enum E5 {};
+enum E6 {};
+
+void dummy();                 // line 11
+
+void operator+(E1,E1);        // line 13
+void operator+(E2,int);       // line 14
+void operator+(E2,E3);        // line 15
+
+void operator<(E1,E1);        // line 17
+
+void f()
+{
+  // turn on operator overloading
+  __testOverload(dummy(), 11);
+
+  E1 e1;
+  E2 e2;
+  E3 e3;
+  E4 e4;
+  E5 e5;
+  E6 e6;
+
+  __testOverload(e1+e1, 13);
+  __testOverload(e2+1, 14);
+  __testOverload(e2+e2, 14);
+  __testOverload(e2+e3, 15);
+  __testOverload(e3+e3, 0);
+
+  __testOverload(e1<e1, 17);
+  __testOverload(e1<e2, 0);
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0137.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0137.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0137.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0137.cc
+// overloading of operator[]
+  
+void dummy();               // line 4
+
+struct A {
+  int operator[] (int);     // line 7
+};
+
+
+void f()
+{
+  int *p;
+  A a;
+
+  // turn on overload resolution
+  __testOverload(dummy(), 4);
+
+  __testOverload(p[4], 0);      // built-in
+  __testOverload(a[4], 7);      // overloaded
+}
+
+
+// violate some operator[] rules
+//ERROR(1): void operator[](int x);     // not a member
+
+struct B {
+  //ERROR(2): static void operator[](int x);    // static
+  //ERROR(3): void operator[]();                // too few params
+  //ERROR(4): void operator[](int x, int y);    // too many params
+};
+
+
+
+
+

Added: vendor/elsa/current/elsa/in/t0138.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0138.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0138.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,75 @@
+// t0138.cc
+// testing cppstd 13.6 para 17
+  
+void dummy();            // line 4
+
+// unfortunately, what's here isn't a very good test because
+// nothing ensures the right conversions are chosen, etc; I
+// mostly watch the tracing output to verify my expectations..
+
+struct A {
+  operator int ();
+};
+
+struct B {
+  operator float ();
+};
+  
+struct C {
+  operator short ();
+  operator int ();
+};
+
+struct D {
+  operator char ();
+  operator short ();
+};
+
+struct E {
+  operator float ();
+  operator int ();
+};
+
+struct G {
+};
+
+void f()
+{
+  // turn on operator overloading
+  __testOverload(dummy(), 4);
+
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+  G g;
+
+  // ok
+  a%a;
+
+  // B->float->int
+  b%b;
+
+  // ok, because C->short requires a final promotion,
+  // whereas C->int does not
+  c%a;
+
+  // not ok because can't decide between two promotions
+  //ERROR(1): d%a;
+
+  // E->int is better for both
+  e%e;
+
+  // no conversions
+  //ERROR(2): g%g;
+
+  // round out the menagerie
+  a%a;
+  a&a;
+  a^a;
+  a|a;
+  a<<a;
+  a>>a;
+}
+

Added: vendor/elsa/current/elsa/in/t0139.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0139.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0139.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// t0139.cc
+// overloaded operator && and ||
+
+// turn on operator overloading
+void dummy();           // line 5
+void f1() { __testOverload(dummy(), 5); }
+
+struct A {
+  operator bool ();
+};
+
+void f2()
+{
+  A a;
+  __testOverload(a&&a, 0);    // built-in &&
+}
+
+struct B {
+  void operator&& (B const &b) const;    // line 19
+};
+
+void f3()
+{
+  B b;
+  __testOverload(b&&b, 19);
+
+  // no conversion from B to bool, nor from A to 'B const &'
+  //ERROR(1): b&&a;
+}
+
+bool operator&& (bool x, bool y);       // line 31
+
+void f4()
+{
+  A a;                                 
+  
+  // now this uses the user's operator function
+  __testOverload(a&&a, 31);
+}
+
+

Added: vendor/elsa/current/elsa/in/t0140.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0140.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0140.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,136 @@
+// t0140.cc
+// more operator- stuff
+
+// turn on operator overloading
+int dummy();           // line 5
+void ddummy() { __testOverload(dummy(), 5); }
+
+//        F     G     .
+//        | \ / |     .
+//        | / \ |     .
+//        H     I     .
+//         \   /      .
+//          \ /       .
+//           J        .
+struct F {};
+struct G {};
+struct H : F, G {};
+struct I : F, G {};   
+struct J : H, I {};
+
+
+struct HH {
+  operator H* ();
+};
+
+struct II {
+  operator I* ();
+};
+
+int f1()
+{
+  HH hh;
+  II ii;
+
+  // candidate: operator- (F*,F*);
+  //   arg0: H*->F* SC_PTR_CONV
+  //   arg1: I*->F* SC_PTR_CONV
+  //
+  // candidate: operator- (G*,G*);
+  //   arg0: H*->G* SC_PTR_CONV
+  //   arg1: I*->G* SC_PTR_CONV
+  //
+  // cannot decide
+  //ERROR(1): return hh-ii;     // ambiguous
+}
+
+
+// will still be ambiguous
+int operator- (void*, void*);
+
+int f2()
+{
+  HH hh;
+  II ii;
+
+  // candidate: operator- (F*,F*);
+  //   arg0: H*->F* SC_PTR_CONV
+  //   arg1: I*->F* SC_PTR_CONV
+  //
+  // candidate: operator- (G*,G*);
+  //   arg0: H*->G* SC_PTR_CONV
+  //   arg1: I*->G* SC_PTR_CONV
+  //
+  // candidate: operator- (void*, void*);
+  //   arg0: H*->void* SC_PTR_CONV
+  //   arg1: I*->void* SC_PTR_CONV
+  //
+  // cannot decide
+  //ERROR(2): return hh-ii;     // ambiguous
+}
+
+
+// but this changes everything!
+int operator- (HH&, II&);
+
+int f3()
+{
+  HH hh;
+  II ii;
+
+  // candidate: operator- (F*,F*);
+  //   arg0: H*->F* SC_PTR_CONV
+  //   arg1: I*->F* SC_PTR_CONV
+  //
+  // candidate: operator- (G*,G*);
+  //   arg0: H*->G* SC_PTR_CONV
+  //   arg1: I*->G* SC_PTR_CONV
+  //
+  // candidate: operator- (HH&, II&);
+  //   arg0: SC_IDENTITY
+  //   arg1: SC_IDENTITY
+  //
+  // winner:
+  //   operator- (HH&, II&);
+  return hh-ii;     // not ambiguous!
+}
+
+
+
+
+
+//         A          .
+//        / \         .
+//       B   C        .
+//      /     \       .
+//     E       D      .
+struct A {};
+struct B : A {};
+struct C : A {};
+struct D : C {};
+struct E : B {};
+
+struct BE {
+  operator B* ();
+  operator E* ();
+};
+
+struct CD {
+  operator C* ();
+  operator D* ();
+};
+
+int f4()
+{
+  BE be;
+  CD cd;
+  
+  // this should cause multiple instantiations of
+  //   operator- (A*,A*)
+  // though ultimately it's the only viable candidate, and
+  // the conversions are unambiguous
+  return be-cd;
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0141.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0141.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0141.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,95 @@
+// t0141.cc
+// test operator~
+
+// turn on operator overloading
+int dummy();             // line 5
+void ddummy() { __testOverload(dummy(), 5); }
+
+enum E1 {};
+enum E2 {};
+
+void operator~ (E1);     // line 11
+
+void f1()
+{
+  E1 e1;
+  E2 e2;
+  
+  __testOverload(~e1, 11);
+  __testOverload(~e2, 0);
+}
+
+
+struct A {
+  void operator~ ();     // line 24
+};
+  
+struct B {
+  operator int ();       // line 28
+};
+
+void f2()
+{
+  A a;
+  B b;
+  
+  __testOverload(~a, 24);
+  __testOverload(~b, 0);
+}
+
+
+
+struct C {
+  void operator~ ();     // line 43
+  operator char ();      // line 44
+};
+
+struct D {
+  void operator~ ();     // line 48
+  operator int ();       // line 49
+};
+
+void f3()
+{
+  C c;
+  D d;
+                         
+  // operator~ wins, because the conversion to char and then
+  // to int requires a promotion
+  __testOverload(~c, 43);       
+  
+  // operator~ still wins; operator int() is considered a conversion,
+  // whereas use of operator~ doesn't require any conversions
+  __testOverload(~d, 48);
+}
+
+
+
+// finish up some unary operators
+void operator+(C&);    // line 69
+void operator-(C&);    // line 70
+void operator!(C&);    // line 71
+
+void f4()
+{
+  C c;
+  E1 e1;
+
+  __testOverload(+c, 69);
+  __testOverload(-c, 70);
+  __testOverload(!c, 71);
+
+  __testOverload(+e1, 0);
+  __testOverload(-e1, 0);
+  __testOverload(!e1, 0);
+}
+
+
+
+// wrong # of arguments
+//ERROR(1): void operator!(C&,C&);
+
+
+
+
+

Added: vendor/elsa/current/elsa/in/t0142.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0142.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0142.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// t0142.cc
+// operator+
+
+// turn on operator overloading
+int dummy();             // line 5
+void ddummy() { __testOverload(dummy(), 5); }
+
+struct A {
+  operator void* ();
+};
+          
+typedef int (*FuncPtr)();
+struct B {
+  operator FuncPtr ();
+};
+
+struct C {
+  operator C* ();
+};
+
+struct D {
+  operator int ();
+};
+
+struct E {
+  operator C* ();
+  operator int ();
+};
+
+void f1()
+{
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+
+  +a;
+  +b;
+  +c;
+  +d;     
+  
+  // ambiguous
+  //ERROR(1): +e;
+}
+

Added: vendor/elsa/current/elsa/in/t0143.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0143.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0143.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,68 @@
+// t0143.cc
+// operator* (unary)
+
+// turn on operator overloading
+int dummy();             // line 5
+void ddummy() { __testOverload(dummy(), 5); }
+
+
+struct A {
+  operator int* ();
+};
+
+typedef int (*Func)();
+struct B {
+  operator Func ();
+};
+
+struct C {
+  operator void* ();
+};
+
+struct D {
+  operator void const* ();
+};
+
+struct E {
+  operator int();
+};
+
+
+void f1()
+{
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+  
+  *a;
+  *b;
+  //ERROR(1): *c;     // no built-in derefs void*
+  //ERROR(2): *d;     // nor void const* (etc.)
+  //ERROR(3): *e;     // nor non-pointers
+}
+
+
+// usual kind of thing
+struct F {
+  void operator* ();      // line 49
+  operator int* ();       // won't interfere
+};
+
+// this whacked!
+enum G {};
+void operator* (G);       // line 55
+
+void f2()
+{
+  F f;
+  G g;
+  
+  __testOverload(*f, 49);
+  __testOverload(*g, 55);
+}
+
+
+
+

Added: vendor/elsa/current/elsa/in/t0144.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0144.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0144.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,72 @@
+// t0144.cc
+// operator++
+
+// turn on operator overloading
+int dummy();                    // line 5
+void ddummy() { __testOverload(dummy(), 5); }
+
+struct A {
+  operator int& ();
+};
+
+struct B {
+  void operator++ ();           // line 13
+};
+
+struct C {
+  operator volatile int& ();
+};
+
+struct D {
+  operator int ();
+};
+
+struct E {
+  operator const int& ();
+};
+
+struct F {
+  void operator++ (int);        // line 29
+};
+
+struct G {
+  operator bool& ();        
+};
+
+struct H {
+  operator int*& ();
+};
+
+struct I {
+  operator int* volatile & ();
+};
+
+void f1()
+{
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+  F f;
+  G g;
+  H h;
+  I i;
+
+  ++a;                          // A::operator int& ()
+  __testOverload(++b, 13);      // B::operator ++ ()
+  ++c;                          // C::operator volatile int& ()
+  //ERROR(1): ++d;              // not an lvalue
+  //ERROR(2): ++e;              // can't unify with VQ T&
+  ++g;                          // deprecated but legal
+  ++h;
+  ++i;
+
+  __testOverload(f++, 29);      // F::operator ++ (int)
+  a++;
+  c++;
+  //ERROR(3): d++;              // not an lvalue
+  //ERROR(4): e++;              // can't unify with VQ T&
+  h++;
+  i++;
+}

Added: vendor/elsa/current/elsa/in/t0145.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0145.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0145.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,72 @@
+// t0145.cc
+// operator--, shamelessly copied from t0144.cc
+
+// turn on operator overloading
+int dummy();                    // line 5
+void ddummy() { __testOverload(dummy(), 5); }
+
+struct A {
+  operator int& ();
+};
+
+struct B {
+  void operator-- ();           // line 13
+};
+
+struct C {
+  operator volatile int& ();
+};
+
+struct D {
+  operator int ();
+};
+
+struct E {
+  operator const int& ();
+};
+
+struct F {
+  void operator-- (int);        // line 29
+};
+
+struct G {
+  operator bool& ();        
+};
+
+struct H {
+  operator int*& ();
+};
+
+struct I {
+  operator int* volatile & ();
+};
+
+void f1()
+{
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+  F f;
+  G g;
+  H h;
+  I i;
+
+  --a;                          // A::operator int& ()
+  __testOverload(--b, 13);      // B::operator -- ()
+  --c;                          // C::operator volatile int& ()
+  //ERROR(1): --d;              // not an lvalue
+  //ERROR(2): --e;              // can't unify with VQ T&
+  //ERROR(5): --g;              // not legal for --
+  --h;
+  --i;
+
+  __testOverload(f--, 29);      // F::operator -- (int)
+  a--;
+  c--;
+  //ERROR(3): d--;              // not an lvalue
+  //ERROR(4): e--;              // can't unify with VQ T&
+  h--;
+  i--;
+}

Added: vendor/elsa/current/elsa/in/t0146.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0146.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0146.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,63 @@
+// t0146.cc
+// operator=
+
+// 2005-08-09: It turns out most of this test is invalid because of
+// 13.3.1.2p4b2.  So I am replacing uses of operator= with calls to
+// 'assign', which behaves the way I had previously implemented
+// operator=, thus retaining some of this test's ability to test
+// overload resolution.
+int &assign(int &, int);
+int volatile &assign(int volatile &, int);
+
+// turn on operator overloading
+int dummy();                    // line 13
+void ddummy() { __testOverload(dummy(), 13); }
+
+struct A {
+  operator int& ();
+  // Elsa doesn't diagnose this anymore b/c of 'nonstandardAssignmentOperator'
+  //-ERROR(2): operator short& ();     // would create ambiguity
+};
+struct B {
+  operator int ();
+};
+
+struct C {
+  void operator= (int);       // line 26
+};
+
+// not a problem to have two conversion operators, if only
+// one of them can yield a reference
+struct D {
+  operator int& ();
+  operator int ();
+};
+
+struct E {
+  operator int volatile & ();
+};
+
+enum { ENUMVAL };
+
+void f1()
+{
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+
+  assign(a, b);        // was: "a = b"
+  __testOverload(c = b, 26);
+  //ERROR(1): b.operator int() = b;           // 'b' can't convert to an L&
+  assign(d, b);        // was: "d = b"
+  assign(e, 3);        // was: "e = 3"
+  
+  // similar to netscape test; hit all the operators
+  int mFlags;
+  mFlags = ENUMVAL;
+  mFlags *= ENUMVAL;
+  mFlags /= ENUMVAL;
+  mFlags += ENUMVAL;
+  mFlags -= ENUMVAL;
+}

Added: vendor/elsa/current/elsa/in/t0147.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0147.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0147.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0147.cc
+// inherit a conversion operator
+
+struct A {
+  operator int& ();
+};
+
+struct B : A {
+  operator int ();
+};
+
+int &assign(int &, int);
+
+void f1()
+{
+  B b;
+
+  // needs B to inherit A::operator int& ()
+  assign(b, 3);
+}

Added: vendor/elsa/current/elsa/in/t0148.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0148.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0148.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,52 @@
+// t0148.cc
+// operator+=, operator-= on pointer types
+// based on t0146.cc
+
+struct A {
+  operator int* & ();
+  //ERROR(2): operator short* & ();     // would create ambiguity
+};
+
+struct B {
+  operator int* ();
+};
+
+struct C {
+  void operator+= (int);      // line 15
+};
+
+// not a problem to have two conversion operators, if only
+// one of them can yield a reference
+struct D {
+  operator int* & ();
+  operator int* ();
+};
+
+struct E {
+  operator int* volatile & ();
+};
+
+enum { ENUMVAL };
+
+void f1()
+{
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+
+  a += 3;
+  a -= 3;
+  __testOverload(c += 3, 15);
+  //ERROR(1): b += 3;           // 'b' can't convert to a reference
+  d += 3;
+  d -= 3;
+  e += 3;
+  e -= 3;
+
+  // similar to netscape test
+  int *mFlags;
+  mFlags += ENUMVAL;
+  mFlags -= ENUMVAL;
+}

Added: vendor/elsa/current/elsa/in/t0149.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0149.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0149.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// t0149.cc
+// operator%
+
+struct A {
+  operator int& ();
+};
+
+struct Av {
+  operator int volatile & ();
+};
+
+struct B {
+  operator float& ();
+};
+
+struct Bad {
+  operator char ();            // RHS instantiation: int
+  operator unsigned char ();    // RHS instantiation: int
+};
+
+void f1()
+{
+  A a;
+  Av av;
+  B b;
+  Bad bad;
+
+  a %= 3;
+  av %= 3;
+  //ERROR(1): b %= 3;     // can't convert to reference-to-integral
+  
+  //ERROR(2): a %= bad;
+}
+
+

Added: vendor/elsa/current/elsa/in/t0150.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0150.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0150.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,92 @@
+// t0150.cc
+// operator= with correlated parameters
+
+// 2005-08-09: Had to change to operator== b/c of 13.3.1.2p4b2.
+
+//         A          .
+//        / \         .
+//       B   C        .
+//        \ /         .
+//         D          .
+struct A {};
+struct B : A {};
+struct C : A {};
+struct D : C {};
+enum E { E_VAL };
+
+struct Ap {
+  operator A* ();
+};
+
+struct Apr {
+  operator A* & ();
+};
+
+struct Apvr {
+  operator A* volatile & ();
+};
+
+struct Bp {
+  operator B* ();
+};
+
+struct Bpr {
+  operator B* & ();
+};
+
+struct Cp {
+  operator C* ();
+};
+
+struct Er {
+  operator E& ();
+};
+
+struct Apm {
+  operator int A::* ();
+};
+
+struct Apmr {
+  operator int A::* & ();
+};
+
+struct Bpm {
+  operator int B::* ();
+};
+
+struct Bpmr {
+  operator int B::* & ();
+};
+
+
+void f1()
+{
+  Ap ap;
+  Apr apr;
+  Apvr apvr;
+  Bp bp;
+  Bpr bpr;
+  Cp cp;
+  Er er;
+  Apm apm;
+  Apmr apmr;
+  Bpm bpm;
+  Bpmr bpmr;
+
+  apr == ap;
+  apvr == ap;
+  apr == ap;
+  //nerfed(1): ap.operator A*() == ap;       // lhs isn't reference
+  //nerfed(2): bpr == cp;      // would not be sound
+  bpr == bp;
+  apr == bp;
+
+  er == E_VAL;
+
+  bpmr == bpm;
+  bpmr == apm;    // inverted subtyping for ptr-to-member
+  //nerfed(3): apmr == bpm;    // violates inverted order
+
+}
+
+

Added: vendor/elsa/current/elsa/in/t0151.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0151.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0151.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,109 @@
+// ERR-MATCH: c312d480-2c8d-43ee-9d9d-13d900e51aa3
+
+// t0151.cc
+// operator->*
+
+//         A      D   .
+//        / \         .
+//       B   C        .
+//      /             .
+//     E              .
+struct A {};
+struct B : A {};
+struct C : A {};
+struct D {};
+struct E : B {};
+
+struct Ap {
+  operator A* ();
+};
+
+struct Apm {
+  operator int A::* ();
+};
+
+struct Bp {
+  operator B* ();
+};
+
+struct Bpm {
+  operator int B::* ();
+};
+
+struct Cp {
+  operator C* ();
+};
+
+struct CDpm {
+  operator int C::* ();
+  operator int D::* ();
+};
+
+struct ADp {
+  operator A* ();
+  operator D* ();
+};
+
+struct AEp {
+  operator A* ();
+  operator E* ();
+};
+
+struct BEp {
+  operator B* ();
+  operator E* ();
+};
+
+struct BCp {
+  operator B* ();
+  operator C* ();
+};
+
+void f1()
+{
+  Ap ap;
+  Apm apm;
+  Bp bp;
+  Bpm bpm;
+  Cp cp;
+  CDpm cdpm;
+  ADp adp;
+  AEp aep;
+  BEp bep;
+  BCp bcp;
+
+  ap->*apm;
+
+  bp->*bpm;
+
+  bp->*apm;
+
+  cp->*apm;
+
+  // both possible conversions for 'cdpm' yield classes that
+  // are not superclasses of B
+  //ERROR(1): bp->*cdpm;
+
+  // ADp::operator int D::* () isn't in a viable pair
+  adp->*apm;
+
+  // neither conversion for 'adp' yields a viable pair
+  //ERROR(2): adp->*bpm;
+
+  // these are all ambiguous, because all of the viable pairs
+  // are perfect conversions
+  //ERROR(3): aep->*apm;
+  //ERROR(4): bep->*apm;
+  //ERROR(5): bcp->*apm;
+
+  // one pair goes wrong way in inheritance hierarchy, the other is
+  // not related all
+  //ERROR(6): ap->*cdpm;
+
+  // repeat all the good ones, to exercise my instantiation cache
+  ap->*apm;
+  bp->*bpm;
+  bp->*apm;
+  cp->*apm;
+  adp->*apm;
+}

Added: vendor/elsa/current/elsa/in/t0152.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0152.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0152.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// t0152.cc
+// example from nsAtomTable involving operator[]
+
+// this failure is caused by incomplete overload resolution in the
+// presence of templates
+
+typedef unsigned int PRUint32;
+typedef unsigned short PRUint16;
+typedef PRUint16 PRUnichar;
+
+template <class CharT>
+class nsReadingIterator {
+};
+
+class nsAString {
+public:
+  typedef PRUnichar                         char_type;
+  typedef nsReadingIterator<char_type>      const_iterator;
+};
+
+class nsASingleFragmentString : public nsAString {
+public:
+  typedef const char_type*  const_char_iterator;
+
+  // this one appears first, and involves a template, so overload
+  // resolution of the BeginReading function call does not happen;
+  // the AST continues to look like a call to this one
+  const_iterator& BeginReading( const_iterator& I ) const;
+
+  // but this is the one that the operator[] implementation is
+  // expecting to use
+  const_char_iterator&
+  BeginReading( const_char_iterator& aResult ) const;
+
+  char_type operator[]( PRUint32 i ) const {
+    const_char_iterator temp;
+    return BeginReading(temp)[ i ];
+  }
+};

Added: vendor/elsa/current/elsa/in/t0153.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0153.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0153.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0153.cc
+// explicit ctor call expr, as RHS of assignment
+
+struct A {
+  A() {}
+  A(int x) {}
+};
+int main() {
+  int arg = 3;
+  A a;
+  (1, A(arg));   // test the ctor call alone
+  a = A(arg);
+}

Added: vendor/elsa/current/elsa/in/t0154.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0154.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0154.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// in/t0154.cc
+// attempting to minimize nsAtomTable.i failure:
+// mString(aStart.string())
+
+
+class nsAString {
+};
+
+class nsACString;
+
+
+template <class CharT>
+struct nsStringTraits {
+  typedef nsAString                 abstract_string_type;
+};
+
+template <>
+struct nsStringTraits<char> {
+  typedef nsACString                abstract_string_type;
+};
+
+
+template <class CharT>
+class nsReadingIterator {
+public:
+  // type: nsACString
+  typedef typename nsStringTraits<CharT>::abstract_string_type abstract_string_type;
+
+  const abstract_string_type& string() const;
+};
+
+
+class nsACString {
+public:
+  typedef char                              char_type;
+
+  typedef nsACString                        abstract_string_type;
+  typedef nsReadingIterator<char_type>      const_iterator;
+};
+
+
+class nsDependentCSubstring : public nsACString {
+public:
+  nsDependentCSubstring( const const_iterator& aStart,
+                         const const_iterator& aEnd )
+    : mString(aStart.string() /* type: nsACString& */)
+  {}
+
+  const abstract_string_type&  mString;    // type: nsACString&
+};

Added: vendor/elsa/current/elsa/in/t0155.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0155.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0155.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0155.cc
+// example from John Kodumal of a ctorVar not being set?
+// now fixed
+
+int z;
+
+class C {
+  int *y;
+  public:
+  C() { y = &z; }
+  virtual int *foo() { return y; }
+};
+
+int main() {
+  C *c = new C;
+  int *x;
+  x = c->foo();
+}

Added: vendor/elsa/current/elsa/in/t0156.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0156.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0156.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0156.cc
+// a variant of d0026.cc
+
+template <class T> struct F {};
+template <class T> struct I {
+  F<T> m;
+};
+
+// nasty: there is no fully-qualified name for 'char_type'!
+//
+// turn on the 'buildASTTypeId' tracing flag to see the solution work
+void foo()
+{
+  typedef short* char_type;
+  typedef F<char_type> f;
+  typedef I<char_type> i;
+}

Added: vendor/elsa/current/elsa/in/t0157.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0157.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0157.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0157.cc
+// very simple namespace example
+
+asm("collectLookupResults x=7");
+
+namespace N {
+  int x;               // line 7
+}
+
+int f()
+{
+  return N::x;
+}

Added: vendor/elsa/current/elsa/in/t0158.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0158.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0158.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0158.cc
+// define a function that was declared inside a namespace
+
+namespace N {
+  int f();
+  int x;
+}
+
+int N::f()
+{
+  // I can't find where the standard specifies that the body
+  // of N::f can see all of N, but I think it's safe to assume
+  // that it can, similar to how class methods work
+  return x;
+}

Added: vendor/elsa/current/elsa/in/t0159.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0159.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0159.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// t0159.cc
+// namespace alias
+
+asm("collectLookupResults x=7");
+
+namespace N1 {
+  int x;                 // line 7
+}
+
+namespace N2 = N1;
+
+int f()
+{
+  return N2::x;
+}
+
+
+// see what happens if I use a template name
+template <class T>
+struct S {
+  struct Q;
+};
+
+//ERROR(1): namespace N3 = S<int>;
+//ERROR(2): namespace N4 = S<int>::Q;

Added: vendor/elsa/current/elsa/in/t0160.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0160.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0160.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0160.cc
+// simple use of a "using declaration"
+
+namespace N {
+  int x;
+}
+
+int foo()
+{
+  using N::x;
+  return x;
+}
+

Added: vendor/elsa/current/elsa/in/t0161.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0161.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0161.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0161.cc
+// multiple introduction of alias base class members
+
+struct B {
+  int f();
+};    
+
+struct D : B {
+  using B::f;
+  //ERROR(1): using B::f;
+};

Added: vendor/elsa/current/elsa/in/t0162.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0162.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0162.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0162.cc
+// simple using directive
+
+asm("collectLookupResults x=7");
+
+namespace N {
+  int x;           // line 7
+}
+
+using namespace N;
+
+int foo()
+{
+  return x;        // N::x
+}

Added: vendor/elsa/current/elsa/in/t0163.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0163.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0163.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0163.cc
+// using directive example demonstrating difference between
+// "using" and "active using" edges
+
+asm("collectLookupResults g=13 x=8 g=13 x=26");
+
+namespace N {
+  int x;               // line 8
+}
+
+void foo()
+{
+  int g;               // line 13
+
+  // This puts a "using" edge from foo's scope to N.  But that
+  // is irrelevant because no one can nominate foo's scope using
+  // another using-directive.  (So I will probably not add it
+  // at all.)
+  //
+  // It also puts an "active using" edge from the global scope to N,
+  // and schedules that edge for removal once foo's scope is gone.
+  using namespace N;
+
+  g = x;               // N::x
+
+  int x;               // line 26
+  g = x;               // local variable x, since N::x as if at toplevel
+}
+

Added: vendor/elsa/current/elsa/in/t0164.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0164.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0164.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0164.cc
+// derived from t0078.cc, but with a ctor for hash
+
+//    struct hash2 {
+//      int x;
+//      //hash2(hash2 &other) /*: x(other.x)*/ {}
+//      hash2(hash2 &other);
+//    };
+
+// see also oink/Test/nested_no_def_constr1.cc
+// (5b1d3a6a-1520-4765-95d4-3f53516f4e13)
+
+struct Foo {
+  struct hash {
+    int x;
+    hash(hash &other) : x(other.x) {}
+    //hash(hash &other);
+  } hash;
+//    Foo(Foo &other) : hash(other.hash) {}
+};

Added: vendor/elsa/current/elsa/in/t0165.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0165.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0165.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0165.cc
+// specialization of nsCOMPtr
+        
+template <class T>
+class nsCOMPtr {
+  // nsCOMPtr === nsCOMPtr<T>
+};
+      
+// specialization
+template <>
+class nsCOMPtr<int> {
+  // nsCOMPtr === nsCOMPtr<int>
+  nsCOMPtr(nsCOMPtr<int> &blah);
+};

Added: vendor/elsa/current/elsa/in/t0166.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0166.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0166.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0166.cc
+// potential ambiguity in type lookup
+
+struct A {};
+
+struct B : A {};
+struct C : A {};
+
+struct D : B, C {
+  A *a;       // B::A or C::A?  but same type!
+};
+

Added: vendor/elsa/current/elsa/in/t0167.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0167.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0167.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0167.cc
+// variation on d0046.cc: specialization refers to its own
+// class using template arguments
+
+template <class T>
+struct B {};
+
+template <class T2>
+struct B<T2*> {
+  void g(B<T2*> &);
+};

Added: vendor/elsa/current/elsa/in/t0168.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0168.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0168.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0168.cc
+// in/big/nsAtomTable.i:9857:36: error: class `nsWritingIterator' isn't a template
+
+template <class CharT>
+class nsWritingIterator {
+public:
+  void f() {
+    nsWritingIterator<CharT> result(*this);
+  }
+};
+
+void f()
+{
+  nsWritingIterator<int> w;
+}

Added: vendor/elsa/current/elsa/in/t0169.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0169.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0169.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// t0169.cc
+// problem with scope of 'if' substatements?
+
+void f()
+{       
+  // are all three different decls, and therefore allowed?
+  // yes: cppstd 6.4 para 1
+
+  if (true)
+    int x;
+  else
+    int x;
+  int x;
+}
+
+
+// test switch statement as well (other part of 6.4 para 1)
+void g()
+{
+  switch (4)
+    int x;
+  int x;
+}
+
+
+// and 6.5 para 2
+void h()
+{
+  while (false)
+    int x;      
+
+  do
+    int x;
+  while (false);
+  
+  for ( ; false; )
+    int x;
+    
+  int x;
+}

Added: vendor/elsa/current/elsa/in/t0170.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0170.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0170.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// in/t0170.cc
+// isolated from nsAtomTable.i, this caused a problem with
+// an early version of separate-pass elaboration
+
+struct _IO_FILE_plus;
+
+extern struct _IO_FILE_plus _IO_2_1_stdin_;

Added: vendor/elsa/current/elsa/in/t0171.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0171.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0171.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0171.cc
+// test from Rob van Behren: Expression nonterm is ambiguous
+             
+
+template <class _T1, class _T2>
+struct pair {
+  pair(_T1, _T2);
+};
+
+template <class _T1, class _T2>
+inline pair<_T1, _T2> make_pair(const _T1& __x, const _T2& __y)
+{
+  return pair<_T1, _T2>(__x, __y);
+}

Added: vendor/elsa/current/elsa/in/t0172.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0172.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0172.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0172.cc
+// simplified version of t0171.cc, this one choosing the other
+// interpretation
+        
+int a,b,c,d;
+int foo()
+{
+  return a < b , c > (d);
+}

Added: vendor/elsa/current/elsa/in/t0173.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0173.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0173.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5 @@
+// t0173.cc
+// another from jrvb
+
+template<typename foo>
+class bar;

Added: vendor/elsa/current/elsa/in/t0174.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0174.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0174.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0174.cc
+// from jrvb
+
+int uselocale;
+namespace __gnu_cxx
+{
+  extern "C" int __uselocale;
+}

Added: vendor/elsa/current/elsa/in/t0175.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0175.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0175.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0175.cc
+// test from jrvb: definition of a static data member of a template
+// outside the body of the template-class declaration
+
+template <class T>
+class C {
+  static int x;
+};
+
+template <class T>
+int C<T>::x = 0;

Added: vendor/elsa/current/elsa/in/t0176.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0176.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0176.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0176.cc
+// templatized class member
+
+struct A {
+  template <class T>
+  void foo(T t);
+};
+

Added: vendor/elsa/current/elsa/in/t0177.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0177.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0177.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0177.cc
+// a weird "typename" thing
+
+class A {
+  typedef int foo;
+};
+
+void bar()
+{
+  typename A::foo();
+}

Added: vendor/elsa/current/elsa/in/t0178.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0178.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0178.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0178.cc
+// refer to a member template using "template" keyword in qualified name
+
+struct A {
+  template <class T>
+  struct B {
+    static int foo();
+    typedef int other;
+  };
+};
+
+int main()
+{
+  typedef A::template B<int>::other myother;
+  return A::template B<int>::foo();
+}
+

Added: vendor/elsa/current/elsa/in/t0179.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0179.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0179.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0179.cc
+// template, partially specialized to a template argument
+
+// this one uncovered all kinds of subtle errors in the
+// handling of template argument lists ...
+
+template <class S, class T>
+struct A {};
+        
+template <class T>
+struct B {};
+
+typedef int myint;
+
+template <>
+struct A<int, B<myint> >
+{};

Added: vendor/elsa/current/elsa/in/t0180.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0180.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0180.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+// t0180.cc
+// parse-time ambiguity of TemplateArgumentList
+
+
+// ----------------------
+// the following example contains an ambiguous
+// TemplateArgumentList, and the ambiguity survives
+// into the final parse
+
+// I've commented it out since I now don't allow
+// as large a syntax for non-template arguments
+// (at least for the moment)
+
+// 2005-03-13: can put it back now?
+
+
+namespace N {
+  // primary
+  template <class S, class T>
+  struct A { /*...*/ };
+
+  template <class S, int T>
+  struct Helper1 {};
+
+  typedef int myint;
+  enum foo { enumerator };
+
+  // specialization
+  template <>
+  struct A<int, Helper1<myint, enumerator<3> >
+  {};
+}
+
+
+// -----------------------------
+// the following example parses with an ambiguous
+// TemplateArgumentList, but the ambiguity is part of
+// a parse that then fails
+
+
+// primary
+template <typename A, typename T>
+struct Traits { /*...*/ };
+
+template <class S, class T>
+struct Helper1 {};
+
+template <int C>
+struct Helper2 {};
+
+// specialization
+template <typename A, typename B, int C>
+struct Traits<A, Helper1<B, Helper2<C> > >
+{};
+

Added: vendor/elsa/current/elsa/in/t0181.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0181.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0181.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0181.cc
+// templatized constructor!
+
+struct C {
+  template <class T>
+  C(T t);
+};
+    

Added: vendor/elsa/current/elsa/in/t0182.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0182.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0182.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// t0182.cc
+// ambiguity in ExpressionList
+
+
+// ------------------
+// in this section, the correct interpretation has 1 arg
+template <class S, class T>
+int a1(int d) 
+{ return d + sizeof(S) + sizeof(T); }
+
+typedef int b1;
+typedef int c1;
+
+int f1(int);
+
+int foo(int d1)
+{
+  return f1(a1<b1,c1>(d1));
+}
+
+
+// ------------------
+// in this section, the correct interpretation has 2 args
+
+int a2;
+int b2;
+int c2;
+
+int f2(int, int);
+
+int bar(int d2)
+{
+  return f2(a2<b2,c2>(d2));
+}
+
+
+// the parser thinks this looks like a global variable with
+// its ctor being called...
+//  template<typename _CharT, typename _Traits, typename _Alloc>
+//  inline void swap(basic_string<_CharT, _Traits, _Alloc>& __lhs,
+//                   basic_string<_CharT, _Traits, _Alloc>& __rhs)
+//  {
+//    __lhs.swap(__rhs);
+//  }

Added: vendor/elsa/current/elsa/in/t0183.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0183.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0183.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0183.cc
+// multi-yield DeclSpecifier
+
+// the declaration looks like a function prototype (which it is), 
+// but also looks like a declaration of a templatized static member
+// where "T&s" is the ctor argument
+
+// fixed by using (the already ambiguous) InitDeclarator in
+// TemplateDeclaration instead of splitting the two cases
+
+template<class T>
+int nothing(T &s);

Added: vendor/elsa/current/elsa/in/t0184.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0184.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0184.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0184.cc
+// template member out-of-line definition
+
+template <class S>
+struct C {
+  template <class T>
+  int foo(T *t);
+};
+
+template <class S>
+template <class T>
+int C<S>::foo(T *t)
+{
+  return 5 + sizeof(t);
+}

Added: vendor/elsa/current/elsa/in/t0185.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0185.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0185.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0185.cc
+// explicit specialization of template class constructor
+// cppstd 14.7.3 para 4
+
+template <class T>
+struct A {
+public:
+  A(const char *s);
+};
+                    
+// what if A<char> has already been instantiated?
+//typedef A<char> foo;
+
+// what if I leave out the "template <>"?  parse error...
+template <>
+A<char>::A(const char*);

Added: vendor/elsa/current/elsa/in/t0186.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0186.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0186.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0186.cc
+// Assertion failed: dt.funcSyntax, file cc_tcheck.cc line 2232
+
+template <class T>
+struct A {
+  int foo(int (T::*f)());
+  int (T::*m)();
+};

Added: vendor/elsa/current/elsa/in/t0187.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0187.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0187.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0187.cc
+// template class with template variable as the base
+// (this probably duplicates some other existing test..)
+
+template <class T>
+struct C : T {
+};
+
+struct B {
+  int a;
+};
+        
+template <class T>
+struct D {
+  C<T> c;
+};
+
+int foo()
+{
+  D<B> d;
+  return d.c.a;     // refers to B::a, since C<B> inherits B
+}
+

Added: vendor/elsa/current/elsa/in/t0188.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0188.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0188.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0188.cc
+// Assertion failed: asked for list element 0 (0-based) but list only
+// has 0 elements, file voidlist.cc line 43
+//
+// cause: instantating a template whose definition scope is no longer
+// on the scope stack
+
+namespace N {
+  template <class T>
+  struct C {
+    T *t;
+  };
+}
+
+int foo()
+{
+  N::C<int> c;
+  return *(c.t);
+}

Added: vendor/elsa/current/elsa/in/t0189.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0189.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0189.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0189.cc
+// nested class definition that appears outside its containing class
+
+struct A {
+  struct B;      // forward decl of nested class
+};
+
+struct A::B {
+  int x;
+};
+
+int foo()
+{
+  A::B b;
+  return b.x;
+}
+

Added: vendor/elsa/current/elsa/in/t0190.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0190.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0190.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0190.cc
+// constructor-style cast to an enumerated type that is inside a namespace;
+// this triggers construction of its fully qualified name, which used to
+// segfault because of an odd bug that pointlessly(?) made a certain scope
+// pointer NULL whenever it didn't correspond to a class
+
+namespace N          // not a class scope
+{
+  enum E { v };      // must use a typedef to name 'E'
+
+  E foo()
+  {
+    return E(0);     // constructor-style cast
+  }
+}

Added: vendor/elsa/current/elsa/in/t0191.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0191.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0191.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0191.cc
+// segfault: base->templateInfo->instantiations
+//
+// similar to t0189.cc, but it is a nested class of a
+// template class
+//
+// needed for ostream
+
+template <class T>
+struct A {
+  struct B;       // forward decl of nested class
+};
+
+template <class T>
+struct A<T>::B {
+  int x;
+};
+
+int foo()
+{
+  A<int>::B b;
+  return b.x;
+}

Added: vendor/elsa/current/elsa/in/t0192.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0192.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0192.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0192.cc
+// template function forward declarations
+
+template <class T>
+int foo(T *t);
+
+int g()
+{
+  int *x;
+  return foo/*<int>*/(x);     // should be able to deduce args
+}
+
+template <class T>
+int foo(T *t)
+{
+  return sizeof(*t) + sizeof(T);
+}
+
+

Added: vendor/elsa/current/elsa/in/t0193.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0193.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0193.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0193.cc
+// Assertion failed: ctor0, file cc_tcheck.cc line 1488
+// from ostream.i, around line 7010
+
+// one problem: a disambiguating error in one place prevents all
+// future additions to the environment from taking place
+
+namespace std {
+  template < typename _Category >
+  struct iterator
+  { };
+
+  template < typename _Iterator >
+  struct iterator_traits
+  { };
+}
+
+// it seems that 'using' is a necessary part of this testcase...
+using std::iterator_traits;
+using std::iterator;
+
+template < typename _Iterator >
+class __normal_iterator :
+  public iterator
+    < typename iterator_traits
+                 < _Iterator >
+                 ::iterator_category >
+{};
+
+template < typename _Iterator >
+inline __normal_iterator < _Iterator >
+operator+ (int __n,
+           const __normal_iterator < _Iterator > &__i)
+{
+  return __normal_iterator < _Iterator > (__i.base () + __n);
+}

Added: vendor/elsa/current/elsa/in/t0194.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0194.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0194.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0194.cc
+// namespaces: say "using Foo" when Foo is a class template
+
+namespace N {
+  template <class T>
+  struct C {
+    T *p;
+  };
+};
+  
+using N::C;
+
+// I should now be able to say C<int>, etc.  It's not clear exactly
+// how the standard implies this; none of its examples explicitly
+// show this usage.  Perhaps if I tracked down the precise meaning
+// of the standard's usage of "name" I might find it; but for now
+// I'm just relying on gcc's acceptance of the syntax.
+
+int *f()
+{
+  C<int> c;
+  return c.p;
+}
+
+// cppstd 7.3.3 para 5 disallows this
+//ERROR(1): using N::C<float>;
+

Added: vendor/elsa/current/elsa/in/t0195.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0195.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0195.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0195.cc
+// "default constructor" creation of a built-in type
+
+typedef int myint;
+
+void f()
+{
+  int i;
+  i = myint();      // invoke it like a default constructor; indeterminate value
+  
+  // should also work w/o the typedef
+  i = int();
+  
+  // this will be an error
+  //ERROR(1): i = int(4,5);
+}
+

Added: vendor/elsa/current/elsa/in/t0196.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0196.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0196.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0196.cc
+// constructor call and 'typename'
+
+class N {      // behaves like a namespace
+public:
+  class C {
+  public:
+    C();
+  };
+};
+
+void f()
+{
+  // normally, 'typename' would be used only in the body of
+  // a template, and in fact I don't know if it is legal to
+  // use it outside a template; but I will assume that it is
+
+  typename N::C();        // constructor call to make a temporary
+}

Added: vendor/elsa/current/elsa/in/t0197.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0197.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0197.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0197.cc
+// forward-declared template class, and the template param
+// names of the forward and actual decl are different
+
+// relevant cppstd parts:
+//   14.1 para 3: "... defines identifier ... in the scope of
+//                the template declaration", i.e. and not
+//                anywhere else
+//   14.1 para 10: compares default arguments in templates to
+//                 default arguments in functions, implicitly
+//                 suggesting similar rules, particularly w.r.t.
+//                 positional matching
+
+// forward, using parameter name "S"
+template <class S>
+class C;
+
+// create a pending instantiation
+C<float> *foo;
+
+// actual, using parameter name "T"
+template <class T>
+class C {
+public:
+  T *p;
+};
+
+// in fact, I have the same problem even if the first instantiation
+// happens later
+C<int> *bar;
+
+
+

Added: vendor/elsa/current/elsa/in/t0198.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0198.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0198.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0198.cc
+// some erroroneous code, related to t0197.cc
+
+template <class T> class A;
+            
+// parameter type mismatch
+//ERROR(1): template <int T> class A {};
+
+// too many parameters
+//ERROR(2): template <class S, class T> class A;

Added: vendor/elsa/current/elsa/in/t0199.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0199.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0199.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0199.cc
+// alpha conversion + default arguments
+
+template <int s, int t = s>
+class B;
+
+template <int z, int t> 
+class B {};

Added: vendor/elsa/current/elsa/in/t0200.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0200.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0200.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0200.cc
+// template type params with defaults
+
+template <class T = int>
+class C {};
+
+// should use the default argument
+C<> x;

Added: vendor/elsa/current/elsa/in/t0201.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0201.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0201.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0201.cc
+// specialize one parameter completely, leave behind one template parameter
+
+// primary: two parameters
+template <class S, class T>
+struct C
+{};
+
+// specialization: one (the first!) parameter
+template <class U>
+struct C<int, U> 
+{};
+
+// make use of the primary
+C<float,float> *p;
+
+// and also use the specialization
+C<int,float> *q;

Added: vendor/elsa/current/elsa/in/t0202.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0202.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0202.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0202.cc
+// member function of a template class accepting a ptr-to-member argument
+
+template <class T>
+class C {
+public:
+  void foo(  int (T::*mf)()  )
+  {  }
+};

Added: vendor/elsa/current/elsa/in/t0203.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0203.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0203.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0203.cc
+// tricky use of typename and lookups
+
+namespace M
+{
+  template <class T>
+  struct B {
+    typedef int myint;
+  };
+}
+
+namespace N
+{
+  using M::B;
+
+  template <class T>
+  struct C {
+    typename B<T>::myint a;      // dependent name
+  };
+}
+
+N::C<char> c;

Added: vendor/elsa/current/elsa/in/t0204.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0204.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0204.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0204.cc
+// a non-dependent name is not visible at the point of
+// instantiation, but it is visible within the original
+// template definition
+
+namespace N
+{
+  // name only visible in N
+  typedef int anotherint;
+
+  // this template uses 'anotherint'
+  template <class T>
+  struct C {
+    anotherint *b;        // non-dependent name
+  };
+}
+
+// but where we instantiate, 'anotherint' is not visible
+N::C<char> c;

Added: vendor/elsa/current/elsa/in/t0205.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0205.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0205.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0205.cc
+// instantiation leads to need for one name, while at the point
+// of instantiation there is a hiding name
+
+namespace N {
+  typedef float A;            // name we want to find; it's a type
+
+  template <class T>
+  struct B {
+    A x;                      // request for name "A" as a type in template body
+  };
+
+  struct C {
+    int A;                    // hiding name; it's not a type
+    B<int> y;                 // first instantiation
+  };
+}

Added: vendor/elsa/current/elsa/in/t0206.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0206.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0206.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0206.cc
+// Daniel's ptr-to-memberI.cc
+
+// illegal pointer to member declarations
+class A;
+
+int main() {
+  int A::*q;
+  //ERROR(1): int & A::*q2;                 // illegal
+}

Added: vendor/elsa/current/elsa/in/t0207.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0207.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0207.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0207.cc
+// default template type arguments
+
+template <class S, class T = int>
+class C {};
+
+C<float> c;

Added: vendor/elsa/current/elsa/in/t0208.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0208.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0208.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0208.cc
+// default type arg that demonstrates need to do bindings
+// before/during use of default args
+
+template <class S, class T = S*>
+class C {
+public:
+  T t_inst;
+};
+
+int f()
+{
+  // default argument ought to be 'int*'
+  C<int> x;
+  
+  int arr[ sizeof(x.t_inst) ];
+  
+  return 6;
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0209.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0209.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0209.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0209.cc
+// type equality with and w/o default args supplied
+
+template <class T = int>
+class C {};
+
+int f()
+{    
+  // these should have the same type
+  C<> *p;
+  C<int> *q;
+
+  // hence conversion between them should be identity
+  // (casts needed to avoid them being considered references...)
+  __getStandardConversion((C<>*)p, (C<int>*)q, 0 /*SC_IDENTITY*/);
+
+  return 8;
+}

Added: vendor/elsa/current/elsa/in/t0210.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0210.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0210.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// this is an example that Scott cooked up to demonstrate that greedy
+// instantiation of function members of class templates doesn't work
+
+// if function members of class templates are instantiated greedily
+// then this causes A to be instantiated with T=B and, since the
+// definition of f() has been seen (in this example, it is inlined),
+// the body of f().  However, since we have not finished typechecking
+// B, the member B::x (which is t->x in f() ) does not exist yet, and
+// typechecking fails.
+
+template <class T>
+struct A {
+  void f() {
+    T *t;// = new T;               // pointer
+    t->x = 0;
+  }
+};
+
+struct B {                      // nsAString in nsAtomTable.i
+  A<B> ab;                      // no pointer
+  int x;                        // field we need in the body of f()
+};
+
+int main() {
+  B b;
+  b.ab.f();
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0211.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0211.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0211.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// Same as t0210.cc except that the body of the function member of the
+// templatized class is pulled out-of-line
+
+template <class T>
+struct A {
+  void f();
+};
+
+template <class T>
+void A<T>::f()
+{
+  T *t;                         // pointer
+  t->x = 0;
+}
+
+struct B {                      // nsAString in nsAtomTable.i
+  A<B> ab;                      // no pointer
+  int x;                        // field we need in the body of f()
+};
+
+int main() {
+  B b;
+  b.ab.f();
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0212.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0212.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0212.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// another version of t0210.cc where in the body of f() we have a
+// stack-allocated T instead of a pointer to one
+
+template <class T>
+struct A {
+  void f();
+};
+
+template <class T>
+void A<T>::f()
+{
+  T t;                          // NOTE: no pointer
+  t.x = 0;
+}
+
+struct B {
+  A<B> ab;                      // no pointer
+  int x;                        // field we need in the body of f()
+};
+
+int main() {
+  B b;
+  b.ab.f();
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0213.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0213.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0213.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// another version of t0210.cc; attempt to cause a problem by calling
+// f() in B in a function body before getting to x
+
+template <class T>
+struct A {
+  int f();
+};
+
+template <class T>
+int A<T>::f()
+{
+  T t;                          // no pointer
+  t.x = 0;
+  return 0;
+}
+
+struct B {
+  A<B> ab;                      // no pointer
+  B() {
+    // NOTE: still too soon to instantiate f()!  this will be done on
+    // the second pass throught the class members so we are OK.
+    int y = ab.f();
+  }
+
+  int x;                        // field we need in the body of f()
+};
+
+int main() {
+  B b;
+  b.ab.f();
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0214.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0214.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0214.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// unlike t0231.cc, this does compile in g++, but only because the
+// '*p' allows for delay in instantiating A<B> during the compilation
+// process; since we do not delay instantiating class templates in
+// elsa/ccparse, this does NOT compile
+
+template <class T>
+struct A {
+  // NOTE: 'q' is not a typedef; it is a normal variable of some
+  // strange type
+  typename T::theType q;
+};
+
+struct B {
+  A<B> *ab_p;                   // pointer
+  typedef int theType;
+};
+
+int main() {
+  B b;
+}

Added: vendor/elsa/current/elsa/in/t0215.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0215.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0215.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// here is an example of a program that makes sense and yet does not
+// compile with g++ anyway; this also does not compile in elsa/ccparse
+// for the same reason.
+
+template <class T>
+struct A {
+  // NOTE: 'q' is not a typedef; it is a normal variable of some
+  // strange type
+  typename T::theType q;
+};
+
+struct B {
+  A<B> ab;                      // no pointer
+  typedef int theType;
+};
+
+int main() {
+  B b;
+}

Added: vendor/elsa/current/elsa/in/t0216.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0216.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0216.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// check that delayed instantiation of function members of templatized
+// classes works in the presence of inner classes
+
+template <class T>
+struct A {
+  struct C {                    // inner class makes scope stack of f() interesting
+    void foo() {
+      // refer to T::x to test A<B> below really instantiates A<B>
+      int q = T::x;
+      // refer to z to test that function body tcheck is delayed
+      int y = z;
+    }
+    // put Z in C to test that the PartialScopeStack mechanism for
+    // delayed template instantiation works
+    int z;
+  };
+};
+
+struct B {                      // nsAString in nsAtomTable.i
+  A<B>::C abc;                  // no pointer
+  int x;                        // field we need in the body of f()
+};
+
+int main() {
+  B b;
+  b.abc.foo();
+}

Added: vendor/elsa/current/elsa/in/t0217.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0217.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0217.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0217.cc
+// two gotos to the same target (!)
+
+void f()
+{
+  int x;
+  
+lab:       
+  if (x == 3) {
+    goto lab;
+  }
+  
+  if (x == 4) {
+    goto lab;
+  }
+}

Added: vendor/elsa/current/elsa/in/t0218.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0218.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0218.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0218.cc
+// template class with template constructor
+// needed for iostream
+
+template <class S>
+struct A {
+  // inline templatized constructor
+  template <class T>
+  A(A<T> const &obj)
+  {}
+};
+
+//  void foo()
+//  {
+//    A<int> a;        // instantiate A<int>
+//    A<float> b(a);   // instantiate A<float> and A<float>::A<int>()
+//  }
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0219.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0219.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0219.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0219.cc
+// more nested template members; more extensive version of t0184.cc
+
+template <class S>
+struct A {
+  S *s;
+
+  // out-of-line implementation
+  template <class T>
+  int f(T *t);
+
+  template <class T>
+  int g(T *t)
+  {
+    return 5;
+  }
+};
+
+template <class S>
+template <class T>
+int A<S>::f(T *t)
+{
+  return 6;
+}
+
+void foo()
+{
+  A<int> a;     // instantiate A<int>
+
+  float x;
+  a.f(&x);      // instantiate A<int>::f<float>
+
+  a.g(&x);      // instantiate A<int>::g<float>
+}

Added: vendor/elsa/current/elsa/in/t0220.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0220.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0220.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0220.cc
+// partial specialization of a class template,
+// specialized for use with another template.
+// needed for iostream
+
+template <class S>
+struct A {};
+
+template <class T>
+struct B {
+  void f();
+};
+
+// specialization of B when used with A
+template <class U>
+struct B< A<U> > {
+  void g();
+};
+
+void foo()
+{
+  B<int> b1;          // use the primary
+  b1.f();
+
+  B< A<int> > b2;     // use the specialization
+  b2.g();
+}

Added: vendor/elsa/current/elsa/in/t0221.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0221.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0221.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// t0221.cc
+// simple use of dependent name from pseudo-instantiation
+
+template <class S>
+class A {
+  typedef S *someType;
+  
+  enum E { someValue=4 };
+};
+
+template <class T>
+class B {
+  typename A<T>::someType x;         // 'someType' is a dependent name
+};
+
+void f()
+{
+  // so 'b.x' has type 'int*'
+  B<int> b;
+
+  __getStandardConversion(b.x, (int*&)0, 0 /*SC_IDENTITY*/);
+}
+
+
+template <class T>
+int foo(T *t)
+{
+  return A<T>::someValue;            // 'someValue' is a dependent name
+}
+
+int g()
+{
+  float *x;
+  return foo(x);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0222.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0222.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0222.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+// t0222.cc
+// scope introduction from qualified-id, with template classes
+
+// primary
+template <class S>
+struct A {
+  enum E { value };
+  int func(E e);
+};
+
+// partial specialization
+template <class T>
+struct A<T*> {
+  enum F { value2 };
+  int func(F f);
+};
+
+
+// definition of primary func
+template <class S>
+int A<S>::func(E e)    // note that 'E' refers to 'A<S>::E'
+{
+  return 3;
+}
+
+// definition of specialization func
+template <class T>
+int A<T*>::func(F f)   // note that 'F' refers to 'A<T*>::F'
+{
+  return 4;
+}
+
+
+// instantiate them
+void foo()
+{
+  A<int> a1;
+  a1.func(A<int>::value);
+  
+  A<int*> a2;
+  a2.func(A<int*>::value2);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0223.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0223.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0223.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0223.cc
+// return by value an instance of a PseudoInstantiation
+
+template <class T>
+struct C {
+  C(T *x);    
+};
+
+template <class T>
+C<T> foo(T *x)
+{
+  return C<T>(x);
+}

Added: vendor/elsa/current/elsa/in/t0224.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0224.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0224.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0224.cc
+// template with conversion operator yielding dependent type
+
+template <class T>
+struct A {};
+
+template <class T>
+struct B {
+  operator A<T>* ()
+    { return 0; }
+    
+  // and a variable with dependent type ..
+  A<T> &foo;
+};
+
+void f()
+{
+  B<int> b;
+  b.operator A<int>* ();
+}

Added: vendor/elsa/current/elsa/in/t0225.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0225.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0225.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0225.cc
+// template with conversion operator yielding dependent type
+// even simpler version of t0224.cc
+
+template <class T>
+struct A {
+  operator void*();
+  operator T*();
+};
+
+void foo()
+{
+  A<int> a;
+  a.operator void* ();
+  a.operator int* ();
+}
+

Added: vendor/elsa/current/elsa/in/t0226.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0226.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0226.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0226.cc
+// explicit call to overloaded conversion operators
+// this is a simplified version of t0225.cc
+
+struct A {
+  operator void*();
+  operator int*();
+};
+
+void foo()
+{
+  A a;
+  a.operator void* ();
+  a.operator int* ();
+  //ERROR(1): a.operator char* ();     // not declared
+}
+

Added: vendor/elsa/current/elsa/in/t0227.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0227.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0227.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0227.cc
+// some experiments with the "partial scope stack"
+
+namespace N {
+  // eat templ inst scope
+  template <class T>
+  struct C {
+    int f() {
+      return 2;
+    }
+
+    inline int g();
+  };
+
+  // has DF_INLINE but the definition is actually out of line  
+  template <class T>
+  int C<T>::g()
+  {
+    return 3;
+  }
+}
+
+namespace M {
+  void func()
+  {
+    N::C<int> c;
+    c.f();
+    c.g();
+  }
+}
+

Added: vendor/elsa/current/elsa/in/t0228.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0228.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0228.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0228.cc
+// test a recent fix to 'computeArraySizeFromLiteral'
+
+void f()
+{
+  char sName[] = "SOAPPropertyBag";
+  char arr[16];
+
+  // should be same type
+  __elsa_checkType(sName, arr);
+
+  // not the same type!
+  char const arr2[16];
+  //ERROR(1): __elsa_checkType(sName, arr2);
+  
+  // this is not a legal type
+  // UPDATE: dsw: I moved this test to t0228b.cc so I can turn it off
+  // in the presence of GNU
+  //ERROR - OFF - (2): char arr3[];
+}

Added: vendor/elsa/current/elsa/in/t0228b.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0228b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0228b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0228b.cc
+
+// dsw: this is the part of t0228.cc that should not be an error in
+// GNU mode
+
+void f()
+{
+  // this is not a legal type
+  //ERROR(2): char arr3[];
+}

Added: vendor/elsa/current/elsa/in/t0229.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0229.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0229.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0229.cc
+// function template with complete specialization
+
+template <class T>
+int foo(T *t)
+{
+  return 2;
+}
+
+template <>
+int foo<int>(int *t)
+{
+  return 3;
+}
+
+void f()
+{
+  int *i;
+  float *f;
+         
+  foo(f);      // use primary
+  foo(i);      // use specialization
+}

Added: vendor/elsa/current/elsa/in/t0230.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0230.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0230.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0230.cc
+// function template overloadings that differ only in constness under pointer
+// needed for ostream.h, __copy_aux2
+
+// overloading 0: most general
+template <class S>
+int foo(S x)                      // line 7
+{
+  return 1;
+}
+
+// overloading 1: pointer to non-const
+template <class T>
+int foo(T *x)                     // line 14
+{
+  return 2;
+}
+
+// overloading 2: pointer to const
+template <class T>
+int foo(T const *x)               // line 21
+{
+  return 3;
+}
+
+// use them
+void f()
+{
+  int x;
+  int *y;
+  int const *z;
+
+  __testOverload(foo(x), 7);        // use 0
+  __testOverload(foo(y), 14);       // use 1
+  __testOverload(foo(z), 21);       // use 2
+}

Added: vendor/elsa/current/elsa/in/t0231.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0231.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0231.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0231.cc
+// func template defn and inst within a namespace
+
+namespace N {
+  template <class T>
+  int foo(T *t)
+  {
+    return 2;
+  }
+  
+  void g()
+  {
+    int *x;
+    foo(x);
+  }
+}
+

Added: vendor/elsa/current/elsa/in/t0232.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0232.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0232.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0232.cc
+// template class with out-of-line member defn having different
+// template parameter lists
+
+template <class T1>
+struct A {
+  int foo(T1 *t1)        // throw in an inline defn too
+  {
+    return sizeof(T1);
+  }
+
+  int foo2(T1 *t1);
+};
+
+template <class T2>
+int A<T2>::foo2(T2 *t2)
+{
+  return sizeof(T2) + sizeof(t2);
+}
+
+void f()
+{
+  A<int> a;
+  int *x;
+
+  a.foo2(x);
+  a.foo(x);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0233.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0233.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0233.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0233.cc
+// demonstrate flaw in interaction between overload resolution and
+// instantiation
+
+template <class T>
+struct A {
+  int foo(T *t, T *u)      // overloaded declaration
+  {
+    // if instantiated with T=int, this statement causes an error
+    return T::doesNotExist;
+  }
+
+  int foo(T *t)
+  { return 1; }
+};
+
+void f()
+{
+  A<int> a;
+  int *x;
+
+  // this should only instantiate the *second* foo, but our
+  // implementation currently instantiates both, which is wrong
+  //
+  // actually, right now, it always just instantiates the first,
+  // regardless of args, so that's two flaws this demonstrates 
+  a.foo(x);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0234.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0234.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0234.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0234.cc
+// forward-declared function template with differing template
+// parameter lists
+                             
+// fwd
+template <class S1, class T1>
+int foo(S1 *s, T1 *t);
+
+// defn
+template <class S2, class T2>
+int foo(S2 *s, T2 *t)
+{
+  return sizeof(S2) + sizeof(T2);
+}
+
+// instantiation
+void f()
+{
+  // use explicit template argument syntax
+  int *s;
+  float *t;
+  foo<int,float>(s, t);
+
+  // let the template arguments be deduced from the function arguments
+  char *s2;
+  double *t2;
+  foo(s2, t2);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0235.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0235.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0235.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0235.cc
+// member function delayed instantiation
+
+template <class T1>
+struct A {
+  int foo(T1 *t)
+  { return 2; }
+
+  int someDumbThing()           // will not be instantiated
+  { return T1::doesNotExist; }  // so this would-be error is ok
+
+
+  // used 'T' instead of 'T1'
+  //ERROR(1): int bar(T *t)   { return 2; }
+
+  // again, but this time as scope qualifier
+  //
+  // actually, it's ok if this error isn't diagnosed, according
+  // to the standard; but for the moment Elsa does so may as well
+  // leave it here
+  //
+  // 9/21/04: Elsa no longer diagnoses this; I had to weaken its
+  // checking for d0102.cc.
+  //int anotherDumbThing()
+  //{ return T::doesNotExist; }
+};
+
+void f()
+{
+  A<int> a;
+  int *x;
+
+  a.foo(x);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0236.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0236.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0236.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// t0236.cc
+// member template functions
+
+template <class T1>
+struct A {
+  template <class V1>
+  int foo(T1* x, V1 *w)
+  { 
+    return sizeof(T1) + sizeof(V1);
+  }
+
+  template <class S1>
+  int bar(T1 *x, S1 *y);
+};
+
+template <class T2>
+template <class S2>
+int A<T2>::bar(T2 *x, S2 *y)
+{
+  return sizeof(T2) + sizeof(S2);
+}
+
+void f()
+{
+  A<int> a;
+  int *x;
+  char *w;
+  float *y;
+
+  // instantiate A<int>::foo's inline defn with arg 'char'
+  a.foo(x, w);
+
+  // instantiate A<int>::bar's out-of-line defn with arg 'float'
+  a.bar(x, y);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0237.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0237.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0237.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0237.cc
+// same as t0234, except defn provided after instantiation request
+
+// fwd
+template <class S1, class T1>
+int foo(S1 *s, T1 *t);
+
+// instantiation
+void f()
+{
+  // use explicit template argument syntax
+  int *s;
+  float *t;
+  foo<int,float>(s, t);
+
+  // let the template arguments be deduced from the function arguments
+  char *s2;
+  double *t2;
+  foo(s2, t2);
+}
+
+// defn
+template <class S2, class T2>
+int foo(S2 *s, T2 *t)
+{
+  return sizeof(S2) + sizeof(T2);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0238.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0238.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0238.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// t0238.cc
+// same as t0234/t0237, except defn not provided
+
+// fwd
+template <class S1, class T1>
+int foo(S1 *s, T1 *t);
+
+// instantiation
+void f()
+{
+  // use explicit template argument syntax
+  int *s;
+  float *t;
+  foo<int,float>(s, t);
+
+  // let the template arguments be deduced from the function arguments
+  char *s2;
+  double *t2;
+  foo(s2, t2);
+}
+
+// no defn
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0239.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0239.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0239.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0239.cc
+// same as t0229, but infer specialization argument
+
+template <class T>
+int foo(T *t)
+{
+  return 2;
+}
+
+template <>
+int foo(int *t)      // no "<int>", must be inferred
+{
+  return 3;
+}
+
+void f()
+{
+  int *i;
+  float *f;
+         
+  foo(f);      // use primary
+  foo(i);      // use specialization
+}

Added: vendor/elsa/current/elsa/in/t0240.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0240.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0240.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0240.cc
+// template function invokes a method on its parameter type
+// needed for nsUnicodeToTeXCMRt1.cpp, CallQueryInterface()
+
+template <class T>
+void func(T *p)
+{
+  p->method();
+}
+
+// instantiate it
+
+struct A {
+  void method();
+};
+
+void f()
+{
+  A *a;
+  func(a);
+}

Added: vendor/elsa/current/elsa/in/t0241.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0241.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0241.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0241.cc
+// specialization tries to construct a base class; the spec's
+// ctor takes a specialization parameter; the passed argument
+// is a member of the base class
+//
+// from nsAtomTable.i, nsCOMPtr<nsISupports>::nsCOMPtr( const nsCOMPtr<nsISupports>& aSmartPtr )
+
+class Base {
+public:
+  int ptrField;
+
+  Base(int p);
+};
+
+
+template <class T>
+class Derived {            
+  // this is just for looking at selfname for a primary in the debug trace
+  Derived *whatever();
+};
+
+template <>
+class Derived<int> : public Base {
+public:          
+  // use selfname with args
+  Derived(Derived<int> const &obj)
+    : Base(obj.ptrField)
+  {}
+                           
+  // use selfname without args
+  Derived(Derived const &obj, int foo)
+    : Base(obj.ptrField)
+  {}
+};

Added: vendor/elsa/current/elsa/in/t0242.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0242.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0242.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0242.cc
+// overload resolution involving complete specialization
+// from nsAtomTable.i, nsGetterAddRefs<nsISupports>::~nsGetterAddRefs()
+
+class A;
+
+
+// primary
+template <class T>
+class B {
+};
+
+// specialization for A
+template <>
+class B<A> {
+};
+
+
+// two overloaded functions that do stuff with 'B'
+template <class T>
+void func(B<T> &x);
+
+template <class T>
+void func(B<T> const &x);
+
+
+void g()
+{
+  B<A> &y;
+  func(y);     // should call first 'func'
+}

Added: vendor/elsa/current/elsa/in/t0243.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0243.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0243.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0243.cc
+// throw(bad_alloc)
+// from my own new.h!
+
+class bad_alloc {};
+
+void* operator new(int size) throw(bad_alloc);             

Added: vendor/elsa/current/elsa/in/t0244.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0244.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0244.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0244.cc
+// use 'this' in an inline method of a template class
+// from nsAtomTable.i, nsSharedBufferHandle<CharT>::AcquireReference
+
+template <class T>
+class A {
+  void func()
+  {
+    this;
+  }
+};
+
+void f()
+{
+  A<int> *a;
+  a->func();
+}
+

Added: vendor/elsa/current/elsa/in/t0245.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0245.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0245.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0245.cc
+// invoking a static method of a template class w/o prior instantiation
+// from nsAtomTable.i, copy_string
+
+
+template <class T>
+struct A {
+  static void method();
+};
+
+void g()
+{
+  typedef A<unsigned short *> AU;
+
+  // explicit instantiation first would solve it
+  //AU x;
+
+  AU::method();
+
+  // this should be an error, but should not cause an assertion failure
+  //ERROR(1): A<U>::method();
+}
+
+

Added: vendor/elsa/current/elsa/in/t0246.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0246.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0246.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0246.cc
+// invoke an inline-defined static method in a specialization
+// from nsAtomTable.i, copy_string
+
+
+template <class T>
+struct A {
+};
+
+template <class S>
+struct A<S*>
+{
+  static void method()
+  { }
+};
+
+void foo2()
+{
+  A<int*> a;
+  a.method();
+}

Added: vendor/elsa/current/elsa/in/t0247.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0247.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0247.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// t0247.cc
+// from oink/test/template_func2.cc
+// and template_func3_partial.cc
+
+// function template
+template<int I, class T>
+T f(T x)
+{
+  return sizeof(T) + I;
+}
+
+// specialization
+template<>
+int f<2, int>(int x)
+{
+  return x;
+}
+
+// partial specialization: not allowed!
+//ERROR(1): template<class S>
+//ERROR(1): S f<2, S>(S x)
+//ERROR(1): {
+//ERROR(1):   return x;
+//ERROR(1): }
+
+int main()
+{
+  int y;
+  int z = f<1, int>(y);     // use primary
+  
+  f<2, int>(y);             // use specialziation
+}

Added: vendor/elsa/current/elsa/in/t0248.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0248.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0248.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0248.cc
+// out-of-line definition of a member of a complete specialization
+
+// primary
+template <class T>
+class A {
+  int g();
+};
+
+// complete specialization
+template <>
+class A<int> {
+  int f();
+};
+
+// out-of-line definition for specialization's f
+// no "template <>" here!
+int A<int>::f()
+{
+  return 2;
+}
+
+// out-of-line implicit specialization definition for primary's g
+template <>
+int A<float>::g()
+{
+  return 3;
+}
+
+

Added: vendor/elsa/current/elsa/in/t0249.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0249.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0249.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0249.cc
+// test forwarding of function template specializations
+// from Oink, template_func6_fwd1.cc
+
+// forward primary
+template<class T> T g(T x);
+
+// forward specialization
+template<> int g<int>(int x);              // line 9
+
+template<class T> T g(T x) {
+  // no return here
+}
+
+// this isn't used
+template<> float g<float>(float x) {
+  // no return here
+}
+
+// define specialization
+template<> int g<int>(int x) {             // line 21
+  return x;                     // bad
+}
+
+int main() {
+  int /*$tainted*/ a;
+  // launder the $tainted off of the type so function template
+  // argument inference doesn't go an infer the return type to be an
+  // int $tainted
+  int a2 = a;
+  int /*$untainted*/ b;
+  b = __checkCalleeDefnLine(g(a2), 21);
+}

Added: vendor/elsa/current/elsa/in/t0250.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0250.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0250.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// t0250.cc
+// explicit instantiation of a template class
+
+template <class T>
+class A {
+  int foo() { return 2; }
+  int bar();
+  int baz();
+};
+
+// out-of-line defn before inst req
+template <class T>
+int A<T>::bar()
+{
+  return 3;
+}
+
+// explicit instantiation request
+template class A<int>;
+
+// out-of-line defn after inst req
+template <class T>
+int A<T>::baz()
+{
+  return 4;
+}

Added: vendor/elsa/current/elsa/in/t0251.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0251.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0251.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0251.cc
+// simple example with anonymous namespaces
+
+namespace {
+  int a;
+  int b;
+}
+
+namespace {
+  int b;
+  int c;
+}
+
+void f()
+{
+  a;        // from first one
+  //ERROR(1): b;        // ambiguous
+  c;        // from second one
+}

Added: vendor/elsa/current/elsa/in/t0252.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0252.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0252.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// t0252.cc
+// forward-declare a template class specialization
+// needed for ostream, char_traits<char>
+        
+// fwd declare the primary
+template <class T>
+class A;
+
+// fwd declare a specialization
+template <>
+class A<int>;
+
+// use the primary so as to cause decl instantiation
+A<float> *primary;
+
+// use the spec in a benign way
+A<int> *spec;
+
+// implement the spec
+template <>
+class A<int> {
+public:
+  int x;
+};
+
+// use spec
+int f()
+{
+  return spec->x;
+}
+
+// define primary
+template <class T>
+class A {
+public:
+  T x;
+};
+
+// use primary, forcing instantiation
+float g()
+{
+  return primary->x;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0253.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0253.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0253.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// t0253.cc
+// uninstantiated template body,
+// invoking a method on a concrete instantiation,
+// of a template class with non-type parameter,
+// that method being defined out of line
+
+// needed for ostream, std::allocator::allocate()
+
+template <int I>
+class A {
+public:
+  void foo(int n);
+};
+
+template <int I>
+void A<I>::foo(int n)
+{ }
+
+template <class T>
+class B {
+public:
+  void bar(int n)
+  {
+    A<0>::foo(n);
+  }
+};

Added: vendor/elsa/current/elsa/in/t0254.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0254.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0254.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,52 @@
+// t0254.cc
+// dependent inner template scope and funky 'template' keyword
+
+template <class S, class T>
+struct A {
+  typedef typename S::template Inner<T>::its_type my_type;
+
+  // must use the 'template' keyword
+  //ERROR(1): typedef typename S::Inner<T>::its_type another_my_type;
+  
+  // inner scope that is *not* a template
+  typedef typename S::InnerNontemplate::another_type yet_another_type;
+
+  // must not use 'template' if it is not a template
+  //ERROR(2): typedef typename S::template InnerNontemplate::another_type yet_another_type2;
+  
+  
+  // some tests where the name in question is at the end of the
+  // qualifier chain, not in the middle
+  typedef typename S::template Inner<T> inner_t;
+  //ERROR(3): typedef typename S::Inner<T> inner_t2;
+  
+  typedef typename S::InnerNontemplate innerNontemplate;
+  //ERROR(4): typedef typename S::template InnerNontemplate innerNontemplate2;
+};
+
+// one possible type to use in place of 'S'
+struct Outer {
+  template <class T>
+  struct Inner {
+    typedef T *its_type;
+  };
+
+  struct InnerNontemplate {
+    typedef int another_type;
+  };
+};
+
+// put it all together
+int f()
+{
+  A<Outer, int>::my_type pointer_to_integer = 0;
+  A<Outer, int>::yet_another_type integer = 0;
+
+  int x = *pointer_to_integer;
+  x = integer;
+  
+  return x;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0255.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0255.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0255.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0255.cc
+// demonstrate two ambiguities that require a merge() after
+// I allowed "template" in TemplateId ...
+
+template <class T>
+class A {};
+
+template <class T>
+A<T>& foo(T)
+{ }
+
+
+template class A<char>;
+template class A<int>;
+
+// requires merge of SimpleDeclaration
+// this is gnu-specific it seems, and is tested in gnu/g0002.cc
+//extern template
+//A<char>& foo(char);
+
+// requires merge of Declaration
+template
+A<int>& foo(int);

Added: vendor/elsa/current/elsa/in/t0256.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0256.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0256.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0256.cc
+// explicit instantiation of template function
+
+
+// template primary decl
+template <class T>
+int foo(T t)
+{
+  return sizeof(T);
+}
+
+// explicit instantiation request
+template
+int foo(int t);
+
+// another, with template arguments supplied
+template
+int foo<float>(float t);
+
+// mismatch between inferred and supplied arguments
+//ERROR(1): template
+//ERROR(1): int foo<double>(char t);
+

Added: vendor/elsa/current/elsa/in/t0257.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0257.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0257.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0257.cc
+// explicit instantiation request of a class that has
+// a templatized constructor
+
+template <class S>
+struct A {
+  template <class T>
+  A(T t) { }
+};
+
+template struct A<char>;

Added: vendor/elsa/current/elsa/in/t0258.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0258.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0258.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,68 @@
+// t0258.cc
+// template class with member template class
+// needed for ostream
+
+template <class S>
+struct A {
+  // fwd decl of B
+  template <class T>
+  struct B;
+
+  template <class T>
+  struct B {
+    int foo(S *s, T *t);
+
+    // inline func defn
+    int bar(S *s, T *t)
+    {
+      return sizeof(S) + sizeof(T);
+    }
+  };
+};
+
+// out-of-line func defn
+template <class S2>
+template <class T2>
+int A<S2>::B<T2>::foo(S2 *s, T2 *t)
+{
+  return 2 + sizeof(S2) + sizeof(T2);
+}
+
+// duplicate defn of 'bar'
+//ERROR(1): template <class S2>
+//ERROR(1): template <class T2>
+//ERROR(1): int A<S2>::B<T2>::bar(S2 *s, T2 *t)
+//ERROR(1): {
+//ERROR(1):   return 2 + sizeof(S2) + sizeof(T2);
+//ERROR(1): }
+
+// duplicate defn of 'foo'
+//ERROR(2): template <class S2>
+//ERROR(2): template <class T2>
+//ERROR(2): int A<S2>::B<T2>::foo(S2 *s, T2 *t)
+//ERROR(2): {
+//ERROR(2):   return 2 + sizeof(S2) + sizeof(T2);
+//ERROR(2): }
+
+// instantiate A's decl
+A<int> *aptr;
+
+// instantiate A's defn
+A<int> a;
+
+// instantiate B's decl
+A<int>::B<float> *bptr;
+
+// instantiate B's defn
+A<int>::B<float> b;
+
+void f()
+{
+  int *ip;
+  float *fp;
+
+  b.foo(ip, fp);
+  b.bar(ip, fp);
+
+  return 1;
+}

Added: vendor/elsa/current/elsa/in/t0259.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0259.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0259.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0259.cc
+// tricky "duplicate" definitions
+// needed for ostream
+
+
+template <class T>
+int foo(T *x, T *t)
+{
+  return 1;
+}
+
+template <class T>
+int foo(T *x, T const *t)
+{
+  return 2;
+}
+
+
+template <class T>
+int bar(T const *t)
+{
+  return 1;
+}
+
+template <class T>
+int bar(T *t)
+{
+  return 2;
+}

Added: vendor/elsa/current/elsa/in/t0260.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0260.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0260.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0260.cc
+// member func and template member func with similar signatures
+// needed for ostream
+
+
+template <class T>
+struct A {
+  // member func
+  int foo(A *a)
+  {
+    return sizeof(A);
+  }
+
+  //ERROR(1): int foo(A *a)
+  //ERROR(1): {
+  //ERROR(1):   return sizeof(A);
+  //ERROR(1): }
+
+  // template member func
+  template <class S>
+  int foo(A<S> *a)
+  {
+    return sizeof(A<S>);
+  }
+
+  // member func
+  int bar(A *a);
+  //ERROR(2): int bar(A *a);
+
+  // template member func
+  template <class S>
+  int bar(A<S> *a);
+};
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0261.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0261.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0261.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// t0261.cc
+// non-template member class of a template class
+// needed for ostream
+
+template <class T>
+class A {
+  struct B {
+    int x;
+    char y;
+    
+    int foo() 
+    { return sizeof(T) + x; }
+    
+    int bar();
+  };
+};
+
+// instantiate class decl
+A<int> *aptr;
+
+// instantiate class defn
+A<int> a;                
+
+// eager-instantiate all of A<int>
+template class A<int>;
+
+
+template <class T2>
+int A<T2>::B::bar()
+{
+  return sizeof(T2) + y;
+}
+
+
+void f()
+{
+  // demand-instantiate all of A<float>
+  A<float>::B b;
+  b.x + b.y;
+  b.foo() + b.bar();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0262.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0262.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0262.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0262.cc
+// template class with a friend
+
+template <class T>
+class A {
+  friend class B;
+};
+
+A<int> x;
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0263.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0263.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0263.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0263.cc
+// inner union that is referenced twice inside the template
+
+struct C {
+  struct C *p;
+};
+
+  template<bool __threads, int __inst>
+    class __default_alloc_template
+    {
+      union _Obj
+      {
+        union _Obj* _M_free_list_link;
+        char _M_client_data[1];
+      };
+
+
+      static void
+      deallocate(void* __p, int __n)
+      {      }
+    };
+
+  typedef __default_alloc_template<true,0> __alloc;
+  
+  void foo()
+  {
+    __alloc::deallocate(0,0);
+  }
+
+

Added: vendor/elsa/current/elsa/in/t0264.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0264.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0264.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// t0264.cc
+// an error that at one time caused a segfault
+
+  template<bool __threads, int __inst>
+    class __default_alloc_template
+    {
+      struct _Obj
+      {
+        //ERROR(1): union _Obj* _M_free_list_link;    // wrong keyword
+        char _M_client_data[1];
+      };
+
+
+      static void
+      deallocate(void* __p, int __n)
+      {      }
+    };
+
+  typedef __default_alloc_template<true,0> __alloc;
+  
+  void foo()
+  {
+    __alloc::deallocate(0,0);
+  }
+
+

Added: vendor/elsa/current/elsa/in/t0265.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0265.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0265.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0265.cc
+// does <dependent> match <dependent>?
+// needed for ostream, basic_string::replace
+
+template <class T>
+struct A {
+  int foo(typename T::type1 x);
+  int foo(typename T::type2 x);
+                                                
+  // cannot apply template args to T
+  //ERROR(1): int bar(typename T<int>::type3 x);
+};
+
+
+template <class T>
+int A<T>::foo(typename T::type1 x)
+{
+  return 1;
+}
+
+
+template <class T>
+int A<T>::foo(typename T::type2 x)
+{
+  return 2;
+}
+
+
+class B {
+  typedef int type1;
+  typedef float type2;
+};
+
+
+void f()
+{
+  A<B> a;
+  int i;
+  float f;
+  a.foo(i);
+  a.foo(f);
+}

Added: vendor/elsa/current/elsa/in/t0266.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0266.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0266.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// t0266.cc
+// basic_string::_S_copy_chars
+
+  template <class S, class T>
+  class __normal_iterator {};
+
+  template<typename _CharT, typename _Traits, typename _Alloc>
+    class basic_string
+    {
+
+    public:
+      typedef typename _Alloc::pointer pointer;
+      typedef typename _Alloc::const_pointer const_pointer;
+      typedef __normal_iterator<pointer, basic_string> iterator;
+      typedef __normal_iterator<const_pointer, basic_string>
+                                                            const_iterator;
+
+      template<class _Iterator>
+        static void
+        _S_copy_chars(_CharT* __p, _Iterator __k1, _Iterator __k2)
+        {
+        }
+
+      static void
+      _S_copy_chars(_CharT* __p, iterator __k1, iterator __k2)
+      { }
+
+      static void
+      _S_copy_chars(_CharT* __p, const_iterator __k1, const_iterator __k2)
+      { }
+
+      static void
+      _S_copy_chars(_CharT* __p, _CharT* __k1, _CharT* __k2)
+      { }
+
+      static void
+      _S_copy_chars(_CharT* __p, const _CharT* __k1, const _CharT* __k2)
+      { }
+
+  };

Added: vendor/elsa/current/elsa/in/t0267.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0267.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0267.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0267.cc
+// is this a valid template definition?
+
+// g++ does not like it, and I don't want to like it either.  However,
+// it is debatable whether this is legal since it seems that a valid
+// specialization *can* be generated (14.6 para 7).  14.5.1.1 is not
+// very clear on how an implementation is to associate an out-of-line
+// definition with the declaration.
+
+template <class T>
+struct A {
+  int foo(typename T::type1 x);      // use 'type1' in decl
+};
+
+template <class T>
+int A<T>::foo(typename T::type2 x)   // use 'type2' in defn
+{
+  return 1;
+}
+
+struct B {
+  typedef int type1;                 // for *this* template argument, 'type1'
+  typedef int type2;                 // and 'type2' are the same!
+};
+
+void f()
+{
+  A<B> a;                            // so this is a valid specialization (?)
+  a.foo(3);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0268.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0268.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0268.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0268.cc
+// problem associating a defn with a decl
+// from ostream, basic_string::append
+
+// this fwd decl appears to be important for my failing testcase
+template <class T >
+struct A;
+
+template <class T>
+struct A {
+  typedef typename T::size_type size_type;
+
+  // out-of-line defn goes with this decl
+  A& append(T* t, size_type n);
+
+  int append(int, int, int)  { }
+};
+
+template <class T>
+A<T>& A<T>::append(T* t, size_type n)
+{ }
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0268a.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0268a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0268a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0268a.cc
+// slightly simpler than t0268.cc, so should be tested first
+
+template <class T>
+struct A {
+  // out-of-line defn goes with this decl
+  void append(T* t);
+
+  int append(int, int, int)  { }
+};
+
+template <class T>
+void A<T>::append(T* t)
+{}

Added: vendor/elsa/current/elsa/in/t0269.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0269.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0269.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0269.cc
+// tricky use of templatized overloaded ctor
+// from ostream, basic_string<char>::_M_destroy
+
+template <class T>
+struct A {
+  A(const A&) {}
+
+  template <class S>
+  A(const A<S>&);
+
+  void func(int);
+};
+
+void f(A<char> &a)
+{
+  A<char> obj(a);
+  obj.func(3);
+
+  A<char>(a).func(3);
+}

Added: vendor/elsa/current/elsa/in/t0270.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0270.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0270.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// t0270.cc
+// minimized from ostream, basic_string<char> ctor
+
+template < typename _Tp > 
+class allocator
+{
+  typedef int _Alloc;
+};
+
+template < typename _CharT, 
+           typename _Alloc >
+class basic_string {
+public:
+  struct _Alloc_hider : _Alloc {
+    _Alloc_hider (const _Alloc & __a)
+      : _Alloc (__a)
+    { }
+    _CharT *_M_p;
+  };
+
+  _Alloc_hider _M_dataplus;
+
+  basic_string ();
+};
+
+template < typename _CharT,
+           typename _Alloc >
+basic_string < _CharT, _Alloc >::basic_string ()
+  : _M_dataplus (_Alloc())
+{ }
+
+template class basic_string < char, allocator<char> >;

Added: vendor/elsa/current/elsa/in/t0271.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0271.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0271.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// t0271.cc
+// template parameter hides *dependent* base class member
+// this is what is going wrong in t0270.cc
+
+// base class; will be *dependent*
+template <class T>
+struct Base {
+  int S;
+  int I;
+  
+  // I made this overloaded to force Elsa to compare the
+  // arguments to the parameters
+  int foo(int);
+  int foo(float);
+};
+
+// this typedef is what is seen when 'I' is used, below
+typedef int I;
+
+// and one more for a function call
+int foo(int, int);
+int foo(float, float);
+
+// derived struct
+template <class S>
+struct Derived : Base<S> {
+  // Since we inherit from Base<S>, and Base<S> has a member called
+  // 'S', it might naively hide the template parameter 'S'.  In fact,
+  // if the base class were not dependent on the template parameter,
+  // that would be the correct semantics (14.6.1 para 7).  However,
+  // since it *is* dependent, the template parameter name takes
+  // precedence (14.6.2 paras 3, 4).
+
+  S x;     // only works if 'S' is a type, namely the template parameter
+
+  I y;     // same deal
+
+  void bar() {
+    foo(2,3);     // non-dependent; uses ::foo(int, int)
+    
+    S s;
+    foo(s);       // dependent; uses Base<S>::foo
+  }
+};
+
+// instantiate it
+template class Derived<float>;
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0272.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0272.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0272.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// t0272.cc
+// counterpart to t0271.cc: *non*-dependent base class names hide others
+
+// base class; will be *non*-dependent
+struct Base {
+  int S;
+  int I;
+
+  // I made this overloaded to force Elsa to compare the
+  // arguments to the parameters
+  int foo(int);
+  int foo(float);
+};
+
+// this typedef is what is seen when 'I' is used, below
+typedef int I;
+
+// and one more for a function call
+int foo(int, int);
+int foo(float, float);
+
+// derived struct
+template <class S>
+struct Derived : Base {
+  // Since we inherit from Base, and Base has a member called
+  // 'S', it *does* hide the template parameter 'S'.
+
+  //ERROR(1): S x;     // only works if 'S' is a type
+
+  //ERROR(2): I y;     // same deal
+
+  void bar() {
+    foo(I);            // non-dependent; uses Base::I and Base::foo(int)
+    foo(S);            // non-dependent; uses Base::S and Base::foo(int)
+  }
+};
+
+// instantiate it
+template class Derived<float>;
+
+
+// EOF
+
+
+
+

Added: vendor/elsa/current/elsa/in/t0273.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0273.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0273.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0273.cc
+// explicitly instantiate a template class that inherits a non-template
+
+struct Base {
+};
+
+template <class T>
+struct Derived : Base {
+  // threw this in too.. though it didn't cause any new problems
+  struct Inner {
+  };
+};
+
+template class Derived<float>;
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0274.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0274.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0274.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0274.cc
+// namespace names vs. template param names
+// variation on cppstd 14.6.1p6.cc
+
+namespace N {
+  // all uses of "C" below will cause an error if
+  // lookup erroneously finds this one
+  int C;
+
+  template <class T> 
+  class B {
+    void f(T);
+  };
+}
+
+template <class C>
+void N::B<C>::f(C param)
+{
+  C b;                          // C is the template parameter, not N::C
+}
+
+template class N::B<int>;

Added: vendor/elsa/current/elsa/in/t0275.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0275.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0275.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// t0275.cc
+// template function definition with an error
+
+
+typedef int barf;
+
+namespace M {
+  template <class T>
+  class A {
+    int foo(int);
+  };
+                       
+  //ERROR(1): int barf;      // hides type name above
+
+  template <class T>
+  int A<T>::foo(barf)
+  {
+    return 2;
+  }
+}
+
+
+namespace N {
+  //ERROR(2): int barf;      // hides type name above
+
+  template <class T>
+  class B {
+    int f(int);
+  };
+}
+
+template <class T>
+int N::B<T>::f(barf)
+{
+  return 3;
+}
+

Added: vendor/elsa/current/elsa/in/t0276.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0276.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0276.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0276.cc
+// problem with overload resolution when arguments include type vars
+
+     
+int foo(int);
+int foo(int, int);
+
+template <class S>
+void f(S s)
+{
+  foo(3, s);
+}
+
+void g()
+{
+  int x;
+  f(x);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0277.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0277.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0277.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0277.cc
+// another dependent name problem
+
+
+void bar();
+void bar(int *);
+
+
+template <class T>
+void foo(T t)
+{
+  typedef T *Ptr;    // not a member of a template
+
+  Ptr p;             // will be regarded as non-dependent
+
+  bar(p);            // overload resolution will fail
+}
+
+template void foo(int t);

Added: vendor/elsa/current/elsa/in/t0278.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0278.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0278.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// t0278.cc
+// from oink/test/template_class4_func_fwd2.cc
+
+// test mutual resursion of function members of templatized classes
+
+//  #include <iostream>
+//  using namespace std;
+
+template <class T>
+struct A {
+  T f(T x, T y);                // forward declaration
+  T g(T x, T y);                // forward declaration
+};
+
+template <class T> 
+T A<T>::f(T x, T y) 
+{
+  if (1) {                      // cqual doesn't see this is determined at compile time
+    return x;                   // bad
+  } else {
+    return g(0, y);
+  }
+}
+
+template <class T> 
+T A<T>::g(T x, T y) 
+{
+  if (1) {                      // cqual doesn't see this is determined at compile time
+    return 17;                  // irrelevant
+  } else {
+    return f(y, 0);
+  }
+}
+
+int main() 
+{
+  int /*$tainted*/ x;
+//    int x = 1;
+  int x2 = x;                   // launder taintedness
+  int /*$untainted*/ y;
+//    int y = 2;
+  A<int> a;
+  y = a.f(0, x2);
+//    cout << "y:" << y << endl;
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0279.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0279.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0279.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0279.cc
+// overloading template vs. non-template
+
+void f(int) {}                        // line 4
+template <class T2> void f(T2) {}     // ;ine 5
+
+int main()
+{
+  __checkCalleeDefnLine(f(1), 4);                // non-template
+  __checkCalleeDefnLine(f('c'), 5);              // template
+}

Added: vendor/elsa/current/elsa/in/t0280.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0280.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0280.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0280.cc
+// overloading + template inst.
+
+void f(int) {}                        // line 4
+template <class T2> void f(T2) {}     // ;ine 5
+
+int main()
+{
+  f(1);                // non-template
+  f('c');              // template
+  f<>(1);              // template
+}

Added: vendor/elsa/current/elsa/in/t0281.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0281.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0281.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0281.cc
+// demonstrate problem with STA_REFERENCE
+
+template <int i>
+class A {
+};
+
+template <int j>
+class B {
+  A<j+1> a;
+};
+
+B<1> b;

Added: vendor/elsa/current/elsa/in/t0282.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0282.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0282.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// t0282.cc
+// playing with computation of built-in operator return types
+
+// need an operand that will trigger overload resolution
+enum E { e };
+int i;
+unsigned int ui;
+long l;
+unsigned long lu;
+
+void f()
+{
+  __elsa_checkType(e + i,  (int)0);
+  __elsa_checkType(e + ui, (unsigned)0);
+  __elsa_checkType(e + l,  (long)0);
+  __elsa_checkType(e + lu, (unsigned long)0);
+
+  __elsa_checkType(e - ui, (unsigned)0);
+}
+
+
+
+// more variety!
+struct Char {
+  operator char ();
+} c2;
+
+struct Unsigned {
+  operator unsigned ();
+} u2;
+
+void g()
+{
+  __elsa_checkType(c2 + i,  (int)0);
+  __elsa_checkType(c2 + c2, (int)0);     // char + char = int
+  
+  __elsa_checkType(u2 + l, (unsigned long)0);
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0283.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0283.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0283.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,156 @@
+// t0283.cc
+// delta-minimized from ostream, not yet hand-minimized
+
+namespace std
+{
+  template < typename _Alloc > 
+  class allocator;
+
+  template < class _CharT >
+  struct char_traits;
+
+  template < typename _CharT,
+             typename _Traits = char_traits < _CharT >,
+             typename _Alloc = allocator < _CharT > >
+  class basic_string;
+}
+
+typedef int ptrdiff_t;
+typedef unsigned size_t;
+
+struct __false_type {} ;
+
+template < class _Tp > 
+struct _Is_integer {
+  typedef __false_type _Integral;
+};
+
+namespace std
+{
+  struct input_iterator_tag {};
+  struct forward_iterator_tag : input_iterator_tag {};
+  struct bidirectional_iterator_tag : forward_iterator_tag {};
+  struct random_access_iterator_tag : bidirectional_iterator_tag {};
+
+  template < typename _Category,
+             typename _Tp,
+             typename _Distance,
+             typename _Pointer = _Tp,
+             typename _Reference = _Tp >
+  struct iterator {
+    typedef _Category iterator_category;
+  };
+
+  template < typename _Iterator > 
+  struct iterator_traits {
+    typedef typename _Iterator::iterator_category iterator_category;
+  };
+
+  template < typename _Tp > 
+  struct iterator_traits <_Tp * > {
+    typedef random_access_iterator_tag iterator_category;
+    typedef _Tp value_type;
+    typedef ptrdiff_t difference_type;
+    typedef _Tp * pointer;
+    typedef _Tp reference;
+  };
+}
+
+namespace __gnu_cxx
+{
+  using std::iterator_traits;
+  using std::iterator;
+
+  template < typename _Iterator, 
+             typename _Container > 
+  class __normal_iterator 
+    : public iterator < typename iterator_traits < _Iterator >:: iterator_category,
+                        typename iterator_traits < _Iterator >:: value_type,
+                        typename iterator_traits < _Iterator >:: difference_type,
+                        typename iterator_traits < _Iterator >::pointer, 
+                        typename iterator_traits < _Iterator >::reference >
+  { };
+}
+
+namespace std
+{
+  template < int __inst > 
+  class __default_alloc_template {
+  };
+
+  template < typename _Tp > 
+  class allocator {
+  public:
+    typedef size_t size_type;
+    typedef _Tp * pointer;
+  };
+
+  template < typename _T1, 
+             typename _T2 > 
+  bool operator== (allocator < _T1 >, allocator < _T2 >)
+  { }
+}
+
+namespace std
+{
+  template < class _Arg2, 
+             class _Result > 
+  struct binary_function {
+  };
+
+  template < typename _CharT, 
+             typename _Traits, 
+             typename _Alloc > 
+  class basic_string {
+    typedef typename _Alloc::size_type size_type;
+    typedef typename _Alloc::pointer pointer;
+    typedef __gnu_cxx::__normal_iterator < pointer, basic_string > iterator;
+
+    struct _Alloc_hider : _Alloc {
+      _Alloc_hider (_CharT *, _Alloc)
+      { }
+    };
+
+  public:
+    static const size_type npos = static_cast < size_type > (-1);
+
+  private:
+    _Alloc_hider _M_dataplus;
+
+    iterator _M_check (size_type) { }
+    iterator _M_fold (size_type, size_type) const { }
+    basic_string (const basic_string &, size_type, size_type);
+    size_type size () { }
+
+    template < class _InIter >
+    static _CharT * _S_construct_aux
+      (_InIter __beg, _InIter __end, _Alloc __a, __false_type)
+    {
+      typedef typename iterator_traits < _InIter >::iterator_category _Tag;
+      _S_construct (__beg, __end, __a, _Tag ());
+    }
+
+    template < class _InIter >
+    static _CharT * _S_construct (_InIter __beg, _InIter __end, _Alloc __a)
+    {
+      typedef typename _Is_integer < _InIter >::_Integral _Integral;
+      _S_construct_aux (__beg, __end, __a, _Integral ());
+    }
+
+    template < class _InIter >
+    static _CharT * _S_construct (_InIter, _InIter, _Alloc, input_iterator_tag);
+  };
+
+  template <typename _CharT,
+            typename _Traits,
+            typename _Alloc>
+  basic_string<_CharT,_Traits,_Alloc>::basic_string
+    (const basic_string &__str, size_type __pos, size_type __n)
+    : _M_dataplus(_S_construct(_M_check (__pos),
+                               __str._M_fold (__pos, __n),
+                               _Alloc ()),
+                  _Alloc ())
+  { }
+
+  template class basic_string < char >;
+}

Added: vendor/elsa/current/elsa/in/t0284.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0284.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0284.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0284.cc
+// out-of-line class definition
+
+namespace N {
+  typedef int Int;
+  class A;
+}
+
+class N::A {
+  Int i;          // refer back to N, even out of line
+};
+

Added: vendor/elsa/current/elsa/in/t0285.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0285.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0285.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,54 @@
+// t0285.cc
+// assertion failure: canAcceptNames
+
+namespace std
+{
+  template < class _CharT > struct char_traits;
+}
+typedef int ptrdiff_t;
+extern "C"
+{
+  typedef ptrdiff_t streamsize;
+}
+namespace std
+{
+  template < typename _CharT, typename _Traits =
+    char_traits < _CharT > >class basic_ios;
+  template < typename _CharT, typename _Traits =
+    char_traits < _CharT > >class basic_streambuf;
+}
+extern "C++"
+{
+}
+typedef int _Atomic_word;
+static inline _Atomic_word
+__exchange_and_add (volatile _Atomic_word * __mem, int __val)
+{
+}
+
+namespace std
+{
+  enum _Ios_Fmtflags
+  {
+    _M_ios_fmtflags_end = 1L << 16
+  };
+    template < typename _CharT,
+    typename _Traits > streamsize __copy_streambufs (basic_ios < _CharT,
+						     _Traits > &_ios,
+						     basic_streambuf < _CharT,
+						     _Traits > *__sbin,
+						     basic_streambuf < _CharT,
+						     _Traits > *__sbout);
+    template < typename _CharT, typename _Traits > class basic_streambuf
+  {
+  public:typedef _CharT char_type;
+    typedef _Traits traits_type;
+    typedef basic_streambuf < char_type, traits_type > __streambuf_type;
+    friend streamsize __copy_streambufs <> (basic_ios < char_type,
+					    traits_type > &__ios,
+					    __streambuf_type * __sbin,
+					    __streambuf_type * __sbout);
+  };
+  //extern    // let it go through in non-gnu mode
+  template class basic_streambuf < char >;
+}

Added: vendor/elsa/current/elsa/in/t0286.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0286.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0286.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0286.cc
+// non-member operator |=
+
+enum E { evalue };
+
+E &operator|= (E &e1, E e2)
+{
+  e1 = (E)(e1 | e2);
+  return e1;
+}
+ 

Added: vendor/elsa/current/elsa/in/t0287.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0287.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0287.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0287.cc
+// default non-type template argument
+
+template <class T, bool f = false>
+class A {
+  T t;
+  bool getF() {
+    return f;
+  }
+};
+
+bool func()
+{
+  A<int> a;
+  return a.getF();
+}
+
+bool func2()
+{
+  A<int, true> a;
+  return a.getF();
+}
+
+bool func3()
+{
+  A<int, false> a;
+  return a.getF();
+}

Added: vendor/elsa/current/elsa/in/t0288.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0288.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0288.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+// t0288.cc
+// "ambiguous function template instantiation"
+
+// 2005-08-03: This appears to be fixed by the switch to
+// the new mtype module.
+
+namespace std
+{
+  template < class _CharT > struct char_traits;
+}
+typedef int ptrdiff_t;
+extern "C"
+{
+  typedef struct __locale_struct
+  {
+  }
+   *__locale_t;
+};
+typedef struct __pthread_attr_s
+{
+}
+pthread_barrierattr_t;
+namespace std
+{
+  typedef ptrdiff_t streamsize;
+    template < typename _CharT, typename _Traits =
+    char_traits < _CharT > >class basic_ios;
+    template < typename _CharT, typename _Traits =
+    char_traits < _CharT > >class basic_streambuf;
+}
+extern "C++"
+{
+  namespace std
+  {
+    class exception
+    {
+    };
+  }
+}
+namespace std
+{
+  template < typename _CharT, typename _Traits > class basic_streambuf
+  {
+  public:typedef _CharT char_type;
+    typedef _Traits traits_type;
+    typedef basic_streambuf < char_type, traits_type > __streambuf_type;
+    friend streamsize __copy_streambufs <> (basic_ios < char_type,
+					    traits_type > &__ios,
+					    __streambuf_type * __sbin,
+					    __streambuf_type * __sbout);
+  };
+  template < typename _CharT,
+    typename _Traits > streamsize __copy_streambufs (basic_ios < _CharT,
+						     _Traits > &__ios,
+						     basic_streambuf < _CharT,
+						     _Traits > *__sbin,
+						     basic_streambuf < _CharT,
+						     _Traits > *__sbout)
+  {
+    try
+    {
+    }
+    catch (exception & __fail)
+    {
+    }
+  }
+  extern template streamsize __copy_streambufs (basic_ios < wchar_t > &,
+						basic_streambuf < wchar_t > *,
+						basic_streambuf < wchar_t >
+						*);
+}

Added: vendor/elsa/current/elsa/in/t0289.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0289.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0289.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0289.cc
+// repeated 'using' declarations
+
+typedef int Int;
+
+namespace N
+{
+  using ::Int;
+  using ::Int;
+}

Added: vendor/elsa/current/elsa/in/t0290.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0290.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0290.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0290.cc
+// problem matching definition and decl
+
+template < typename _CharT >
+class basic_string;
+
+class locale { };
+
+struct messages_base
+{
+  typedef int catalog;
+};
+
+template < typename _CharT >
+class messages : public messages_base
+{
+  catalog open (const basic_string < char >&__s, const locale & __loc) const
+  {
+  }
+  catalog open (const basic_string < char >&, const locale &,
+                const char *) const;
+};
+
+template < typename _CharT >
+typename messages < _CharT >::catalog
+messages < _CharT >::open (const basic_string <char >&__s,
+                           const locale & __loc,
+                           const char *__dir) const
+{
+}

Added: vendor/elsa/current/elsa/in/t0290a.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0290a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0290a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0290a.cc
+// essence of the difficulty with t0290.cc
+
+template <class T>
+struct B {
+  typedef int INT;
+  INT foo(int);
+};
+
+// the type is called "B<T>::INT" (a DependentQType) out here, but is
+// called simply "INT" (which maps to "int", a SimpleType) in the
+// scope of B (above); to match this defn with the decl, we have to
+// re-process the type once the declarator scope (B<T>) has been
+// pushed
+template <class T>
+typename B<T>::INT B<T>::foo(int)
+{
+  return 2;
+}
+
+int f()
+{
+  B<int> a;
+  return a.foo(1);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0291.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0291.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0291.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0291.cc
+// friend function with definition at point of declaration
+
+struct A {
+  friend int foo() { return 2; }
+};
+
+
+// 11.4 para 5 is (IMO) unclear about precisely what names are in
+// scope in an inline friend definition; gcc likes the following
+// code, so I'm putting it in my test suite too..
+
+int I;                  // non-type; *not* seen
+
+class B {
+  typedef int I;        // type; this is what 'I' looks up to (at least in gcc)
+
+  friend int bar()
+  {
+    I i;                // use of type 'I'
+    return i;
+  }
+};

Added: vendor/elsa/current/elsa/in/t0292.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0292.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0292.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// t0292.cc
+// conversion operator accepting "(void)"
+
+class A {
+  operator int (void);
+};

Added: vendor/elsa/current/elsa/in/t0293.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0293.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0293.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0293.cc
+// cast from templatized derived to template param base
+// but no other syntax to instantiate the Derived class
+
+class Base {
+public:
+};
+
+template <class T>
+class Derived : public T {
+};
+
+//class Derived2 : public Base {
+//};
+
+
+void find(Base* instance);
+void find(const char * mimetype);
+
+void foo()
+{
+  Derived<Base> *d;
+  //Derived<Base> inst;
+  //Derived2 *d2;
+
+  find(d);     // overload resolution; need to cast to Base
+  //find(d2);
+}

Added: vendor/elsa/current/elsa/in/t0294.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0294.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0294.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// t0294.cc
+// overloaded operator -> yields a type that is then involved
+// in overload resolution
+
+// needed for Mozilla xpcwrappednative.i
+
+
+struct A {
+  int x;
+};
+
+
+struct Ptr {
+  A* operator -> ();
+};
+
+
+void func(int);
+void func(float);
+
+
+void f()
+{
+  Ptr p;
+  func(p->x);
+}

Added: vendor/elsa/current/elsa/in/t0295.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0295.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0295.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0295.cc
+// overloaded operator* and conversion operators returning pointer
+
+struct A {
+  int* operator* ();    // use this one
+  
+  // these are red herrings
+  operator int* ();
+  operator float* ();
+};
+
+// to provoke Elsa's bug I need to obtain the A via a function call,
+// instead of just having a variable of type A ...
+A getA();
+
+void f()
+{
+  *getA();
+}

Added: vendor/elsa/current/elsa/in/t0296.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0296.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0296.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0296.cc
+// check receiver arg
+
+struct A {
+  int f();
+  int g() const;
+};
+
+void foo(A const &a2)
+{
+  A a;
+  a.f();                   // ok
+
+  a2.g();                  // ok
+
+  //ERROR(1): A::f();      // no recevier supplied
+
+  //ERROR(2): a2.f();      // cannot convert
+}

Added: vendor/elsa/current/elsa/in/t0297.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0297.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0297.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// t0297.cc
+// overloaded operator()
+
+struct A {
+  int operator() ();            // line 5
+  int operator() (int);         // line 6
+  int operator() (int,int);     // line 7
+};
+
+struct B {};
+
+void foo()
+{
+  A a;
+  B b;
+
+  __testOverload( a(),     5);
+  __testOverload( a(3),    6);
+  __testOverload( a(4,5),  7);
+
+  //ERROR(1): a(6,7,8);       // doesn't match any overloaded instance
+
+  //ERROR(2): b(5,6,7);       // no operator() defined
+}
+
+

Added: vendor/elsa/current/elsa/in/t0298.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0298.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0298.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// t0298.cc
+// pointers to members
+
+// variation of 8.3.3.2.cc
+
+class X {
+public:
+  void f(int);
+  int a;
+};
+class Y;
+
+int X::* pmi = &X::a;
+void (X::* pmf)(int) = &X::f;
+double X::* pmd;
+char Y::* pmc;
+
+void foo()
+{
+  X obj;
+
+  obj.*pmi = 7;        // assign 7 to an integer
+                       // member of obj
+  (obj.*pmf)(7);       // call a function member of obj
+                       // with the argument 7
+
+  X *ptr;
+  (ptr->*pmf)(7);      // call a function member of *ptr
+                       // with the argument 7
+                       
+  //ERROR(1): (obj->*pmf)(7);      // wrong, LHS of ->* must be pointer
+}

Added: vendor/elsa/current/elsa/in/t0299.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0299.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0299.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0299.cc
+// slightly tricky overload resolution
+
+struct A {
+  void foo() const;    // line 5
+  void foo();          // line 6
+
+  void bar() const;
+};
+
+void A::bar() const
+{
+  foo();       // should pick first one
+
+  // again..
+  __testOverload(foo(), 5);
+}

Added: vendor/elsa/current/elsa/in/t0300.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0300.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0300.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0300.cc
+// char** to void*
+
+void f(void *);
+
+void foo()
+{
+  char **p;
+  f(p);
+
+  //ERROR(1): char const *cp;
+  //ERROR(1): f(cp);
+  
+  // according to gcc this is ok..
+  char const **cpp;
+  f(cpp);
+}

Added: vendor/elsa/current/elsa/in/t0301.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0301.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0301.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0301.cc
+// convert to pointer for comparison with 0
+
+struct A {
+  operator int* ();
+};
+
+void f()
+{
+  A a;
+  
+  a != 0;
+}

Added: vendor/elsa/current/elsa/in/t0302.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0302.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0302.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0302.cc
+// convert parenthesized 0 to pointer (doh)
+
+struct A {};
+
+void (*f)(int, A *);
+
+void foo()
+{
+  (*f)(0, (0) );
+}

Added: vendor/elsa/current/elsa/in/t0303.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0303.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0303.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// t0303.cc
+// more issues with polymorphic operator returns
+
+// from Mozilla inDOMUtils.i
+
+
+struct nsStyleStructID {
+  operator int () const;
+};
+
+struct nsCachedStyleData
+{
+  struct StyleStructInfo {
+    bool    mIsReset;
+  };
+
+  static StyleStructInfo gInfo[];
+
+  static bool IsReset(const nsStyleStructID& aSID) {
+    return gInfo[aSID].mIsReset;
+  };
+
+  static bool IsReset2(const nsStyleStructID& aSID) {
+    return (*(gInfo+aSID)).mIsReset;
+  };
+};

Added: vendor/elsa/current/elsa/in/t0304.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0304.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0304.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0304.cc
+// dereference a conversion-to-const-pointer operator
+
+struct A {
+  operator int const * ();     // the 'const' is the issue
+};
+
+void foo()
+{
+  A a;
+  *a;
+  (a && *a);   // needs polymorphic built-in unary operators to have accurate returns
+}

Added: vendor/elsa/current/elsa/in/t0305.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0305.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0305.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0305.cc
+// (int)0 works as NULL pointer
+
+typedef long int time_t;
+extern time_t time (time_t *__timer)  ;
+
+void f()
+{
+  time_t tt;
+  tt = time((time_t)0 );
+}

Added: vendor/elsa/current/elsa/in/t0306.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0306.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0306.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0306.cc
+// ?: with NULL 2nd arg
+
+struct A {};
+
+void f(A *);
+
+void foo(bool b)
+{
+  A *a;
+
+  f(b? 0 : a);
+}

Added: vendor/elsa/current/elsa/in/t0307.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0307.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0307.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0307.cc
+// 5.16 para 1: conversion applied to first argument of ?:
+
+struct A {
+  operator bool ();
+};
+
+struct B {};
+
+
+void f(A const &aref)
+{
+  A a;
+  a? 1 : 2;                   // ok
+
+  B b;
+  //ERROR(1): b? 3 : 4;       // no conversion operator
+
+  //ERROR(2): aref? 5 : 6;    // operator not usable b/c of 'const'
+  
+  A const *aptr;
+  aptr? 7 : 8;                // pointer-to-bool conversion ok
+}
+
+
+
+

Added: vendor/elsa/current/elsa/in/t0308.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0308.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0308.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,62 @@
+// t0308.cc
+// 5.16 para 2
+
+struct A {};
+
+void g();
+void h();
+void j(A &a);
+void jc(A const &a);
+
+void f(int x, int y)
+{
+  int *ptr;
+  int arr[3];
+  A a;
+  void (*funcptr)();
+
+  switch (x) {
+    case 1:
+      // both void
+      return y? g() : h();
+
+    case 11:
+      // error: void vs. non-void
+      //ERROR(1): return y? g() : 3;
+      //ERROR(2): return y? 3 : g();
+
+    case 2:
+      // second is throw
+      x = (y? throw 2 : 3);
+      break;
+
+    case 3:
+      // third is throw
+      x = (y? 2 : throw 3);
+      break;
+
+    case 4:
+      // both throw
+      return (y? throw 2 : throw 3);
+
+    case 5:
+      // lvalue-to-rvalue
+      jc(y? throw 2 : a);
+      //ERROR(3): j(y? throw 2 : a);    // rvalue after conversion
+      break;
+
+    case 6:
+      // array-to-pointer (actually hard to tell, b/c the conversion
+      // could happen in the assignment...)
+      ptr = (y? throw 2 : arr);
+      break;
+
+    case 7:
+      // function-to-pointer (again, could occur in assignment)
+      funcptr = (y? throw 2 : h);
+      break;
+  }
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0309.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0309.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0309.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,128 @@
+// t0309.cc
+// 5.16 para 3, 4
+
+struct Base {
+  Base();
+  void baseFunc();
+  void baseFuncC() const;
+};
+struct Derived : public Base {
+  Derived();
+};
+
+struct ConvToInt {
+  operator int ();
+};
+
+struct ConvToIntRef {
+  operator int& ();
+};
+
+struct ConvFromInt {
+  ConvFromInt(int);
+};
+
+struct ConvBoth {
+  ConvBoth(int);
+  operator int ();
+};
+
+struct ConvToCharOrShort {
+  operator char ();
+  operator short ();
+};
+
+void f(int x, int y)
+{
+  Base b;
+  Base const bc;
+  Derived d;
+  Derived const dc;
+
+  int i = 3, j = 7;
+  long k = 8;
+  ConvToInt toInt;
+  ConvToIntRef toIntRef;
+  ConvFromInt fromInt(1);
+  ConvBoth both(1);
+  ConvToCharOrShort charShort;
+
+  switch (x) {
+    case 1:
+      // conv second to lvalue of third
+      (y? toIntRef : i) = 3;
+      break;
+
+    case 2:
+      // conv third to lvalue of second
+      (y? i : toIntRef) = 3;
+      break;
+
+    case 3:
+      // derived-to-base as lvalue conv
+      (y? b : d).baseFunc();
+      break;
+
+    case 4:
+      // derived-to-base as rvalue conv
+      //ERROR(1): (y? bc : d).baseFunc();
+      (y? bc : d).baseFuncC();
+      break;
+
+    case 41:
+      // actual rvalue, rather than ref-to-const?
+      (y? Base() : Derived()).baseFunc();
+      break;
+
+    case 5:
+      // illegal due to base having less cv qualification
+      //ERROR(2): (y? b : dc);
+      break;
+
+    case 6:
+      // second to rvalue of third
+      x = (y? toInt : i);
+      __elsa_checkType(y? toInt : i, (int)0);
+      //(elsa doesn't detect this..) ERROR(3): (y? toInt : i) = 3;
+      break;
+      
+    case 7:
+      // can't tell which direction to convert
+      //ERROR(4): (y? both : i);
+      break;
+      
+    case 8:
+      // can't convert in either direction
+      //ERROR(5): (y? b : i);
+      break;
+
+    case 9:
+      // simple lval situation
+      (y? i : j) = 9;
+      break;
+
+    case 10:
+      // simple rval situation
+      (y? 1 : 2);
+      __elsa_checkType(y? 1 : 2, (int)0);
+      //(elsa doesn't detect) ERROR(6): (y? 1 : 2) = 10;
+      break;
+
+    case 11:
+      // rval due to different types
+      (y? i : k);
+      __elsa_checkType(y? i : k, (long)0);
+      //(elsa doesn't detect) ERROR(7): (y? i : k) = 11;
+      break;
+      
+    case 12:
+      // ambiguous th->el or el->th conversion
+      (y? charShort : 'a'/*char*/);
+      //ERROR(6): (y? charShort : 1/*int*/);
+      //ERROR(7): (y? 1/*int*/ : charShort);
+      break;
+  }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0310.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0310.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0310.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,216 @@
+// t0310.cc
+// 5.16 para 5
+
+// gcc (3.4.0) erroneously rejects many of the things this file tests,
+// but Intel C++ (EDG) accepts it
+
+struct Int {
+  operator int();
+};
+
+struct Int2 {
+  operator int();
+};
+
+struct Long {
+  operator long();
+};
+
+struct Long2 {
+  operator long();
+};
+
+struct IntLong {
+  operator int();
+  operator long();
+};
+
+struct IntLong2 {
+  operator int();
+  operator long();
+};
+
+
+struct PInt {
+  operator int*();
+};
+
+struct PInt2 {
+  operator int*();
+};
+
+struct PLong {
+  operator long*();
+};
+
+struct PLong2 {
+  operator long*();
+};
+
+struct PIntLong {
+  operator int*();
+  operator long*();
+};
+
+struct PIntLong2 {
+  operator int*();
+  operator long*();
+};
+
+       
+//       A        .
+//      / \       .
+//     B   C      .
+//      \ /       .
+//       D        .
+struct A {};
+struct B : public A {};
+struct C : public A {};
+struct D : public B, public C {};
+
+struct PA {
+  operator A* ();
+};
+struct PB {
+  operator B* ();
+};
+struct PC {
+  operator C* ();
+};
+struct PD {
+  operator D* ();
+};
+
+
+struct AcceptInt {
+  void func(int i);
+private:
+  void func(long l);
+};
+
+struct AcceptLong {
+  void func(long i);
+private:
+  void func(int l);
+};
+
+struct AcceptPInt {
+  void func(int *i);
+private:
+  void func(long *l);
+};
+
+struct AcceptPLong {
+  void func(long *i);
+private:
+  void func(int *l);
+};
+
+struct AcceptPA {
+  void func(A*);    
+  private:  void func(B*);  void func(C*);  void func(D*);
+};
+struct AcceptPB {
+  void func(B*);    
+  private:  void func(A*);  void func(C*);  void func(D*);
+};
+struct AcceptPC {
+  void func(C*);    
+  private:  void func(A*);  void func(B*);  void func(D*);
+};
+struct AcceptPD {
+  void func(D*);    
+  private:  void func(A*);  void func(B*);  void func(C*);
+};
+
+
+// this structure contains an overloaded 'op' set that is a (finite) subset
+// of the signatures specified for '?:'; by filling it with all the relevant
+// members, I can compare real overload resolution to what happens for '?:'
+struct LikeQuestion {
+  // arithmetic types
+  int op(bool,int,int);
+  long op(bool,int,long);
+  long op(bool,long,int);
+  long op(bool,long,long);
+
+  // pointer types
+  int* op(bool,int*,int*);
+  long* op(bool,long*,long*);
+  A* op(bool,A*,A*);
+  B* op(bool,B*,B*);
+  C* op(bool,C*,C*);
+  D* op(bool,D*,D*);
+};
+
+
+void f(int x)
+{
+  Int i;
+  Int2 i2;
+  Long l;
+  Long2 l2;
+  IntLong il;
+  IntLong2 il2;
+
+  PInt pi;
+  PInt2 pi2;
+  PLong pl;
+  PLong2 pl2;
+  PIntLong pil;
+  PIntLong2 pil2;
+
+  PA pa;
+  PB pb;
+  PC pc;
+  PD pd;
+
+  AcceptInt accInt;
+  AcceptLong accLong;
+  AcceptPInt accPInt;
+  AcceptPLong accPLong;
+  AcceptPA accPA;
+  AcceptPB accPB;
+  AcceptPC accPC;
+  AcceptPD accPD;
+
+  LikeQuestion lq;
+
+  // result is int
+  __elsa_checkType(x? i : i2, (int)0);
+
+  // result is long
+  __elsa_checkType(x? i : l, (long)0);
+
+  // result is long
+  __elsa_checkType(x? l2 : l, (long)0);
+
+  // ambiguous
+  //ERROR(4): (x? i : il);
+
+  // result is int*
+  __elsa_checkType(x? pi : pi2, (int*)0);
+
+  // result is int*
+  __elsa_checkType(x? pi : pil, (int*)0);
+
+  // result is long*
+  __elsa_checkType(x? pl : pil, (long*)0);
+
+  // ambiguous
+  //ERROR(8): (x? pil : pil2);
+
+  // result is A*
+  __elsa_checkType(x? pa : pc, (A*)0);
+
+  // result is B*
+  __elsa_checkType(x? pb : pd, (B*)0);
+
+  // result is A*
+  __elsa_checkType(x? pb : pc, (A*)0);            // icc gets this wrong too
+}
+
+
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0311.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0311.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0311.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,51 @@
+// t0311.cc
+// 5.16 para 6
+
+//       A    E   .
+//      / \       .
+//     B   C      .
+//      \ /       .
+//       D        .
+struct A {};
+struct B : public A {};
+struct C : public A {};
+struct D : public B, public C {};
+struct E {};
+
+void foo(int x)
+{
+  A *pa = 0;
+  B *pb = 0;
+  C *pc = 0;
+  D *pd = 0;
+  E *pe = 0;
+
+  __elsa_checkType(x? pb : pa, (A*)0);
+  //(x? pb : pc);
+  //(x? pb : pe);
+  //(x? pd : pa);
+
+  // I really don't know what the right spec is here, so I'm
+  // just going to cross my fingers ....
+  
+  int A::*pma = 0;
+  int const A::*pmac = 0;
+  __elsa_checkType(x? pma : pmac, (int const A::*)0);
+  __elsa_checkType(x? pma : 0, (int A::*)0);
+  __elsa_checkType(x? 0 : pmac, (int const A::*)0);
+}
+
+// modified form of example in 5.9
+void bar(int x)
+{
+  void *p;
+  void const *pc;
+  const int *q;
+  int **pi;
+  const int *const *pci;
+
+  __elsa_checkType(x? p : q, (const void *)0);
+  __elsa_checkType(x? pi : pci, (const int * const *)0);
+  __elsa_checkType(x? p : pc, (const void *)0);
+  __elsa_checkType(x? pc : p, (const void *)0);
+}

Added: vendor/elsa/current/elsa/in/t0312.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0312.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0312.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0312.cc
+// ambiguous use of built-in assignment operator
+
+struct A {
+  operator int();
+  operator unsigned int();
+  operator double();
+};
+
+
+int main()
+{
+  A a;
+  int i = 4;
+  double d = 5;
+  unsigned int u = 6;
+
+  // for some reason, gcc and icc both accept these
+  i = a;
+  d = i;
+  u = i;
+
+  // even though they correctly reject this
+  //ERROR(1): i += a;
+
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0313.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0313.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0313.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0313.cc
+// convert array to bool (always converts as true...)
+
+// this comes from mozilla stopwatch.i, where it is actually
+// a bug (programmer said assert("...") instead of assert(!"..."))
+
+void b(bool);
+
+int f()
+{
+  b("a");
+
+  // same with function..
+  b(f);
+
+  "a"? 1 : 2;
+
+  char buf[20];
+  return buf? 1 : 2;
+}
+

Added: vendor/elsa/current/elsa/in/t0314.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0314.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0314.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0314.cc
+// another situation of needing to instantiate a template...
+
+struct A {};
+
+template <class T>
+struct B : public T {};
+
+void f(A *);
+
+void foo()
+{
+  B<A> *b;
+  f(b);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0315.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0315.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0315.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0315.cc
+// overload resoln with template func and pointer conversion
+
+template <class T>
+void f(T const *);
+
+template <class T>
+void f(T const *, int);
+
+void foo()
+{
+  int *i;
+  f(i);
+}
+

Added: vendor/elsa/current/elsa/in/t0316.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0316.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0316.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0316.cc
+// a 'T const &' param can be treated like 'T' ..
+
+// why would you do this??
+void f(int const &x);
+
+void foo(unsigned int &y)
+{                       
+  f(y);
+  
+  int const &x = y;
+}
+

Added: vendor/elsa/current/elsa/in/t0317.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0317.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0317.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0317.cc
+// static vs nonstatic in overload resoln
+
+struct A {
+  int foo(int);
+  static int foo(int,int);
+
+  void f();
+};
+
+void A::f()
+{
+  foo(2);
+  foo(2,3);
+}
+
+void g()
+{
+  A::foo(2,3);
+  //ERROR(1): A::foo(2);      // need receiver
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0318.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0318.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0318.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0318.cc
+// static class-valued member
+
+struct S {};
+
+struct A {
+  static S x;
+};
+
+S A::x;
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0319.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0319.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0319.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0319.cc
+// index a const array with an enumeration
+
+enum E { a,b,c };
+
+int const arr[5] = {1,2,3,4,5};
+
+void f()
+{
+  E e;
+  arr[e];
+}

Added: vendor/elsa/current/elsa/in/t0320.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0320.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0320.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0320.cc
+// parameter 'char' and argument 'char const &' are compatible
+
+template <class T>
+void f(T *t, char c);
+
+void foo(char const &c)
+{
+  int *i;
+  
+  f(i, c);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0321.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0321.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0321.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0321.cc
+// char* - char* = int
+
+void seek(int);
+
+void f()
+{
+  char line[5000];
+  char* replacementSubstring;
+
+  seek(replacementSubstring - line);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0322.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0322.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0322.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0322.cc
+// ok to have a static member that is of incomplete type
+
+struct A;
+
+struct B {
+  static A a;
+};
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0323.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0323.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0323.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0323.cc
+// trigger class instantiation during second pass tcheck of another class
+
+template <class T>
+struct A {
+  A(int*);
+};
+
+struct B {
+  A<int*> get() {
+    int *x;
+    return x;
+  }
+};

Added: vendor/elsa/current/elsa/in/t0324.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0324.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0324.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// t0324.cc
+// mix of abstract params requiring template argument deduction,
+// and concrete params where conversions are allowed
+
+template <class T>
+void f(T x, T *y);
+
+template <class T>
+void g(int x, T *y);
+
+
+struct A {
+  operator int ();
+};
+
+void foo()
+{
+  A a;
+  int *p;
+
+  //ERROR(1): f(a, p);   // does not work b/c first param uses template param
+  g(a, p);               // does work b/c first param is concrete
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0325.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0325.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0325.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0325.cc
+// this input was causing Oink's integrity checker to fail ....
+
+template<class T> struct A {};
+
+template<class T> struct B: A<T> {
+  T &f(int i) {
+    return A<T>::g(i);
+  }
+};
+
+struct C {};
+
+struct D {
+  B<int*> shells;
+  B<C*> delays;
+};

Added: vendor/elsa/current/elsa/in/t0326.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0326.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0326.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0326.cc
+// invoke a function through a function pointer
+
+void (*func)(int);
+
+void f()
+{
+  func(3);
+  //ERROR(1): func();     // wrong # of args
+}

Added: vendor/elsa/current/elsa/in/t0327.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0327.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0327.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0327.cc
+// use constructor to satisfy 'class const &' param
+// (instantiation problem)
+
+template <class T>
+struct A {
+  A(T);
+};
+
+void f(A<int> const &a);
+
+//A<int> a(4);
+
+void foo()
+{
+  int i;
+  f(i); 
+}

Added: vendor/elsa/current/elsa/in/t0328.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0328.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0328.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0328.cc
+// expression with lots of ambiguities
+
+typedef int x;
+
+void foo()
+{
+  int y;
+
+  0 +
+    // this outermost expression has 7 ambiguous alternatives, due to
+    // the interaction of cast-vs-funcall and multiplication-vs-deref;
+    // adding more "*(x)(y)" would add linearly to the # of
+    // ambiguities at the outer level
+    (x)(y)*(x)(y)*(x)(y)*(x)(y)*(x)(y)*(x)(y)*(x)(y);
+}

Added: vendor/elsa/current/elsa/in/t0329.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0329.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0329.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// t0329.cc
+// access a class member using a typedef in a qualifier
+
+struct Other {
+  int foo();
+};
+
+struct A {
+  int foo();
+  typedef Other A3;
+  typedef A Myself;
+};
+
+typedef A A2;
+typedef A A3;
+
+void f()
+{
+  A a;                          
+
+  // use the class name directly
+  a.A::foo();
+                   
+  // use a global typedef alias
+  a.A2::foo();
+
+  // use a member alias
+  a.Myself::foo();
+
+  // error: try to access a non-member
+  //ERROR(1): a.Other::foo();
+  //ERROR(2): a.::Other::foo();
+
+  // error: lookup in class != lookup in global
+  //--nerfed--ERROR(3): a.A3::foo();
+  // nerfed b/c it doesn't work; see t0330.cc
+
+  // only use lookup in global
+  a.::A3::foo();
+}

Added: vendor/elsa/current/elsa/in/t0330.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0330.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0330.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0330.cc
+// lookup bug: failure to diagnose ambiguous lookup
+
+struct Other {
+  int foo();
+};
+
+struct A {
+  int foo();
+  typedef Other A3;
+};
+
+typedef A A3;
+
+void f()
+{
+  A a;
+
+  // error: lookup in class != lookup in global
+  //ERROR(1): a.A3::foo();
+}

Added: vendor/elsa/current/elsa/in/t0331.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0331.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0331.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0331.cc
+// use operator on dependent type in template code
+
+template <class T>
+class Ptr {
+public:
+  T operator* ();
+};
+
+enum E { e1 } e;
+
+template <class T>
+T deref(Ptr<T> &p)
+{
+  return *p << e;     // *p has dependent type when tchecking the template body
+}
+
+int f()
+{
+  Ptr<int> p;
+  return deref(p);
+}
+

Added: vendor/elsa/current/elsa/in/t0332.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0332.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0332.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0332.cc
+// pass array where reference to const pointer is expected
+
+void f(char * const &p);
+
+void foo()
+{
+  char arr[2];
+  
+  f(arr);
+  f("whatever");
+}
+

Added: vendor/elsa/current/elsa/in/t0333.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0333.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0333.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0333.cc
+// friends that are const member functions
+
+struct A {
+  int foo() const;
+};
+
+struct B {
+  friend int A::foo() const;
+};

Added: vendor/elsa/current/elsa/in/t0334.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0334.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0334.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// t0334.cc
+// initialization by conversion
+// from qt/src/kernel/qfont_x11.cpp
+
+class QChar {
+};
+
+class QCharRef {
+public:
+  operator QChar ();
+};
+
+void f(QChar const &c);
+void f2(QChar &c);
+
+void foo()
+{
+  QCharRef r;
+
+  f(r);            // init an ordinary parameter
+  QChar c1(r);     // init with explicit copy ctor
+  QChar c2 = r;    // init with implicit copy ctor
+  
+  // illegal b/c a temporary gets bound to a non-const reference
+  //ERROR(1): f2(r);
+}

Added: vendor/elsa/current/elsa/in/t0335.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0335.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0335.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0335.cc
+// delete an incomplete type (5.3.5 para 5)
+
+class A;
+
+A *p;
+
+void foo()
+{
+  delete p;
+}          
+
+// this program is valid (has defined behavior) only if this
+// definition appears (e.g. in another translation unit) with
+// trivial destructor
+//class A {};

Added: vendor/elsa/current/elsa/in/t0336.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0336.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0336.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// t0336.cc
+// default argument union
+
+void f(int, int);
+void f(int x, int y = 2);
+
+void f();
+
+
+void g(int x, int y, int z);
+void g(int x, int y, int z=3);
+void g(int x, int y=2, int z);
+void g(int x=1, int y, int z);
+
+// would provide a redundant value
+//ERROR(2): void g(int x=1, int y, int z);
+
+void g(char*);
+
+
+void h(int x, int y);
+
+// would make a param w/o default after one with default
+//ERROR(1): void h(int x=1, int y);
+
+
+void foo()
+{
+  f(1);     // needs default arg for 'y' from 2nd decl
+
+  g();      // needs all defaults
+}

Added: vendor/elsa/current/elsa/in/t0337.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0337.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0337.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0337.cc
+// situation requiring argument-dependent re-lookup
+
+// some global function (not the one we want to call)
+void f(char*);
+
+template <class T>
+struct A {
+  // here is the one we want
+  void f(T);
+
+  // this is needed to make a complicated argument, below
+  T otherFunc();
+};
+
+// but the one we want is only visible via a dependent base class
+template <class T>
+struct B : public A<T> {
+  void foo()
+  {
+    T t;
+
+    // the argument here is a little complicated; I think my
+    // computation of what is dependent is being fooled by it
+    f( this->otherFunc() );      // invoke 'f'
+  }
+};
+
+void bar()
+{
+  B<int> b;
+  b.foo();     // instantiate B<int>::foo
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0338.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0338.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0338.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0338.cc
+// access a type_info
+
+// this would normally come from the <typeinfo> header
+namespace std {
+  class type_info {
+  public:
+    char const *name() const;
+  };
+}
+
+void foo()
+{
+  int i;
+  
+  typeid(i).name();
+}

Added: vendor/elsa/current/elsa/in/t0339.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0339.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0339.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0339.cc
+// overload resolution when passing a function
+
+void foo( int (*f)(int) );     // line 4
+void foo( int (*f)(int, int, int, int) );
+
+int g(int, int, int);          // line 7
+int g(int, int);               // line 8
+int g(int);                    // line 9
+
+void foo2( int (*f)(int,int) );      // line 11
+void foo3( int (*f)(int,int,int) );  // line 12
+
+void bar()
+{
+  foo(g);        // pass third 'g'
+  foo(&g);       // pass third 'g'
+  foo2(g);       // pass second 'g'
+  foo3(&g);      // pass first 'g'
+  
+  foo( ((((&((((g)))))))) );     // third 'g'
+}
+
+asm("collectLookupResults foo=4 g=9 foo=4 g=9 foo2=11 g=8 foo3=12 g=7 foo=4 g=9");

Added: vendor/elsa/current/elsa/in/t0340.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0340.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0340.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0340.cc
+// define a static member of a class using ctor-call syntax
+
+struct A {
+  static int x;
+  static int y;
+  static int z;
+};
+
+// no ambiguity
+int A::x(5);
+
+enum E { val=5 };
+
+// type-variable ambiguity
+int A::y(val);
+
+// error: declare the name as the wrong type
+// (currently causes an assertion failure)
+//ERROR(1): int A::z(int);
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0341.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0341.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0341.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0341.cc
+// test where type of unary - must be computed properly.
+// then extended for 0L also
+
+class CPPValue {
+public:
+  CPPValue(long val);
+  CPPValue(double val);
+};
+
+void foo()
+{
+  long x;
+
+  // the "0," is to make it clearly an expression; the first case
+  // below would otherwise (correctly) be parsed as a declaration, and
+  // then diagnosed as erroneous
+
+  0, CPPValue(x);
+  0, CPPValue(-x);
+  
+  0, CPPValue(0L);
+}

Added: vendor/elsa/current/elsa/in/t0342.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0342.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0342.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,63 @@
+// t0342.cc
+// test 5.3.1 paras 6--9
+
+struct S {};
+
+void foo()
+{
+  char c;
+  int i;
+  unsigned u;
+  long L;
+  float f;
+  double d;
+  int *p;
+  S s;
+
+  // 5.3.1 para 6
+  __elsa_checkType(+c, (int)0);
+  __elsa_checkType(+i, (int)0);
+  __elsa_checkType(+u, (unsigned int)0);
+  __elsa_checkType(+L, (long)0);
+  __elsa_checkType(+f, (float)0);
+  __elsa_checkType(+d, (double)0);
+  __elsa_checkType(+p, (int *)0);
+  //ERROR(1): +s;    // '+' to struct
+  //ERROR(2): +foo;  // '+' to function
+
+  // 5.3.1 para 7
+  __elsa_checkType(-c, (int)0);
+  __elsa_checkType(-i, (int)0);
+  __elsa_checkType(-u, (unsigned int)0);
+  __elsa_checkType(-L, (long)0);
+  __elsa_checkType(-f, (float)0);
+  __elsa_checkType(-d, (double)0);
+  //ERROR(3): -p;    // '-' to pointer
+  //ERROR(4): -s;    // '-' to struct
+  //ERROR(5): -foo;  // '-' to function
+
+  // 5.3.1 para 8
+  __elsa_checkType(!c, (bool)0);
+  __elsa_checkType(!i, (bool)0);
+  __elsa_checkType(!u, (bool)0);
+  __elsa_checkType(!L, (bool)0);
+  __elsa_checkType(!f, (bool)0);
+  __elsa_checkType(!d, (bool)0);
+  __elsa_checkType(!p, (bool)0);
+  //ERROR(6): !s;    // '!' to struct
+  // Elsa allows converting a function to bool, and I think that is
+  // right, but I'm not sure so I am not going to test it.
+
+  // 5.3.1 para 9
+  __elsa_checkType(~c, (int)0);
+  __elsa_checkType(~i, (int)0);
+  __elsa_checkType(~u, (unsigned int)0);
+  __elsa_checkType(~L, (long)0);
+  //ERROR(7): ~f;    // '~' to floating point
+  //ERROR(8): ~d;    // '~' to floating point
+  //ERROR(9): ~p;    // '~' to pointer
+  //ERROR(10): ~s;   // '~' to struct
+  //ERROR(11): ~foo; // '~' to function
+  
+  // see also t0343.cc
+}

Added: vendor/elsa/current/elsa/in/t0343.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0343.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0343.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0343.cc
+// 5.3.1 para 9: ambiguity between ~X() as destructor call
+// and ~X() as bitwise complement after conversion to int
+
+extern "C" int printf(char const *format, ...);
+
+struct X {
+  X()                 { printf("constructor invocation\n"); }
+  ~X()                { printf("destructor invocation\n"); }
+  operator int ()     { printf("conversion to int\n"); }
+
+  void foo();
+};
+
+void X::foo()
+{
+  // definitely a conversion to int
+  printf("test 1\n");
+  0 + X();
+
+  // definitely a destructor invocation
+  printf("test 2\n");
+  this->X::~X();
+
+  // also a destructor invocation, I think, but gcc does not like it ...
+  //printf("test 3\n");
+  //X::~X();
+
+  // nominally ambiguous, but cppstd says prefer conversion + bitwise
+  // complement (can see that Elsa agrees with "-tr prettyPrint".. I
+  // can't think of a way to make that automatic here...)
+  printf("test 4\n");
+  ~X();
+
+  printf("end of foo()\n");
+}
+
+int main()
+{
+  X x;
+  x.foo();
+}

Added: vendor/elsa/current/elsa/in/t0344.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0344.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0344.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0344.cc
+// pass ptr-to-member where member is inherited
+
+
+struct Base {
+  void func();
+  int x;
+};
+struct A : public Base {
+};
+
+void forall( void (A::*func)() );
+//void forall( int ) ;
+
+void another( int A::*p );
+
+
+void foo()
+{
+  // the conversions up here require special treatment because the
+  // Elsa type system puts the receiver parameter into the param list
+
+  forall(&A::func);
+
+  void (Base::*bptr)();
+  forall(bptr);
+
+
+  // the conversions below here only require that ptr-to-base-member
+  // be convertible to ptr-to-derived-member (no param lists involved)
+
+  another( &A::x );
+  
+  int Base::*bptr2;
+  another(bptr2);
+}

Added: vendor/elsa/current/elsa/in/t0345.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0345.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0345.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0345.cc
+// types of integer literals
+
+void foo()
+{
+  __elsa_checkType(1, (int)0);
+  __elsa_checkType(1U, (unsigned)0);
+  __elsa_checkType(1L, (long)0);
+  __elsa_checkType(1UL, (unsigned long)0);
+  __elsa_checkType(1LL, (long long)0);
+  __elsa_checkType(1ULL, (unsigned long long)0);
+
+  // the following tests are dependent on the host architecture, so I
+  // have them commented-out; they are correct for a 32-bit int
+  //
+  // actually, the int rolls over to long long if int and long are
+  // the same size ...
+
+  // decimal: int -> long
+  //__elsa_checkType(2147483647, (int)0);
+  //__elsa_checkType(2147483648, (long long)0);
+
+  // hex: int -> unsigned
+  //__elsa_checkType(0x7FFFFFFF, (int)0);
+  //__elsa_checkType(0x80000000, (unsigned)0);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0346.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0346.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0346.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0346.cc
+// type of character literals
+
+void foo()
+{
+  __elsa_checkType('a', (char)0);
+  __elsa_checkType('ab', (int)0);
+  __elsa_checkType(L'a', (wchar_t)0);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0347.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0347.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0347.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0347.cc
+// compare pointers by converting to void*
+
+struct A {
+  operator void* ();
+};
+
+struct B {
+  operator void const * ();
+};
+
+void foo()
+{
+  A a;
+  int *p;
+
+  a != p;
+  
+
+  // convert to 'void const volatile *' (union the atType cv flags)
+  B b;
+  int volatile * q;
+  
+  // this is another one that gcc and icc can't handle, though I
+  // believe it to be legal (and Elsa allows it)
+  b == q;
+}

Added: vendor/elsa/current/elsa/in/t0348.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0348.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0348.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0348.cc
+// template argument deduction where a qualification conversion
+// is involved
+
+template <class T>
+struct L {};
+
+template <class T>
+void f(L<T> const *list, int indent);
+
+
+struct A {};
+
+void foo()
+{
+  L<A> *list;
+
+  f(list, 3);
+}

Added: vendor/elsa/current/elsa/in/t0349.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0349.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0349.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0349.cc
+// problem with operator[] inside template bodies
+
+// class with operator[]
+template <class T>
+struct AS {
+  T const& operator[] (int i) const;
+  T      & operator[] (int i)      ;
+
+  void foo(int i)
+    { operator[](i); }
+};
+
+// no problem
+void foo(AS<int> const &src)
+{
+  int i;
+  src[i];
+}
+
+// problem
+template <class T>
+void copyIndexPtrArray(T *base, AS<int> const &src)
+{
+  int i;
+  src[i];
+}
+
+// instantiate the template
+void foo()
+{
+  int *p;
+  AS<int> a;
+
+  copyIndexPtrArray(p, a);
+}

Added: vendor/elsa/current/elsa/in/t0350.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0350.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0350.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0350.cc
+// problem with argument deduction after a variable is bound
+
+template <class T, class Y>
+void f(int indent, T *t, Y (*map)(T const *t));
+
+class Variable {};
+
+int varName(Variable const *v);
+
+void foo()
+{
+  Variable *v;
+  f(3, v, &varName);
+  f(3, v, varName);
+}

Added: vendor/elsa/current/elsa/in/t0351.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0351.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0351.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// t0351.cc
+// pass 'Foo const' as a template argument
+
+template <class T>
+struct A {
+  void foo(T *t);
+};
+
+struct B {};
+
+void bar(B *);
+
+void f()
+{
+  // first, make a distracting instantiation *without* the const;
+  // this causes Elsa to re-use the distractor instantiation, thus
+  // forgetting about the 'const'
+  A<B> distractor;
+
+  // now instantiate with 'const'
+  A<B const> a;
+  B const *p;
+
+  // have to get 'Bar const *' as parameter type, which means not
+  // ignoring the 'const' in the template argument
+  a.foo(p);
+  
+  // not allowed
+  //ERROR(1): bar(p);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0352.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0352.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0352.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,46 @@
+// t0352.cc
+// nasty example using very dependent types
+// (even gcc-3 doesn't get this right, though icc does)
+
+
+template <class T>
+struct A {
+  int foo(typename T::template S<int> x);
+  int foo(typename T::template S<float> x);
+};
+
+
+template <class T>
+int A<T>::foo(typename T::template S<int> x)
+{
+  return 1;
+}
+
+
+template <class T>
+int A<T>::foo(typename T::template S<float> x)
+{
+  return 2;
+}
+
+
+class B {
+public:
+  template <class U>
+  class S {
+  public:
+    S();       // silence an icc warning
+
+    U u;
+  };
+};
+
+
+void f()
+{
+  A<B> a;
+  B::S<int> i;
+  B::S<float> f;
+  a.foo(i);
+  a.foo(f);
+}

Added: vendor/elsa/current/elsa/in/t0353.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0353.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0353.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,69 @@
+// t0353.cc
+// even nastier than t0352.cc
+
+
+template <class T>
+struct A {
+  int foo(typename T::Inner::template S<int> x);
+  int foo(typename T::Inner::template S<float> x);
+  int foo(typename T::Inner2::template S<float> x);
+};
+
+
+template <class T>
+int A<T>::foo(typename T::Inner::template S<int> x)
+{
+  return 1;
+}
+
+
+template <class T>
+int A<T>::foo(typename T::Inner::template S<float> x)
+{
+  return 2;
+}
+
+
+template <class T>
+int A<T>::foo(typename T::Inner2::template S<float> x)
+{
+  return 3;
+}
+
+
+class B {
+public:
+  class Inner {
+  public:
+    template <class U>
+    class S {
+    public:
+      S();       // silence an icc warning
+
+      U u;
+    };
+  };
+
+  class Inner2 {
+  public:
+    template <class U>
+    class S {
+    public:
+      S();       // silence an icc warning
+
+      U u;
+    };
+  };
+};
+
+
+void f()
+{
+  A<B> a;
+  B::Inner::S<int> i;
+  B::Inner::S<float> f;
+  B::Inner2::S<float> f2;
+  a.foo(i);
+  a.foo(f);
+  a.foo(f2);
+}

Added: vendor/elsa/current/elsa/in/t0354.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0354.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0354.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0354.cc
+// type of string literal affects semantics
+
+extern "C" {
+  int printf(char const *fmt, ...);
+}
+
+void foo(char*)                      // line 8
+{
+  printf("foo(char*)\n");
+}
+
+void foo(char const*)                // line 13
+{
+  printf("foo(char const*)\n");
+}
+
+int main()
+{
+  __testOverload(foo("hi"), 13);
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0355.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0355.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0355.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0355.cc
+// testing that msvc/m0001.cc is rejected in non-MSVC mode
+
+class Integer {
+public:
+  // this is fine
+  int operator<(int);
+  
+  // this is illegal, but allowed by MSVC
+  //ERROR(1): operator==(const Integer&) const { return 0; }
+};

Added: vendor/elsa/current/elsa/in/t0356.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0356.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0356.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0356.cc
+// argument-dependent lookup bug reported by Altac Edena
+// this is very similar to the example of 3.4.2 para 2
+
+namespace N {
+  class B {};
+  void g(B);
+  int h;
+  
+  // interestingly, icc does not regard this as an error,
+  // though gcc-3 does ...
+  //ERROR(3): int k;
+}
+
+int k(N::B);
+
+class A {
+public:
+  void f() {
+    N::B b;
+    g(b);
+
+    //ERROR(1): g(b,1);
+
+    //ERROR(2): h(b);
+    
+    k(b);
+  }
+};

Added: vendor/elsa/current/elsa/in/t0357.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0357.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0357.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0357.cc
+// trying to demonstrate effect of this-> elaboration 
+// for parenthesized functions
+
+class C {
+public:
+  int foo();
+  void bar();
+};
+
+void C::bar()
+{
+  foo();
+
+  (foo)();
+
+  // this syntax causes a segfault with cc_tcheck.cc version 1.475
+  ((((foo))))();
+}
+
+

Added: vendor/elsa/current/elsa/in/t0358.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0358.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0358.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0358.cc
+// isolated from nsHTMLEditRules, this syntax is causing a segfault
+
+
+typedef int Int32;
+
+struct Foo {
+  int Length();
+};
+
+
+void foo(Foo *f)
+{
+  //(Int32)(*f).Length();
+
+  3 < (Int32)(*f).Length();
+}

Added: vendor/elsa/current/elsa/in/t0359.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0359.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0359.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0359.cc
+// problem with dependentness of 'this'; the problem only recently
+// arose because we recently added the insertion of otherwise
+// implicit uses of 'this'
+
+class HashTable
+{
+};
+
+struct HashTableIter {
+  HashTableIter(HashTable &t);
+};
+
+template < class T >
+class OwnerHashTable
+{
+  HashTable table;
+  void empty (int initSize);
+};
+
+template < class T >
+void OwnerHashTable
+  <T>
+  ::empty (int initSize)
+{
+  HashTableIter iter (table);
+}

Added: vendor/elsa/current/elsa/in/t0360.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0360.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0360.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0360.cc
+// cppstd apparently wants arg-dep lookup here, but Elsa can't do it
+
+class stringBuilder
+{
+  typedef void (*Manipulator) (stringBuilder & sb);
+  void foo(Manipulator manip);
+};
+
+void stringBuilder::foo(Manipulator manip)
+{
+  manip (*this);
+}

Added: vendor/elsa/current/elsa/in/t0361.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0361.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0361.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+// t0361.cc
+// declare member function with qualified name
+
+struct C {
+  int x;
+
+  // icc says this syntax is illegal                
+  //
+  // gcc says it is ok
+  //
+  // right now, Elsa rejects it
+  int 
+    //ERROR(2): C::
+    foo();
+  
+  // related: actually, Elsa is failing an assertion right now
+  // whenever a static method uses a nonstatic variable (now fixed)
+  static int bar();
+};
+
+int C::foo()
+{
+  return x;
+}
+
+int C::bar()
+{
+  int ret = 1;
+  //ERROR(1): ret += x;
+  return ret;
+}
+

Added: vendor/elsa/current/elsa/in/t0362.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0362.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0362.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0362.cc
+// another problem with implicit this
+
+struct C {
+  int foo(int);
+  static int foo(int,int);
+};
+
+/*static*/ int C::foo(int x, int y)
+{
+  // attempt recursive call
+  foo(x,y);
+}
+

Added: vendor/elsa/current/elsa/in/t0363.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0363.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0363.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,73 @@
+// in/t0363.cc
+// some uses of implicit 'this' to check for elaboration
+
+// for now I just inspect the output manually; in the future
+// I'd like to add a post-tcheck walk that checks to be sure
+// that this-> is used in the proper places
+
+            struct S {
+              int x;
+              static int y;
+
+              int foo();
+
+              static int bar();
+
+              // overloaded, nonstatic first
+              int baz(int);
+              static int baz(int,int);
+
+              // overloaded, static first
+              static int zoo(int,int);
+              int zoo(int);
+            };
+
+            int S::foo()
+            {
+              int ret = 0;
+              int (S::*ptm);
+              int *p;
+
+              ret += x;            // this->x
+              ret += S::x;         // this->x
+              ret += this->x;
+
+              ptm = &S::x;         // S::x
+              p = &(S::x);         // this->x
+
+              ret += y;            // S::x
+              ret += this->y;      // legal, but redundant
+
+              ret += baz(1);       // this->baz
+              ret += (baz)(1);     // this->baz
+              ret += ((baz))(1);   // this->baz
+              ret += baz(1,2);     // S::baz
+              ret += (baz)(1,2);   // S::baz
+              ret += ((baz))(1,2); // S::baz
+
+              ret += zoo(1);       // this->baz
+              ret += zoo(1,2);     // S::zoo
+
+              return ret;
+            }
+
+            /*static*/ int S::bar()
+            {
+              int ret = 0;
+
+//ERROR(1):   ret += x;
+//ERROR(2):   ret += this->x;
+
+              ret += y;            // S::x
+//ERROR(3):   ret += this->y;
+
+//ERROR(4):   ret += baz(1);
+              ret += baz(1,2);     // S::baz
+
+//ERROR(5):   ret += zoo(1);
+              ret += zoo(1,2);     // S::zoo
+
+              return ret;
+            }
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0364.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0364.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0364.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,49 @@
+// t0364.cc
+// tricky problem with arg-dep lookup
+
+// isolated from nsCSSFrameConstructor.cpp:7312:5: error: no viable candidate for function call
+
+
+class nsIStyleContext {
+public:
+  virtual void myGetStyleData(int aSID);
+};
+
+
+template <class T>
+inline void
+myGetStyleData(nsIStyleContext* aStyleContext, const T** aStyleStruct)
+{}
+
+template <class T>
+inline void
+myGetStyleData(void * aFrame, const T** aStyleStruct)
+{}
+
+void foo()
+{
+  const int *vis;
+  nsIStyleContext *ctx;
+
+  // call site where no receiver is present
+  myGetStyleData(ctx, &vis);
+}
+
+
+struct S {
+  void bar();
+};
+
+void S::bar()
+{
+  const int *vis;
+  nsIStyleContext *ctx;
+
+  // call site with an irrelevant receiver
+  myGetStyleData(ctx, &vis);
+}
+
+
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0365.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0365.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0365.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0365.cc
+// another one from Altac Edena
+
+namespace N {
+  class A {};
+  class B {};
+  A& operator<<(A&, B&);
+  A& f(A&, B&);
+}
+
+void g() {
+  N::A a;
+  N::B b;
+  f(a, b);  // <=== OK
+  a << b;   // <=== KO
+}

Added: vendor/elsa/current/elsa/in/t0366.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0366.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0366.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,56 @@
+// t0366.cc
+// testing some of the finer points of arg-dep operator lookup
+
+namespace N {
+  class A {};
+  class B {};
+  A& operator<<(A&, B&);
+  A& f(A&, B&);
+
+  struct C {        //ERRORIFMISSING(3): just testing multitest.pl
+    void operator+(B&);
+  };
+}
+
+// would make the use of '<<' below ambiguous
+//ERROR(2): void operator<<(N::A&, N::B&);
+
+void g() {
+  N::A a;
+  N::B b;
+  f(a, b);  // <=== OK
+  a << b;   // <=== KO
+}
+
+void h(N::C &c, N::B &b)
+{
+  // this tests that during 3.4.2 lookup we skip class members,
+  // because otherwise we would find C::operator+ twice and
+  // thus complain about an ambiguity
+  c + b;
+}
+
+enum E { E_FOO };
+
+struct D {
+  D(E e);     // implicit conversion to D from E
+};
+
+void foo(D d);
+void operator*(D d);
+
+void j(D &d)
+{
+  E e = E_FOO;
+
+  foo(d);
+  foo(e);     // possible via implicit conversion
+
+  *d;         // finds ::operator*(D)                                
+  
+  // icc recognizes this as illegal, gcc (3.4.0, 3.4.3) does not
+  //ERROR(1): *e;         // finds nothing, since no class-typed args
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0367.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0367.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0367.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0367.cc
+// from Altac Edena
+// Assertion failed: during type matching, recursion depth exceeded the limit 500, file matchtype.cc line 880
+
+template <class T, class U>
+class A {};
+
+template <class T, class U>
+A<T, U> f(A<T, U>);
+
+template <class U>
+A<int, U> f(A<int, U>);
+
+void g() {
+  A<int, double> a;
+  f(a);
+}

Added: vendor/elsa/current/elsa/in/t0368.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0368.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0368.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// t0368.cc
+// from Altac Edena
+// error: during function template argument deduction: argument 1 `class B &' is incompatible with parameter, `A<T>'
+
+template <class T>
+class A {};
+
+class B : public A<int> {};
+
+typedef A<int> C;
+
+template <class T>
+void f(A<T>);
+
+void g()
+{
+  A<int> a;
+  f(a); // <== OK
+  C c;
+  f(c); // <== OK
+  B b;
+  f(b); // <== KO
+}
+
+
+template <class T>
+void f2(A<T> &);
+
+template <class T>
+void f3(A<T> *);
+
+void h()
+{
+  B b;
+  f2(b);
+  f3(&b);
+}

Added: vendor/elsa/current/elsa/in/t0369.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0369.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0369.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,61 @@
+// t0369.cc
+// from Altac Edena
+// error: there is no function called `f'
+
+struct A {
+  A(int b, int a = f());
+
+  void foo(int x, int y = f());
+
+  int i_am_retarded()
+  {
+    return bar(2,3 /*implicit*/);
+  }
+
+  int bar(int x, int y, int z = f())
+  {
+    return x+y+z;
+  }
+
+  void h()
+  {
+    foo(3,4);
+    foo(5 /*A::f() implicit*/);
+
+    bar(3,4,5);
+    bar(6,7 /*A::f() implicit*/);
+  }
+
+  static int f();
+};
+
+void g()
+{
+  A a(1,2);
+  A a2(1 /*implicit*/);
+
+  a.foo(3,4);
+  a.foo(5 /*A::f() passed implicitly*/);
+
+  a.bar(3,4,5);
+  a.bar(6,7 /*A::f() implicit*/);
+}
+
+
+// ------ try with a templatized class ------
+template <class T>
+struct C {
+  int foo(int x, int y = 3);
+  int bar(int x, int y = 3) { return 1; }
+};
+
+void h()
+{
+  C<int> c;
+
+  c.foo(2,3);
+  c.foo(2 /*implicit*/);
+
+  c.bar(2,3);
+  c.bar(2 /*implicit*/);
+}

Added: vendor/elsa/current/elsa/in/t0370.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0370.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0370.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0370.cc
+// another from A.E.
+
+template <class T>
+struct B {
+  static const int _n = -1;
+  B(int n = _n);
+};
+
+void f() {
+  B<int> b;
+}

Added: vendor/elsa/current/elsa/in/t0371.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0371.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0371.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0371.cc
+// arg-dep lookup of template-id
+
+namespace N {
+  class A {};
+  
+  template <class T>
+  void foo(A &a, T t);
+};
+
+template <class T>
+void foo(int x, int y, int z);
+
+void bar(N::A &a)
+{                
+  // the "<int>" following "foo" is permitted only because lookup of
+  // "foo" yields (at least?) a template name; but then, since the
+  // name is unqualified, arg-dep lookup augments the original lookup
+  // set with N::foo, which is the one chosen (14.8.1 para 6)
+  //
+  // interestingly, gcc does not like this syntax, though icc does
+  foo<int>(a, 3);
+}

Added: vendor/elsa/current/elsa/in/t0372.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0372.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0372.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0372.cc
+// testing 14.2 para 2
+
+template <class T>
+void templ1(int x, T y);
+
+void templ1(int x, int y, int z);
+
+
+void templ2(int x, int y, int z);
+
+template <class T>
+void templ2(int x, T y);
+
+
+void nontempl(int x, int y);
+
+
+void bar()
+{
+  templ1(3,4);
+  templ1<int>(3,4);
+
+  nontempl(3,4);
+  //ERROR(1): nontempl<int>(3,4);
+
+  templ2(3,4);
+  templ2<int>(3,4);
+}

Added: vendor/elsa/current/elsa/in/t0373.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0373.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0373.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0373.cc
+// ambiguity with angle brackets, this time for function templates
+
+// bears some relation to t0182.cc
+
+template <int x>
+void foo(int z);
+
+int bar;
+
+void f()
+{
+  foo<3>(4);         // template function call
+  bar<3>(4);         // comparison expression
+  
+  //ERROR(1): foo<3>4;           // syntax error, arguments must be parenthesized
+  //ERROR(2): bar<>(4);          // error, bar is not a template
+}

Added: vendor/elsa/current/elsa/in/t0374.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0374.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0374.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0374.cc
+// E.A.: user copy ctor should prevent compiler-supplied
+
+struct B {
+  B(const B&, int n = 0);
+};
+
+void f(const B& b) {
+  B _b(b);
+}

Added: vendor/elsa/current/elsa/in/t0375.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0375.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0375.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0375.cc
+// copy ctor cannot be a template
+
+struct S {
+  // this member template is not the copy constructor because
+  // it is a template (12.8 para 2), and will not be used below
+  template <class T>
+  S(S const &s, T *t = 0)
+  {
+    int x = T::doesNotExist;
+  }
+};
+
+void foo(S const &src)
+{
+  S s(src);      // calls compiler-supplied implicit copy ctor
+}
+

Added: vendor/elsa/current/elsa/in/t0376.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0376.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0376.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0376.cc
+// E.A.: namespace lookup returning set
+
+namespace N {
+  struct A {};
+
+  A& operator<<(A&, int);
+}
+
+N::A& operator<<(N::A&, char*);
+
+template <class T>
+struct B {
+  B(T t) {
+    N::A a;
+    a << t;
+  }
+};
+
+using namespace N;
+
+void f() {
+  B<int> b(1);
+}

Added: vendor/elsa/current/elsa/in/t0377.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0377.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0377.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0377.cc
+// namespace-aware lookup yielding set
+
+namespace N {
+  void foo(int x);
+}
+
+using namespace N;
+
+void foo(int x, int y);
+
+void bar()
+{
+  foo(3);          // N::foo
+  foo(4,5);        // ::foo
+}

Added: vendor/elsa/current/elsa/in/t0378.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0378.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0378.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0378.cc
+// qualified lookup of names after '~'
+
+struct A {
+  ~A();
+};
+
+typedef A B;
+  
+namespace N {
+  struct C {
+    ~C();
+  };
+};
+
+
+
+void foo(A *a, N::C *c)
+{
+  a->~A();         // explicit dtor call w/o qualification
+  a->~B();         // use the typedef
+
+  a->A::~A();      // qualified
+  
+  // this this legal?  both icc and gcc accept it, but I do not know
+  // why; as far as I can tell, ~B should be looked up in the scope of
+  // A, which won't find anything
+  //a->A::~B();
+
+  c->N::C::~C();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0379.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0379.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0379.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// t0379.cc
+// typedef as qualifier
+
+namespace A {
+  struct B {
+    int f();
+    int g();
+  };
+  int x;
+  
+  namespace C {
+    int y;
+  }
+}
+
+
+// both A and B get searched, since both appear explicitly
+int A::B::f()
+{
+  return x;
+}
+
+
+typedef A::B AB;
+
+// A does not appear explicitly, so does not get searched
+//
+// 2005-08-10: This is now fixed; searching is done right.
+int AB::g()
+{
+  return x;
+}
+
+
+// can't nominate a namespace with a typedef
+//ERROR(1): typedef A::C AC;
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0380.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0380.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0380.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0380.cc
+// testing an aspect of non-dependent lookup
+
+int f(char);             // line 4
+
+template <class T>
+int foo(T *t)            // line 7
+{
+  return f(4);           // should get 'f' on line 4
+}
+
+int f(int);              // line 12
+
+void bar()
+{
+  int *y = 0;            // line 16
+  foo(y);
+}
+
+asm("collectLookupResults f=4 foo=7 y=16");

Added: vendor/elsa/current/elsa/in/t0381.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0381.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0381.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0381.cc
+// some games with elaborated type specifiers
+
+// icc fails to reject: 1
+
+struct C {};
+struct D {};
+
+int C;
+
+enum E { e1 };
+enum F { f1 };
+
+int foo()
+{
+  {
+    // would make use of 'D' below refer to typedef
+    //ERROR(1): typedef struct C D;
+
+    struct D d;
+  }
+
+  {
+    // similar for enums
+    //ERROR(2): typedef enum E F;
+    
+    enum F f;
+  }
+
+
+  struct C c;
+
+  return C;
+}
+
+

Added: vendor/elsa/current/elsa/in/t0382.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0382.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0382.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// t0382.cc
+// use a 'using' declaration to name an enum
+
+// icc fails to reject: 1
+
+namespace N {
+  enum E { e };
+  int g(int);
+}
+
+struct S { int x; };
+
+void foo()
+{
+  using namespace N;     // get it all
+
+  enum E e1;
+  struct S s1;
+
+  //ERROR(1): enum S s2;      // S is a struct, not an enum
+
+  int x = e;      // 'e' *does* come along
+
+  g(3);
+}
+
+
+void bar()
+{
+  using N::E;     // get just 'E'
+
+  enum E e1;
+  struct S s1;
+
+  //ERROR(2): int x = e;      // 'e' does not come along
+
+  int y = N::e;   // must explicitly qualify
+}

Added: vendor/elsa/current/elsa/in/t0383.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0383.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0383.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0383.cc
+// from http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11828
+
+int x;
+int y;
+
+namespace n
+{
+  template <typename T>
+  void
+  f(T a)
+  {
+    a.f();
+  }
+
+  template <typename T>
+  void
+  g(T a)
+  {
+    x;
+    n::f(a);
+    y;
+  }
+}
+
+struct S
+{};
+
+namespace n
+{
+  void f(S) {}       //ERRORIFMISSING(1): would find 'f' above
+}
+
+int
+main()
+{
+  n::g(S());
+
+  return 0;
+}
+
+//asm("collectLookupResults");

Added: vendor/elsa/current/elsa/in/t0384.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0384.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0384.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,61 @@
+// t0384.cc
+// global function is friend
+
+// experimenting with how :: is parsed in relation to identifiers
+
+// icc wants this
+void f();
+int f2();
+
+class C {};
+
+C g();
+
+class C g2();
+
+
+typedef int INT;
+
+INT h();
+
+INT *j();
+
+
+enum E { blah };
+
+enum E k();
+
+
+namespace N {
+  class Foo {};
+};
+
+
+struct A {
+  friend void ::f();
+  friend int ::f2();
+
+  // TODO: make Elsa reject the illegal forms below
+
+  // illegal
+  //friend C ::g();
+
+  // illegal
+  //friend class C ::g2();
+
+  // illegal
+  //friend INT ::h();
+
+  friend INT* ::j();
+
+  // illegal
+  //friend enum E ::k();
+  
+  friend class N::Foo;
+};
+
+class QCollection
+{
+  typedef void *Item;
+  void inSort (QCollection::Item);
+};

Added: vendor/elsa/current/elsa/in/t0385.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0385.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0385.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0385.cc
+// overload resolution of qualified nondependent name
+
+namespace N {
+  void foo(int);         // line 5
+  void foo(int,int);     // line 6
+}
+
+template <class T>
+struct C {
+  void bar()             // line 11
+  {
+    N::foo(3,3);         // *second* foo
+  }
+};
+
+void baz(C<int> &c)      // line 17
+{
+  c.bar();
+}
+
+asm("collectLookupResults foo=6 bar=11 c=17");
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0386.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0386.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0386.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// t0386.cc
+// qualified nondependent lookup of inherited member
+
+struct QGArray
+{
+  void duplicate (const QGArray & a);
+  void duplicate (const char *d, unsigned len);
+};
+
+
+template < class type > 
+class QArray : public QGArray {
+public:
+  void duplicate (const type * a, unsigned n)
+  {
+    char const *s;
+    QGArray::duplicate (s, n);
+  }
+};
+
+
+void foo(QArray<char> &a, char const *s)
+{
+  a.duplicate(s, 5);
+}

Added: vendor/elsa/current/elsa/in/t0387.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0387.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0387.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0387.cc
+// overload resolution getting same function twice?
+
+class MyEmitCode {};
+
+
+template <class EltType>
+void emitTable(MyEmitCode &out, EltType const *table, int size, int rowLength,
+               char const *typeName, char const *tableName)
+{
+}
+
+ 
+template <class EltType>
+void emitOffsetTable(MyEmitCode &out, EltType **table, EltType *base, int size,
+                     char const *typeName, char const *tableName, char const *baseName)
+{
+  char const *s;
+  emitTable(out, (int*)0, size, 16, "int", s);
+}
+
+void ParseTables__emitConstructionCode(MyEmitCode &out,
+  char const *className, char const *funcName)
+{
+  unsigned char **errorBitsPointers;
+  unsigned char *errorBits;
+  int numStates;
+  emitOffsetTable(out, errorBitsPointers, errorBits, numStates,
+                  "ErrorBitsEntry*", "errorBitsPointers", "errorBits");
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0388.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0388.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0388.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// t0388.cc
+// template friend class
+
+struct A {
+  template <class T> friend class B;
+};

Added: vendor/elsa/current/elsa/in/t0389.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0389.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0389.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0389.cc
+// integer parameter arithmetic ...
+
+template <class T>
+struct C {};
+
+template <class T, int n>
+struct B {};
+
+template <class T, int n>
+struct A {
+  typedef B<T, n+1> B_t;
+  C<B_t> _a;
+};
+
+void f() {
+  A<int, 16> a;
+}

Added: vendor/elsa/current/elsa/in/t0390.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0390.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0390.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0390.cc
+// ctor member init via a typedef
+
+struct B {};
+
+struct A : public B {
+  typedef B S;
+  A() : S() {}
+};

Added: vendor/elsa/current/elsa/in/t0391.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0391.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0391.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0391.cc
+// using declaration refers to templatized base class overloaded function
+
+template <class T>
+struct B {
+  void f();
+  void f(int) const;
+
+  // original second alternative:
+  void f() const;
+};
+
+struct A : public B<char> {
+
+  using B<char>::f;
+
+  void g() {
+    f();
+  }
+};

Added: vendor/elsa/current/elsa/in/t0392.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0392.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0392.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0392.cc
+// like t0391.cc but with a member template (!)
+
+template <class T>
+struct B {
+  template <class U>
+  void f(U);
+};
+
+struct A : public B<char> {
+
+  using B<char>::f;
+
+  void g() {
+    f(1);
+  }
+};

Added: vendor/elsa/current/elsa/in/t0393.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0393.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0393.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0393.cc
+// another template test from A.E.: enum from instantiated template
+// as a template arg
+
+template <int n>
+struct C {};
+
+template <int n>
+struct B {
+  enum {
+    N = n
+  };
+};
+
+struct A {
+  typedef B<16> B_t;
+  C<B_t::N> _c;
+};

Added: vendor/elsa/current/elsa/in/t0394.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0394.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0394.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0394.cc
+// simpler version of t0393.cc
+
+enum E { foo=3 };
+
+template <int n>
+struct S {};
+
+void foof()
+{
+  S<foo> s;
+}

Added: vendor/elsa/current/elsa/in/t0395.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0395.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0395.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0395.cc
+// ambiguous overload?
+
+struct A
+{
+  bool operator!=(const char*) const;
+  operator char*() const;
+};
+
+void g() {
+  A a;
+  if (a != 0) {}
+}

Added: vendor/elsa/current/elsa/in/t0396.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0396.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0396.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0396.cc
+// need to not instantiate a default argument
+
+struct A {
+  A(int);
+};
+
+template <class T>
+struct B {
+  void f(const T& t = T()) {}
+};
+
+void g() {
+  B<A> b;
+}

Added: vendor/elsa/current/elsa/in/t0397.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0397.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0397.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// t0397.cc
+// testing default args of non-member template functions
+// derived from example in 14.7.1p12
+
+// never defined
+template<class T>
+void f(T x, T y = ydef(T()), T z = zdef(T()));
+                
+// defined below use
+template<class T>
+void g(T x, T y = ydef(T()), T z = zdef(T()));
+                    
+// defined here
+template<class T>
+void h(T x, T y = ydef(T()), T z = zdef(T())) {}
+
+class  A { };
+
+A zdef(A);
+
+void foo(A a, A b, A c) 
+{
+  f(a, b, c);             // no default argument instantiation
+  f(a, b);                // default argument z = zdef(T()) instantiated
+  //ERROR(1): f(a);       // ill-formed; ydef is not declared
+
+  g(a,b,c);
+  g(a,b);
+  //ERROR(2): g(a);       // error
+
+  h(a,b,c);
+  h(a,b);
+  //ERROR(3): h(a);       // error
+}
+
+template<class T>
+void g(T x, T y, T z) {}

Added: vendor/elsa/current/elsa/in/t0398.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0398.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0398.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,79 @@
+// t0398.cc
+// testing default args of member functions of a template class
+// derived from example in 14.7.1p12
+
+template<class T>
+struct S {
+  S();
+
+  // constructor (never defined)
+  S(int, T x, T y = ydef(T()), T z = zdef(T()));
+
+  // never defined
+  void f(T x, T y = ydef(T()), T z = zdef(T()));
+
+  // defined out of line below use
+  void g(T x, T y = ydef(T()), T z = zdef(T()));
+
+  // defined out of line above use
+  void g2(T x, T y = ydef(T()), T z = zdef(T()));
+
+  // defined inline
+  void h(T x, T y = ydef(T()), T z = zdef(T())) {}
+
+  // static (not defined)
+  static void i(T x, T y = ydef(T()), T z = zdef(T()));
+};
+
+template<class T>
+void S<T>::g2(T x, T y, T z) {}
+
+class  A { };
+
+A zdef(A);
+
+void foo(A a, A b, A c)
+{
+  S<A> s;
+
+  s.f(a, b, c);             // no default argument instantiation
+  s.f(a, b);                // default argument z = zdef(T()) instantiated
+  //ERROR(1): s.f(a);       // ill-formed; ydef is not declared
+
+  s.g(a,b,c);
+  s.g(a,b);
+  //ERROR(2): s.g(a);       // error
+
+  s.g2(a,b,c);
+  s.g2(a,b);
+  //ERROR(3): s.g2(a);      // error
+
+  s.h(a,b,c);
+  s.h(a,b);
+  //ERROR(4): s.h(a);       // error
+
+  s.i(a,b,c);
+  s.i(a,b);
+  //ERROR(5): s.i(a);       // error
+
+  // invoke constructor via IN_ctor
+  S<A> s1(3, a,b,c);
+  S<A> s2(3, a,b);
+  //ERROR(6): S<A> s3(3, a);
+  
+  // invoke constructor via E_constructor
+  0, S<A>(3, a,b,c);
+  0, S<A>(3, a,b);
+  //ERROR(7): 0, S<A>(3, a);
+
+  // invoke constructor via E_new
+  new S<A>(3, a,b,c);
+  new S<A>(3, a,b);
+  //ERROR(8): new S<A>(3, a);
+  
+  // there is also invocation via member initializer, but that should
+  // be covered if the above cases are since they all use the same code
+}
+
+template<class T>
+void S<T>::g(T x, T y, T z) {}

Added: vendor/elsa/current/elsa/in/t0399.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0399.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0399.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0399.cc
+// a couple tricky(?!) qualified lookups
+
+struct A {
+  static int i;
+};
+
+struct B : A {};
+
+struct C : B {};
+
+void foo()
+{
+  int x;
+  C *c;
+
+  x = c->B::A::i;
+  
+  x = B::A::i;
+}

Added: vendor/elsa/current/elsa/in/t0400.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0400.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0400.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0400.cc
+// instantiate template function where function accepts template
+// class instance which is *not* instantiated, such that when
+// we tcheck the function instantiation's declaration we have
+// to instantiate the class (subtle scope insertion/deletion
+// ordering bug)
+
+template <class T>
+struct S {};
+
+template <class T>
+S<T> foo(S<T> *s)
+{
+  S<T> x;
+  return x;
+}
+
+void bar()
+{
+  S<int> *s = 0;     // does not instantiate S<int>
+  foo(s);
+}
+

Added: vendor/elsa/current/elsa/in/t0401.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0401.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0401.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0401.cc
+// form pointer-to-member out of overloaded name
+
+struct S {
+  int foo();         // line 5
+  int foo(int);      // line 6
+};
+
+typedef int (S::*ptm1)();
+typedef int (S::*ptm2)(int);
+
+void bar()
+{
+  ptm1 p1 = &S::foo;    // refers to line 5
+  ptm2 p2 = &S::foo;    // refers to line 6
+}
+
+asm("collectLookupResults foo=5 foo=6");
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0402.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0402.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0402.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0402.cc
+// resolve overloaded function name in assignment or initialization
+
+
+int foo();         // line 5
+int foo(int);      // line 6
+
+typedef int (*pf1)();
+typedef int (*pf2)(int);
+
+// assignment expressions
+void baz()
+{
+  pf1 p1;
+  p1 = foo;    // refers to line 5
+
+  pf2 p2;
+  p2 = foo;    // refers to line 6
+}
+
+// object initialization
+void bar()
+{
+  pf1 p1 = foo;    // refers to line 5
+  pf2 p2 = foo;    // refers to line 6
+}
+
+asm("collectLookupResults p1=14 foo=5 p2=17 foo=6 foo=5 foo=6");
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0403.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0403.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0403.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// t0403.cc
+// resolve overloaded function name as argument to user-def operator
+
+
+int foo();         // line 5
+int foo(int);      // line 6
+
+typedef int (*pf1)();
+typedef int (*pf2)(int);
+
+struct S {
+  void operator+ (pf1);     // line 12
+  void operator- (pf2);     // line 13
+  void operator= (pf2);     // line 14
+};
+void operator+ (pf1, S&);   // line 16
+void operator- (pf2, S&);   // line 17
+
+// argument to user-defined operator
+void zoo(S &s)              // line 20
+{
+  s + foo;         // refers to line 5
+  s - foo;         // refers to line 6
+  s = foo;         // refers to line 6
+
+  foo + s;         // refers to line 5
+  foo - s;         // refers to line 6
+}
+
+asm("collectLookupResults "
+    "operator+=12 s=20 foo=5 "
+    "operator-=13 s=20 foo=6 "
+    "s=20 foo=6 "       // not entirely sure why operator= doesn't show up..
+    "operator+=16 foo=5 s=20 "
+    "operator-=17 foo=6 s=20");
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0404.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0404.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0404.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+// t0404.cc
+// lookup of mem-initializer-id
+
+
+struct A {  
+  typedef A AA;     // alias for 'A', within scope of 'A'
+
+  A(int x);
+
+  struct B;
+};
+
+typedef A AAA;      // alias for 'A' at global scope
+
+struct A::B : A {
+  B(int x);
+  B(int x, int);
+  B(int x, int, int);
+};
+
+A::B::B(int x)
+  : A(x)
+{}
+
+// According to 12.6.2p2, 'AA' should be looked up in this sequence:
+//   - A::B (scope of the constructor's class)
+//   - global scope (scope containing the constructor's definition)
+// and since neither contains it, it should be an error.  However, icc,
+// gcc and Elsa all accept it, presumably because they all do the same
+// lookup for mem-initializers as they do for identifiers in the body
+// of the function.
+//
+// Actually, what is the "scope of the constructor's class"?  Is it
+// the class itself, or the scope that would be nominally used for
+// names appearing in class member functions?  If it means the latter,
+// then all three parsers are correct, and this is legal.
+A::B::B(int x, int)
+  : AA(x)
+{}
+
+A::B::B(int x, int, int)
+  : AAA(x)
+{}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0405.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0405.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0405.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// t0405.cc
+// 'using' declaration pulling a struct tag from a struct
+
+enum B { bad };
+
+struct A {
+  struct B {};
+  int B();
+  int B(int);
+
+  void foo();
+};
+
+void A::foo()
+{
+  struct B b;
+  B();
+  B(3);
+}
+
+struct C : A {
+  // pulls in the struct tag and the overloaded functions
+  using A::B;
+
+  void bar();
+};
+
+void C::bar()
+{
+  struct B b;
+  B();
+  B(3);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0406.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0406.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0406.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,85 @@
+// t0406.cc
+// tests of 5.2.4: E_fieldAcc with a non-class LHS
+
+// icc gets all of these tests right
+// gcc fails to reject tests: 1 4 6 11 12 13 14
+
+
+typedef int INT;
+typedef int const INTC;
+typedef int INT2;
+typedef float FLOAT;
+
+namespace N {
+  typedef int INT3;
+  typedef int INT4;
+  typedef float FLOAT3;
+}
+
+void foo()
+{
+  int x;
+  int const xc = 4;
+  int *p = 0;
+  INT y;
+  INT2 z;
+
+  // unqualified
+  x.~INT();
+  y.~INT();
+  z.~INT();
+  p->~INT();
+
+  // 1/2 qualifier
+  //ERROR(1): x.::~INT();
+
+  // one qualifier
+  x.INT::~INT();
+  x.INT::~INT2();
+  p->INT2::~INT();
+  //ERROR(2): x.INT::~FLOAT();
+  //ERROR(3): x.FLOAT::~FLOAT();
+  //ERROR(4): x.FLOAT::~INT();
+
+  // one+1/2 qualifier
+  x.::INT::~INT();
+  x.::INT::~INT2();
+  p->::INT2::~INT();
+  //ERROR(5): x.::INT::~FLOAT();
+
+  // two qualifiers
+  x.N::INT3::~INT3();
+  x.N::INT3::~INT4();
+  p->N::INT4::~INT3();
+  //ERROR(6): x.N::FLOAT3::~INT3();
+
+  // two+1/2 qualifiers
+  x.::N::INT3::~INT3();
+  x.::N::INT3::~INT4();
+  p->::N::INT4::~INT3();
+  //ERROR(7): x.N::INT3::~FLOAT3();
+  //ERROR(8): x.N::FLOAT3::~FLOAT3();
+
+  // totally nonexistent type names
+  //ERROR(9): x.nonexist::~INT();
+  //ERROR(10): x.INT::~nonexist();
+  //ERROR(15): x.nonexist::~nonexist2();
+
+  // const qualification
+  xc.~INTC();
+  xc.~INT();                   // ok
+  xc.INTC::~INTC();
+  xc.INT::~INT();              // ok
+  //ERROR(11): xc.INTC::~INT();
+  //ERROR(12): xc.INT::~INTC();
+
+  x.~INTC();
+  x.~INT();                    // ok
+  x.INTC::~INTC();
+  x.INT::~INT();               // ok
+  //ERROR(13): x.INTC::~INT();
+  //ERROR(14): x.INT::~INTC();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0407.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0407.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0407.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,146 @@
+// t0407.cc
+// testing 5.2.5
+
+// icc fails to reject tests: 8
+// gcc fails to reject tests: 5 8 16
+
+
+struct A {
+  struct B {
+    struct C {
+      int c;
+    };
+
+    int b;
+
+    void g(int);
+    void g(int,int);
+  };
+
+  int a;
+  ~A();
+
+  typedef int INT;
+
+  void f(int);
+  void f(int,int);
+
+  struct N { int q; };
+  struct N2 { int q; };
+  struct N3 { int q; };
+};
+
+typedef int INT2;
+
+struct C {
+  int d;
+};
+
+struct E : A {
+};
+
+int x;
+
+namespace N {};
+int N2(int);
+int N3;
+
+template <class T>
+struct F {};
+
+void foo()
+{
+  A a;
+  a.a;
+  a.A::a;
+  a.::A::a;
+  //ERROR(1): a.nonexist;    // field does not exist
+  //ERROR(2): a.A::B::b;     // wrong class
+  //ERROR(3): a.::x;         // not a class member
+
+  A::B b;
+  b.b;
+  b.B::b;
+  b.A::B::b;
+  b.::A::B::b;
+
+  A::B::C c;
+  c.c;
+  //ERROR(4): c.d;           // wrong class
+  //ERROR(5): c.C::c;        // 'C' looks up differently
+  //ERROR(6): c.B::C::c;     // 'B' not in global, nor in 'C'
+  c.A::B::C::c;              // finds 'A' in global
+  c.::A::B::C::c;
+
+  a.~A();
+  a.A::~A();
+  a.::A::~A();
+  //ERROR(7): a.::A::~B();
+
+  b.~B();
+  b.A::B::~B();
+  b.::A::B::~B();
+
+  //ERROR(8): c.~C();        // 'C' looks up differently
+  //ERROR(9): a.~INT();      // not a class (found in A)
+  //ERROR(10): a.~INT2();    // not a class (found in global)
+
+  //ERROR(11): a.INT::~INT();    // not a class
+  //ERROR(12): a.INT2::~INT2();  // not a class
+  
+  a.f(1);
+  a.A::f(1,2);
+  a.::A::f(2);
+  //ERROR(13): a.::A::f(4,5,6);     // too many args
+
+  b.g(1);
+  b.B::g(1,2);
+  b.A::B::g(2);
+  //ERROR(14): b.A::f(1);           // wrong class
+  
+  //ERROR(15): a.INT;               // type
+
+  E e;
+  e.A::f(1);
+
+  (a).f(1);
+  ((a)).f(1);
+
+  A *p = 0;
+  p->f(1);
+  (p->f)(1);
+  (*p).f(1);
+  (*(p)).f(1);
+  ((*(p))).f(1);
+
+  // The following syntax has a *nasty* consequence: gcc believes that
+  // 'N' refers to A::N, while icc believes it refers to ::N!  Thus,
+  // they both allow it but with different semantics!  (As it happens,
+  // I did not put a 'q' member in ::N, so icc ends up rejecting the
+  // program.  Actually, I'm not sure if I could ever convince icc to
+  // completely accept the syntax; how would a member of ::N be legal
+  // to use as a field of 'n', with type A::N?)
+
+  A::N n;
+  //ERROR(16): n.N::q;              // different: namespace vs. class
+  
+  // the following two *are* legal, because qualified lookup
+  // does not consider object and function names
+
+  A::N2 n2;
+  n2.N2::q;            // function vs. class
+
+  A::N3 n3;
+  n3.N3::q;            // object vs. class
+               
+  //ERROR(17): a.~N2();
+  //ERROR(18): a.~N3();
+
+  //ERROR(19): x.::AAA::~INT2();
+  //ERROR(20): x.::F<int>::~INT2();
+  //ERROR(21): x.~nonexist();
+  //ERROR(22): a.~nonexist();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0408.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0408.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0408.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0408.cc
+// resolve overloaded name of static functions
+
+struct A {
+  static int foo(int);            // line 5
+  static int foo(int,int);        // line 6
+};
+
+void foo()
+{
+  A *ap;            // line 11
+  A a;              // line 12
+
+  int (*f1)(int) = a.foo;
+  int (*f2)(int,int) = ap->foo;
+}
+
+asm("collectLookupResults foo=5 a=12 foo=6 ap=11");
+

Added: vendor/elsa/current/elsa/in/t0409.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0409.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0409.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0409.cc
+// use of overloaded template member operator= in extern "C" function
+
+template <class T>
+struct S {
+  void operator=(T *);
+  void operator=(S&);
+};
+
+extern "C" 
+void foo()
+{        
+  S<int> s;
+  
+  int *p;
+  s = p;
+
+  s = 0;
+}

Added: vendor/elsa/current/elsa/in/t0410.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0410.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0410.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0410.cc
+// some overloading+template problem
+
+
+class string {
+  string (char const *src);
+};
+
+template < class T > 
+class StringSObjDict {
+  void remove (char const *key);        // line 11
+  void remove (string const &key)       // line 12
+  {
+    char const *s;
+    __testOverload(remove (s), 11);
+  }
+};
+
+//  class A {};
+
+//  void foo()
+//  {
+//    StringSObjDict<A> s;
+//  }
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0411.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0411.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0411.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0411.cc
+// variant of t0410.cc
+
+
+class string {
+  string (char const *src);
+};
+
+template < class T >
+class StringSObjDict {
+  T *remove (char const *key, int);    // genuinely not viable
+  T *remove (string const &key)
+  {
+    char const *s;
+    return remove (s);                 // recursive call
+  }
+};
+                       
+class A {};
+
+void foo()
+{
+  StringSObjDict<A> s;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0412.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0412.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0412.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0412.cc
+// dependent resolution in an E_constructor
+
+struct A {
+  A(int);
+  A(int,int);
+};
+
+template <class T>
+void bar(T &t)
+{
+  0, A(t);          // dependent
+}
+
+void foo()
+{ 
+  int x;
+  bar(x);
+}

Added: vendor/elsa/current/elsa/in/t0413.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0413.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0413.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0413.cc
+// variant of t0382.cc that also tests struct tags
+
+namespace N {
+  enum E { e };
+  struct S { int x; };
+  int g(int);
+}
+
+void foo()
+{
+  using namespace N;     // get it all
+
+  enum E e1;
+  struct S s1;
+
+  //ERROR(1): enum S s2;      // S is a struct, not an enum
+
+  int x = e;      // 'e' *does* come along
+  
+  g(3);
+}
+
+
+void bar()
+{
+  using N::E;     // get just 'E'
+  using N::S;     // and 'S'
+
+  enum E e1;
+  struct S s1;
+
+  //ERROR(2): int x = e;      // 'e' does not come along
+
+  int y = N::e;   // must explicitly qualify
+}

Added: vendor/elsa/current/elsa/in/t0414.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0414.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0414.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,66 @@
+// t0414.cc
+// what does 3.4.4p2,3 "ignoring non-type names" mean?
+
+
+struct S {
+  int x;
+};
+
+namespace N {
+  struct S {
+    int y;
+  };
+  
+  int S(int);    // non-type names
+  
+  void foo()
+  {        
+    // what does "ignoring ..." means if we see a non-type in the 'variables'
+    // space?  two possibilities:
+    //   - skip the scope, which would find ::S
+    //   - first check the tag space, which would find N::S
+    struct S s;                                            
+    
+    //ERROR(1): s.x;    // legal?
+                s.y;    // legal?     icc and gcc like this one, i.e., N::S
+
+    // so at least according to icc and gcc, you look in tags
+    // before going to the next level
+  }
+}
+
+namespace N2 {
+  struct S {
+    int y;
+  };
+
+  // same thing as above, it seems
+  typedef S S;
+
+  void foo()
+  {
+    // Actually, I question whether this is legal; is it not the case
+    // that 'S' is a typedef-name here?  Consequently, 3.4.4p2,3 would
+    // say this is ill-formed.  But both icc and gcc allow it, so Elsa
+    // will too ...
+    struct S s;
+    //ERROR(2): s.x;
+                s.y;
+  }
+}
+
+namespace N3 {
+  struct S {
+    int y;
+  };
+
+  // invalid redeclaration
+  //ERROR(3): typedef int S;
+}
+
+
+typedef struct S S;
+void foo()
+{
+  struct S s;
+}

Added: vendor/elsa/current/elsa/in/t0415.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0415.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0415.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,61 @@
+// t0415.cc
+// t0265.cc but with a partial specialization in the mix too
+
+template <class T>
+struct A {
+  int foo(typename T::type1 x);
+  int foo(typename T::type2 x);
+};
+
+template <class V>
+struct A<V*> {
+  int foo(typename V::type1 x);
+  int foo(typename V::type2 x);
+};
+
+
+template <class T>
+int A<T>::foo(typename T::type1 x)
+{
+  return 1;
+}
+
+template <class V>
+int A<V*>::foo(typename V::type1 x)
+{
+  return 11;
+}
+
+
+template <class S>
+int A<S>::foo(typename S::type2 x)
+{
+  return 2;
+}
+
+template <class V2>
+int A<V2*>::foo(typename V2::type2 x)
+{
+  return 12;
+}
+
+
+struct B {
+  typedef int type1;
+  typedef float type2;
+};
+
+
+void f()
+{
+  int i = 0;
+  float f = 0;
+
+  A<B> a;
+  a.foo(i);
+  a.foo(f);
+
+  A<B*> a2;
+  a2.foo(i);
+  a2.foo(f);
+}

Added: vendor/elsa/current/elsa/in/t0416.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0416.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0416.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0416.cc
+// dependent type matching that does not involve qualifiers
+// but nevertheless isomorphic type matching is insufficient
+
+// interesting: can only be instantiated if S != T
+template <class S, class T>
+struct A {
+  int foo(S *s, T *t);           // line 8
+  int foo(T *t, S *s);           // line 9
+};
+
+template <class S1, class T1>
+int A<S1,T1>::foo(S1 *s, T1 *t)
+{
+  return 1;
+}
+
+template <class S2, class T2>
+int A<S2,T2>::foo(T2 *t, S2 *s)
+{
+  return 2;
+}
+
+int main()
+{
+  A<int,float> a;
+  int *i = 0;
+  float *f = 0;
+
+  // same type will not work
+  //ERROR(1): A<int,int> a2;
+
+  int x = __testOverload(a.foo(i,f), 8);            // foo on line 8
+  int y = __testOverload(a.foo(f,i), 9);            // foo on line 9
+
+  if (x==1 && y==2) {
+    return 0;
+  }
+  else {
+    return 4;
+  }
+}

Added: vendor/elsa/current/elsa/in/t0417.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0417.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0417.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,76 @@
+// t0417.cc
+// order of template parameters
+
+template <class S, class T>
+struct A {
+  int f0(S *s, T *t);
+  int f1(S *s, T *t);
+  int f2(S *s, T *t);
+  int f3(S *s, T *t);
+  int f4(S *s, T *t);
+  int f5(S *s, T *t);
+  int f6(S *s, T *t);
+  int f7(S *s, T *t);
+};
+
+// normal
+template <class S, class T>
+int A<S,T>::f0(S *s, T *t)
+{
+  return 0;
+}
+
+// three places S,T could be swapped:
+//   - template declaration parameter list    001 = 1
+//   - template-id before the ::              010 = 2
+//   - function parameter list                100 = 4
+
+//ERROR(1): template <class T, class S /*swapped*/>
+//ERROR(1): int A<S,T>::f1(S *s, T *t)
+//ERROR(1): {
+//ERROR(1):   return 0;
+//ERROR(1): }
+
+//ERROR(2): template <class S, class T>
+//ERROR(2): int A<T,S /*swapped*/ >::f2(S *s, T *t)
+//ERROR(2): {
+//ERROR(2):   return 0;
+//ERROR(2): }
+
+//ERROR(3): template <class T, class S /*swapped*/>
+//ERROR(3): int A<T,S /*swapped*/>::f3(S *s, T *t)
+//ERROR(3): {
+//ERROR(3):   return 0;
+//ERROR(3): }
+
+//ERROR(4): template <class S, class T>
+//ERROR(4): int A<S,T>::f4(T *t, S *s /*swapped*/)
+//ERROR(4): {
+//ERROR(4):   return 0;
+//ERROR(4): }
+
+//ERROR(5): template <class T, class S /*swapped*/>
+//ERROR(5): int A<S,T>::f5(T *t, S *s /*swapped*/)
+//ERROR(5): {
+//ERROR(5):   return 0;
+//ERROR(5): }
+
+//ERROR(6): template <class S, class T>
+//ERROR(6): int A<T,S /*swapped*/ >::f6(T *t, S *s /*swapped*/)
+//ERROR(6): {
+//ERROR(6):   return 0;
+//ERROR(6): }
+
+// when all are swapped, is ok again
+template <class T, class S /*swapped*/>
+int A<T,S /*swapped*/>::f7(T *t, S *s /*swapped*/)
+{
+  return 0;
+}
+
+
+
+void f()
+{
+  A<int,float> a;
+}

Added: vendor/elsa/current/elsa/in/t0418.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0418.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0418.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// t0418.cc
+// duplicate definition of template member function
+
+template <class T>
+struct A {
+  int foo(T *t);
+};
+
+template <class T>
+int A<T>::foo(T *t)
+{
+  return 0;
+}
+
+//ERROR(1): template <class T>
+//ERROR(1): int A<T>::foo(T *t)
+//ERROR(1): {
+//ERROR(1):   return 1;
+//ERROR(1): }
+          
+void f()
+{
+  A<int> a;
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0419.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0419.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0419.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0419.cc
+// another from A.E.
+
+struct B {
+  template <class U>
+  B(const U &);
+};
+
+template <class T>
+void f(const T & t) {
+  B b(t);
+}

Added: vendor/elsa/current/elsa/in/t0420.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0420.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0420.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0420.cc
+// another from A.E.
+
+template <class T>
+struct C {
+  struct B {
+    B();
+  };
+  void f() {
+    B b;
+  }
+};

Added: vendor/elsa/current/elsa/in/t0421.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0421.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0421.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0421.cc
+// n+1 as template argument..
+
+template <int n>
+struct A {};
+
+template <class T>
+struct B {};
+
+template <int n>
+struct C {
+  typedef B<A<n+1> > V;
+};

Added: vendor/elsa/current/elsa/in/t0422.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0422.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0422.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0422.cc
+// duplicate member with dependent type error...
+
+template <int n>
+struct A {};
+
+template <class T>
+struct B {};
+
+template <class T, int n>
+struct C {
+  typedef A<n+1> U;
+  typedef B<U> V;
+
+  void f(U);
+  void f(V);
+};

Added: vendor/elsa/current/elsa/in/t0422a.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0422a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0422a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0422a.cc
+// simplified version of t0422.cc
+
+template <int n>
+struct A {};
+
+template <int n>
+struct C {
+  void f(A<n+1>);
+  void f(A<n+2>);
+};
+
+template <int n>
+void C<n>::f(A<n+1>)
+{}
+
+template <int n>
+void C<n>::f(A<n+2>)
+{}
+
+void foo()
+{
+  C<1> c;
+  A<2> a2;
+  A<3> a3;
+  c.f(a2);
+  c.f(a3);
+}

Added: vendor/elsa/current/elsa/in/t0423.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0423.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0423.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,56 @@
+// t0423.cc
+// test more dependent expression matching
+
+template <int n>
+struct A {};
+
+template <int n, class T>
+struct C {
+  void f(A<n+1>);              // line 9
+  void f(A<n-2>);              // line 10
+  void f(A<~n>);               // line 11
+  void f(A<sizeof(T)>);        // line 12
+  void f(A<n+10>);             // line 13
+};
+
+template <int n, class T>
+void C<n,T>::f(A<n+1>)
+{}
+
+template <int n, class T>
+void C<n,T>::f(A<n-2>)
+{}
+
+template <int n, class T>
+void C<n,T>::f(A<~n>)
+{}
+
+template <int n, class T>
+void C<n,T>::f(A<sizeof(T)>)
+{}
+
+template <int n, class T>
+void C<n,T>::f(A<n+10>)
+{}
+
+
+void foo()
+{
+  C<1,int> c;
+
+  A<2> a2;
+  A<-1> am1;
+  A<~1> at1;
+  A<sizeof(int)> asi;
+  A<4> a4;
+  A<11> a11;
+
+  __testOverload( c.f(a2),  9);
+  __testOverload( c.f(am1), 10);
+  __testOverload( c.f(at1), 11);
+  __testOverload( c.f(asi), 12);
+  __testOverload( c.f(a4),  12);
+  __testOverload( c.f(a11), 13);
+  
+  //ERROR(1): C<-6,int> c2;    // lines 12,13 are same type then
+}

Added: vendor/elsa/current/elsa/in/t0424.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0424.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0424.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0424.cc
+// get a base class member template via 'using'
+
+struct B {
+  template <class T>
+  void f(T t) {}
+};
+
+struct D : public B {
+  using B::f;
+  D() {
+    f(1);
+  }
+};

Added: vendor/elsa/current/elsa/in/t0425.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0425.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0425.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0425.cc
+// use of self-name with different arguments as qualifier
+
+template <class T, class U>
+struct A {
+  typename A<int, U>::INT a;
+  typedef int INT;
+};
+
+template <class U>
+struct A<int, U> {
+  int x;
+  typedef int INT;
+};
+
+A<char,char> a;

Added: vendor/elsa/current/elsa/in/t0426.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0426.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0426.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0426.cc
+// more complicated version of t0425.cc:                 
+
+// use of self-name with different arguments as qualifier, and
+// the qualified name then becomes a typedef
+
+
+template <class T, class U>
+struct B {
+};
+
+template <class T, class U = int>
+struct A {
+  typedef typename A<U>::W V;
+  typedef B<T, V> W;
+};
+
+template <>
+struct A<int, int> {
+  typedef int W;
+};
+
+A<char, char> a;

Added: vendor/elsa/current/elsa/in/t0427.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0427.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0427.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0427.cc
+// * 'using' declaration that nominates a class member
+// * the member is a member template class
+
+// icc and Elsa accept this input
+// gcc rejects this input
+
+struct B {
+  template <class T>
+  struct S {
+    T x;
+  };
+};
+
+// I added the intermediate class 'D1' so that this 'using'
+// declaration is required (without it, 'S' does not refer
+// to a template).  Without the intermediate layer, gcc
+// accepts the code.
+struct D1 : B {
+  struct S {     // not a template
+    int y;
+  };
+};
+
+struct D2 : D1 {
+  using B::S;      //ERRORIFMISSING(1): this is required
+  
+  int foo()
+  {
+    S<int> s;
+    s.x = 5;
+    return s.x;
+  }
+};

Added: vendor/elsa/current/elsa/in/t0428.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0428.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0428.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0428.cc
+// dependent qualified self-name name in an enumerator initializer
+// in a template partial spec
+
+template <typename T, typename U>
+struct B;
+
+template <typename W, typename V>
+struct A;
+
+template <typename V>
+struct A<int, V> {
+  enum { z = 0 };
+};
+
+template <typename T, typename U, typename V>
+struct A<B<T, U>, V> {
+  enum { x = A<U, V>::z };
+  enum { z = 1 };
+};
+
+A<B<int, int>, int> a;

Added: vendor/elsa/current/elsa/in/t0429.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0429.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0429.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0429.cc
+// more with qualified destructor names
+// (variations on 3.4.3p5.cc)
+
+struct A {
+  ~A();
+};
+typedef A AB;
+void foo()
+{
+  AB *p = 0;
+  p->AB::~AB();
+  p->::AB::~AB();
+}
+
+namespace N {
+  struct B {};
+  typedef B BB;
+}
+void bar()
+{
+  N::B *b = 0;
+  N::BB *bb = 0;
+  b->N::~B();          // both icc and gcc reject this
+  b->N::~BB();         // and this
+  b->N::B::~B();
+  b->N::BB::~B();
+  b->N::B::~BB();
+  b->N::BB::~BB();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0430.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0430.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0430.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0430.cc
+// build a dependent qualified type out of a typedef
+ 
+template <class T>
+struct A {
+  typedef T *foo_t;
+};
+
+struct B {
+  typedef int qoo_t;
+};
+
+template <class T>
+void foo(T t)
+{
+  typedef A<T> AT;
+  typedef typename AT::foo_t bar;
+
+  typedef T TT;
+  typedef typename TT::qoo_t barq;
+}
+
+void goo()
+{
+  B b;
+  foo(b);
+}

Added: vendor/elsa/current/elsa/in/t0431.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0431.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0431.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// t0431.cc
+// overload resolution where args are classes in subtype relation
+
+struct Base {};
+
+struct Derived : Base {};
+
+struct FurtherDerived : Derived {};
+
+int foo(Base b);        // line 10
+int foo(Derived d);     // line 11
+   
+//void __testOverload(int,int);
+
+void bar()
+{
+  FurtherDerived d;
+  foo(d);
+
+  __testOverload(foo(d), 11);
+  __testOverload(foo(FurtherDerived()), 11);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0432.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0432.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0432.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0432.cc
+// erroneous code that is causing assertion failure
+
+void foo()
+{
+  class C {
+    //ERROR(1): template <class T> friend void bar(T t);
+
+    //ERROR(2): template <class T> void bar2(T t);
+  };
+
+  //ERROR(3): template <class T> void bar2(T t);
+}

Added: vendor/elsa/current/elsa/in/t0433.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0433.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0433.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// t0433.cc
+// matching out-of-line defn when arg type is dependent qualified
+
+template <class T>
+struct A {
+  typedef T some_type;
+  
+  int foo1(some_type s);
+  int foo2(some_type s);
+};
+
+template <class T>
+int A<T>::foo1(typename A<T>::some_type s)
+{
+  return 2;
+}
+
+template <class T2>
+int A<T2>::foo2(typename A<T2>::some_type s)
+{
+  return 3;
+}
+
+void f()
+{
+  A<int> a;
+  a.foo1(1);
+  a.foo2(2);
+}
+
+
+template <class T>
+struct A<T*> {
+  typedef T some_type;
+
+  int foo(some_type** s);
+};
+
+template <class T>
+int A<T*>::foo(typename A<T*>::some_type** s)
+{
+  return 2;
+}
+
+void g()
+{
+  A<int*> a;
+  int **q = 0;
+  a.foo(q);
+}

Added: vendor/elsa/current/elsa/in/t0434.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0434.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0434.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// t0434.cc
+// some DQTs
+
+template <class S, class T>
+class A {
+public:
+  typedef S char_type;
+  typedef T int_type;
+
+  int      foo1 (char_type c);
+  int_type foo2 (char      c);
+  int_type foo3 (char_type c);
+};
+
+//ERROR(1): template <class S, class T>
+//ERROR(1): int A<S,T>::dorf(char_type c)  {}
+
+template <class S, class T>
+                 int       A<S,T>::foo1(char_type c)  {}
+
+template <class S, class T>
+typename A<S,T>::int_type  A<S,T>::foo2(char      c)  {}
+
+template <class S, class T>
+typename A<S,T>::int_type  A<S,T>::foo3(char_type c)  {}

Added: vendor/elsa/current/elsa/in/t0435.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0435.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0435.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0435.cc
+// need for ArrayType with dependent size
+
+template <int n>
+struct A {
+  int foo(int (*p)[n]);         // line 6
+  int foo(int (*p)[n+1]);       // line 7
+};
+
+template <int n>
+int A<n>::foo(int (*p)[n])
+{
+  return 1;
+}
+
+template <int n>
+int A<n>::foo(int (*p)[n+1])
+{
+  return 2;
+}
+
+void f()
+{
+  A<3> a;
+  int arr1[3];
+  int arr2[4];
+
+  a.foo(&arr1);                 // calls line 6
+  a.foo(&arr2);                 // calls line 7
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0436.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0436.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0436.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,69 @@
+// t0436.cc
+// scope in which the class of a ptr-to-member is looked up
+
+struct B {
+  int member;
+  int *p;
+  int f();
+};
+
+int func();
+
+struct A {        
+  // interloper!  If I do the lookups of the names preceding
+  // "::*" in the scope of A, I will find this one, instead of
+  // ::B, which is the right one
+  struct B {
+    int memb;
+  };
+
+  int ::B::* f1();
+  int ::B::* f2();
+
+  int* ::B::* f3();
+
+  int (*f4())();;
+
+  int (::B::* f5())();
+
+  int B::* g1();
+  int B::* g2();
+};
+
+int ::B::* A::f1()
+{
+  return &::B::member;
+}
+
+int B::* A::f2()
+{
+  return &::B::member;
+}
+
+int* B::* A::f3()
+{
+  return &::B::p;
+}
+
+int (*A::f4())()
+{
+  return &func;
+}
+
+int (B::* A::f5())()
+{
+  return &::B::f;
+}
+
+int A::B::* A::g1()
+{
+  return &B::memb;
+}
+
+// should *not* find A::B without qualifier
+//ERROR(1): int B::* A::g2()
+//ERROR(1): {
+//ERROR(1):   return &B::memb;
+//ERROR(1): }
+
+

Added: vendor/elsa/current/elsa/in/t0437.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0437.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0437.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,99 @@
+// t0437.cc
+// type specifier PseudoInstantiations
+
+template <class T>
+struct A {
+  A* f1();
+  A<T>* f2();
+
+  static A *p3;
+  static A<T> *p4;
+};
+
+template <class T1>
+A<T1>* A<T1>::f1()
+{
+  return this;
+}
+
+template <class T2>
+A<T2>* A<T2>::f2()
+{
+  return this;
+}
+
+template <class T3>
+A<T3>* A<T3>::p3 = 0;
+
+template <class T4>
+A<T4>* A<T4>::p4 = 0;
+
+
+void inst_A()
+{
+  A<int> a;
+  a.f1();
+  a.f2();
+}
+
+
+template <class S, class T>
+struct B {
+  B* f1();
+  B<S,T> *f2();
+  B<T,S> *f3();
+  B<T,S> *f4();
+  
+  static B* p5;
+  static B<S,T> *p6;
+  static B<T,S> *p7;
+  static B<T,S> *p8;
+};
+
+template <class S1, class T1>
+B<S1,T1>* B<S1,T1>::f1()
+{
+  return this;
+}
+
+template <class S2, class T2>
+B<S2,T2>* B<S2,T2>::f2()
+{
+  return this;
+}
+
+template <class S3, class T3>
+B<T3,S3>* B<S3,T3>::f3()
+{
+  return new B<T3,S3>;
+}
+
+//ERROR(1): template <class S4, class T4>
+//ERROR(1): B<S4,T4>* B<S4,T4>::f4()
+//ERROR(1): {
+//ERROR(1):   return new B<T4,S4>;
+//ERROR(1): }
+
+template <class S5, class T5>
+B<S5,T5>* B<S5,T5>::p5 = 0;
+
+template <class S6, class T6>
+B<S6,T6>* B<S6,T6>::p6 = 0;
+
+template <class S7, class T7>
+B<T7,S7>* B<S7,T7>::p7 = 0;
+
+//ERROR(2): template <class S8, class T8>
+//ERROR(2): B<S8,T8>* B<S8,T8>::p8 = 0;
+
+
+
+void inst_B()
+{
+  B<int,float> b;
+  b.f1();
+  b.f2();
+  b.f3();
+}
+
+

Added: vendor/elsa/current/elsa/in/t0438.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0438.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0438.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,148 @@
+// t0438.cc
+// DQT type specifier resolution
+
+// dimensions to test:
+//   * various levels of qualification
+//   - stopping at another DQT vs. full resolution
+//   - partial specs vs primaries vs complete specs
+//   * nested templates
+//   - type parameters vs. non-type parameters
+//   - variations like arguments in the wrong order, wrong #, etc.
+//   - default args? (no, subsequent tests...)
+
+
+template <class T>
+struct A {
+  typedef int INT;
+  
+  INT a1();
+  typename A<T>::INT a2();
+
+  struct B {
+    typedef float FLOAT;
+
+    FLOAT b1();
+    
+    template <class V>
+    struct D {
+      typedef char CHAR;
+      
+      CHAR d1();
+    };
+    
+    struct E {
+      typedef short SHORT;
+      
+      SHORT e1();
+    };
+  };
+
+  template <class U>
+  struct C {
+    typedef double DOUBLE;
+
+    DOUBLE c1();
+    typename A<T>::template C<U>::DOUBLE c2();
+    typename ::A<T>::template C<U>::DOUBLE c3();
+
+    template <class W>
+    struct F {
+      typedef long LONG;
+
+      LONG f1();
+    };
+
+    struct G {
+      typedef int *INTPTR;
+
+      INTPTR g1();
+    };
+  };
+};
+
+
+// ---- A ----
+template <class T1>
+typename A<T1>::INT         A<T1>::a1()
+{ return 1; }
+
+template <class T2>
+typename A<T2>::INT         A<T2>::a2()
+{ return 1; }
+
+// ---- B ----
+template <class T2a>
+typename A<T2a>::B::FLOAT   A<T2a>::B::b1()
+{ return 1.1; }
+
+// ---- D ----
+template <class T1>
+template <class V1>
+typename A<T1>::B::template D<V1>::CHAR    A<T1>::B::D<V1>::d1()
+{ return 'a'; }
+
+// ---- E ----
+template <class T1>
+typename A<T1>::B::E::SHORT                A<T1>::B::E::e1()
+{ return 123; }
+
+// ---- C ----
+template <class T1>
+template <class U1>
+typename A<T1>::template C<U1>::DOUBLE     A<T1>::C<U1>::c1()
+{ return 1.2; }
+
+template <class T2>
+template <class U2>
+double                                     A<T2>::C<U2>::c2()
+{ return 1.3; }
+
+template <class T3>
+template <class U3>
+typename ::A<T3>::template C<U3>::DOUBLE   A<T3>::C<U3>::c3()
+{ return 1.3; }
+
+// ---- F ----
+template <class T1>
+template <class U1>
+template <class W1>
+typename A<T1>::template C<U1>::template F<W1>::LONG    A<T1>::C<U1>::F<W1>::f1()
+{ return 123456789; }
+
+// ---- G ----
+int x;
+template <class T1>
+template <class U1>
+typename A<T1>::template C<U1>::G::INTPTR               A<T1>::C<U1>::G::g1()
+{ return &x; }
+
+
+void foo()
+{
+  A<int> a;
+  a.a1();
+  a.a2();
+
+  A<int>::B b;
+  b.b1();
+
+  A<int>::B::D<int> d;
+  d.d1();
+
+  A<int>::B::E e;
+  e.e1();
+
+  A<int>::C<int> c;
+  c.c1();
+  c.c2();
+  c.c3();
+  
+  A<int>::C<int>::F<int> f;
+  f.f1();
+
+  A<int>::C<int>::G g;
+  g.g1();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0438a.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0438a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0438a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0438a.cc
+// triply-nested templates, a simplification of one aspect
+// of t0438.cc
+
+
+template <class T>
+struct A {
+
+  template <class U>
+  struct C {
+
+    template <class W>
+    struct F {
+      long f2();
+    };
+
+  };
+};
+
+template <class T1>
+template <class U1>
+template <class W1>
+long   A<T1>::C<U1>::F<W1>::f2()
+{ return 123456789; }
+
+
+void foo()
+{
+  A<int>::C<int>::F<int> f;
+  f.f2();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0439.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0439.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0439.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0439.cc
+// use a default argument in an explicit specialization spec (!)
+
+template <class T = int>
+struct A {};
+
+template <>
+struct A</*int*/> {      // !!
+  int x;
+};
+
+int f()
+{
+  A<> a;
+  a.x = 5;
+  return a.x;
+}

Added: vendor/elsa/current/elsa/in/t0440.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0440.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0440.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// t0440.cc
+// use a default argument in a DQT
+// more complex version of t0439.cc
+
+template <class T = int>
+struct A {};
+
+template <>
+struct A</*int*/> {      // !!
+  int x;
+  
+  A *f1();
+  A<> *f2();
+  A<int> *f3();
+};
+
+A<> *A<int>::f1()
+{
+  return this;
+}
+
+A<int> *A<>::f2()
+{
+  return this;
+}
+
+A<int> *A<int>::f3() 
+{
+  return this;
+}
+
+
+int f()
+{
+  A<> a;
+  a.x = 5;
+  return a.x;
+}

Added: vendor/elsa/current/elsa/in/t0441.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0441.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0441.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0441.cc
+// out-of-line defn of a member template
+
+template <class T>
+struct A {
+  template <class U>
+  struct C;
+
+  template <class V>
+  struct D;
+};
+
+template <class T>
+template <class U>
+struct A<T>::C {
+  int c1();
+};
+
+//ERROR(1): template <class Q2>    // spurious param list
+template <class T2>
+template <class V2>       //ERRORIFMISSING(2):   // needed param list
+struct A<T2>::D {
+  int d1();
+};
+
+void foo()
+{
+  A<int>::C<int> c;
+  c.c1();
+
+  A<int>::D<int> d;
+  d.d1();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0441a.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0441a.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0441a.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0441a.cc
+// simplified version of t0441.cc
+
+struct Outer { 
+  template <class T>
+  struct A;
+};
+
+template <class T>
+struct Outer::A
+{};

Added: vendor/elsa/current/elsa/in/t0442.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0442.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0442.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0442.cc
+// variation of t0438a.cc with all out-of-line defns
+
+
+template <class T>
+struct A;
+
+template <class T1>
+struct A {
+  template <class U1>
+  struct C;
+};
+
+template <class T2>
+template <class U2>
+struct A<T2>::C {
+  template <class W2>
+  struct F;
+};
+
+template <class T3>
+template <class U3>
+template <class W3>
+struct A<T3>::C<U3>::F {
+  long f2();
+};
+
+template <class T4>
+template <class U4>
+template <class W4>
+long   A<T4>::C<U4>::F<W4>::f2()
+{ return 123456789; }
+
+
+void foo()
+{
+  A<int>::C<float>::F<char> f;
+  f.f2();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0443.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0443.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0443.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0443.cc
+
+// error: typedef'd name `U' doesn't refer to a class, so it can't be
+// used as a scope qualifier
+
+template <class T>
+struct A {
+  struct T1 {
+    typedef int T2;
+  };
+};
+
+template <class T>
+struct C {};
+
+template <class T>
+struct List {};
+
+template <class T>
+struct Vector {};
+
+template <class T>
+struct B {
+  typedef typename A<T>::T1 U;
+  typedef typename U::T2 V;
+  typedef Vector<List<C<V> > > W;
+};

Added: vendor/elsa/current/elsa/in/t0444.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0444.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0444.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0444.cc
+// DQTs with non-type args
+
+template <int N>
+struct A {
+  struct B {};
+  
+  B *f();
+};
+
+template <int M>
+typename A<M>::B *A<M>::f()
+{
+  return new B;
+}
+
+void foo()
+{
+  A<3> a3;
+  a3.f();
+
+  A<4> a4;
+  a4.f();
+}
+
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0445.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0445.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0445.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0445.cc
+// DQTs in non-function declarators
+
+template <class T>
+struct A {
+  struct B {};
+  
+  static B *array[2];
+};
+
+template <class T2>
+typename A<T2>::B *A<T2>::array[2] = { 0,0 };
+
+void foo()
+{
+  A<int>::array[0] = A<int>::array[1];
+}

Added: vendor/elsa/current/elsa/in/t0446.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0446.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0446.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0446.cc
+// template parameter and ?:
+
+template <class T>
+int foo(T t)
+{
+  return t? t->something() : 0;
+}
+

Added: vendor/elsa/current/elsa/in/t0447.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0447.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0447.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0447.cc
+// invoke static methods, in proximity to a DQT
+
+
+template <class T>
+struct A {
+};
+
+template <>
+struct A<int> {
+  static int f();
+};
+
+template <class T>
+void foo(T *t)
+{
+  A<typename T::INT>::f();
+}
+
+struct B {
+  typedef int INT;
+};
+
+void bar()
+{
+  B *bp = 0;
+  foo(bp);
+}
+

Added: vendor/elsa/current/elsa/in/t0448.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0448.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0448.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0448.cc
+// nondependent lookup..
+
+template <class T>
+struct B {
+  int foo(int);
+};
+
+template <class T>
+struct D : B<T> {
+  int bar()
+  {
+    //ERROR(1): return foo(3);          // nondependent--illegal
+  }
+
+  int baz()
+  {
+    return this->foo(3);    // ok
+  }
+};
+
+template <class T>
+struct E : B<int> {
+  int blorf()
+  {
+    return foo(4);          // legal!
+  }
+
+  int garf()
+  {
+    //ERROR(2): return nonexist(5);     // non-dependent but no unsearched bases
+  }
+};
+
+template <class T>
+struct F : T::Q {
+  int f()
+  {
+    //ERROR(3): return foo(5);
+  }
+};
+

Added: vendor/elsa/current/elsa/in/t0449.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0449.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0449.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,301 @@
+// t0449.cc
+// exercising some cases gcov says are not hit
+
+// icc fails to reject: 3
+
+
+// ------------------
+template <class T>
+struct A {
+  int foo(T *t);
+};
+
+//ERROR(1): class A;
+
+//ERROR(2): template class A;
+
+//ERROR(3): template A<int>;
+
+
+// ------------------
+template <class T>
+int foo(T t)
+{ return 1; }
+
+template int foo(int);
+
+//ERROR(4): template int foo(float), foo(char);
+
+
+// ------------------
+//ERROR(5): namespace foo { int x; }
+
+
+// ------------------
+//ERROR(6): int bar { return x; }
+
+
+// ------------------
+struct B {
+  ~B()
+//ERROR(7):    : something(5)     // stray member init
+  {}
+  
+  B();
+  
+  int x;
+  static int y;
+  int f(int);
+};
+
+B::B()
+  : x(3)
+//ERROR(8):  , y(7)     // member init of static data
+//ERROR(9):  , f(4)     // member init of a member function
+{}
+
+
+// ------------------
+// two things:
+//   - non-member constructor
+//   - member inits on non-constructor
+//ERROR(10):  d()
+//ERROR(10):    : something(6)
+//ERROR(10):  {}
+
+
+// ------------------
+void func()
+{
+  struct A {
+    // local class template
+    //ERROR(11): template <class T> struct B {};
+    //ERROR(12): template <class T> int foo(T *t);
+  };
+};
+
+
+// ------------------
+typedef int Func(int);
+//ERROR(13): Func const cfunc;
+
+
+// ------------------
+//ERROR(14): friend 
+class MyFriend {
+  int x;
+};
+
+
+// ------------------
+//ERROR(15): template <class T>
+union CrazyUnion {
+  int x;
+};
+
+
+// ------------------
+//ERROR(16): enum B::Blah blah;
+
+
+// ------------------
+enum SomeEnum { SE_ONE };
+//ERROR(17): enum SomeEnum { SE_TWO };
+
+
+// ------------------
+struct C {
+  //ERROR(18): auto int x;
+  //ERROR(19): extern int y;
+  //ERROR(20): register int z;
+};
+
+
+// ------------------
+//ERROR(21): int AE_THREE;    // would conflict
+enum AnotherEnum { AE_ONE, AE_TWO, AE_THREE, AE_FOUR };
+//ERROR(22): int AE_TWO;      // would conflict
+
+
+// ------------------
+//ERROR(23): int operator+;
+
+
+// ------------------
+int operator++ (B &c, int);
+//ERROR(24): int operator++ (C &c, float);
+//ERROR(25): int operator++ (C &c, int = 2);
+
+
+// ------------------
+struct D {
+  int f();
+  int f(int);
+};
+
+//ERROR(26): int D::f;
+
+
+// ------------------
+//ERROR(27): int &*ptr_to_ref;
+//ERROR(28): int &&ref_to_ref;
+
+typedef int &reference;
+//ERROR(29): reference &ref_to_ref;
+
+
+// ------------------
+struct E {
+  E();
+};
+ 
+// grouping parens on a ctor declarator
+(E::E)()      // icc rejects this!
+{}
+
+
+// ------------------
+// destructors must be class members
+//ERROR(30): ~foo() {}
+
+
+// ------------------
+//ERROR(31): int someFunc(int x(3));
+//ERROR(32): int someFunc(int x = {3});
+
+
+// ------------------
+struct F {
+  //ERROR(33): operator int (int);
+};
+
+
+// ------------------
+//ERROR(34): reference array_of_ref[3];
+
+typedef void VOID;
+//ERROR(35): VOID array_of_void[4];
+
+//ERROR(36): Func array_of_func[5];
+
+int *makeSomeInts(int x)
+{
+  //ERROR(37): return new (int[/*oops*/]);
+
+  //ERROR(38): return new int[4][x];
+  
+  return 0;
+}
+
+
+// ------------------
+int x;
+
+struct G {
+  int bitfield1 : 3;
+  //ERROR(39): int bitfield2 : x;
+};
+
+
+// ------------------
+void makePtrsToMembers()
+{
+  //ERROR(40): void G::*ptr_to_void;
+
+  //ERROR(41): int Nonexist::*ptr_to_nonexist;
+  
+  typedef int INT;
+  //ERROR(42): int INT::*ptr_to_int;
+}
+
+
+// ------------------
+void charStuff()
+{
+  char x;
+  
+  x = 'a';                  // ok
+  //ERROR(43): x = '';      // not ok
+}
+
+
+// ------------------
+struct Incomplete;
+
+void makeIncomplete(Incomplete &x)
+{
+  //ERROR(44): 0, Incomplete(1,2,3);
+  //ERROR(441): new Incomplete;
+
+  //ERROR(45): sizeof(Incomplete);
+  //ERROR(46): sizeof(x);
+}
+
+
+// ------------------
+int overloadedFunc();
+int overloadedFunc(int);
+
+void useOverloadedFunc()
+{
+  overloadedFunc(2);       // ok
+  
+  //ERROR(47): overloadedFunc++;        // not ok
+}
+
+
+// ------------------
+void coerceArrayToPtr()
+{
+  int a[3];
+  int *p = 0;
+  
+  a < p;
+}
+
+
+// ------------------
+struct H {
+  int x;
+  
+  int &intref;
+  //ERROR(55): void v;           // needed below
+  
+  H();
+};
+
+void dotStar()
+{
+  int x = 0;
+  int *p = 0;
+  int H::*ptm = 0;
+  H *bp = 0;
+
+  bp->*ptm;                      // ok
+  //ERROR(48): x.*ptm;
+  //ERROR(49): x->*ptm;
+  //ERROR(50): p->*ptm;
+  //ERROR(51): bp->*x;
+
+  //ERROR(52): void H::*ptmVoid = 0;
+  //ERROR(53): int& H::*ptmRef = 0;
+
+  &H::x;                         // ok
+  //ERROR(54): &H::intref;       // not ok
+  //ERROR(55): &H::v;            // not ok
+}
+
+
+// ------------------
+void derefFuncType()
+{
+  typedef int (*Func)(int);
+  Func f = 0;
+  
+  f(3);          // ok
+  (*f)(3);       // ok
+  (**f)(3);      // ok
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0450.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0450.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0450.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,52 @@
+// t0450.cc
+// function-try-block for non-ctors
+
+int nonmember()
+try {
+  return 2;
+}
+catch (int) {
+  return 3;
+}
+
+struct A {
+  int x;
+  static int y;
+
+  A();
+  ~A();
+  operator int ();
+  void f();
+};
+
+A::A()
+try
+  : x(4)
+{
+  y++;
+}
+catch (int) {}
+
+A::~A()
+try
+{
+  y++;
+}
+catch (int) {}
+
+A::operator int()
+try
+{
+  y++;
+  return 5;
+}
+catch (int) {
+  return 6;
+}
+
+void A::f()
+try
+{
+  y++;
+}
+catch (int) {}

Added: vendor/elsa/current/elsa/in/t0451.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0451.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0451.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,74 @@
+// t0451.cc
+// continuing to improve coverage, this time with base-class related stuff
+
+// icc fails to reject: 7
+
+//ERROR(1): struct C1 : nonexist {};
+
+typedef int INT;
+//ERROR(2): struct C2 : INT {};
+
+//ERROR(3): struct C3 : int {};
+
+struct C4 {
+  //ERROR(4): C4() : nonexist(4) {};
+  //ERROR(5): C4() : INT(4) {};
+  //ERROR(6): C4() : int(4) {};
+};
+
+// wrong ctor/dtor names
+struct C5 {
+  //ERROR(7): C5a();      // maybe icc thinks implicit int?
+  //ERROR(8): ~C5b();
+};
+
+
+struct A {
+  A(int);
+};
+
+struct B {
+  B();         // required but I do not notice...
+  B(int);
+};
+
+struct C : A, virtual B {
+  C(int)
+    : A(1)
+    , B(2)
+  {}
+};
+
+struct D : A, C {
+  D(int)
+    : A(1)
+    , B(1)
+    , C(1)
+  {}
+};
+
+struct E : A, D {
+  E(int)
+    : A(1)
+    //ERROR(9): , C(1)
+    , D(1)
+  {}
+};
+
+struct F : A, B, D {
+  F(int) 
+    : A(1)
+    //ERROR(10): , B(1)
+    , D(1)
+  {}
+};
+
+
+
+// incomplete base class
+struct G;
+//ERROR(11): struct C6 : G {};
+
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0452.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0452.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0452.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,113 @@
+// t0452.cc
+// coverage: template stuff
+
+//ERROR(1): template <class T>
+//ERROR(1): int A<T>::foo() { return 2; }
+
+template <class T>
+struct A {
+  template <class U>
+  struct B {
+    int foo();
+    int foo2();
+
+    typedef int INT;
+    INT bar();
+  };
+  
+  int f();
+};
+
+template <class T>
+template <class U>
+int A<T>::B<U>::foo() 
+{
+  int x;
+  //ERROR(6): x = sizeof(typename INT);
+  return x;
+}
+
+template <class T>
+template <class U>
+typename           //ERRORIFMISSING(2): required
+          A<T>::
+                template                 //ERRORIFMISSING(3): required
+                          B<U>::INT  A<T>::
+                                            //template    // required? no
+                                                      B<U>::bar() { return 3; }
+
+// Is the second 'template' required?  14.2p4 is where the requirement
+// to specify 'template' is stated, but it is hard to interpret.  icc
+// accepts it but does not require it; gcc rejects it.  For now, Elsa
+// behaves like icc, but I will not test that behavior.
+//
+// Thinking more, I believe icc is right:
+//   - p4 says it is *required* only when the member template name
+//     is dependent.  But A<T>::B<U> is not dependent on what T is;
+//     we simply match A<T> with existing specializations, and the
+//     result of that match is used regardless of what value T might
+//     have in a particular instantiation.
+//   - p5 says it is *illegal* if either
+//     (1) it does not precede a member template, but here A<T>::B<U>
+//         is of course a member template, or
+//     (2) it is not in the scope of a template.
+//     Now, it is a little unclear what "in the scope of a template"
+//     means, since we are in the declarator portion of a template.
+//     But notice that the 'template' keyword is clearly required
+//     in the type specifier, and if that is "in the scope" then
+//     the declarator is too.  I think "in the scope" simply means
+//     in the scope of template *parameters*, as opposed to the scope
+//     of a particular template.
+
+// so here is one where 'template' *is* used, and I believe allowed
+// (gcc rejects)
+template <class T>
+template <class U>
+int A<T>::template B<U>::foo2() { return 3; }
+
+//ERROR(4): template <class T>
+//ERROR(4): template <class U>
+//ERROR(4): int AA<T>::BB<U>::foo() { return 3; }
+
+// wrong template arg
+//ERROR(5): template <class T1>
+//ERROR(5): int A<T2>::f() { return 4; }
+
+
+
+struct S {
+  int x;
+};
+
+//ERROR(7): template <>
+//ERROR(7): struct S<int> { int y; };
+
+
+//ERROR(8): template <>
+//ERROR(8): struct A<nonexist> { int z; };
+
+
+template <class T>
+struct C {
+  static int x;
+};
+
+// specialize a non-function
+template <>
+int C<int>::x = 5;
+
+// specialize a non-member non-function
+//ERROR(9): template <>
+//ERROR(9): int y<int>;
+
+
+template <class T>
+void dependentPTM(T *t)
+{
+  &T::x;     // dependent PTM type
+}
+
+
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0453.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0453.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0453.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0453.cc
+// coverage for some built-in functions
+
+void f(int);
+
+void g(int) {}
+
+void f()
+{
+  //ERROR(1): __elsa_checkType();
+  //ERROR(1): __getStandardConversion();
+  //ERROR(1): __getImplicitConversion();
+  //ERROR(1): __testOverload();
+  //ERROR(1): __computeLUB();
+  //ERROR(1): __checkCalleeDefnLine();
+
+  //ERROR(2): __testOverload(f(3), 1);         // wrong line
+  //ERROR(3): __testOverload(1+2, 1);          // not a function
+
+  //ERROR(4): __checkCalleeDefnLine(f(3), 1);  // not a defined function
+  //ERROR(5): __checkCalleeDefnLine(g(4), 1);  // wrong line
+  //ERROR(6): __checkCalleeDefnLine(1+2, 1);   // not a function
+}

Added: vendor/elsa/current/elsa/in/t0454.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0454.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0454.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0454.cc
+// variety of template argument syntaxes
+
+template <int n>
+struct A {};
+  
+int f();
+  
+struct B {
+  int b;
+};
+
+void foo()
+{
+  B b;
+  int x;
+  int *p;
+
+  //ERROR(1):   A< f() > a1;        // error: not const
+  //ERROR(2):   A< b.b > a2;        // error: not const
+                A< -1 > a3;
+  //ERROR(3):   A< x++ > a4;        // error: not const (side effect)
+                A< 1+2 > a5;
+  //ERROR(4):   A< 1>2 > a6;        // error: unparenthesized '>'
+  //ERROR(5):   A< &x > a7;         // error: type mismatch
+  //ERROR(6):   A< *p > a8;         // error: not const
+                A< 1?2:3 > a9;
+  //ERROR(7):   A< x=3 > a10;       // error: not const (side effect)
+  //ERROR(8):   A< delete p > a11;  // error: not const (side effect)
+  //ERROR(9):   A< throw x > a12;   // error: not const (side effect)
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0455.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0455.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0455.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,58 @@
+// t0455.cc
+// PQName ambiguity
+
+
+namespace N1 {
+  template <class T>
+  struct A {
+    int x;
+  };
+
+  template <int n>
+  struct B {
+    template <int m>
+    struct C {};
+  };
+
+  int const D = 1;
+
+  void foo(int val)
+  {
+    // +--------------------------+
+    //     +--------------------+
+    //                +---------+
+    //     +-----+        +---+
+       A < B < 3 > :: C < D < 3 > >  a;
+       
+       a.x = val;
+  }
+}
+
+
+namespace N2 {
+  template <int n>
+  struct A {
+    template <class U>
+    struct C {
+      int x;
+    };
+  };
+
+  int const B = 2;
+
+  template <int m>
+  struct D {};
+
+  void foo(int val)
+  {
+    // +--------------------------+
+    // +---------+    +-----------+
+    //     +---+          +-----+
+       A < B < 3 > :: C < D < 3 > >  c;
+
+       c.x = val;
+  }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0456.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0456.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0456.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0456.cc
+// make sure Elsa can handle #line directives that refer to
+// nonexistent files
+
+int foo();
+
+# 10 "nonexist.cc"
+
+int bar();
+
+// even with an error there, causing an error message to point at it
+//ERROR(1): int array[does_not_exist];
+
+# 15 "t0456.cc"
+
+int main()
+{
+  return foo() + bar();
+}
+

Added: vendor/elsa/current/elsa/in/t0457.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0457.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0457.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0457.cc
+// differing prototypes for main()
+
+int main(int, char**, char **);
+int main(int, char**);
+int main(int);
+int main() { return 0; }
+
+// main() cannot be overloaded
+//ERROR(1): int main(float,float,float);
+

Added: vendor/elsa/current/elsa/in/t0458.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0458.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0458.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0458.cc
+// from Karl; template without params
+
+template <
+  class T                  //ERRORIFMISSING(1): required
+>
+class C {};

Added: vendor/elsa/current/elsa/in/t0459.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0459.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0459.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0459.cc
+// invalid C++ causes ambiguity to remain, then cloning dies
+
+typedef int my_size_t;    //ERRORIFMISSING(1): also needs to be gone to trigger problem
+
+template<bool t> class C {
+    void foo() {
+        int x;            //ERRORIFMISSING(1): if this is missing, input is ambiguously erroneous
+        (x) + (my_size_t)0;
+    }
+};
+template class C<true>;

Added: vendor/elsa/current/elsa/in/t0460.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0460.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0460.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0460.cc
+
+struct S {
+  int x;
+  int (*funcptr)(int);
+  
+  template <int n>
+  int templfunc(int);
+} *s;
+
+int foo() {
+  //ERROR(1): (s->funcptr<1>)(2);     // applying template args to non-template
+
+  int (*anotherFuncPtr)(int);
+
+  s->funcptr<anotherFuncPtr>(2);      // "<" and ">" parsed as less-then and greater-than
+
+  s->x<1>(2);
+  s->x < 1 || 2 > (3);
+  
+  s->templfunc<1>(2);
+  (s->templfunc<1>)(2);
+}
+

Added: vendor/elsa/current/elsa/in/t0461.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0461.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0461.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0461.cc
+// in template class, use A<T> form in name of constructor
+// derived from k0005a.cc
+
+template <typename T>
+struct A {
+    A<T> (int) {}
+    A<T> (float);
+    A<T> (int*);
+};
+
+// external definition without A<T>
+template <class T>
+A<T>::A(float) {}
+
+// external definition *with* A<T>
+//
+// this one is tricky b/c of scope delegation nonsense
+template <class T>
+A<T>::A<T>(int*) {}
+
+

Added: vendor/elsa/current/elsa/in/t0462.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0462.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0462.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,189 @@
+// t0462.cc
+// testing some of 14.8.2.1, template argument deduction
+
+// if this primary is ever instantiated, it will generate an error;
+// the idea is I will define specializations for each case that is
+// *supposed* to be called
+template <class T>
+void f1(T)
+{
+  typename T::foo x;
+}
+
+template <>
+void f1( int* )
+{}
+
+template <>
+void f1( int (*)() )
+{}
+
+template <>
+void f1( int )
+{}
+
+
+// test that the 'const' will be ignored during deduction
+template <class T>
+void f2(T const)
+{
+  typename T::foo x;
+}
+
+template <>
+void f2(int const)      // i.e., f2<int>
+{}
+
+// just check that explicit specification of template args
+template <>
+void f2<float>(float const)
+{}
+
+
+// try with a parameter type that is a reference
+template <class T>
+void f3(T const &)
+{
+  typename T::foo x;
+}
+
+template <>
+void f3(int const &)
+{}
+
+
+template <class T>
+void f4(T volatile &)
+{
+  typename T::foo x;
+}
+
+template <>
+void f4(int volatile &)
+{}
+
+
+template <class T>
+void f5(T const *)
+{
+  typename T::foo x;
+}
+
+template <>
+void f5(int const *)
+{}
+
+
+template <class T>
+void f6(T volatile * const *)
+{
+  typename T::foo x;
+}
+
+template <>
+void f6(int volatile * const *)
+{}
+
+
+struct A { int x; };
+
+template <class T>
+void f7(T const A::*)
+{
+  typename T::foo x;
+}
+
+template <>
+void f7(int const A::*)
+{}
+
+
+template <class T>
+class B {};
+
+class C : public B<int> {};
+
+template <class T>
+class D : public B<T> {};
+
+template <class T>
+void f8(B<T>)
+{
+  typename T::foo x;
+}
+
+template <>
+void f8(B<int>)
+{}
+
+template <class T>
+void f9(B<T>*)
+{
+  typename T::foo x;
+}
+
+template <>
+void f9(B<int>*)
+{}
+
+
+
+int main()
+{
+  // 14.8.2.1
+
+  // para 2
+
+  // bullet 1
+  int a[5];
+  f1(a);         // call f1< int* >
+
+  // bullet 2
+  int (*b)() = 0;
+  f1(*b);        // call f1< int (*)() >
+
+  // bullet 3
+  int const c = 0;
+  f1(c);         // call f1< int >, *not* f1< int const >
+  f2(c);         // call f2< int >
+
+  // para 2, second to last sentence
+  int d = 0;
+  f2(d);         // call f2< int >
+
+  int volatile e = 0;
+  f2(e);         // call f2< int >
+
+  // para 3
+
+  // bullet 1
+  f3(d);         // call f3< int >, ok that param has extra qualifiers
+  f4(d);         // call f4< int >
+
+  // bullet 2
+  int *g = 0;
+  f5(g);         // call f5< int >, converting int* to int const *
+
+  int **h = 0;
+  f6(h);         // call f6< int >, converting int** to int volatile * const *
+
+  int A::*i = 0;
+  f7(i);         // call f7< int >, converting int A::* to int const A::*
+  
+  // bullet 3
+  C j;
+  f8(j);         // call f8<int>, converting C to B<int>
+  f9(&j);        // similar, but converting pointers
+
+  D<int> k;
+  f8(k);         // call f8<int>, converting D<int> to B<int>
+  f9(&k);        // similar, but converting pointers
+  
+  // The final part of para 3 mentions that the bullets are considered
+  // only if type deduction would otherwise fail, and that multiple
+  // possible deduced parameter types are cause for failure, but I do
+  // not know how to write a test case that would expose the effect of
+  // either rule.
+
+  return 0;
+}

Added: vendor/elsa/current/elsa/in/t0463.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0463.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0463.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// t0463.cc
+// ambiguous function template parameter
+
+// Neither syntax below is valid, because function templates
+// are not allowed to have default arguments.
+
+template <int m>
+struct D {};
+
+namespace N1 {
+
+  enum { A=2 };
+
+              //       +-----params----+
+              //                 +---+   +---ret--+ +-name-+ +--defn---+
+  //ERROR(1): template < int n = A < 3 > :: D < n > myfunc() { /*...*/ }
+}
+
+
+namespace N2 {
+
+  template <int n>
+  struct A {
+    enum { D=5 };
+  };
+
+  enum { n=6 };
+
+
+              //       +-------params-------------+
+              //                 +less-than-expr+
+              //                 +-member---+
+              //                 +-qual+            +-name-+ +--defn---+
+  //ERROR(2): template < int n = A < 3 > :: D < n > myfunc() { /*...*/ }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0464.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0464.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0464.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// t0464.cc
+// ambiguous expression list
+
+int f(int,int,int);
+int f(int,int,int,int);
+
+namespace N1 {
+  template <int n, int m>
+  struct A {
+    static int B;
+  };
+
+  void foo()
+  {
+    //   +---------arg------+
+    //   +----member----+
+    //   +--qual---+
+    f(1, A < 1 , 2 > :: B < 4, 3);
+  }
+}
+
+
+int B;
+
+namespace N2 {
+  int A;
+
+  void foo()
+  {
+    //           +----------+
+    //           +------+
+    //   +---+       +--+
+    f(1, A < 1 , 2 > :: B < 4, 3);
+  }
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0465.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0465.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0465.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,58 @@
+// t0465.cc
+// ambiguous class template parameter
+
+// gcc-3.4.3 accepts both
+// icc-8.1 incorrectly rejects the second one
+
+
+// Currently, Elsa cannot parse this because it does not disambiguate
+// declarations properly.  If a declaration is ambiguous, but the
+// ambiguity is in the initializer, then both declarations are added
+// to the environment, which is bad.
+//
+// The solution is to reorganize tchecking of declarations so that
+// common prefixes are somehow identified and processed only once.
+
+
+namespace N1 {
+  template <int n1, int n2>
+  struct A {
+    enum { B=2 };
+  };
+  
+  enum { C=5 };
+
+  //         +--------ntparam-----------+
+  //                 +------member------+
+  //                 +----qual-----+
+  //                     +   +arg+
+  template < int n = A < 3 , C < 4 > :: B >
+  class X {};
+
+  X<> x;         // X<2>
+}
+
+
+namespace N2 {
+  enum { A=2 };
+
+  template <int m>
+  struct C {
+    typedef int B;
+  };
+
+  // must add a default for the second param, since the first has one
+  template <int n, C<4>::B m = 6>
+  class X;
+
+  //                         +--tparam--+
+  //         +--ntparam--+   +--member--+
+  //                 +def+   +-qual+
+  template < int n = A < 3 , C < 4 > :: B >
+  class X {};
+
+  X<> x;         // X<2,6>
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0466.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0466.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0466.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0466.cc
+// ambiguous declaration
+
+
+// (some stuff would need to come first to make this valid)
+
+int n = A < 3 , C < 4 > :: B ;

Added: vendor/elsa/current/elsa/in/t0467.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0467.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0467.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0467.cc
+// another from A.E.
+
+// The issue with this test is that the call to 'f' below is
+// syntactically ambiguous, possibly using one or two arguments, but
+// the proper # of args is needed to do overload resolution.
+
+template <class T1, class T2>
+struct C {
+  C(const T1&, const T2&);
+};
+
+void f(C<int,int> const &);
+void f(int const &);
+
+typedef int INT;
+
+void g()
+{
+  f(C<INT,INT>(0,0));
+}

Added: vendor/elsa/current/elsa/in/t0468.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0468.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0468.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,58 @@
+// t0468.cc
+// 'using' declaration refers to a dependent qualified name,
+// that is then used
+
+template <class T, class U>
+struct B {
+  void f();
+  void g();
+  void h();
+  void j();
+};
+
+template <class U>
+struct A : public B<char, U> {
+  // simplest case 'using', then a use
+  using B<char, U>::f;
+  void call_f() {
+    f();
+  }
+  
+  // a normal func, then 'using' brings in an overloaded version
+  int g(int);
+  using B<char, U>::g;
+  void call_g() {
+    g(3);                   // declared here
+    g();                    // imported
+    //ERROR(1): g(3,4);     // not declared anywhere (only found upon instantiation)
+  }
+
+  // two normal funcs, so it's already overloaded
+  int h(int);
+  int h(int, int);
+  using B<char, U>::h;
+  void call_h() {
+    h(3);                   // declared here
+    h(3,4);                 // also here
+    h();                    // imported
+    //ERROR(2): h(3,4,5);   // not declared anywhere
+  }
+
+  // 'using' comes first
+  using B<char, U>::j;
+  int j(int);
+  void call_j() {
+    j(3);                   // declared here
+    j();                    // imported
+    //ERROR(3): j(3,4);     // not declared anywhere
+  }
+};
+
+void foo()
+{
+  A<int> a;
+  a.call_f();
+  a.call_g();
+  a.call_h();
+  a.call_j();
+}

Added: vendor/elsa/current/elsa/in/t0469.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0469.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0469.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0469.cc
+// another use of a dependent qualified name
+
+struct C {};
+
+template <class T>
+void f(T t) {
+  C& c;
+  c.T::g();
+}

Added: vendor/elsa/current/elsa/in/t0470.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0470.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0470.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// t0470.cc
+// some experiments with friends of class templates
+
+template <class T>
+struct A {
+  friend int foo(T *t);
+  
+  // friend that does not use any of the template params
+  friend int zoo(int *p);
+  
+  void member()
+  {
+    int *q = 0;
+    
+    // I cannot tell whether these nondependent lookups should
+    // find the friends; icc accepts while gcc rejects
+    //foo(q);
+    //zoo(q);
+  }
+};
+
+struct B {
+  friend int bar(int *p);
+};
+
+void g()
+{
+  // is 'foo' now accessible here?  according to gcc and icc, no
+  int *p = 0;
+  //ERROR(1): foo(p);
+
+  // but 'bar' is, right?  yes
+  bar(p);
+
+  // what about 'zoo'?  gcc and icc again say no
+  //ERROR(2): zoo(p);
+}

Added: vendor/elsa/current/elsa/in/t0471.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0471.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0471.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0471.cc
+// arg-dep lookup does not find class members
+
+struct A {
+  static int f(A *a);
+};
+
+
+void foo()
+{
+  A *a = 0;
+
+  //ERROR(1): f(a);
+
+  // the above is not legal; 3.4.2p1 is not very clear, but the
+  // apparent intepretation is that namespace members and
+  // namespace-scope friends declared in classes (but not other class
+  // members) are the only things found by arg-dep; some other
+  // references:
+  //
+  //   http://groups-beta.google.com/group/comp.std.c++/browse_thread/thread/984bb13bc4ef5f7/a864e5af184ae877
+  //   http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_thread/thread/3456d46180a4e6c3/a08b673397148825
+  //   http://www.open-std.org/jtc1/sc22/WG21/docs/cwg_active.html#218
+  //   http://groups-beta.google.com/group/comp.std.c++/msg/e2cf2d0f8ac46fe9?hl=en
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0472.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0472.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0472.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0472.cc
+// do friends inject names?
+
+struct A {
+  friend int f(A *a);
+  friend int g(int *p);
+};
+
+void foo()
+{
+  // both gcc and icc accept this code, even though it appears to
+  // contradict the footnote in 14.6.5 and the rationale at
+  // http://groups-beta.google.com/group/comp.std.c++/msg/64407cbd5bb82189
+  int *p = 0;
+  //ERROR(1): g(p);
+  
+  // this is legal either by name injection, or by arg-dep lookup
+  A *a = 0;
+  f(a);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0473.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0473.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0473.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0473.cc
+// variant of t0243.cc where bad_alloc is in std::
+
+namespace std {
+  class bad_alloc {};
+}
+
+int *foo()
+{
+  try {
+    return new int;
+  }
+  catch (std::bad_alloc) {
+    return 0;
+  }
+}

Added: vendor/elsa/current/elsa/in/t0474.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0474.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0474.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,53 @@
+// t0474.cc
+// instantiating a pre-declared friend template
+
+// pre-declare A
+template <class T>
+struct A;
+
+// now I can pre-declare 'foo'
+template <class T>
+int foo(T t);
+
+template <class T>
+struct A {
+  // this says that there is a template function called 'foo'
+  // (Q: what determines how it is parameterized?) that is
+  // a friend of this class
+  friend int foo<> (T t);
+};
+
+// here I define that template
+template <class T>
+int foo(T t)
+{
+  return sizeof(T);
+}
+
+// and now I want to instantiate it
+template int foo(float t);
+
+
+// ---------------------
+// now repeat the above, except for an operator function
+template <class T>
+struct B;
+
+template <class T>
+int operator+ (int x, B<T> t);
+
+template <class T>
+struct B {
+  friend int operator+ <> (int, B<T> t);
+};
+
+template <class T>
+int operator+ (int x, B<T> t)
+{
+  return x + sizeof(B<T>);
+}
+
+template int operator+ (int x, B<float> t);
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0475.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0475.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0475.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,78 @@
+// t0475.cc
+// explicit specialization of a ctor, then use it
+
+template <class T>
+struct A {
+  A(int);
+  A(int, T);
+  A(int*);
+
+  int foo(int);
+  int foo(int, T);
+  int foo(int*);
+};
+
+// definition in general of ctor
+template <class T>
+A<T>::A(int, T)
+{ A<T*>::glarg(); }           // never instantiated
+
+// explicit specialization of ctor; overrides the general
+// definition at <float>
+template <>
+A<float>::A(int, float) {}
+
+// similar for an ordinary function
+template <class T>
+int A<T>::foo(int, T)
+{ return A<T*>::glarg(); }    // never instantiated
+
+template <>
+int A<float>::foo(int, float)
+{ return 2; }
+
+// use it
+void test_a()
+{
+  A<float> a(1, 2.3);
+  a.foo(1, 2.3);
+}
+
+
+// ------------------
+// same thing, but explicit spec comes first
+template <class T>
+struct B {
+  B(int);
+  B(int, T);
+  B(int*);
+
+  int foo(int);
+  int foo(int, T);
+  int foo(int*);
+};
+
+// explicit specialization of ctor
+template <>
+B<float>::B(int, float) {}
+
+// definition in general of ctor
+template <class T>
+B<T>::B(int, T)
+{ B<T*>::glarg(); }           // never instantiated
+
+template <>
+int B<float>::foo(int, float)
+{ return 2; }
+
+template <class T>
+int B<T>::foo(int, T)
+{ return B<T*>::glarg(); }    // never instantiated
+
+// use it
+void test_b()
+{
+  B<float> b(1, 2.3);
+  b.foo(1, 2.3);
+}
+

Added: vendor/elsa/current/elsa/in/t0476.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0476.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0476.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0476.cc
+// use of a qualified class type name inside its scope
+
+template <class T>
+struct A {
+  typedef int INT;
+  
+  void foo(INT i);
+};
+
+template <class T>
+void A<T>::foo(A::INT i)    // 'typename' keyword is *not* required here
+{}

Added: vendor/elsa/current/elsa/in/t0477.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0477.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0477.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0477.cc
+// template class with nested class and instance declared together
+
+template < class T >
+class A {
+private:
+  struct B { } b;
+};
+
+void foo()
+{
+  A<int> x;
+}

Added: vendor/elsa/current/elsa/in/t0478.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0478.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0478.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0478.cc
+// -> is rewritten to operator-> only when template is instantiated
+
+template < class ACE_CB >
+void open (void)
+{
+  typename ACE_CB::MALLOC_HEADER_PTR freep_;
+  &(freep_->next_block_);
+}
+
+
+template < class CONCRETE >
+class ACE_Based_Pointer {
+public:
+  CONCRETE *operator-> (void);
+};
+
+class ACE_PI_Control_Block {
+public:
+  class ACE_Malloc_Header;
+
+  typedef ACE_Based_Pointer < ACE_Malloc_Header > MALLOC_HEADER_PTR;
+
+  class ACE_Malloc_Header {
+  public:
+    MALLOC_HEADER_PTR next_block_;
+  };
+};
+
+void foo()
+{
+  open<ACE_PI_Control_Block>();
+}
+

Added: vendor/elsa/current/elsa/in/t0479.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0479.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0479.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0479.cc
+// invoke method via -> in a template
+
+struct nsISupports {
+  void AddRef();
+};
+
+template <class T>
+void f(nsISupports *p)
+{
+  p->AddRef();
+}
+
+template <class T>
+void g(T *t)
+{
+  t->~T();
+}
+
+

Added: vendor/elsa/current/elsa/in/t0480.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0480.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0480.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,65 @@
+// t0480.cc
+// expanding on t0478.cc and t0479.cc, trying to exercise various
+// possibilities for rewriting -> dependind on templateness and
+// presence of operator->
+
+
+struct A {
+  int x;
+};
+
+struct B {
+  A* operator->();
+};
+
+struct C {
+  B operator-> ();
+};
+
+template <class T>
+struct D {
+  T operator-> ();
+};
+
+
+// ------------------------
+// not dependent, no operator ->
+template <class T>
+int f1(T t, A *a)
+{
+  return a->x;
+}
+
+// instantiation
+template int f1(int, A*);
+
+
+// ------------------------
+// dependent
+template <class T>
+int f2(T t)
+{
+  return t->x;
+}
+
+// instantiate it such that operator -> is not used
+template int f2(A *t);
+
+// instantiate, and *do* use operator ->
+template int f2(B t);
+
+// instantiate and use operator-> twice
+template int f2(C t);
+
+
+// ------------------------
+// more complicated
+template <class T>
+int f3(D<T> d)
+{
+  return d->x;
+}
+
+template int f3(D<A*> d);
+template int f3(D<B> d);
+template int f3(D<C> d);

Added: vendor/elsa/current/elsa/in/t0481.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0481.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0481.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0481.cc
+// invoke dtor of template class w/o naming its template args
+
+template <class T>
+struct A {
+};
+
+void foo()
+{
+  A<int> *a = 0;
+  a->~A();
+  (*a).~A();    // equivalent
+}

Added: vendor/elsa/current/elsa/in/t0482.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0482.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0482.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0482.cc
+// ambiguous NewExpression
+
+void *operator new (unsigned size, int x);
+
+void *foo()
+{
+  int x = 0;
+  typedef int y;
+  return new (x)(y);     // placement x, then parenthesized type-id y
+}
+
+void *bar()
+{
+  typedef int x;
+  int y = 0;
+  return new (x)(y);     // parenthesized type-id x, new-initializer
+}

Added: vendor/elsa/current/elsa/in/t0483.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0483.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0483.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0483.cc
+// virtual inheritance and operator overloading
+
+struct A {
+  operator void* ();
+};
+
+// Note that if either of the 'virtual' is missing, then the
+// code is invalid.  However,
+//   - gcc accepts it anyway (it is wrong), and
+//   - Elsa gives a misleading error message ("no viable candidate")
+
+struct B : virtual A {};
+struct C : virtual A {};
+
+struct D : B, C {};
+
+void foo(D &d)
+{            
+  d && true;
+}
+
+

Added: vendor/elsa/current/elsa/in/t0484.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0484.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0484.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0484.cc
+// template member operator (from A.E.)
+
+struct A {
+  template <class T>
+  A& operator<<(T t);
+  
+  // hmm.. I can't make a unary operator like this because it would
+  // have no arguments with which to perform deduction, and there is
+  // no way to explicitly specify template args for operator
+  // invocations (w/o using explicit function call syntax, which is
+  // not my concern at the moment)
+};
+
+void f(A& a, int b) {
+  a.operator<<(b);
+  a << b;
+}

Added: vendor/elsa/current/elsa/in/t0485.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0485.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0485.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// t0485.cc
+// explicit specialization of member template
+
+struct A {
+  template <class T>
+  T f(T);
+};
+
+template <class T>
+T A::f(T)
+{
+  return 1;
+}
+
+template <>
+int A::f(int);
+
+template <>
+int A::f<int>(int);
+
+template <>
+int A::f<int>(int)
+{
+  return 2;
+}
+
+void foo()
+{
+  A a;
+  int x = 0;
+  float y = 0;
+  
+  a.f(x);      // uses specialization
+  a.f(y);      // uses primary
+}

Added: vendor/elsa/current/elsa/in/t0486.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0486.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0486.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,67 @@
+// t0486.cc
+// overloaded member function templates, determination of
+// which to use is done via specificity partial order, where
+// we have to compare U to B<T> *twice* (once in return type,
+// once in parameter list)
+
+template <class T>
+struct B {};
+
+struct A {
+  template <class U>
+  U f(U);
+
+  template <class T>
+  B<T> f(B<T>);
+};
+
+void g(A& a, B<int>& b) {
+  a.f(b);
+}
+
+
+// ---------------------
+namespace Blah {
+  template <class T>
+  struct B {};
+
+  struct A {
+    template <class U>
+    U f(U);
+
+    // true ambiguity
+    //ERROR(1): template <class T>
+    //ERROR(1): B<T*> f(B<T>);
+  };
+
+  void g(A& a, B<int>& b) {
+    a.f(b);
+  }
+}
+
+
+// --------------------
+namespace Whatever {
+  template <class U, class W>
+  U f(W, U);
+
+  // NOTE: Currently this works but for the wrong reason!
+  // t0487.cc shows the problem.  Once t0487.cc is fixed then
+  // this should *stop* working, because I have not implemented
+  // structural equality in DependentQType::innerEquals.
+  //
+  // 2005-08-03: This now appears to be fixed, in part by using
+  // the new mtype module.
+  template <class T>
+  typename T::INT f(T*, typename T::INT);
+         
+  struct C {
+    typedef int INT;
+  };
+
+  void g(C *c, int i)
+  {
+    f(c, i);
+  }
+}
+

Added: vendor/elsa/current/elsa/in/t0487.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0487.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0487.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0487.cc
+// matching against a DQT (see also t0488.cc)
+
+template <class T>
+void f(T*, typename T::INT, int);
+
+struct C {
+  typedef int INT;
+};
+
+void g(C *c, int i)
+{
+  f(c, i, 1);
+}

Added: vendor/elsa/current/elsa/in/t0487b.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0487b.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0487b.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0487b.cc
+// more complex version of t0487.cc, exposing need to
+// translate the DQT at the level of CVAtomicType, not
+// just AtomicType
+
+template <class T>
+void f(T*, typename T::INTC *, int);
+
+struct C {
+  typedef int const INTC;
+};
+
+void g(C *c, int const *i)
+{
+  f(c, i, 1);
+}

Added: vendor/elsa/current/elsa/in/t0488.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0488.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0488.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0488.cc
+// difficult type matching scenario
+
+// 2005-08-15: Oops, my previous comments here were in error,
+// the code was just wrong.  Elsa now accepts this.
+
+template <class T>
+void f(typename T::INT, T*, typename T::INT, int);
+
+struct C {
+  typedef int INT;
+};
+
+void g(C *c, int i)
+{
+  f(i, c, i, 1);
+}

Added: vendor/elsa/current/elsa/in/t0489.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0489.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0489.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,4 @@
+// t0489.cc
+// const-eval static_cast
+
+char _M_widen[1 + static_cast<unsigned char>(-1)];

Added: vendor/elsa/current/elsa/in/t0490.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0490.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0490.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// t0490.cc
+// conversions of function pointers
+// normalization of parameter types is the thing?
+
+typedef int (*param)(char *buf);
+void foo(param);
+
+typedef int (*arg)(char * const inbuf);
+void bar(arg x)
+{
+  foo((arg)x);
+}
+
+typedef int (*arg2)(char * __restrict inbuf);
+void bar2(arg2 x)
+{
+  // I actually think it is unsound to allow this, but the rules
+  // for C++ function types say to drop cv, and the rules for 
+  // C99 restrict say to treat it like cv, so here we are.
+  foo((arg2)x);
+}
+
+
+
+// but don't drop 'const' for the parameter inside
+// the function!
+
+int g(int &);
+
+int f(int const x)
+{
+  int const y = 4;
+
+  //ERROR(1): g(y);      // obviously wrong
+
+  //ERROR(2): g(x);      // wrong only if we remember 'x' is const
+}

Added: vendor/elsa/current/elsa/in/t0491.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0491.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0491.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0491.cc
+// explicit instantiation request with explicit specialization
+
+template <class T, class U>
+void foo(T t, U u) {}
+
+template <class T>
+void foo(T t, int u) {
+  // this would be an error because it is *this* template that
+  // the instantiation selects, but T is not a class in that case
+  //ERROR(1): return T::foo;
+}
+
+template void foo(int,int);
+

Added: vendor/elsa/current/elsa/in/t0492.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0492.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0492.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0492.cc
+// befriend containing template w/o using template args
+
+template <class T>
+struct A {
+  struct B {
+    friend struct A;
+  };
+};

Added: vendor/elsa/current/elsa/in/t0493.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0493.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0493.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0493.cc
+// anonymous bool-valued template parameter
+
+template<typename, bool>
+struct __enable_if
+{
+};

Added: vendor/elsa/current/elsa/in/t0494.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0494.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0494.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0494.cc
+// overloaded functions differing only in constrained type equalities
+
+// for the current bug to manifest, the less-general version
+// must come first in the file
+template <class W>
+void f(W x, W y) {}
+
+template <class T, class U>
+void f(T x, U y) {}
+
+void foo()
+{
+  f(1, 2);
+  f(1, 2.3);
+}

Added: vendor/elsa/current/elsa/in/t0495.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0495.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0495.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0495.cc
+// function-style cast with ambiguous argument list
+
+template <class T, class U>
+struct A {
+  static int i;
+  typedef int some_type;
+  A(int);
+};
+
+typedef int x;
+typedef int y;
+
+int f()
+{
+  return A<int,int>::some_type(A<x,y>::i);
+}

Added: vendor/elsa/current/elsa/in/t0496.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0496.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0496.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// t0496.cc
+// function-style cast with hidden dependent dest type
+
+struct Q {
+  Q(int,int);
+  operator int();
+};
+
+template <class T>
+struct A {
+  typedef Q some_type;
+};
+
+template <class T>
+struct B {
+  typedef typename A<T>::some_type another_type;
+  int f(int i);
+};
+
+template <class T>
+int B<T>::f(int i)
+{
+  return another_type(i,i);
+}
+
+void foo()
+{
+  B<int> b;
+  b.f(2);
+}

Added: vendor/elsa/current/elsa/in/t0497.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0497.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0497.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0497.cc
+// ambiguous argument to dependent base in template class ctor init
+
+template <class T>
+struct A {
+  typedef int some_type;
+  
+  A(int,int);
+};
+
+template <class T>
+struct B : A<T> {
+  typedef typename A<T>::some_type my_type;
+
+  B(int i) : A<T>(my_type(), i)
+  {}
+};
+

Added: vendor/elsa/current/elsa/in/t0498.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0498.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0498.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0498.cc
+// use a template parameter in an E_constructor of default arg
+// of method in nested template class
+
+struct A {
+  template <class T>
+  struct B {
+    void f(T t = T())
+    {}
+  };
+};
+
+
+

Added: vendor/elsa/current/elsa/in/t0499.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0499.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0499.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0499.cc
+// ?: on enums const variable
+
+enum E {a,b};
+const E aa = a;
+
+void f(E);
+
+void foo()
+{
+  f(true? aa : a);
+}

Added: vendor/elsa/current/elsa/in/t0500.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0500.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0500.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0500.cc
+// template template parameters
+// from gcc-3.4.3 <valarray> header
+
+template < class _Oper, 
+           template < class, class > class _Meta1,
+           template < class, class > class _Meta2, 
+           class _Dom1,
+           class _Dom2 > 
+class _BinClos;

Added: vendor/elsa/current/elsa/in/t0501.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0501.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0501.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0501.cc
+// nested class befriends containing template
+
+template <class T>
+struct A {
+  struct B {
+    friend class A<T>;
+  };
+};

Added: vendor/elsa/current/elsa/in/t0502.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0502.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0502.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0502.cc
+// invoke method on non-dependent class with dependent base
+
+template <class T>
+struct A {
+  struct B : T {};
+
+  void f()
+  {
+    B b;
+    b.foo();
+  };
+};
+
+struct C {
+  void foo();
+};
+
+void f()
+{
+  A<C> a;
+  a.f();
+}
+
+
+// ---------------
+// in contrast, this would be error; gcc diagnoses, icc does not
+template <class T>
+struct D {
+  void f()
+  {
+    C c;                      // C has no dependent bases
+    //ERROR(1): c.bar();      // and no method 'bar'
+  };
+};
+
+
+// there is an intermediate variant where C is a nested class but
+// still has no dependent bases; since gcc does not diagnose that
+// case, I am not going to add a test requiring that Elsa diagnose it,
+// even though right now it does (the standard allows both behaviors)
+

Added: vendor/elsa/current/elsa/in/t0503.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0503.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0503.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0503.cc
+// DQT in return type, as template arg
+
+template <class T>
+struct A {};
+
+template <class T, class U>
+struct A2 {};
+
+template <class V>
+struct B {
+  typedef int I;
+
+  A<I> f();
+  A2<I,float> g();
+};
+
+template <class V>
+A<typename B<V>::I> B<V>::f()
+{}
+
+template <class V>
+A2<typename B<V>::I, float> B<V>::g()
+{}

Added: vendor/elsa/current/elsa/in/t0504.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0504.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0504.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0504.cc
+// partial specialization nested inside a template class
+
+// This testcase motivated the introduction of several rather
+// ugly hacks.  Maybe someday I will figure out the right way
+// to implement this.
+
+// container
+template <class T>
+struct A {
+  // primary
+  template <class U, class V>
+  struct B {};
+
+  // specialization
+  template <class U>
+  struct B <U, int> {
+    typedef int INT;
+  };
+};
+
+// instantiate
+A<int> a;
+
+A<int>::B<float,char> ab_prim;
+A<int>::B<float,int> ab_spec;
+
+// make sure we're getting the spec; the primary doesn't have INT
+A<int>::B<float,int>::INT some_global_int;

Added: vendor/elsa/current/elsa/in/t0505.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0505.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0505.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0505.cc
+// non-type template parameter with type of previous param
+
+template <class T, T i>
+int f(T t)
+{
+  return sizeof(t) + i;
+}
+
+int foo()
+{
+  return f<int,4>(7);
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0506.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0506.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0506.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0506.cc
+// ordinary template function returning DQT
+
+template <class T> 
+struct A {
+  typedef int INT;
+          
+  template <class U>
+  struct B {
+    typedef float FLOAT;
+  };
+};
+
+template <class T>
+typename A<T>::INT f(A<T> x, int y)
+{ return 3; }
+
+template <class T>
+typename A<T>::template B<T*>::FLOAT g(T t)
+{ return 3.4; }
+
+int main() {
+  A<int> x;
+  f(x, 3);
+
+  g(3);
+}

Added: vendor/elsa/current/elsa/in/t0507.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0507.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0507.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0507.cc
+// template argument goes through two levels of constant variables
+
+int const a = 1;
+int const aa = a;
+
+template <int i>
+int f()
+{
+  return i;
+}
+
+void foo()
+{
+  f<a>();          // one level
+  f<aa>();         // two levels
+}

Added: vendor/elsa/current/elsa/in/t0508.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0508.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0508.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// t0508.cc
+// template accepts reference, pointer and pointer-to-member
+
+template <int &IR>
+int f()
+{
+  &IR;       // legal
+  return IR + 10;
+}
+
+
+template <int *IP>
+int g()
+{
+  return *IP + 20;
+}
+
+
+struct S {
+  int m;
+};
+
+template <int S::*PTM>
+int h(S *s)
+{
+  return s->*PTM;
+}
+
+
+int x;
+
+void foo()
+{
+  f<x>();
+  g<&x>();
+  
+  S *s = 0;
+  h<&S::m>(s);
+}

Added: vendor/elsa/current/elsa/in/t0509.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0509.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0509.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0509.cc
+// template accepts int&, argument is int const
+
+// Elsa, edg and gcc all reject this input, I think for the same
+// reason: they see the 'int const' and decide the argument is '4',
+// when in fact it needs to be (reference to) 'x'.  But if it
+// doesn't work in those systems, I won't bother fixing it in
+// Elsa either (for now).
+
+// Nevertheless, I believe the code is valid C++.
+
+template <int &IR>
+int f()
+{
+  &IR;       // legal
+  return IR + 10;
+}
+
+extern int const x = 4;
+
+void foo()
+{
+  f<x>();
+}

Added: vendor/elsa/current/elsa/in/t0510.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0510.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0510.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0510.cc
+// a class befriending itself
+// from Sohail Somani
+
+template <class Y>
+class test {
+  template <class T> 
+  friend class test;
+};
+
+test<int> ff;

Added: vendor/elsa/current/elsa/in/t0511.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0511.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0511.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,628 @@
+// t0511.cc
+// testing mtype module
+
+// 2005-08-02: The tests in this file alone are able to drive mtype to
+// 100% statement coverage except for the MF_POLYMORPHIC stuff.  The
+// tests in this file were mostly constructed specifically (and only)
+// to obtain that coverage level.
+
+
+// copied from mflags.h
+enum MatchFlags {
+  // complete equality; this is the default; note that we are
+  // checking for *type* equality, rather than equality of the
+  // syntax used to denote it, so we do *not* compare (e.g.)
+  // function parameter names or typedef usage
+  MF_NONE            = 0x0000,
+
+  // ----- basic behaviors -----
+  // when comparing function types, do not check whether the
+  // return types are equal
+  MF_IGNORE_RETURN   = 0x0001,
+
+  // when comparing function types, if one is a nonstatic member
+  // function and the other is not, then do not (necessarily)
+  // call them unequal
+  MF_STAT_EQ_NONSTAT = 0x0002,    // static can equal nonstatic
+
+  // when comparing function types, only compare the explicit
+  // (non-receiver) parameters; this does *not* imply
+  // MF_STAT_EQ_NONSTAT
+  MF_IGNORE_IMPLICIT = 0x0004,
+
+  // In the C++ type system, cv qualifiers on parameters are not part
+  // of the type [8.3.5p3], so by default mtype ignores them.  If you
+  // set this flag, then they will *not* be ignored.  It is provided
+  // only for completeness; Elsa does not use it.
+  MF_RESPECT_PARAM_CV= 0x0008,
+
+  // ignore the topmost cv qualification of the two types compared
+  MF_IGNORE_TOP_CV   = 0x0010,
+
+  // when comparing function types, compare the exception specs;
+  // by default such specifications are not compared because the
+  // exception spec is not part of the "type" [8.3.5p4]
+  MF_COMPARE_EXN_SPEC= 0x0020,
+  
+  // allow the cv qualifications to differ up to the first type
+  // constructor that is not a pointer or pointer-to-member; this
+  // is cppstd 4.4 para 4 "similar"; implies MF_IGNORE_TOP_CV
+  MF_SIMILAR         = 0x0040,
+
+  // when the second type in the comparison is polymorphic (for
+  // built-in operators; this is not for templates), and the first
+  // type is in the set of types described, say they're equal;
+  // note that polymorhism-enabled comparisons therefore are not
+  // symmetric in their arguments
+  MF_POLYMORPHIC     = 0x0080,
+
+  // for use by the matchtype module: this flag means we are trying
+  // to deduce function template arguments, so the variations
+  // allowed in 14.8.2.1 are in effect (for the moment I don't know
+  // what propagation properties this flag should have)
+  MF_DEDUCTION       = 0x0100,
+
+  // this is another flag for MatchTypes, and it means that template
+  // parameters should be regarded as unification variables only if
+  // they are *not* associated with a specific template
+  MF_UNASSOC_TPARAMS = 0x0200,
+
+  // ignore the cv qualification on the array element, if the
+  // types being compared are arrays
+  MF_IGNORE_ELT_CV   = 0x0400,
+
+  // enable matching/substitution with template parameters
+  MF_MATCH           = 0x0800,
+
+  // do not allow new bindings to be created; but existing bindings
+  // can continue to be used
+  MF_NO_NEW_BINDINGS = 0x1000,
+
+  // when combined with MF_MATCH, it means we can bind variables in
+  // the pattern only to other variables in the "concrete" type, and
+  // that the binding function must be injective (no two pattern
+  // variables can be bound to the same concrete variable); this
+  // is used to compare two templatized signatures for equivalence
+  MF_ISOMORPHIC      = 0x2000,
+
+  // ----- combined behaviors -----
+  // all flags set to 1
+  MF_ALL             = 0x3FFF,
+
+  // number of 1 bits in MF_ALL
+  MF_NUM_FLAGS       = 14,
+
+  // signature equivalence for the purpose of detecting whether
+  // two declarations refer to the same entity (as opposed to two
+  // overloaded entities)
+  MF_SIGNATURE       = (
+    MF_IGNORE_RETURN |       // can't overload on return type
+    MF_STAT_EQ_NONSTAT       // can't overload on static vs. nonstatic
+  ),
+
+  // ----- combinations used by the mtype implementation -----
+  // this is the set of flags that allow CV variance within the
+  // current type constructor
+  MF_OK_DIFFERENT_CV = (MF_IGNORE_TOP_CV | MF_SIMILAR),
+
+  // this is the set of flags that automatically propagate down
+  // the type tree equality checker; others are suppressed once
+  // the first type constructor looks at them
+  MF_PROP = (
+    MF_RESPECT_PARAM_CV |
+    MF_POLYMORPHIC      |
+    MF_UNASSOC_TPARAMS  |
+    MF_MATCH            |
+    MF_NO_NEW_BINDINGS  |
+    MF_ISOMORPHIC       
+    
+    // Note: MF_COMPARE_EXN_SPEC is *not* propagated.  It is used only
+    // when the compared types are FunctionTypes, to compare those
+    // toplevel exn specs, but any FunctionTypes appearing underneath
+    // are compared just as types (not objects), and hence their exn
+    // specs are irrelevant.
+  ),
+
+  // these flags are propagated below ptr and ptr-to-member
+  MF_PTR_PROP = (
+    MF_PROP            |
+    MF_SIMILAR         |
+    MF_DEDUCTION
+  )
+};
+
+
+struct B {
+  int x;
+  
+  static int f_stat();
+  int f_nonstat();
+  
+  typedef int INT;
+  typedef int const INTC;
+};
+
+struct B2 {
+  int x;
+};
+
+
+template <class T>
+struct C {
+  T t;
+};
+
+
+template <class U, class V>
+struct Pair {
+  U u;
+  V v;
+};
+
+template <class U, class V>
+struct Pair2 {
+  U u;
+  V v;
+};
+
+
+template <int m>
+struct Num {};
+             
+
+int const global_const1 = 1;
+int const global_const2 = 2;
+
+
+int f_nonvararg(int);
+int f_vararg(int, ...);
+
+int f_throws_int(int) throw(int);
+int f_throws_float(int) throw(float);
+
+
+
+int global_n;
+int global_m;
+
+template <class T, int &intref>
+struct TakesIntRef {};
+
+template <class T, int *intptr>
+struct TakesIntPtr {};
+                   
+
+template <class T, int B::*ptm>
+struct TakesPTM {};
+
+
+struct D {
+  template <class T>
+  struct E {
+    typedef int INT;
+  };
+
+  // partial spec
+  template <class T>
+  struct E<T*> {};
+
+  // explicit full spec
+  template <>
+  struct E<float*> {};
+  
+  struct F {
+    typedef int INT;
+  };
+  
+  typedef int INT;
+};
+
+
+template <class S, class T, int n, int n2>
+struct A {
+  void f()
+  {
+    // very simple
+    __test_mtype((int*)0, (T*)0, MF_MATCH,
+                 "T", (int)0);
+    __test_mtype((int*)0, (float*)0, MF_MATCH, false);
+
+
+    // CVAtomicType
+    __test_mtype((int const volatile)0, (T const)0, MF_MATCH,
+                 "T", (int volatile)0);
+
+    // PointerType
+    __test_mtype((int const * const)0, (T * const)0, MF_MATCH,
+                 "T", (int const)0);
+    __test_mtype((int const * const)0, (T *)0, MF_MATCH,
+                 false);
+
+    // ReferenceType
+    __test_mtype((int &)0, (T &)0, MF_MATCH,
+                 "T", (int)0);
+
+    // FunctionType
+    __test_mtype((int (*)())0, (T (*)())0, MF_MATCH,
+                 "T", (int)0);
+
+    // ArrayType
+    __test_mtype((int (*)[3])0,
+                 (T   (*)[3])0, MF_MATCH,
+                 "T", (int)0);
+    __test_mtype((int (*)[])0,
+                 (T   (*)[])0, MF_MATCH,
+                 "T", (int)0);
+    __test_mtype((int (*)[3])0,
+                 (T   (*)[4])0, MF_MATCH,
+                 false);
+
+
+    // testing binding of variables directly to atomics
+    __test_mtype((int B::*)0, (int T::*)0, MF_MATCH,
+                 "T", (B)0);
+
+    __test_mtype((int (*)(B const *, int B::*))0,
+                 (int (*)(T       *, int T::*))0, MF_MATCH,
+                 "T", (B const)0);
+
+    __test_mtype((int (*)(B const *, int B::*, B const *))0,
+                 (int (*)(T       *, int T::*, T       *))0, MF_MATCH,
+                 "T", (B const)0);
+
+    __test_mtype((int (*)(int B::*, B const *))0,
+                 (int (*)(int T::*, T       *))0, MF_MATCH,
+                 "T", (B const)0);
+
+    __test_mtype((int (*)(int B::*, B const *, int B::*))0,
+                 (int (*)(int T::*, T       *, int T::*))0, MF_MATCH,
+                 "T", (B const)0);
+
+    __test_mtype((int (*)(int B::*, B const *, B const volatile *))0,
+                 (int (*)(int T::*, T       *, T       volatile *))0, MF_MATCH,
+                 "T", (B const)0);
+
+    __test_mtype((int (*)(int B::*, B const          *))0,
+                 (int (*)(int T::*, T       volatile *))0, MF_MATCH,
+                 false);
+
+    __test_mtype((int (*)(int B::*, B const *, B const          *))0,
+                 (int (*)(int T::*, T       *, T       volatile *))0, MF_MATCH,
+                 false);
+
+    // second binding is not to an atomic
+    __test_mtype((int (*)(int B::*, B const * *))0,
+                 (int (*)(int T::*, T         *))0, MF_MATCH,
+                 false);
+
+    // wrong atomic
+    __test_mtype((int (*)(int B::*, B2 const *))0,
+                 (int (*)(int T::*, T        *))0, MF_MATCH,
+                 false);
+
+    // first binding is not an atomic
+    __test_mtype((int (*)(B const * *, int B::*))0,
+                 (int (*)(T         *, int T::*))0, MF_MATCH,
+                 false);
+
+    // wrong atomic
+    __test_mtype((int (*)(B2 const *, int B::*))0,
+                 (int (*)(T        *, int T::*))0, MF_MATCH,
+                 false);
+
+    // wrong AtomicType
+    __test_mtype((int (*)(int B2::*, int B::*))0,
+                 (int (*)(int T ::*, int T::*))0, MF_MATCH,
+                 false);
+
+    // not a type (causes an early error diagnosis)
+    //__test_mtype((int (*)(Num<3>, int B::*))0,
+    //             (int (*)(Num<n>, int n::*))0, MF_MATCH,
+    //             false);
+
+
+    // multiple occurrences of variables in patterns
+    __test_mtype((int (*)(int,int))0,
+                 (int (*)(T,T))0, MF_MATCH,
+                 "T", (int)0);
+
+    __test_mtype((int (*)(int,float))0,
+                 (int (*)(T,T))0, MF_MATCH,
+                 false);
+
+
+    // match instantiation with PseudoInstantiation
+    __test_mtype((Pair<int,int>*)0,
+                 (Pair<T,T>*)0, MF_MATCH,
+                 "T", (int)0);
+    __test_mtype((Pair<int,int>*)0,
+                 (Pair2<T,T>*)0, MF_MATCH,
+                 false);
+
+
+    // match template param with itself
+    __test_mtype((T*)0,
+                 (T*)0, MF_NONE);
+    __test_mtype((T*)0,
+                 (S*)0, MF_NONE, false);
+
+    // Q: should this yield a binding?  for now it does...
+    __test_mtype((T*)0,
+                 (T*)0, MF_MATCH,
+                 "T", (T)0);
+
+    // PseudoInstantiation
+    __test_mtype((Pair<T,int>*)0,
+                 (Pair<T,int>*)0, MF_NONE);
+    __test_mtype((Pair<T,int>*)0,
+                 (Pair<T,int const>*)0, MF_NONE, false);
+    __test_mtype((Pair<T,int>*)0,
+                 (Pair2<T,int>*)0, MF_NONE, false);
+
+    // DependentQType
+    __test_mtype((typename T::Foo*)0,
+                 (typename T::Foo*)0, MF_NONE);
+    __test_mtype((typename T::Foo::Bar*)0,
+                 (typename T::Foo::Bar*)0, MF_NONE);
+    __test_mtype((typename T::Foo::template Baz<3>*)0,
+                 (typename T::Foo::template Baz<3>*)0, MF_NONE);
+    __test_mtype((typename T::Foo::template Baz<3>*)0,
+                 (typename T::Foo::template Baz<4>*)0, MF_NONE, false);
+
+
+    // match with an integer
+    __test_mtype((Num<3>*)0,
+                 (Num<n>*)0, MF_MATCH,
+                 "n", 3);
+
+    // ask the infrastructure for an unbound value
+    //ERROR(1): __test_mtype((Num<3>*)0,
+    //ERROR(1):              (Num<n>*)0, MF_MATCH,
+    //ERROR(1):              "nn", 3);
+
+    // attempt to compare different kinds of atomics
+    __test_mtype((B*)0, (int*)0, MF_NONE, false);
+    
+    // Mix different binding kinds together.
+    //
+    // These are currently triggering match failures in mtype.cc, as
+    // intended (to improve coverage), but it is possible that a
+    // future change to the tcheck code might diagnose them as syntax
+    // errors.  If that happens, these can just be commented out I
+    // suppose.  
+    __test_mtype((Pair<int, Num<3> >*)0,
+                 (Pair<T,   Num<T> >*)0, MF_MATCH, false);
+
+    __test_mtype((Pair<Num<3>, int>*)0,
+                 (Pair<Num<T>, T  >*)0, MF_MATCH, false);
+
+    __test_mtype((Pair<int, Num<3> >*)0,
+                 (Pair<n,   Num<n> >*)0, MF_MATCH, false);
+
+    __test_mtype((Pair<Num<3>, int>*)0,
+                 (Pair<Num<n>, n  >*)0, MF_MATCH, false);
+
+    // nontype bound to 3 then 4
+    __test_mtype((Pair<Num<3>, Num<4> >*)0,
+                 (Pair<Num<n>, Num<n> >*)0, MF_MATCH, false);
+
+    // cover a specific line in mtype.cc ...
+    __test_mtype((Num<3>*)0,
+                 (Num<n>*)0, MF_MATCH|MF_NO_NEW_BINDINGS, false);
+    __test_mtype((int*)0,
+                 (T*)0, MF_MATCH|MF_NO_NEW_BINDINGS, false);
+    __test_mtype((int B::*)0,
+                 (int T::*)0, MF_MATCH|MF_NO_NEW_BINDINGS, false);
+
+    // DQTs with mismatching leading atomics
+    __test_mtype((typename C<T>::Foo*)0,
+                 (typename Pair<T,T>::Foo*)0, MF_NONE, false);
+                 
+    // and mismatching PQName kinds
+    __test_mtype((typename C<T>::template Foo<3>*)0,
+                 (typename C<T>::Foo*)0, MF_NONE, false);
+
+    // differing PQ_qualifier names
+    __test_mtype((typename C<T>::Foo::Baz*)0,
+                 (typename C<T>::Bar::Baz*)0, MF_NONE, false);
+
+    // differing template arguments to PQ_qualifier
+    __test_mtype((typename C<T>::template Foo<1>::Baz*)0,
+                 (typename C<T>::template Foo<2>::Baz*)0, MF_NONE, false);
+
+
+    // different Type kinds
+    __test_mtype((int)0,
+                 (int*)0, MF_NONE, false);
+                 
+    // cv-flags in the pattern aren't present in concrete
+    __test_mtype((int const)0,
+                 (T volatile)0, MF_MATCH, false);
+    __test_mtype((int const)0,
+                 (T const)0, MF_MATCH,
+                 "T", (int)0);
+                 
+    // FunctionType with differing return type
+    __test_mtype((int (*)())0,
+                 (float (*)())0, MF_NONE, false);
+                 
+    // static vs. non-static
+    __test_mtype(B::f_stat,
+                 B::f_nonstat, MF_NONE, false);
+    __test_mtype(B::f_stat,
+                 B::f_nonstat, MF_STAT_EQ_NONSTAT);
+    __test_mtype(B::f_nonstat,
+                 B::f_stat, MF_STAT_EQ_NONSTAT);
+
+    // vararg vs. non-vararg
+    __test_mtype(f_vararg, f_nonvararg, MF_NONE, false);
+    
+    // throw vs. non-throw
+    __test_mtype(f_nonvararg, f_throws_int, MF_COMPARE_EXN_SPEC, false);
+
+    // differing exception specs
+    __test_mtype(f_throws_float, f_throws_int, MF_COMPARE_EXN_SPEC, false);
+    __test_mtype(f_throws_int, f_throws_int, MF_COMPARE_EXN_SPEC);
+    
+    // ArrayTypes and MF_IGNORE_ELT_CV
+    //
+    // I am abusing the cast syntax here because MF_IGNORE_ELT_CV does
+    // not propagate below type constructors... at some point Elsa
+    // might be modified to reject these invalid casts altogether, in
+    // which case these tests can just be commented out.
+    __test_mtype((int const [2])0,
+                 (int       [2])0, MF_NONE, false);
+    __test_mtype((int const [2])0,
+                 (int       [2])0, MF_IGNORE_ELT_CV);
+    __test_mtype((int const [2][3])0,
+                 (int       [2][3])0, MF_IGNORE_ELT_CV);
+                 
+    // expression comparison
+    __test_mtype((Num<n+3>*)0,
+                 (Num<n+3>*)0, MF_NONE);
+
+    __test_mtype((Num<(n+3)>*)0,
+                 (Num< n+3 >*)0, MF_NONE);
+
+    __test_mtype((Num< n+3 >*)0,
+                 (Num<(n+3)>*)0, MF_NONE);
+
+    __test_mtype((Num<(n+3)>*)0,
+                 (Num<(n+3)>*)0, MF_NONE);
+
+    __test_mtype((Num<-n>*)0,
+                 (Num<-n>*)0, MF_NONE);
+
+    __test_mtype((Num<n+3>*)0,
+                 (Num<-n>*)0, MF_NONE, false);
+
+    __test_mtype((Num<n+(int)true>*)0,
+                 (Num<n+(int)true>*)0, MF_NONE);
+
+    __test_mtype((Num<n+static_cast<int>(true)>*)0,
+                 (Num<n+static_cast<int>(true)>*)0, MF_NONE);
+
+    __test_mtype((Num<n+'a'>*)0,
+                 (Num<n+'a'>*)0, MF_NONE);
+
+    __test_mtype((Num<n >*)0,
+                 (Num<n2>*)0, MF_NONE, false);
+
+    __test_mtype((Num<n+global_const1>*)0,
+                 (Num<n+global_const2>*)0, MF_NONE, false);
+
+    __test_mtype((Num<n+sizeof(int)>*)0,
+                 (Num<n+sizeof(int)>*)0, MF_NONE);
+
+    __test_mtype((Num<n+sizeof(n)>*)0,
+                 (Num<n+sizeof(n)>*)0, MF_NONE);
+
+    __test_mtype((Num< n? 1 : 2 >*)0,
+                 (Num< n? 1 : 2 >*)0, MF_NONE);
+    __test_mtype((Num< n? 1 : 2 >*)0,
+                 (Num< n? 1 : 3 >*)0, MF_NONE, false);
+                 
+    __test_mtype((TakesIntRef<T, global_n>*)0,
+                 (TakesIntRef<T, global_n>*)0, MF_NONE);
+
+    __test_mtype((TakesIntRef<T, global_n>*)0,
+                 (TakesIntRef<T, global_m>*)0, MF_NONE, false);
+
+    __test_mtype((TakesIntPtr<T, &global_n>*)0,
+                 (TakesIntPtr<T, &global_n>*)0, MF_NONE);
+
+    __test_mtype((TakesPTM<T, &B::x>*)0,
+                 (TakesPTM<T, &B::x>*)0, MF_NONE);
+
+
+    // testing resolution of DQTs (see also in/t0487.cc)
+    __test_mtype((void (*)(B *, int            , int))0,
+                 (void (*)(T *, typename T::INT, int))0, MF_MATCH,
+                 "T", (B)0);
+
+    // bind directly to AtomicType rather than CVAtomicType
+    __test_mtype((void (*)(int B::*, int            , int))0,
+                 (void (*)(int T::*, typename T::INT, int))0, MF_MATCH,
+                 "T", (B)0);
+
+    // failure because the initial binding doesn't work
+    __test_mtype((void (*)(B2 *, int            , int))0,
+                 (void (*)(T  *, typename T::INT, int))0, MF_MATCH,
+                 false);
+
+    // final name component is PQ_template
+    __test_mtype((void (*)(D *, D::E<int>                  , int))0,
+                 (void (*)(T *, typename T::template E<int>, int))0, MF_MATCH,
+                 "T", (D)0);
+
+    // mismatching variant
+    __test_mtype((void (*)(D *, D::E<int>                    , int))0,
+                 (void (*)(T *, typename T::template E<float>, int))0, MF_MATCH,
+                 false);
+
+    // PQ_template, but the name doesn't name a template
+    __test_mtype((void (*)(D *, D::E<int>                    , int))0,
+                 (void (*)(T *, typename T::template INT<int>, int))0, MF_MATCH,
+                 false);
+
+    // exercise the partial specialization
+    __test_mtype((void (*)(D *, D::E<int*>                  , int))0,
+                 (void (*)(T *, typename T::template E<int*>, int))0, MF_MATCH,
+                 "T", (D)0);
+
+    // exercise the full specialization
+    __test_mtype((void (*)(D *, D::E<float*>                  , int))0,
+                 (void (*)(T *, typename T::template E<float*>, int))0, MF_MATCH,
+                 "T", (D)0);
+
+    // PQ_qualifier without template args
+    __test_mtype((void (*)(D *, int               , int))0,
+                 (void (*)(T *, typename T::F::INT, int))0, MF_MATCH,
+                 "T", (D)0);
+
+    // bad PQ_qualifier
+    __test_mtype((void (*)(D *, int                      , int))0,
+                 (void (*)(T *, typename T::NONEXIST::INT, int))0, MF_MATCH,
+                 false);
+
+    // does not name a CompoundType
+    __test_mtype((void (*)(B *, int                 , int))0,
+                 (void (*)(T *, typename T::INT::INT, int))0, MF_MATCH,
+                 false);
+
+    // PQ_qualifier *with* template args
+    //
+    // this does not work, see notes near the xunimp it triggers
+    //__test_mtype((void (*)(D *, int                             , int))0,
+    //             (void (*)(T *, typename T::template E<int>::INT, int))0, MF_MATCH,
+    //             "T", (D)0);
+    
+    // from t0487b.cc
+    __test_mtype((void (*)(B *, int const *       , int))0,
+                 (void (*)(T *, typename T::INTC *, int))0, MF_MATCH,
+                 "T", (B)0);
+
+    __test_mtype((void (*)(B *, int       *       , int))0,
+                 (void (*)(T *, typename T::INTC *, int))0, MF_MATCH,
+                 false);
+
+    __test_mtype((void (*)(B *, int const *       , int))0,
+                 (void (*)(T *, typename T::INT  *, int))0, MF_MATCH,
+                 false);
+                 
+    // from in/t0315.cc
+    __test_mtype((int     *)0,
+                 (T const *)0, MF_MATCH|MF_DEDUCTION,
+                 "T", (int)0);
+                 
+    // from in/t0462.cc; the 'const' is *not* deduced for T
+    __test_mtype((int const)0,
+                 (T        )0, MF_MATCH|MF_DEDUCTION,
+                 "T", (int)0);
+                 
+    // from in/t0486.cc
+    __test_mtype((typename T::INT (*)(typename T::INT))0,
+                 (S               (*)(S              ))0, MF_MATCH,
+                 "S", (typename T::INT)0);
+  }
+};

Added: vendor/elsa/current/elsa/in/t0512.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0512.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0512.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+// t0512.cc
+// const primitive-type variable initialized by IN_ctor
+// reported by Jeremy Smithers
+
+const int ConstVar(1234);
+int ArrayVar[ConstVar];

Added: vendor/elsa/current/elsa/in/t0513.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0513.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0513.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// t0513.cc
+// sizeof a struct with a bitfield
+
+struct S1 {
+  unsigned x : 2;
+  unsigned y : 30;
+};
+
+int arr1[sizeof(S1)==4? +1 : -1];
+
+
+struct S2 {
+  unsigned x : 2;
+  unsigned y : 30;
+  unsigned z : 1;
+};
+
+// edg and icc both say this is 8 ...
+int arr2[sizeof(S2)==8? +1 : -1];
+
+
+
+// this is from a header file somewhere, it shows up in quite a 
+// few of the Debian build failures
+//
+// actually, it's gcc's implementation of __real__, and then a
+// check regarding its size (because gcc must emit machine code
+// to manipulate it), and this appears in both gcc and mingw32
+struct real_value {
+  unsigned int canonical : 1;                       // 1
+  signed int exp : (32 - 5);                        // 27
+  unsigned long sig[((128 + (8 * 4)) / (8 * 4))];   // 5
+};
+
+extern char test_real_width [
+  sizeof(struct real_value) <= (((128 + (8 * 4)) + 32)/(8 * 4) + (((128 + (8 * 4)) + 32)%(8 * 4) ? 1 : 0))*sizeof(long) ? 1 : -1
+];

Added: vendor/elsa/current/elsa/in/t0514.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0514.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0514.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0514.cc
+// use templatized constructor of template class for arg-to-param conversion
+
+template <class S>
+struct A {
+  template <class T>
+  A(T*);
+};
+
+void foo(A<int>);
+void foo(int);
+
+void bar()
+{
+  int *p = 0;
+  foo(p);
+}

Added: vendor/elsa/current/elsa/in/t0515.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0515.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0515.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,58 @@
+// t0515.cc
+// assertion-failure-inducing input from acovea_4.0.0-4_acovea.cpp
+// nested DQTs in return type
+
+// This testcase has another interesting aspect: EDG and GCC both
+// seem to regard the templatized 'sqrt' as not matching any
+// call site if their attempt to compute the return type encounters
+// errors due to member lookup failure, for example because the
+// _M_type members aren't declared.  I find this behavior unexpected,
+// and do not know of any justification for it in the standard, but
+// it might actually be correct.
+
+// Actually, re-reading the relevant sections, I see:
+//   - 14.8.3p1: function templates lead to candidates iff template
+//               argument deduction succeeds
+//   - 14.8.2p1: template argument deduction can fail when 
+//               substitution of arguments for parameters causes
+//               an invalid type to be generated, such as referencing
+//               a non-existent member
+
+template < typename, bool > 
+struct __enable_if {
+  typedef int _M_type;
+};
+
+template < typename _Tp >
+struct __is_integer {
+  static bool const _M_type = false;
+};
+
+long double sqrt (long double __x);
+
+template < typename _Tp >
+typename __enable_if < double, __is_integer < _Tp >::_M_type >::_M_type
+sqrt (_Tp __x);
+
+inline double acosh (const double &x)
+{
+  return sqrt (x);
+}
+
+int foo(int x)
+{
+  return sqrt(x);
+}
+
+int bar(int *x)
+{
+  // this one has to use the template
+  return sqrt(x);
+}
+
+double zoo(double x)
+{
+  // force use of template despite reasonably good match with
+  // the non-template
+  return sqrt<>(x);
+}

Added: vendor/elsa/current/elsa/in/t0516.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0516.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0516.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,202 @@
+// t0516.cc
+// try to exercise applyArgumentMap
+// extended version of t0515.cc
+
+template <class, class, int>
+struct A {
+  typedef int Foo;
+};
+
+template <class, class, int>
+struct A2 {
+  // no 'Foo'
+};
+
+template <class T>
+struct B {
+  static int const bar = 0;
+  typedef int Zoo;
+  class C {
+    static int const zerg = 0;
+  };
+};
+
+template <class T>
+struct B2 {
+  // no 'bar'
+};
+
+
+double sqrt(double x);
+
+template <class T>
+typename A<int, int[4], ::B<T>::bar>::Foo sqrt(T x = 0);
+
+double acosh(const double &x)
+{
+  // template's type is ok, but non-template is more specific
+  return sqrt(x);
+}
+
+
+int f(int x);
+
+template <class T>
+typename A<int, int*, B2<T>::bar>::Foo f(T x);
+
+int call_f(int x)
+{
+  // template type cannot be formed, no 'bar' in B2
+  return f(x);
+}
+
+
+int g(int x);
+
+template <class T>
+typename A2<int, int&, B<T>::bar>::Foo g(T x);
+
+int call_g(int x)
+{
+  // template type cannot be formed
+  return g(x);
+}
+
+
+
+struct E {
+  int x;
+};
+
+int h(int x);
+
+int const zero = 0;
+
+template <class T>
+typename A<int E::*, int T::*, ::zero>::Foo h(T x);
+
+int call_h(E e)
+{
+  // template type is ok
+  return h(e);
+}
+
+int call2_h(int x)
+{
+  // template type is not ok
+  return h(x);
+}
+
+
+
+struct F {
+  typedef int Func(int);
+};
+
+int j(int x);
+
+template <class T>
+typename A<typename T::Func const, int, 0>::Foo j(T x);
+
+int call_j(F f)
+{
+  // template type not ok because it attempts to cv-qualify a function
+  // specified via DQT
+  //ERROR(1): return j(f);
+}
+
+int call2_j(int x)
+{
+  // template type not ok because it wants int::Func
+  j(x);
+}
+
+
+template <class T>
+T const k();
+
+void call_k()
+{
+  // attempts to cv-qualify a function specified via TypeVariable
+  //ERROR(2): k<F::Func>();
+}
+
+
+// NOTE: "<:" is a token (alternate keyword for "["), so the
+// space after "A<" is necessary ...
+
+template <int n, class T>
+A< ::B<T>,int,n> m();
+
+void call_m()
+{
+  m<3, int>();
+}
+
+
+
+int p(int);
+
+template <class T>
+A<int,int, B<T>::Nonexist::bar> p(T);
+
+void call_p()
+{
+  // template type cannot be formed because no 'Nonexist' in B<int>
+  p(3);
+}
+
+
+int q(int);
+
+template <class T>
+A<int,int, B<T>::Zoo::gorf> q(T);
+
+void call_q()
+{
+  // template type cannot be formed because 'B<int>::Zoo' not a class
+  q(3);
+}
+
+
+int r(int);
+
+template <class T>
+A<int,int, B<T>::C::zerg> r(T,T);
+
+void call_r()
+{
+  // template type is ok
+  r(3,4);
+}
+
+
+int s(int);
+
+template <class T>
+A<int,int, B<T>::template C<int>::zerg > s(T);
+
+void call_s()
+{
+  // template type is not ok b/c C isn't a template
+  s(3);
+}
+
+
+template <class T>
+struct G;
+
+int t(int);
+
+template <class T>
+A<int,int, G<T>::zerg > t(T);
+
+void call_t()
+{
+  // template type is not ok b/c G<int> is not defined
+  t(3);
+}
+
+
+
+

Added: vendor/elsa/current/elsa/in/t0517.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0517.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0517.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,43 @@
+// t0517.cc
+// problem with explicit instantiation forgetting default args
+
+template <class T>
+class basic_string {
+public:
+  void resize ();
+  basic_string & erase (int p, int n = -1) {}
+};
+
+template <class T>
+void basic_string <T>::resize ()
+{
+  this->erase (3);
+}
+
+template class basic_string < char >;
+template class basic_string < int >;
+
+
+// ---------------- trigger an assertion failure -------------
+//ERROR(1): template <class S, class U = basic_string<S> >
+//ERROR(1): class A;
+
+
+// ------------ somewhat simplified ------------
+template <class T>
+class A {
+public:
+  void foo(int x, int y = -1)
+    {}
+};
+
+template class A<char>;
+template class A<int>;
+
+void f(A<int> &a)
+{
+  a.foo(1);
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0518.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0518.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0518.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,7 @@
+// t0518.cc
+// raise xfailure and there are no preceding errors
+
+void foo()
+{
+  __cause_xfailure();
+}

Added: vendor/elsa/current/elsa/in/t0519.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0519.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0519.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0519.cc
+// raise xfailure, but a preceding error reduces severity
+
+void foo()
+{
+  x;   // preceding error
+  __cause_xfailure();
+}

Added: vendor/elsa/current/elsa/in/t0520.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0520.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0520.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0520.cc
+// raise xfailure, and there is a preceding error, but it
+// arose on a disambiguation path
+
+template <int n>
+struct A {};
+
+int foo()
+{
+  A < __cause_xfailure(1) > (1);
+}

Added: vendor/elsa/current/elsa/in/t0521.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0521.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0521.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0521.cc
+// this test reveals a bit about the ordering of old vs. new
+// messages in disambiguation error restoration; the behavior
+// of Elsa on this input caused me to change 'takeMessages' to
+// 'prependMessages' in ~DisambiguationErrorTrapper()
+
+typedef int __cause_xfailure;
+
+int foo()
+{
+  //x;
+  __cause_xfailure(x);
+  return x;
+}

Added: vendor/elsa/current/elsa/in/t0522.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0522.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0522.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0522.cc
+// use an explicit specialization before it is declared
+
+template <class T>
+struct A;
+
+// does not require instantiation yet, so it is ok that the definition
+// of A<T> has not been provided, and it is also ok that the
+// declaration of A<int> has not been provided
+typedef A<int> A_int;
+
+template <class T>
+struct A {};
+
+// makes the program ill-formed, because A<int> has not
+// been declared
+//ERROR(1): A<int> bad;
+
+template <>
+struct A<int> {
+  int x;
+};
+
+int foo()
+{
+  A_int a;
+  return a.x;    //ERRORIFMISSING(1): error 1 is still bad even without this
+}

Added: vendor/elsa/current/elsa/in/t0523.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0523.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0523.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0523.cc
+// explicit inst request doesn't specify throw clause
+
+template <class T>
+void f(T) throw() {}
+
+// 'throw' isn't part of the type, so should not be used
+// in the signature comparison
+template void f(int);

Added: vendor/elsa/current/elsa/in/t0524.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0524.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0524.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,12 @@
+// t0524.cc
+// use of operator() must trigger instantiation
+
+template <class T>
+struct A {
+  void operator()() {}
+};
+
+void foo(A<int> &a)
+{
+  a();
+}

Added: vendor/elsa/current/elsa/in/t0525.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0525.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0525.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0525.cc
+// use of a dependent expression in a default argument
+
+template <class T>
+struct A {
+  enum { foo=3 };
+};
+
+template <class T, int n = A<T>::foo>
+struct B {
+  // no 'x' here
+};
+
+template <class T>
+struct B<T,3> {
+  B();        // silence icc warning ..
+  int x;      // specialization has it
+};
+
+int foo()
+{
+  B<int> b;
+
+  // have to have evaluated the default arg correctly, despite the
+  // fact that it was specified using a dependent expression, to get
+  // the specialization that has 'x'
+  return b.x;
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0526.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0526.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0526.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0526.cc
+// use __PRETTY_FUNCTION__ as argument to overloaded function
+
+void f(void const *p);
+void f(bool n);
+
+void foo()
+{
+  // this is the type I give __PRETTY_FUNCTION__, and I am
+  // seeing the same problem with this one
+  static char const pfunc[] = "blah";
+  f(pfunc);
+  
+  // apparently supposed to work same way as pointers
+  char const *ptr = 0;
+  f(ptr);
+
+  f(__PRETTY_FUNCTION__);
+}

Added: vendor/elsa/current/elsa/in/t0527.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0527.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0527.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// t0527.cc
+// use an enumerator to hide a type
+      
+// well-known: use a variable
+struct A {};
+int A;                       
+
+// news to me: use an enumerator
+struct B {
+  int f();
+};
+enum { B };
+
+// but then use it for scope access!
+int B::f() { return 1; }
+
+// conflict with explicit typedef isn't ok, though
+typedef int C;
+//ERROR(1): enum { C };
+
+// nor is it ok to conflict with a variable
+int d;
+//ERROR(2): enum { d };
+
+
+// this is ok too
+namespace N {
+  struct D {
+    int f();
+  };
+
+  enum { D };
+}
+
+using namespace N;
+
+int D::f() { return 1; }
+
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0528.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0528.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0528.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0528.cc
+// befriend another class's constructor
+
+// variant of in/gnu/bugs/gb0007.cc, possibly more like what
+// that had been minimized from
+
+struct A {
+  A(int);
+};
+
+struct B {
+  friend A::A(int);
+};

Added: vendor/elsa/current/elsa/in/t0529.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0529.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0529.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0529.cc
+// constness of member function affects data elements
+
+struct A {
+  void g(int);           // line 5
+  void g() const;        // line 6      right one
+  void g();              // line 7
+};
+
+
+struct B {
+  A a;
+  mutable A a2;
+
+  void f() const
+  {
+    __testOverload(a.g(), 6);
+  }
+
+  void h()
+  {
+    A const b;
+    __testOverload(b.g(), 6);
+  }
+  
+  // using the mutable member, it's not const
+  void k() const
+  {
+    a2.g(3);
+  }
+};

Added: vendor/elsa/current/elsa/in/t0530.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0530.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0530.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,31 @@
+// t0530.cc
+// confusion between operator[] and operator*
+
+struct A {
+  operator float *();
+  
+  // Elsa was getting messed up by the 'const' on 'i', which should
+  // not participate in overload resolution
+  float operator [] (const int i) const;
+};
+
+void foo()
+{
+  A a;
+  a[0];   // operator[] is the right choice
+}
+
+
+// problem with recursive tcheck
+struct B {
+  B (const float * xyz);
+
+  operator float *();
+
+  friend B operator + (const B & v1, const B & v2);
+};
+
+void foo(B &b)
+{
+  b[0];     // translated to *(a+0), but with '+' as built-in
+}

Added: vendor/elsa/current/elsa/in/t0531.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0531.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0531.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// t0531.cc
+// confusion between operator*&() and operator=()
+
+struct A {
+  A (const char *);
+  operator char *&();
+};
+
+void foo(A &s)
+{
+  s = "0";
+}
+
+
+
+struct B {
+  operator int& ();
+};
+
+void foo(B &b)
+{
+  // this would violate 13.3.1.2p4b2
+  //ERROR(1): a = 2;
+}
+

Added: vendor/elsa/current/elsa/in/t0532.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0532.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0532.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,73 @@
+// t0532.cc
+// using template arguments to obtain scopes for arg-dep lookup
+
+
+namespace N1 {
+  template <class T>
+  struct B {};
+
+  namespace M {
+    struct A {};
+
+    int f(B<A>*);       // the function to find
+  }
+
+  int f(int,int);
+
+  int foo(B<M::A> *b)
+  {
+    return f(b);
+  }
+}
+
+
+namespace N2 {
+  namespace M {
+    struct A {
+      friend int f(A*);
+    };
+  }
+
+  int foo(M::A *a)
+  {
+    return f(a);
+  }
+}
+
+
+
+namespace N3 {
+  namespace M {
+    struct A {
+      // neither GCC nor ICC find this ...
+      static int f(A*);
+    };
+  }
+
+  int foo(M::A *a)
+  {
+    //ERROR(1): return f(a);
+  }
+}
+
+
+
+namespace N4 {
+  namespace M {
+    struct A {
+    };
+    
+    // GCC rejects, ICC accepts; I guess I will reject
+    //ERROR(2): int f;
+  }       
+  
+  int f(M::A *);
+
+  int foo(M::A *a)
+  {
+    return f(a);
+  }
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0533.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0533.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0533.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0533.cc
+// double-typed expr
+
+void f(double,double);     // line 4: this is the right one
+void f(int,int);
+
+void foo()
+{
+  double d;
+  f(2*d+4, 3.0);           // calls 'f' on line 4
+  f(4+2*d, 3.0);           // calls 'f' on line 4
+
+  __elsa_checkType(2*d+4, (double)0);
+  __elsa_checkType(4+2*d, (double)0);
+  
+  char *p;
+  int i;
+  
+  __elsa_checkType(p+i, (char*)0);
+  __elsa_checkType(p-i, (char*)0);
+  __elsa_checkType(p-p, (int)0);
+}

Added: vendor/elsa/current/elsa/in/t0534.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0534.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0534.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// t0534.cc
+// template argument deduction with partially-specified arguments
+
+// This tests 14.8.1p4, which says that if a parameter is
+// fully-specified (concrete) by the explicitly-provided
+// template arguments, then you can use conversions to get
+// the argument to match the parameter.  Otherwise, the
+// match must be nearly exact.
+
+template <class T>
+void f(const T &a, const T &b);
+
+template <class T, class U>
+void g(const T &a, const T &b, U u);
+
+template <class T>
+void h(T, T);
+
+template <class T>
+void j(T, unsigned);
+
+void foo()
+{
+  unsigned u;
+  int i;
+
+  //ERROR(1): f(u, i);
+  f<unsigned>(u, i);
+
+  g<unsigned>(u, i, 3);
+
+  //ERROR(2): h(u, i);
+  h<unsigned>(u, i);
+
+  j<unsigned>(u, i);
+
+  j(u, i);
+}

Added: vendor/elsa/current/elsa/in/t0535.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0535.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0535.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,9 @@
+// t0535.cc
+// function return type need not be complete at decl of operator()
+
+struct A;
+
+struct B {
+  operator A ();
+};
+

Added: vendor/elsa/current/elsa/in/t0536.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0536.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0536.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0536.cc
+// typedef of a function pointer in a class
+
+struct A {
+  // ordinary pointer to member
+  typedef void Func();
+
+  struct B {
+    Func *f;
+  };
+};
+
+void foo(A::B *p)
+{
+  p->f();
+}

Added: vendor/elsa/current/elsa/in/t0537.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0537.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0537.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0537.cc
+// float lits have type double, moron
+
+// argument types will have to match
+template <class T>
+void a(T,T);
+
+void foo()
+{
+  double d;
+  a(d, 0.5 /*<-- my IQ*/);
+
+  float f;
+  a(f, 0.5f);
+  
+  long double ld;
+  a(ld, 0.5l);
+}

Added: vendor/elsa/current/elsa/in/t0538.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0538.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0538.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0538.cc
+// gotta push the semantic scope stack, not syntactic
+
+namespace N {
+  typedef int INT;
+  struct A {
+    void f();
+  };
+}
+
+using N::A;
+
+// the "N::" is not syntactally present, but must be searched anyway
+void A::f()
+{
+  INT i;
+}

Added: vendor/elsa/current/elsa/in/t0539.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0539.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0539.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,412 @@
+// t0539.cc
+// scope search order test
+
+
+class Visible {};
+class Hidden {};
+
+
+// Naming scheme:
+//
+// Names are of the form
+//
+//   <visible scope>_<hidden scopes>
+//
+// The name is bound to Visible in the visible scope, and bound to
+// Hidden in each of the set of hidden scopes.  Consequently, a lookup
+// that looks in the first scope before any of the other ones will
+// find Visible, while a lookup that looks in any of the subsequent
+// scopes before the first scope will find Hidden (and this will lead
+// to a type clash).
+//
+// "G" stands for the global scope.
+//
+// These names are used to test the scope searching order by using
+// several of these names in a given lookup context, as each
+// successful or failing lookup adds a constraint on what the possible
+// order is at that point, such that with a relatively small number of
+// tests we can firmly establish the exact scope search order.
+
+
+typedef Visible G_;
+typedef Visible G_A;
+typedef Visible G_ACD;
+typedef Visible G_ABCD;
+typedef Visible G_BCD;
+typedef Visible G_Q;
+
+typedef Hidden A_G;
+typedef Hidden A_QG;
+typedef Hidden B_AG;
+typedef Hidden B_QAG;
+typedef Hidden C_BAG;
+typedef Hidden C_QBAG;
+typedef Hidden D_CBAG;
+typedef Hidden D_QCBAG;
+typedef Hidden Q_G;
+typedef Hidden E_CBAG;
+
+
+namespace A {
+  typedef Visible A_;
+  typedef Visible A_G;
+  typedef Visible A_BCD;
+  typedef Visible A_QG;
+
+  typedef Hidden B_ACD;
+  typedef Hidden B_AG;
+  typedef Hidden B_QAG;
+  typedef Hidden C_BAG;
+  typedef Hidden C_QBAG;
+  typedef Hidden D_CBAG;
+  typedef Hidden D_QCBAG;
+  typedef Hidden E_CBAG;
+  typedef Hidden G_A;
+  typedef Hidden G_ACD;
+  typedef Hidden G_ABCD;
+
+  namespace B {
+    typedef Visible B_;
+    typedef Visible B_AG;
+    typedef Visible B_ACD;
+    typedef Visible B_QAG;
+
+    typedef Hidden A_BCD;
+    typedef Hidden C_BAG;
+    typedef Hidden C_QBAG;
+    typedef Hidden D_CBAG;
+    typedef Hidden D_QCBAG;
+    typedef Hidden E_CBAG;
+    typedef Hidden G_ABCD;
+    typedef Hidden G_BCD;
+
+    struct C {
+      typedef Visible C_;
+      typedef Visible C_BAG;
+      typedef Visible C_QBAG;
+
+      typedef Hidden A_BCD;
+      typedef Hidden B_ACD;
+      typedef Hidden D_CBAG;
+      typedef Hidden D_QCBAG;
+      typedef Hidden E_CBAG;
+      typedef Hidden G_ABCD;
+      typedef Hidden G_ACD;
+      typedef Hidden G_BCD;
+
+      struct D {
+        typedef Visible D_;
+        typedef Visible D_CBAG;
+        typedef Visible D_QCBAG;
+
+        typedef Hidden A_BCD;
+        typedef Hidden B_ACD;
+        typedef Hidden G_ABCD;
+        typedef Hidden G_ACD;
+        typedef Hidden G_BCD;
+
+        Visible f1(Visible);
+        Visible f2(Visible);
+        Visible f3(Visible);
+        Visible f4(Visible);
+        Visible f5(Visible);
+        Visible f6(Visible);
+        Visible f7(Visible);
+        Visible f8(Visible);
+        Visible f9(Visible);
+
+        // lookup order of ret and param: D, C, B, A, global
+        D_CBAG g1(D_CBAG);
+         C_BAG g2( C_BAG);
+          B_AG g3(  B_AG);
+           A_G g4(   A_G);
+            G_ g5(    G_);
+      };
+
+      struct E;
+    };
+
+    struct C::E {
+      typedef Visible E_;
+      typedef Visible E_CBAG;
+
+      Visible f1(Visible);
+      Visible f2(Visible);
+      Visible f3(Visible);
+      Visible f4(Visible);
+      Visible f5(Visible);
+      Visible f6(Visible);
+      Visible f7(Visible);
+      Visible f8(Visible);
+      Visible f9(Visible);
+
+      // lookup order of ret and param: E, C, B, A, G
+      E_CBAG g1(E_CBAG);
+       C_BAG g2( C_BAG);
+        B_AG g3(  B_AG);
+         A_G g4(   A_G);
+          G_ g5(    G_);
+
+      //ERROR(9):    G_ g6(    D_);
+    };
+  }
+}
+
+
+Visible A::B::C::D::g1(Visible) {}
+Visible A::B::C::D::g2(Visible) {}
+Visible A::B::C::D::g3(Visible) {}
+Visible A::B::C::D::g4(Visible) {}
+Visible A::B::C::D::g5(Visible) {}
+
+Visible A::B::C::E::g1(Visible) {}
+Visible A::B::C::E::g2(Visible) {}
+Visible A::B::C::E::g3(Visible) {}
+Visible A::B::C::E::g4(Visible) {}
+Visible A::B::C::E::g5(Visible) {}
+
+
+#if SEL == 1
+  // lookup order of ret: global
+  // lookup order of param: D, C, B, A, global
+  G_     A::B::C::D::f1(D_CBAG) {}
+  G_     A::B::C::D::f2( C_BAG) {}
+  G_     A::B::C::D::f3(  B_AG) {}
+  G_     A::B::C::D::f4(   A_G) {}
+  G_     A::B::C::D::f5(    G_) {}
+
+              G_     A::B::C::D::f8(    G_) {}
+  //ERROR(1): A_     A::B::C::D::f9(    G_) {}
+  //ERROR(2): B_     A::B::C::D::f9(    G_) {}
+  //ERROR(3): C_     A::B::C::D::f9(    G_) {}
+  //ERROR(4): D_     A::B::C::D::f9(    G_) {}
+#endif // 1
+
+
+#if SEL == 2
+  using namespace A;
+
+  // lookup order of ret: global+A
+  // lookup order of param: D, C, B, A, global(+A)
+  G_    B::C::D::f1(D_CBAG) {}
+  A_    B::C::D::f2( C_BAG) {}
+  G_    B::C::D::f3(  B_AG) {}
+  G_    B::C::D::f4(   A_G) {}
+
+              G_     B::C::D::f8(    G_) {}
+  //ERROR(1): A_G    B::C::D::f9(    G_) {}
+  //ERROR(2): G_A    B::C::D::f9(    G_) {}
+  //ERROR(3): B_     B::C::D::f9(    G_) {}
+  //ERROR(4): C_     B::C::D::f9(    G_) {}
+  //ERROR(5): D_     B::C::D::f9(    G_) {}
+#endif // 2
+
+
+
+#if SEL == 3
+  using namespace A::B;
+
+  // lookup order of ret: global+B
+  // lookup order of param: D, C, B, A, global(+B)
+  G_    C::D::f1(D_CBAG) {}
+  B_    C::D::f2( C_BAG) {}
+  G_    C::D::f3(  B_AG) {}
+  G_    C::D::f4(   A_G) {}
+  G_    C::D::f5(    G_) {}
+
+              G_    C::D::f8(    G_) {}
+  //ERROR(1): A_    C::D::f9(    G_) {}
+  //ERROR(2): C_    C::D::f9(    G_) {}
+  //ERROR(3): D_    C::D::f9(    G_) {}
+  //ERROR(4): G_B   C::D::f9(    G_) {}
+  //ERROR(5): B_G   C::D::f9(    G_) {}
+#endif // 3
+
+
+#if SEL == 4
+  typedef A::B::C CC;
+
+  // lookup order of ret: global
+  // lookup order of param: D, C, B, A, global
+  G_     CC::D::f1(D_CBAG) {}
+  G_     CC::D::f2( C_BAG) {}
+  G_     CC::D::f3(  B_AG) {}
+  G_     CC::D::f4(   A_G) {}
+  G_     CC::D::f5(    G_) {}
+
+              G_     CC::D::f8(    G_) {}
+  //ERROR(1): A_     CC::D::f9(    G_) {}
+  //ERROR(2): B_     CC::D::f9(    G_) {}
+  //ERROR(3): C_     CC::D::f9(    G_) {}
+  //ERROR(4): D_     CC::D::f9(    G_) {}
+#endif // 4
+
+
+#if SEL == 5
+  typedef A::B::C::D DD;
+
+  // lookup order of ret: global
+  // lookup order of param: D, C, B, A, global
+  G_     DD::f1(D_CBAG) {}
+  G_     DD::f2( C_BAG) {}
+  G_     DD::f3(  B_AG) {}
+  G_     DD::f4(   A_G) {}
+  G_     DD::f5(    G_) {}
+
+              G_     DD::f8(    G_) {}
+  //ERROR(1): A_     DD::f9(    G_) {}
+  //ERROR(2): B_     DD::f9(    G_) {}
+  //ERROR(3): C_     DD::f9(    G_) {}
+  //ERROR(4): D_     DD::f9(    G_) {}
+#endif // 5
+
+
+#if SEL == 6
+  namespace A {
+    // lookup order of ret: A, global
+    // lookup order of param: D, C, B, A, global
+    A_G   A::B::C::D::f1(D_CBAG) {}
+    G_    A::B::C::D::f2( C_BAG) {}
+    G_    A::B::C::D::f3(  B_AG) {}
+    G_    A::B::C::D::f4(   A_G) {}
+    G_    A::B::C::D::f5(    G_) {}
+
+                G_    A::B::C::D::f8(    G_) {}
+    //ERROR(1): B_    A::B::C::D::f9(    G_) {}
+    //ERROR(2): C_    A::B::C::D::f9(    G_) {}
+    //ERROR(3): D_    A::B::C::D::f9(    G_) {}
+  }
+#endif // 6
+
+
+#if SEL == 7
+  namespace A {
+    // lookup order of ret: A, global
+    // lookup order of param: D, C, B, A, global
+    A_G   B::C::D::f1(D_CBAG) {}
+    G_    B::C::D::f2( C_BAG) {}
+    G_    B::C::D::f3(  B_AG) {}
+    G_    B::C::D::f4(   A_G) {}
+    G_    B::C::D::f5(    G_) {}
+
+                G_    B::C::D::f8(    G_) {}
+    //ERROR(1): B_    B::C::D::f9(    G_) {}
+    //ERROR(2): C_    B::C::D::f9(    G_) {}
+    //ERROR(3): D_    B::C::D::f9(    G_) {}
+  }
+#endif // 7
+
+
+#if SEL == 8
+  namespace A {
+    namespace B {
+      // lookup order of ret: B, A, global
+      // lookup order of param: D, C, B, A, global
+      B_AG   C::D::f1(D_CBAG) {}
+      A_G    C::D::f2( C_BAG) {}
+      G_     C::D::f3(  B_AG) {}
+      G_     C::D::f4(   A_G) {}
+      G_     C::D::f5(    G_) {}
+
+                  G_     C::D::f8(    G_) {}
+      //ERROR(1): C_     C::D::f9(    G_) {}
+      //ERROR(2): D_     C::D::f9(    G_) {}
+    }
+  }
+#endif // 8
+
+
+#if SEL == 9
+  namespace Q {
+    typedef Visible Q_;
+    typedef Visible Q_G;
+
+    typedef Hidden A_QG;
+    typedef Hidden B_QAG;
+    typedef Hidden C_QBAG;
+    typedef Hidden D_QCBAG;
+    typedef Hidden G_Q;
+
+    // *not* legal ANSI C++, because definition does not appear in
+    // a scope enclosing the declaration; rejected outright by ICC
+    
+    // but if we use GNU semantics:
+    //   lookup order of ret: Q, global
+    //   lookup order of param: D, C, B, A, global
+    Q_G    A::B::C::D::f1(D_QCBAG) {}
+    G_     A::B::C::D::f2( C_QBAG) {}
+    G_     A::B::C::D::f3(  B_QAG) {}
+    G_     A::B::C::D::f4(   A_QG) {}
+    
+    // GCC looks up in G, and not in Q
+    //G_     A::B::C::D::f5(    G_Q) {}
+
+    // but Elsa looks up in Q before G, and it's a lot of work
+    // to replicate the GCC bug, so I will just check that I see
+    // the proper name in G
+    G_     A::B::C::D::f5(    G_) {}
+
+    // what is visible inside the function?
+    G_     A::B::C::D::f6(    G_) 
+    {
+      G_ g;
+      //Q_ q;   // not visible to GCC
+    }
+
+                G_     A::B::C::D::f8(     G_) {}
+    //ERROR(1): A_     A::B::C::D::f9(     G_) {}
+    //ERROR(2): B_     A::B::C::D::f9(     G_) {}
+    //ERROR(3): C_     A::B::C::D::f9(     G_) {}
+    //ERROR(4): D_     A::B::C::D::f9(     G_) {}
+    
+    // Elsa will probably allow this one, even though GCC does not
+    // indeed.
+    //nerfed(5): G_     A::B::C::D::f9(     Q_) {}
+  }
+#endif // 9
+
+
+#if SEL == 10
+  // lookup order of ret: global
+  // lookup order of param: E, C, B, A, global
+  G_     A::B::C::E::f1(E_CBAG) {}
+  G_     A::B::C::E::f2(C_BAG) {}
+  G_     A::B::C::E::f3(B_AG) {}
+  G_     A::B::C::E::f4(A_G) {}
+  G_     A::B::C::E::f5(G_) {}
+
+              G_     A::B::C::E::f8(G_) {}
+  //ERROR(1): G_     A::B::C::E::f9(D_) {}
+  //ERROR(2): A_     A::B::C::E::f9(G_) {}
+  //ERROR(3): B_     A::B::C::E::f9(G_) {}
+  //ERROR(4): C_     A::B::C::E::f9(G_) {}
+  //ERROR(5): D_     A::B::C::E::f9(G_) {}
+  //ERROR(6): E_     A::B::C::E::f9(G_) {}
+#endif // 10
+
+
+#if SEL == 11
+  typedef A::B::C::E EE;
+
+  // lookup order of ret: global
+  // lookup order of param: E, C, B, A, global
+  G_     EE::f1(E_CBAG) {}
+  G_     EE::f2(C_BAG) {}
+  G_     EE::f3(B_AG) {}
+  G_     EE::f4(A_G) {}
+  G_     EE::f5(G_) {}
+
+              G_     EE::f8(G_) {}
+  //ERROR(1): G_     EE::f9(D_) {}
+  //ERROR(2): A_     EE::f9(G_) {}
+  //ERROR(3): B_     EE::f9(G_) {}
+  //ERROR(4): C_     EE::f9(G_) {}
+  //ERROR(5): D_     EE::f9(G_) {}
+  //ERROR(6): E_     EE::f9(G_) {}
+#endif // 11
+
+
+
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0540.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0540.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0540.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0540.cc
+// overload resolution of pointer-to-member
+
+struct A {
+  int f();
+  int f(int);
+};
+
+void g(int (A::*)(int));
+
+void foo()
+{
+  g(&A::f);
+}

Added: vendor/elsa/current/elsa/in/t0541.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0541.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0541.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0541.cc
+// virtualness computation gets confused
+
+struct A {
+  int f();
+};
+
+struct B {
+  int f();
+};
+
+struct C : A, B {};
+
+struct D : C {
+  int f();
+};

Added: vendor/elsa/current/elsa/in/t0542.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0542.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0542.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0542.cc
+// default arg must be taken into account by matching
+
+template <class T>
+class A {};
+
+template <class T, class U = A<T> >
+class B {};
+
+template <class T>
+void f(B<T> &dst, const B<T> &src, int count);
+
+void foo()
+{
+  B<int> elems;
+  
+  // this causes us to try to match concrete type
+  //   B<int, A<int>>
+  // with pattern type
+  //   B<T>
+  f(elems, elems, 3);
+}
+

Added: vendor/elsa/current/elsa/in/t0543.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0543.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0543.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// t0543.cc
+// dependent qualified variable name in default argument
+
+template < typename _Tp >
+class allocator;
+
+template < typename _Tp > 
+struct __is_pod {};
+
+template < typename _Val, 
+           typename _Compare, 
+           typename _Alloc = allocator < _Val > >
+class _Rb_tree {
+  template < typename _Key_compare,
+             bool _Is_pod_comparator = __is_pod < _Key_compare >::_M_type >
+  struct _Rb_tree_impl {};
+
+  _Rb_tree_impl < _Compare > _M_impl;
+};
+
+
+
+// variant inside a namespace
+namespace std {
+  template < typename _Tp >
+  class allocator;
+
+  template < typename _Tp >
+  struct __is_pod {};
+
+  template < typename _Val,
+             typename _Compare,
+             typename _Alloc = allocator < _Val > >
+  class _Rb_tree {
+    template < typename _Key_compare,
+               bool _Is_pod_comparator = std::__is_pod < _Key_compare >::_M_type >
+    struct _Rb_tree_impl {};
+
+    _Rb_tree_impl < _Compare > _M_impl;
+  };
+}

Added: vendor/elsa/current/elsa/in/t0544.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0544.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0544.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,47 @@
+// t0544.cc
+// initialize an array of elements using a ctor
+
+class A {
+public:
+  A(int);
+};
+
+A a[] = {
+  1, 2
+};
+
+
+struct C {};
+
+
+// initialize an "aggregate"
+struct B 
+//ERROR(2): :C                  // base class
+{
+//ERROR(1): private:            // private data
+  int x, y;
+
+//ERROR(3): virtual int f();    // virtual method
+
+//ERROR(4): B(C*);              // incompatible user-def'd constructor
+};
+
+B b[] = {
+  1,2,3,4,5,6
+};
+
+
+
+// ------- fragment from cc_type.cc -------
+enum SimpleTypeId {
+  ST_CHAR, ST_UNSIGNED_CHAR,
+};
+
+class SimpleType {
+public:  
+  SimpleType (SimpleTypeId t);
+};
+
+SimpleType fixed[] = {
+  SimpleType (ST_CHAR),
+};

Added: vendor/elsa/current/elsa/in/t0545.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0545.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0545.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// t0545.cc
+// overload resolution of address-of-template-func in E_new ctor args
+
+template <class T>
+void f(T);
+
+void g(int);
+void g(int,int);
+
+struct A {
+  A(void (*)(int));
+};
+
+void foo()
+{
+  new A(&g);
+  new A(&f<int>);
+}
+
+
+
+// --------- more complete example --------
+class OpaqueValueData {};
+
+class OpaqueValue {
+public:
+  OpaqueValue (OpaqueValueData * value);
+};
+
+template < typename Type >
+class OVDPtrImpl : public OpaqueValueData {
+public:
+  OVDPtrImpl(Type *src, void (*destructor) (Type *));
+};
+
+template < typename Type >
+void defaultDestructorFunc (Type * data);
+
+template < typename Type >
+class Ptr : public OpaqueValue {
+public:
+  Ptr (Type * value)
+    : OpaqueValue(new OVDPtrImpl<Type>(value, &defaultDestructorFunc<Type>))
+  {}
+};
+
+void bar()
+{
+  Ptr<int> q((int*)0);
+}

Added: vendor/elsa/current/elsa/in/t0546.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0546.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0546.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// t0546.cc
+// error during disambiguation triggers assertion failure
+
+namespace std
+{
+  template < class _CharT > struct char_traits;
+}
+typedef int ptrdiff_t;
+namespace std
+{
+  typedef ptrdiff_t streamsize;
+  class locale
+  {
+    class facet;
+  };
+  class locale::facet
+  {
+  };
+  class ios_base
+  {
+  };
+}
+namespace std
+{
+  template < typename _CharT, typename _Traits > struct __pad
+  {
+  };
+    template < typename _CharT,
+    typename _OutIter > class num_put:public locale::facet
+  {
+  public:typedef _CharT char_type;
+    void _M_pad (char_type __fill, streamsize __w, ios_base & __io,
+		 char_type * __new, const char_type * __cs, int &__len) const;
+  };
+  template < typename _CharT, typename _OutIter > void num_put < _CharT,
+    _OutIter >::_M_pad (_CharT __fill, streamsize __w, ios_base & __io,
+			_CharT * __new, const _CharT * __cs, int &__len) const
+  {
+    __pad < _CharT, char_traits < _CharT > >::_S_pad (__io, __fill, __new,
+						      __cs, __w, __len, true);
+  }
+}

Added: vendor/elsa/current/elsa/in/t0547.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0547.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0547.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0547.cc
+// multiple using-directives naively conflict
+
+typedef int ptrdiff_t;
+namespace std {
+  using ::ptrdiff_t;
+  using std::ptrdiff_t;
+}

Added: vendor/elsa/current/elsa/in/t0548.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0548.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0548.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,141 @@
+// t0548.cc
+// member template class with out-of-line defn
+
+
+namespace Case1 {
+  template <class T>
+  class A {
+  public:
+    template <class S>
+    class B;
+  };
+
+  template <class T>
+  template <class S>
+  class A<T>::B {
+  public:
+    int x;
+  };
+
+  void foo()
+  {
+    A<int>::B<float> b;
+    b.x;
+  }
+}
+
+namespace Case2 {
+  template <class T>
+  class A {
+  public:
+    template <class S>
+    class B;
+  };
+
+  // this intervening instantiation makes us create the declaration
+  // of A<int>::B<S> before the definition of A<T>::B<S> is seen
+  A<int> a;
+
+  template <class T>
+  template <class S>
+  class A<T>::B {
+  public:
+    int x;
+  };
+
+  void foo()
+  {
+    A<int>::B<float> b;
+    b.x;
+  }
+}
+
+
+namespace Case3 {
+  template <class T>
+  class A {
+  public:
+    template <class S>
+    class B;
+            
+    // mention B<T> before we'd get a chance to
+    // transfer template member info
+    B<T> *p;
+  };
+
+  template <class T>
+  template <class S>
+  class A<T>::B {
+  public:
+    int x;
+  };
+
+  void foo()
+  {
+    A<int>::B<int> b;
+    b.x;
+  }
+}
+
+
+// finally, the real case in the code I found
+
+template <class T>
+class A {
+public:
+  int front ();
+
+  template <class S>
+  class B;
+
+  B<T> *d;
+};
+
+template <class T>
+template <class S>
+class A<T>::B {
+public:
+  int x;
+  
+  A<T> *p;
+  B<S> *q;
+
+  int f() { return 1; }
+  int g();
+  int h();
+};
+
+template <class T>
+template <class S>
+int A<T>::B<S>::g()
+{
+  return 2;
+}
+
+template <class T>
+int A<T>::front()
+{
+  return d->x;
+}
+
+void foo()
+{
+  A<int> a;
+  a.front();
+
+  A<int>::B<float> b;
+  b.x;
+  b.f();
+  b.g();
+  b.h();
+}
+
+template <class T>
+template <class S>
+int A<T>::B<S>::h()
+{
+  return 3;
+}
+
+// force it to find the definition
+template int A<int>::B<float>::h();

Added: vendor/elsa/current/elsa/in/t0549.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0549.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0549.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// t0549.cc
+// apply const to reference during template arg deduction
+
+
+// actually this is perfectly legal (8.3.2p1)
+typedef float &FLOATREF;
+float q;
+FLOATREF const fr = q;
+
+// this is simply *syntactically* illegal, though in
+// fact ICC accepts it
+
+// dsw: turned this off as I now accept it since 'restrict' is ok
+// here.
+// ERR-off-OR(1): float & const fr2 = q;
+
+
+template <class T>
+void f(T const x);
+
+void foo()
+{
+  int x = 0;
+  f<int&>(x);
+}
+
+
+struct A {
+  typedef int &INTREF;
+};
+
+
+template <class T>
+void g(T *t, typename T::INTREF const r);
+
+void bar()
+{
+  A *a = 0;
+  int x = 0;
+  g(a, x);
+}
+
+
+
+template <class T>
+struct B {
+  void h(typename T::INTREF const r);
+};
+
+B<A> b;

Added: vendor/elsa/current/elsa/in/t0550.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0550.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0550.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+// t0550.cc
+// template arg deduction misses a 'const'
+
+template <class T>
+struct A {};
+
+template <class T>
+void f(A<T> &x);
+
+void foo(A<int const> &a)
+{
+  f(a);
+}

Added: vendor/elsa/current/elsa/in/t0551.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0551.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0551.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,54 @@
+// t0551.cc
+// problem where we remember as non-dependent a particular
+// template specialization, but we should have remembered
+// the template itself
+
+template <class T> 
+void f(T *p);
+
+struct C {
+  template <class S>
+  void m(S *);
+};
+
+template <class T>
+struct A {
+  struct B {};
+
+  void foo()
+  {
+    B *b = 0;
+    f(b);
+    
+    C c;
+    c.m(b);
+  }
+
+  void bar();
+};
+
+void callfoo()
+{
+  A<char> a;
+  a.foo();
+}
+
+
+void g(A<int>::B *b);
+void g(A<char>::B *b);    //ERRORIFMISSING(1): this is the right one
+void g(A<float>::B *b);
+
+template <class T>
+void A<T>::bar()
+{
+  // try this..
+  B *b = 0;
+  g(b);
+}
+
+void callbar()
+{
+  A<char> a;
+  a.bar();
+}
+

Added: vendor/elsa/current/elsa/in/t0552.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0552.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0552.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0552.cc
+// enum-valued template parameter
+
+enum E { ZERO, ONE, TWO, THREE };
+
+template <E e>
+struct A {};
+
+A<ONE> a1;
+
+//ERROR(1): A<2> a2;

Added: vendor/elsa/current/elsa/in/t0553.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0553.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0553.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+// t0553.cc
+// similar to t0551.cc but involving an intermediate template class
+
+template <class T>
+class C {
+public:
+  void f(T &);
+};
+
+template <class T>
+class A {
+public:
+  struct B {
+    T x;
+  };
+
+  void g(C<B> &c)
+  {
+    B b;
+    c.f(b);
+  }
+
+  void h(int)
+  {
+    C<B> c;
+    g(c);
+  }
+};
+
+
+
+
+template void A<int>::h(int);

Added: vendor/elsa/current/elsa/in/t0554.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0554.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0554.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,98 @@
+// t0554.cc
+// explicit specialization of static data member
+
+// see 14.5.1.3 (ordinary defns) and 14.7.3 (explicit specs)
+
+
+template <class T>
+struct A {
+  static int a;
+  static int b;
+  static int c;
+
+  static T t;
+  static T u;
+  static T v;
+};
+
+
+// ordinary definition w/o initializer
+template <class T>
+int A<T>::a;
+
+// repeated definition
+//ERROR(1): template <class T>
+//ERROR(1): int A<T>::a;
+
+
+// ordinary definition with initializer
+template <class T>
+int A<T>::b = 3;
+
+// repeated
+//ERROR(2): template <class T>
+//ERROR(2): int A<T>::b = 3;
+
+
+// ordinary definition of member with dependent return type
+template <class T>
+T A<T>::t;
+
+
+// ordinary definition, initialized by ctor call
+template <class T>
+T A<T>::u(1,2,3);
+
+
+// another ordinary definition; this will not be explicitly
+// specialized, but will also not prevent A<int> from being
+// instantiated because 'v' will not be used anywhere
+template <class T>
+T A<T>::v(1,2,3,4,5);
+
+
+// explicit specialization *declaration*
+template <>
+int A<int>::a;
+
+// not an error!  just another declaration
+template <>
+int A<int>::a;
+
+// explicit specialization *definition*
+template <>
+int A<int>::a = 1;
+
+// duplicate definition
+//ERROR(3): template <>
+//ERROR(3): int A<int>::a = 1;
+                        
+
+// another explicit spec
+template <>
+int A<int>::b = 2;
+
+
+// another, using a typedef (see also in/t0555.cc)
+typedef A<int> A_int;
+template <>
+int A_int::c = 3;
+
+
+// explicit specialization with dependent type and ctor init
+template <>           //ERRORIFMISSING(4): required
+int A<int>::u(1);     //ERRORIFMISSING(4): required
+
+
+void foo()
+{
+  // this must find the explicit spec of 'u' because otherwise
+  // the normal definition will try to call int(int,int,int)
+  A<int> a;
+  
+  // 14.7.1p1: 'u' must be used in some way to trigger the
+  // instantiation of its definition, needed for error 4
+  a.u;
+}
+
+

Added: vendor/elsa/current/elsa/in/t0555.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0555.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0555.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,115 @@
+// t0555.cc
+// explicit specialization of data members using typedefs
+
+namespace N {
+  template <class T>
+  struct A {
+    static int a1;
+    static int a2;
+    static int a3;
+    static int a4;
+    static int a5;
+    static int a6;
+
+    template <class S>
+    struct B {
+      static int b1;
+      static int b2;
+      static int b3;
+      static int b4;
+      static int b5;
+      static int b6;
+      static int b7;
+      static int b8;
+      static int b9;
+      static int b10;
+    };
+
+    typedef B<float> B_float;
+  };
+
+  typedef A<int> A_int;
+  typedef A<int>::B<float> A_int_B_float;
+}
+
+typedef N::A<int> N_A_int;
+typedef N::A<int>::B<float> N_A_int_B_float;
+
+
+// normal, no typedef
+template <>
+int N::A<int>::a1 = 1;
+
+// use typedef for A
+template <>
+int N::A_int::a2 = 2;
+
+// typedef for N and A
+template <>
+int N_A_int::a3 = 3;
+
+
+// no typedef
+template <>
+template <>
+int N::A<int>::B<float>::b1 = 1;
+
+// typedef for A
+//ERROR(1): template <>     // would be superfluous
+template <>
+template <>
+int N::A_int::B<float>::b2 = 2;
+
+// typedef for B
+template <>
+template <>
+int N::A<int>::B_float::b3 = 3;
+
+// typedef for N and A
+template <>                 //ERRORIFMISSING(2): required
+template <>
+int N_A_int::B<float>::b4 = 4;
+
+// typedef for A and B
+template <>
+template <>
+int N::A_int_B_float::b5 = 5;
+
+// typedef for N and A and B
+template <>
+template <>
+int N_A_int_B_float::b6 = 6;
+
+
+
+// similar to above, but with N implicit
+using namespace N;
+
+// no typedef
+template <>
+int A<int>::a4 = 4;
+
+// typedef for A
+template <>
+int A_int::a5 = 5;
+
+// no typedef
+template <>
+template <>
+int A<int>::B<float>::b7 = 7;
+
+// typedef for A
+template <>
+template <>
+int A_int::B<float>::b8 = 8;
+
+// typedef for B
+template <>
+template <>
+int A<int>::B_float::b9 = 9;
+
+// typedef for A and B
+template <>
+template <>
+int A_int_B_float::b10 = 10;
+

Added: vendor/elsa/current/elsa/in/t0556.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0556.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0556.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0556.cc
+// problem with static data member template with elaborated class type
+
+struct B {};
+
+template <class T>
+struct A {
+  static int a;
+  
+  static B b1;
+  static struct B b2;
+  static B b3;
+};
+
+// leading 'struct' causes problems for Elsa
+
+template <class T>
+struct B A<T>::b1;
+
+template <class T>
+struct B A<T>::b2;
+
+template <class T>
+B A<T>::b3;

Added: vendor/elsa/current/elsa/in/t0557.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0557.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0557.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// t0557.cc
+// default argument refers to namespace member
+
+// actually, the default arg had nothing to do with it;
+// it was an explicit inst request naming something in
+// a namespace that caused the problem
+
+namespace N {
+  template <class T>
+  struct A {};
+
+  template <class U, class V = A<U> >
+  struct B {};
+}
+using namespace N;
+
+template struct B<int>;

Added: vendor/elsa/current/elsa/in/t0558.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0558.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0558.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0558.cc
+// inline defn of friend in template class
+
+template <class T>
+struct A {
+  friend int f(T t)
+  {
+    return sizeof(t);
+  }
+
+  T t;
+  int g()
+  {
+    return f(t);
+  }
+};
+
+void foo()
+{
+  A<int> a;
+  a.g();
+}

Added: vendor/elsa/current/elsa/in/t0559.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0559.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0559.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,16 @@
+// t0559.cc
+// template class with a method that accepts varargs
+
+template <class T>
+struct A {
+  void f(int i, ...) { }
+};
+
+void foo()
+{
+  A<int> a;
+  a.f(0);
+  a.f(0, 3);
+  a.f(0, 1, 3);
+  a.f(0, 1, 2, 3);
+}

Added: vendor/elsa/current/elsa/in/t0560.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0560.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0560.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+// t0560.cc
+// operator= that does not take a reference
+
+struct A {
+  void operator=(A) {}
+};
+
+struct B : A {};

Added: vendor/elsa/current/elsa/in/t0561.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0561.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0561.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// t0561.cc
+// template parameter of ptr-to-func type
+
+// see also oink/Test/templatized_on_func1.cc (750e1581-41c2-4079-b8e1-482a5c78404e)
+
+template <int (*f)(int)>
+struct A {
+  A<f>();
+
+  A<f>(int x)
+  {
+    f(x);
+  }
+
+  int foo(int x)
+  {
+    return f(x);
+  }
+};
+
+int f1(int);
+
+A<f1> af1;
+
+int f2(int) { return 1; }
+
+A<f2> af2;
+A<(f2)> af2b;
+A<((f2))> af3;
+
+A<&f2> af4;
+A<(&f2)> af5;
+A<((&f2))> af6;
+A<((&(f2)))> af7;
+
+// Note that GCC complains about many of the parenthesized versions;
+// ICC accepts them, and I see no justification in the standard for
+// rejecting.
+

Added: vendor/elsa/current/elsa/in/t0562.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0562.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0562.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0562.cc
+// DQT in operator==
+
+template <class T>
+struct A {
+  A(char const *);
+  
+  typedef char const *PTR;
+};
+
+template <class T>
+bool operator==(A<T> const &a, typename A<T>::PTR b);
+
+void foo()
+{
+  A<int> a("bar");
+  
+  char const *ptr;
+  a == ptr;
+  
+  a == "foo";
+}

Added: vendor/elsa/current/elsa/in/t0563.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0563.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0563.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,43 @@
+// t0563.cc
+// tricky template specificity test involving DQTs
+
+struct A {
+  typedef int INT;
+};
+
+template <class T>
+void f(A *a, T i)
+{
+  // I know ICC and GCC choose this one because they report this line
+  // as an error when uncommented.
+  //typename T::NONEXIST blah;
+}
+
+template <class S>
+void f(S *a, typename S::INT i)
+{
+  //typename S::NONEXIST2 blah2;
+}
+
+void foo(A *a, int i)
+{             
+  // I believe this call is ambiguous because both templates
+  // match, yet neither can match with the other.  However, both
+  // ICC and GCC choose the first 'f'.
+  //ERROR(1): f(a,i);
+}
+
+
+
+template <class T>
+void g(A *a, int i, T f);
+
+template <class S>
+void g(S *a, typename S::INT i, float f);
+
+void goo(A *a, int i, float f)
+{
+  // I believe this one is ambiguous as well.  ICC and GCC agree.
+  //ERROR(2): g(a,i,f);
+}
+

Added: vendor/elsa/current/elsa/in/t0564.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0564.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0564.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,14 @@
+// t0564.cc
+// causes ElaboratedOrSpecifier multi-yield
+
+namespace N {
+  template <class S>
+  struct A {};
+}
+
+class B;
+
+void foo()
+{
+  N::A<const class B> blah;
+}

Added: vendor/elsa/current/elsa/in/t0565.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0565.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0565.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,18 @@
+// t0565.cc
+// unhandled MemberDeclaration ambiguity
+
+int f(int);
+
+typedef int INT;
+
+struct A {
+  friend int ::f(int);
+
+  // every C++ parser I've tried binds the "::" tightly, like "INT::f"
+  //friend INT ::f(int);
+
+  friend INT (::f)(int);
+
+  // this line has the MemberDeclaration problem
+  friend INT (::f(int));
+};

Added: vendor/elsa/current/elsa/in/t0566.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0566.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0566.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// t0566.cc
+// templatized conversion operator
+
+template <class T>
+struct B {};
+
+
+struct A {
+  template <class T>
+  operator B<T> ()
+  {
+    // make sure this actually gets instantiated as a consequence
+    // of being selected to do the conversion
+    //ERROR(1): typename T::INT i;
+  }
+
+  // easy if the operator is not templatized
+  //operator B<int> ();
+};
+
+
+void f(B<int> b);
+
+
+void foo(A &a)
+{
+  f(a);
+}

Added: vendor/elsa/current/elsa/in/t0567.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0567.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0567.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// t0567.cc
+// throw-spec irrelevant in type comparison for ?:
+
+void foo(int c)
+{
+  int (*f1)(char const *, char const *);
+  int (*f2)(char const *, char const *) throw();
+
+  c? f1 : f2;
+}

Added: vendor/elsa/current/elsa/in/t0568.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0568.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0568.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,47 @@
+// t0568.cc
+// declaration after use...
+
+// GCC and ICC both accept this.
+
+// I think it is invalid because the point of instantiation
+// of the template functions is too soon to see Min
+// [14.6.1.1p1, 14.7.1p2].  But, Elsa will support it anyway.
+
+template <class T>
+struct A {
+  int capacity;
+  void f (int nsz);
+  inline void g (int nsz);
+  inline void h (int nsz)
+  {
+    Min(this->capacity, nsz);
+  }
+};
+
+template <class T>
+void A<T>::f(int nsz)
+{
+  Min(this->capacity, nsz);
+}
+
+template <class T>
+void A<T>::g(int nsz)
+{
+  Min(this->capacity, nsz);
+}
+
+template void A<int>::f(int nsz);
+
+void foo()
+{
+  A<int> a;
+  a.f(3);
+  a.g(3);
+  a.h(3);
+}
+
+template <class T>
+T Min (const T & x, const T & y, int z = 15)
+{
+  return x + z;
+}

Added: vendor/elsa/current/elsa/in/t0569.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0569.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0569.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// t0569.cc
+// arg-dep lookup finds a friend
+
+template <class T>
+void f(T &t)
+{
+  g(t,t);
+}
+
+namespace N
+{
+  struct A {
+    struct B {
+    };
+
+    friend void g(B &a, B &b);
+  };
+
+  // to find this, must look at the definition namespace (N) of the
+  // class (A) of which B is a member
+  void h(A::B&);
+}
+
+void foo()
+{
+  N::A::B e;
+  f(e);
+  h(e);
+}

Added: vendor/elsa/current/elsa/in/t0570.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0570.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0570.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// t0570.cc
+// matching with a DQT    
+
+// see also t0488.cc
+
+template <class T>
+struct A {
+  typedef int INT;
+};
+
+template <class T>
+void f(typename A<T>::INT i, A<T> *a);
+
+void foo()
+{
+  A<int> *a;
+  int i;
+  f(i, a);
+}
+
+
+      
+// this ought to fail template argument deduction, but
+// *not* by going into an infinite loop
+template <class T>
+void g(typename A<T>::INT i, typename A<T>::INT j);
+
+void goo()
+{
+  int i, j;
+  //ERROR(1): g(i, j);     // arg deduction should fail
+  
+  // but this is ok
+  g<int>(i,j);
+}

Added: vendor/elsa/current/elsa/in/t0571.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0571.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0571.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,19 @@
+// t0571.cc
+// destroy a union
+
+template <class T>
+void destroy(T *p)
+{
+  p->~T();
+}
+
+union U {
+  int x;
+  float y;
+};
+
+void foo()
+{
+  U *u = 0;
+  destroy(u);
+}

Added: vendor/elsa/current/elsa/in/t0572.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0572.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0572.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0572.cc
+// Elsa misdiagnosing this in strict mode
+
+template <class T>
+struct A {
+  void f(char *p)
+  {
+    g(p);
+  }
+  
+  void g(T *p);
+};
+
+void foo()
+{
+  A<char> a;
+  char *p = 0;
+  a.f(p);
+  
+  // confusion partly arises because some specializations are invalid
+  A<float> b;
+  //ERROR(1): b.f(p);
+}

Added: vendor/elsa/current/elsa/in/t0573.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0573.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0573.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// t0573.cc
+// overload resolution with templatized candidates confuses strict mode
+
+template <class T>
+struct A {};
+
+struct B {};
+
+template <class T>
+struct C {
+  void f(A<T>*);
+  void f(B*);
+
+  void foo(B *b)
+  {
+    f(b);
+  }
+
+
+  void g(typename T::CHAR);
+  void g(typename T::SHORT);
+
+  void goo(int i)
+  {
+    g(i);
+  }
+};

Added: vendor/elsa/current/elsa/in/t0574.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0574.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0574.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,45 @@
+// t0574.cc
+// trouble disambiguating a conversion
+
+struct A {
+  A(A const &);    // would be implicitly defined even if not explicitly present
+  A(int *);
+};
+
+class B {
+public:
+  operator A();
+private:
+  // GCC and ICC accept the "a2 = b" line with this entry
+  // private, so they must be selecting the other one
+  operator int*();
+};
+
+
+void foo(B &b)
+{
+  // GCC and ICC agree that this is ambiguous
+  //ERROR(1): A a1(b);
+
+  // but this is not; see 8.5p14
+  A a2 = b;
+}
+
+
+
+// this is related in that the same resolution mechanism is used,
+// though no conversion operator is used; I am using this to test
+// that the proper AST nodes are inserted as a transformation
+// (this test comes from Oink, which wants to see that 'x' can
+// flow into 'z')
+struct C {
+  C(int y) {
+    int /*$untainted*/ z = y;
+  }
+  operator bool () { return true; }
+};
+
+int main() {
+  int /*$tainted*/ x;
+  if (C a = x) {}
+}

Added: vendor/elsa/current/elsa/in/t0575.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0575.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0575.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0575.cc
+// explicit spec of member template func
+
+struct A {
+  template <class T>
+  void f(const T &);
+
+  template <class T>
+  static void g(const T &);
+
+  int d;
+};
+
+template <>
+void A::f(const int &)
+{
+  d;   // ok
+}
+
+template <>
+void A::g(const int &)
+{
+  //ERROR(1): d;    // method is static
+}

Added: vendor/elsa/current/elsa/in/t0576.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0576.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0576.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// t0576.cc
+// throw specs are not part of function pointer type
+
+
+int f1(int);
+int f2(int) throw();
+int f3(int) throw(int);
+int f4(int) throw(int,float);
+
+
+typedef int ft1(int);
+typedef int ft2(int) throw();
+
+
+void foo()
+{
+  int (*f)(int);
+  
+  f = f1;
+  f = f2;
+  f = f3;
+  f = f4;
+}

Added: vendor/elsa/current/elsa/in/t0577.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0577.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0577.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0577.cc
+// demonstrate flaw in abstract enumerator value processing
+  
+
+template <int n>
+struct A {
+  // Elsa will fail to const-eval 'n', then suppress the
+  // error, but go on thinking that n is always 0.
+  enum { x = n };
+  
+  // when x equal to 0, this will fail
+  int arr[x - 5];
+  
+  // on the other hand, it recognizes that this is not necessarily bad
+  int arr2[n - 5];
+};
+
+// valid specialization *can* be generated
+A<10> a;
+
+

Added: vendor/elsa/current/elsa/in/t0578.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0578.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0578.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,36 @@
+// t0578.cc
+// do AbstractEnumerators need to know their value expressions?
+
+// GCC and ICC both reject all six out-of-line member defns
+
+template <int n>
+struct A {
+  enum { x = n, y = n+1, z /*implicitly y+1*/ };
+
+  int f(int (*a)[n]);
+  int f(int (*a)[n+1]);
+  int f(int (*a)[n+2]);
+
+  int g(int (*a)[x]);
+  int g(int (*a)[y]);
+  int g(int (*a)[z]);
+};
+
+template <int n>
+int A<n>::f(int (*a)[x]) { return 1; }
+
+template <int n>
+int A<n>::f(int (*a)[y]) { return 2; }
+
+template <int n>
+int A<n>::f(int (*a)[z]) { return 2; }
+
+template <int n>
+int A<n>::g(int (*a)[n]) { return 1; }
+
+template <int n>
+int A<n>::g(int (*a)[n+1]) { return 2; }
+
+template <int n>
+int A<n>::g(int (*a)[n+2]) { return 2; }
+

Added: vendor/elsa/current/elsa/in/t0579.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0579.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0579.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,49 @@
+// t0579.cc
+// enumerators WTF?  7.2p4(!),5
+
+void f()
+{
+  // everybody thinks 'E' is visible, but gcc rejects
+  // b/c E is incomplete (underlying type not determined)
+  //enum E { e1 = sizeof(E) };
+}
+
+
+template <int n>
+struct A {    typedef int NONE; };
+
+template <>
+struct A<1> { typedef int ONE; };
+
+template <>
+struct A<4> { typedef int FOUR; };
+
+
+void g()
+{
+  enum E {
+    e1 = 'a',                     // type char
+    e2 = 1,                       // type int
+    e3 = (unsigned char)0xff,     // type unsigned char
+    e4,                           // type is unspecified integral type
+
+    e1s = sizeof(e1),             // 1
+    e2s = sizeof(e2),             // 4
+    e3s = sizeof(e3),             // 1
+    e4s = sizeof(e4),             // ? EDG goes to 8!
+    
+    one = 1
+  };
+
+  // confirm specializations are working right
+  A<one>::ONE a0;
+
+  A<e1s>::ONE a1;
+  A<e2s>::FOUR a2;
+  A<e3s>::ONE a3;
+  //A<e4s>::FOUR a4;
+
+}
+
+
+

Added: vendor/elsa/current/elsa/in/t0580.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0580.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0580.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// t0580.cc
+// use of an enumerator in a template-id naming a specialization
+
+enum E { one=1 };
+
+template <int n>
+struct A {};
+
+template <>
+struct A<1> {
+  typedef int INT;
+};
+
+A<one>::INT i;
+

Added: vendor/elsa/current/elsa/in/t0581.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0581.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0581.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// t0581.cc
+// a simpler (than t0435.cc) template array bounds example
+
+template <int ArraySize>
+int *end(int(&array)[ArraySize])
+{
+  int dummy[2];
+  end(dummy);
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0582.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0582.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0582.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+// t0582.cc
+// currently causes Elsa to crash outright
+// from James Dennet
+
+struct vector {
+   template < typename InputIterator > 
+   vector(InputIterator,InputIterator);
+};
+
+struct string : vector {
+   template < typename InputIterator > 
+   string(InputIterator end)
+     : vector(end, end ) 
+   { }
+};
+
+template < typename ElementType,int ArraySize > 
+ElementType *end(ElementType(&array)[ArraySize]) 
+{
+  int dummy[2];
+  string(end(dummy)); // succeeds if this is moved pass the closing brace
+}
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0583.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0583.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0583.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// t0583.cc
+// compare partial specializations using non-type arguments
+
+// based on a report by Gustav Munkby
+
+template <int i, int j>
+struct A {};
+
+template <int i>
+struct A<i, 0> {};
+
+template <>
+struct A<0, 0> {
+  int x;
+};
+
+int foo()
+{
+  A<0,0> a;
+  return a.x;
+}
+

Added: vendor/elsa/current/elsa/in/t0584.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0584.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0584.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// t0584.cc
+// problem with non-concrete types showing up in instantiations
+
+template <typename T_> struct S1 {
+ typedef T_ T;
+};
+
+template <typename T_> struct S2 : S1<T_>
+{
+ typedef typename S1<T_>::T T;
+
+ void foo (T t = T()) {}
+ void bar (T_ t = T_()) {}
+};
+
+int main()
+{
+ S2<int> x;
+ x.foo();
+ x.bar();
+}

Added: vendor/elsa/current/elsa/in/t0585.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0585.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0585.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+// t0585.cc
+// problem with explicit dtor invocation on template class
+
+// Accepted by both ICC and GCC.
+
+template <class T>
+struct A {
+    A();
+    ~A();
+};
+
+int main()
+{
+    A<int> a;
+
+    // error: in ( (a).A<int /*anon*/>::~A), A was found in the
+    // current scope as struct A, and also in the class of (a) as
+    // struct A<int /*anon*/>, but they must be the same
+    a.A<int>::~A();
+}

Added: vendor/elsa/current/elsa/in/t0586.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0586.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0586.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// t0586.cc
+// from oink/Test/outlined_template_dtor1.cc
+
+// reflected as an Elsa test with some template hackery
+
+template <class T>
+struct A {
+    A();
+    ~A();
+};
+
+template <class T>
+class B {};
+
+template <class T>
+A<T>::~A()
+{
+  // The purpose of this line is to ensure that A<T>::~A is
+  // instantiated.  If it is, then when we uncomment the following
+  // line, it will cause a compilation error.
+  //ERROR(1): 1 + B<T>::nonexist;
+}
+
+
+template <class T>
+A<T>::A()
+{
+}
+
+int main()
+{
+    A<int> a;
+    //a.~A();    // this is implicit, essentially
+}

Added: vendor/elsa/current/elsa/in/t0587.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0587.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0587.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// t0587.cc
+// Elsa version of oink/Test/template_impl_addrof_func1.cc
+
+template <typename T>
+struct S1 {
+  static void foo();
+};
+
+template <class T>
+class B {};
+
+template <typename T>
+void S1<T>::foo()
+{
+  // this function should be instantiated, meaning when the following
+  // line is uncommented, we detect the error
+  //ERROR(1): 1 + B<T>::nonexist;
+}
+
+typedef void (*func)(void);
+
+int main()
+{
+  func f = /* missing "&" */ S1<int>::foo;
+}

Added: vendor/elsa/current/elsa/in/t0588.cc
===================================================================
--- vendor/elsa/current/elsa/in/t0588.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/t0588.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// t0588.cc
+// more tests w/ default args
+
+struct S {} *s;
+struct S2 {} *s2;
+
+template <class T>
+int f1(T *t, int x = 5);
+
+template <class T>
+int f1(T *t, int x);
+
+template <class T>
+int f1(T *t, int x)
+{
+  return x + 7;
+}
+
+int foo()
+{
+  return f1(s) + f1(s2);
+}
+
+
+
+template <class T>
+int f2(T *t, int x = 6)
+{
+  return x + 8;
+}
+
+int bar()
+{
+  return f2(s) + f2(s2);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/in/t0589.cc
===================================================================

Added: vendor/elsa/current/elsa/in/t0590.cc
===================================================================

Added: vendor/elsa/current/elsa/in/t0591.cc
===================================================================

Added: vendor/elsa/current/elsa/in/u0001.cc
===================================================================
--- vendor/elsa/current/elsa/in/u0001.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/in/u0001.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// u0001.cc:8:22: error: call site name lookup failed to yield any candidates;
+// last candidate was removed because: incompatible call site args
+
+template <typename T, unsigned int N>
+char (&ArraySize(T (&array)[N]))[N];
+
+int attrs_[32];
+
+void test() {
+   int size = sizeof(ArraySize(attrs_));
+}

Added: vendor/elsa/current/elsa/include/README
===================================================================
--- vendor/elsa/current/elsa/include/README	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/include/README	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+10/29/02 18:34
+author: scott
+
+The files in this directory are the compiler-supplied header
+files for the Elkhound-based C++ parser.  For now they are
+just what is needed to get Mozilla to parse, modified to
+not use namespaces (since my parser doesn't yet handle them).
+
+I envision the parser acquiring more functionality, at which
+time more of the headers specified in the Standard will have
+to be written and placed here.
+
+The headers that are required but not supplied are, in practice,
+taken from gcc's headers since I'm using gcc's "cpp" command
+and it knows where to find its own compiler-specific headers.
+But I'm supplying a -I pointing at this directory, so anything
+here takes precedence.

Added: vendor/elsa/current/elsa/include/exception.h
===================================================================
--- vendor/elsa/current/elsa/include/exception.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/include/exception.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,49 @@
+// exception.h
+// implementation of exception.h, no namespaces
+
+#ifndef __EXCEPTION_H
+#define __EXCEPTION_H
+
+// contents taken from C++ standard, section 18.6
+
+//namespace std {
+  class exception;
+  class bad_exception;
+
+  typedef void (*unexpected_handler)();
+  unexpected_handler set_unexpected(unexpected_handler f) throw();
+  void unexpected();
+
+  typedef void (*terminate_handler)();
+  terminate_handler set_terminate(terminate_handler f) throw();
+  void terminate();
+
+  bool uncaught_exception();
+//}
+
+//namespace std {
+  class exception {
+    // sm: presumably a real implementation would have something
+    // in here, but for now my only interest is with parsing
+  public:
+    exception() throw();
+    exception(const exception&) throw();
+    exception& operator=(const exception&) throw();
+    virtual ~exception() throw();
+    virtual const char* what() const throw();
+  };
+//}
+
+//namespace std {
+  class bad_exception : public exception {
+  public:
+    bad_exception() throw();
+    bad_exception(const bad_exception&) throw();
+    bad_exception& operator=(const bad_exception&) throw();
+    virtual ~bad_exception() throw();
+    virtual const char* what() const throw();
+  };
+//}
+
+
+#endif // __EXCEPTION_H

Added: vendor/elsa/current/elsa/include/new.h
===================================================================
--- vendor/elsa/current/elsa/include/new.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/include/new.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,39 @@
+// new.h
+// implementation of new.h that doesn't use namespaces
+
+#ifndef __NEW_H
+#define __NEW_H
+
+#include <stddef.h>    // size_t
+
+// the contents of this file are taken directly from the
+// C++ standard (section 18.1 para 1), modified to not use
+// namespaces (i.e. this file is "new.h", not "new")
+
+//namespace std {
+  class bad_alloc {};
+  struct nothrow_t {};
+  extern const nothrow_t nothrow;
+  typedef void (*new_handler)();
+  new_handler set_new_handler(new_handler new_p) throw();
+//}
+
+  // sm: the ones marked with a trailing "// implicit" are supposed
+  // to be implicitly declared, so the declarations here are
+  // actually redundant [cppstd 3.7.3 para 2]
+
+  void* operator new(/*std::*/size_t size) throw(/*std::*/bad_alloc);            // implicit
+  void* operator new(/*std::*/size_t size, const /*std::*/nothrow_t&) throw();
+  void operator delete(void* ptr) throw();                                       // implicit
+  void operator delete(void* ptr, const /*std::*/nothrow_t&) throw();
+  void* operator new[](/*std::*/size_t size) throw(/*std::*/bad_alloc);          // implicit
+  void* operator new[](/*std::*/size_t size, const /*std::*/nothrow_t&) throw();
+  void operator delete[](void* ptr) throw();                                     // implicit
+  void operator delete[](void* ptr, const /*std::*/nothrow_t&) throw();
+
+  void* operator new (/*std::*/size_t size, void* ptr) throw();
+  void* operator new[](/*std::*/size_t size, void* ptr) throw();
+  void operator delete (void* ptr, void*) throw();
+  void operator delete[](void* ptr, void*) throw();
+
+#endif // __NEW_H

Added: vendor/elsa/current/elsa/include/stdarg.h
===================================================================
--- vendor/elsa/current/elsa/include/stdarg.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/include/stdarg.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+// stdarg.h
+// variable-argument function support macros
+
+#ifndef __STDARG_H
+#define __STDARG_H
+
+typedef void *va_list;
+
+// sm: this is for compatibility with glibc, which seems to assume
+// it is using gcc's names
+typedef va_list __gnuc_va_list;
+
+void __va_start(va_list, ...);
+#define va_start(__AP, __ARG) __va_start(__AP, __ARG)
+
+void *__va_arg(va_list, int);
+#define va_arg(__AP, __TYPE) *((__TYPE*)__va_arg((__AP), sizeof (__TYPE)))
+
+void va_end(va_list);
+
+#endif /* __STDARG_H */

Added: vendor/elsa/current/elsa/include/stddef.h
===================================================================
--- vendor/elsa/current/elsa/include/stddef.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/include/stddef.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,23 @@
+// stddef.h
+// cppstd section 18.1
+
+#ifndef __STDDEF_H
+#define __STDDEF_H
+
+// not "(void*)0", "__null", or any other junk.  NULL is 0, in my book.
+#undef NULL
+#define NULL 0
+
+typedef signed int ptrdiff_t;
+
+typedef unsigned int size_t;
+
+#undef offsetof
+#define offsetof(objtype, field) ((size_t)(&(((objtype*)0)->field)))
+
+// for parsing C code
+#ifndef __cplusplus
+  typedef int wchar_t;
+#endif
+
+#endif // __STDDEF_H

Added: vendor/elsa/current/elsa/index.html
===================================================================
--- vendor/elsa/current/elsa/index.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/index.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,423 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>Elsa</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+</HEAD>
+
+<body>
+
+<center><h2>
+Elsa: The Elkhound-based C/C++ Parser
+</h2></center>
+
+<p>
+Elsa is a C and C++ parser.  It is based on the <a
+href="../elkhound/index.html">Elkhound</a> parser generator.  It lexes
+and parses input C/C++ code into an abstract syntax tree.  It does
+some type checking, in the interest of elaborating the meaning of
+constructs, but it does not (yet?) reject all invalid programs.
+
+<p>
+To download Elkhound and Elsa, see the
+<a href="http://www.cs.berkeley.edu/~smcpeak/elkhound/">Elkhound distribution page</a>.
+
+<p>
+High-level documentation:
+<ul>
+<li><a href="doc/faq.html">faq.html</a>: Elsa Frequently Asked Questions
+<li><a href="doc/design.html">design.html</a>: Document explaining various
+    aspects of the internal design of Elsa.
+<li><a href="doc/tutorial.html">tutorial.html</a>: Introduction to using and
+    modifying Elsa.
+<li><a href="doc/cc.ast.html">cc.ast.html</a>: The C/C++ abstract syntax tree
+    created by the parser.
+<li><a href="doc/cc_type.html">cc_type.html</a>: The type representation
+    objects created by the type checker.
+<li><a href="doc/cpp_er.html">cpp_er.html</a>: C++ Entities and Relationships.
+    Provides an overview of C++ static semantics.
+</ul>
+
+<p>
+Low-level documentation:
+<ul>
+<li><a href="doc/serialization.txt">serialization.txt</a>: Explains the
+    XML serialization architecture, design decisions, how to use it, etc.
+<li><a href="doc/declarator.html">declarator.html</a>: Some details about how
+    declarators are parsed.
+<li><a href="doc/convertibility.txt">convertibility.txt</a>: A discussion
+    of the standard-convertibility relation, and its application to
+    operator overload resolution.
+<li><a href="doc/lookup.txt">lookup.txt</a>: Documents some of my
+    interpretations of the lookup rules specified in the C++ standard,
+    and how they are implemented in Elsa.
+<li><a href="doc/complex.txt">complex.txt</a>: Brief overview of the
+    degree to which GNU/C99 complex/imaginary types are handled in Elsa.
+<li><a href="doc/permissive.txt">permissive.txt</a>: Explanation of Elsa's
+    "permissive" mode, which is useful during automatic minimization.
+<li><a href="doc/coloncolon.txt">coloncolon.txt</a>: Documents how an
+    ambiguity relating to the "::" operator is handled in cc.gr.
+</ul>
+
+<p>
+Elsa requires the following external software:
+<ul>
+<li><a href="../elkhound/index.html">elkhound</a>, a GLR parser generator.
+<li><a href="../ast/index.html">ast</a>, a system for making abstract syntax trees.
+<li><a href="../smbase/index.html">smbase</a>, a utility library.
+<li><a href="http://www.gnu.org/software/flex/flex.html">Flex</a>,
+    a lexical analyzer generator.
+</ul>
+
+<p>
+Build instructions:
+<pre>
+  $ ./configure
+  $ make
+  $ make check
+</pre>
+<a href="configure.pl"><tt>./configure</tt></a> understands
+<a href="gendoc/configure.txt">these options</a>.  You can also
+look at the <a href="Makefile.in">Makefile</a>.
+
+<p>
+Parsing some sample (already preprocessed) input:
+<pre>
+  $ ./ccparse in/t0001.cc
+</pre>
+The above command will parse and type check the given file.  To
+make it print the annotated, post-type-check AST, say
+<pre>
+  $ ./ccparse -tr printTypedAST in/t0001.cc
+</pre>
+
+<p>
+Additional <tt>-tr</tt> flags of interest:
+<ul>
+<li><tt>printAST</tt>: Print the (possibly ambiguous) AST before type checking.
+<li><tt>printTypedAST</tt>: Print the AST after type checking.
+<li><tt>env</tt>: Print environment modifications as they happen.
+<li><tt>disamb</tt>: Print disambiguation activity.
+<li><tt>printHierarchies</tt>: Print inheritance hierarchies in
+    <a href="http://www.research.att.com/sw/tools/graphviz/">Dot</a> format.
+    Interesting in that virtual inheritance is represented properly;
+    for example <a href="in/std/3.4.5.cc">in/std/3.4.5.cc</a> yields
+    <a href="gendoc/3.4.5.png">3.4.5.png</a>.
+<li><tt>mustBeUnambiguous</tt>: After type checking, scan the AST to verify there
+    are no remaining ambiguities.  If there are, abort.
+<li><tt>prettyPrint</tt>: Print out the AST as C++.  This is still somewhat incomplete.
+</ul>
+The <tt>-tr</tt> flags can be passed separately, or strung together
+separated by commas (e.g. "<tt>-tr env,disamb,printAST</tt>").
+
+<p>
+<a name="module_list">Module List</a>:
+<ul>
+
+<li><a href="ast_build.h">ast_build.h</a>, 
+    <a href="ast_build.cc">ast_build.cc</a>:
+Some utilities for constructing fragments of the C++ AST.
+
+<li><a href="baselexer.h">baselexer.h</a>, 
+    <a href="baselexer.cc">baselexer.cc</a>:
+Intermediate Lexer abstraction, built on top of yyFlexLexer and implementing
+LexerInferface (thus fitting between flex and Elkhound), but not specific to
+any set of tokens.  Lexer (<a href="lexer.h">lexer.h</a>) builds on top of this.
+
+<li><a href="builtinops.h">builtinops.h</a>,
+    <a href="builtinops.cc">builtinops.cc</a>:
+Representation of built-in operators, for use during operator
+overload resolution.
+
+<li><a href="cc.ast">cc.ast</a>:
+C/C++ Abstract Syntax Tree.  This is the most important
+file in the parser, since it defines the interface between
+the parser and everything else that comes after it.  It is
+documented separately in <a href="doc/cc.ast.html">cc.ast.html</a>.
+
+<li><a href="cc.gr">cc.gr</a>:
+C/C++ parsing grammar.  This is the second-most important file,
+as it tells Elkhound how to parse the token stream.  This grammar
+is based on that in the C++ Standard document, but then modified
+to remove unnecessary ambiguities and improve the grammar's ability
+to extract structure.
+
+<li><a href="cc_ast_aux.cc">cc_ast_aux.cc</a>:
+Some auxilliary functions for <a href="cc.ast">cc.ast</a>.
+
+<li><a href="cc_elaborate.ast">cc_elaborate.ast</a>,
+    <a href="cc_elaborate.h">cc_elaborate.h</a>,
+    <a href="cc_elaborate.cc">cc_elaborate.cc</a>:
+This module finds implicit function calls (like constructors) and creates
+an explicit representation of them.  An analysis can then ignore implicit
+calls and just use the constructed explicit AST.
+
+<li><a href="cc_env.h">cc_env.h</a>,
+    <a href="cc_env.cc">cc_env.cc</a>:
+Env, the type checking environment.  Fundamentally just a stack of
+Scopes (<a href="cc_scope.h">cc_scope.h</a>), plus some global
+type checking state.
+
+<li><a href="cc_err.h">cc_err.h</a>,
+    <a href="cc_err.cc">cc_err.cc</a>:
+ErrorMsg, an object for representing type checking errors.  For now
+it's just an error string plus some metadata (like source location),
+but I plan to evolve it to include more structured data like pointers
+to (instead of just string representations of) the types involved in
+the error.
+
+<li><a href="cc_flags.h">cc_flags.h</a>,
+    <a href="cc_flags.cc">cc_flags.cc</a>:
+This module defines a variety of enums relevant to parsing and
+type checking C++, including enums for all the built-in types,
+operators, etc.
+
+<li><a href="cc_lang.h">cc_lang.h</a>,
+    <a href="cc_lang.cc">cc_lang.cc</a>:
+CCLang, a package of language dialect options.  Setting flags in
+this class tells the lexer, parser and type checker what language
+options to support (e.g. C vs. C++).
+
+<li><a href="cc_print.ast">cc_print.ast</a>,
+    <a href="cc_print.h">cc_print.h</a>,
+    <a href="cc_print.cc">cc_print.cc</a>:
+cc_print is a module to pretty-print the AST using C++ syntax.  It
+extends the AST with entry points for printing.
+
+<li><a href="cc_scope.h">cc_scope.h</a>,
+    <a href="cc_scope.cc">cc_scope.cc</a>: 
+A Scope is two maps: variables and types.  The environment (<a
+href="cc_env.h">cc_env.h</a>) consists of a stack of them.
+
+<li><a href="cc_tcheck.ast">cc_tcheck.ast</a>,
+    <a href="cc_tcheck.cc">cc_tcheck.cc</a>:
+This is the type checker.  It consists of an AST extension to
+add type checking entry points and annotations, and an implementation
+of all of those type checking functions.  It's the most complicated
+part of the parser.
+
+<li><a href="cc_tokens.tok">cc_tokens.tok</a>:
+This file lists all of the kinds of tokens the lexer recognizes.  It's
+designed to be extended simply by appending.  The script
+<a href="make-token-files">make-token-files</a>
+takes this as input, and generates
+<a href="cc_tokens.h">cc_tokens.h</a>,
+<a href="cc_tokens.cc">cc_tokens.cc</a> and
+<a href="cc_tokens.ids">cc_tokens.ids</a>.  This last file is then
+included into <a href="cc.gr">cc.gr</a> (the others participate in
+compilation in the obvious way).
+
+<li><a href="cc_type.h">cc_type.h</a>,
+    <a href="cc_type.cc">cc_type.cc</a>:
+This module defines the representation of types.  They
+form the core of the data manipulated by the type checker.
+They are documented separately in
+<a href="cc_type.html">cc_type.html</a>.
+
+<li><a href="ccparse.h">ccparse.h</a>,
+    <a href="ccparse.cc">ccparse.cc</a>:
+This module defines part of the parser context class, and assists
+minimally with parsing.
+
+<li><a href="cfg.ast">cfg.ast</a>,
+    <a href="cfg.h">cfg.h</a>,
+    <a href="cfg.cc">cfg.cc</a>:
+This is type-checking extension that computes a statement-level
+control flow graph for each function.
+
+<li><a href="const_eval.h">const_eval.h</a>,
+    <a href="const_eval.cc">const_eval.cc</a>:
+Constant-expression evaluator.  Tries to predict the effect of
+coercing data among different representation sizes, among other things.
+
+<li><a href="generic_amb.h">generic_amb.h</a>:
+This is the generic ambiguity resolution procedure.  It typechecks
+all of the alternatives, and selects the one that passes.  Note that
+there are other ambiguity resolution procedures in use, but this is
+the one used in the absence of a specialized procedure.
+
+<li><a href="generic_aux.h">generic_aux.h</a>:
+Some routines for printing and modifying AST nodes that have
+<tt>ambiguity</tt> pointers.
+
+<li><a href="gnu.lex">gnu.lex</a>,
+    <a href="gnu_ext.tok">gnu_ext.tok</a>,
+    <a href="gnu.gr">gnu.gr</a>,
+    <a href="gnu.ast">gnu.ast</a>,
+    <a href="gnu.cc">gnu.cc</a>:  
+These files comprise the "gnu" extension module, though in truth this contains
+extensions for both gcc and C99.  See <a href="gnu.gr">gnu.gr</a> for a complete
+list of the extensions implemented.
+
+<li><a href="implconv.h">implconv.h</a>,
+    <a href="implconv.cc">implconv.cc</a>:
+This module represents and computes implicit conversions, as defined
+in sections 13.3.3.1 and 13.3.3.2 of the C++ standard.
+
+<li><a href="implint.h">implint.h</a>,
+    <a href="implint.cc">implint.cc</a>:
+Support routines, including ambiguity resolution, for the implicit-int
+K&amp;R extension.
+
+<li><a href="kandr.gr">kandr.gr</a>,
+    <a href="kandr.ast">kandr.ast</a>,
+    <a href="kandr.cc">kandr.cc</a>:
+K&amp;R extensions, in particular K&amp;R function definitions and the
+implicit-int rule.  Daniel Wilkerson implemented most of this.
+
+<li><a href="cc.lex">cc.lex</a>,
+    <a href="lexer.h">lexer.h</a>,
+    <a href="lexer.cc">lexer.cc</a>:
+This module chops up a given C++ source file into tokens.  It does
+not do any preprocessing, so one must use an external preprocessor
+first.
+
+<li><a href="lookupset.h">lookupset.h</a>,
+    <a href="lookupset.cc">lookupset.cc</a>:
+Class to store the result set of a lookup.
+
+<li><a href="main.cc">main.cc</a>:
+This module contains the main() function of the parser.  It's a simple
+driver around the other modules.  The nominal intent is that people who
+want to use parts of Elsa in their own projects users will copy and modify 
+this file as necessary.
+
+<li><a href="mangle.h">mangle.h</a>,
+    <a href="mangle.cc">mangle.cc</a>:
+This is a very rudmentary name mangler.  It is a somewhat arbitrary injective
+map from Types to character strings, for use by the Oink linker imitator
+(identifying declarations of the same entity from different translation units).
+It does <em>not</em> implement any standard mangling scheme.
+
+<li><a href="matchtype.h">matchtype.h</a>,
+    <a href="matchtype.cc">matchtype.cc</a>:
+Type matching in the presence of type variables corresponding to template 
+parameters; sort of a generalized Type::equals.
+
+<li><a href="overload.h">overload.h</a>,
+    <a href="overload.cc">overload.cc</a>:
+Does overload resolution of a given candidate set.
+
+<li><a href="parssppt.h">parssppt.h</a>,
+    <a href="parssppt.cc">parssppt.cc</a>:
+This is a poorly-designed module intended to abstract some of the
+functionality otherwise common to main()-providing modules.  It
+needs to die.  alt.parssppt.die.die.die.
+
+<li><a href="semgrep.cc">semgrep.cc</a>:
+Sample application of Elsa, a "semantic grep".  This is part
+of the <a href="tutorial.html">tutorial</a>.
+
+<li><a href="serialno.h">serialno.h</a>,
+    <a href="serialno.cc">serialno.cc</a>:
+This is a simple module that can be used to attach object creation
+serial numbers when an appropriate compile-time switch is used.  This
+is sometimes more convenient than working with virtual addresses,
+while debugging.
+
+<li><a href="sprint.h">sprint.h</a>,
+    <a href="sprint.cc">sprint.cc</a>:
+"Structure printer"; work in progress.
+
+<li><a href="stdconv.h">stdconv.h</a>,
+    <a href="stdconv.cc">stdconv.cc</a>:
+Represents and computes standard conversions, as defined in section 
+4 of the C++ standard.  See also
+<a href="convertibility.txt">convertibility.txt</a>.
+
+<li><a href="strmap.h">strmap.h</a>:
+Hashtable-based map from StringRef to some pointer.
+
+<li><a href="template.h">template.h</a>,
+    <a href="template.cc">template.cc</a>:
+Data structures and algorithms for the template instantiation implementation.
+
+<li><a href="tlexer.cc">tlexer.cc</a>:
+Simple test driver program for the lexer.
+
+<li><a href="typelistiter.h">typelistiter.h</a>,
+    <a href="typelistiter.cc">typelistiter.cc</a>:
+Generic interface, plus a couple of implementations, for iterating
+over sequences and examining their stored types.
+
+<li><a href="variable.h">variable.h</a>,
+    <a href="variable.cc">variable.cc</a>:
+Variable, a class for holding information about names in the
+"variable" namespace.  See
+<a href="variable.h">variable.h</a> for a list of the kinds
+of things that get represented with Variables.  This module
+is closely related to <a href="cc_type.h">cc_type</a>.
+
+</ul>
+
+
+<p>
+Module dependency diagram:<br>
+<img src="gendoc/dependencies.png" alt="Module dependencies"><br>
+Or, in <a href="gendoc/dependencies.ps">Postscript</a>.
+
+<p>
+Miscellanous files:
+<ul>
+
+<li><a href="chop_out">chop_out</a>:
+This script extracts pretty-printed C++ syntax from the other
+debugging output produced by ccparse.
+
+<li><a href="extradep.mk">extradep.mk</a>:
+Build-time dependencies among auto-generated source files.
+Produced by
+<a href="../elkhound/find-extra-deps">elkhound/find-extra-deps</a>.
+
+<li><a href="idemcheck">idemcheck</a>:
+Script to verify that parsing then pretty-printing is idempotent.
+
+<li><a href="in/">in</a>:
+Directory with testcases.
+
+<li><a href="include/">include</a>:
+When preprocessing, add this directory to the preprocessor's
+search path.  It contains compiler-specific headers.  Generally
+I just use gcc's headers, but some of gcc's headers use syntax
+that Elsa doesn't (yet?) understand, so this directory contains
+my replacements.
+
+<li><a href="merge-lexer-exts.pl">merge-lexer-exts.pl</a>:
+Merge a base flex lexer with one or more extensions.
+
+<li><a href="multitest.pl">multitest.pl</a>:
+Used by the regression tester to test a given input file, plus
+several variations obtained by un-commenting certain lines.
+
+<li><a href="regrtest">regrtest</a>:
+Regression tests.
+
+<li><a href="run-delta-loop">run-delta-loop</a>:
+Minimize <tt>tmp.i</tt> exhibiting some specified error message.
+
+<li><a href="test-for-error">test-for-error</a>:
+Test for exhibition of a particular error; used by run-delta-loop.
+
+<li><a href="test-parse">test-parse</a>:
+Script to parse a file, making sure the parse is unambiguous.
+
+<li><a href="test-parse-buildlog">test-parse-buildlog</a>:
+This is a script that interprets the output of 'make' in order to
+find C++ inputs to test with Elsa.  I use it to make claims like
+"Elsa can parse Mozilla".
+
+</ul>
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+</body>
+
+</HTML>
+
+

Added: vendor/elsa/current/elsa/integrity.cc
===================================================================
--- vendor/elsa/current/elsa/integrity.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/integrity.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,78 @@
+// integrity.cc
+// code for integrity.h
+
+#include "integrity.h"         // this module
+
+
+void IntegrityVisitor::foundAmbiguous(void *obj, void **ambig, char const *kind)
+{
+  // 2005-06-29: I have so far been unable to provoke this error by
+  // doing simple error seeding, because it appears to be masked by a
+  // check in the elaboration visitor regarding visiting certain lists
+  // more than once.  Among other things, that means if there is a bug
+  // along these lines, a user will discover it by seeing the
+  // unfriendly list-visit assertion failure instead of the message
+  // here.  But, that stuff is wrapped up in the Daniel's lowered
+  // visitor mechanism, which I don't want to mess with now.  Anyway,
+  // I'm reasonably confident that this check will work properly.
+  xfatal(toString(loc) << ": internal error: found ambiguous " << kind);
+}
+
+
+bool IntegrityVisitor::visitDeclarator(Declarator *obj)
+{
+  if (!ASTVisitorEx::visitDeclarator(obj)) {
+    return false;
+  }
+
+  // make sure the type is not a DQT if we are not in a template
+  if (!inTemplate) {
+    checkNontemplateType(obj->var->type);
+    checkNontemplateType(obj->type);
+  }
+
+  return true;
+}
+
+void IntegrityVisitor::checkNontemplateType(Type *t)
+{
+  if (t->containsGeneralizedDependent()) {
+    xfatal(toString(loc) << ": internal error: found dependent type `"
+                         << t->toString() << "' in non-template (0a257264-c6ec-4983-95d0-fcd6aa48a6ce)");
+  }
+}
+
+
+bool IntegrityVisitor::visitExpression(Expression *obj)
+{
+  if (!ASTVisitorEx::visitExpression(obj)) {
+    return false;
+  }
+
+  // 2005-08-18: I started to do this, then realized that these might
+  // survive in template bodies.
+  //
+  // TODO: Make a way for ASTVisitorEx to communicate to visitors
+  // whether they are in template bodies or not.
+  //
+  // 2006-05-30: Um, what was I thinking?  Why is 'inTemplate' not
+  // sufficient?
+  #if 0
+  if (obj->isE_grouping()) {
+    xfatal(toString(loc) << ": internal error: found E_grouping after tcheck");
+  }
+  if (obj->isE_arrow()) {
+    xfatal(toString(loc) << ": internal error: found E_arrow after tcheck");
+  }
+  #endif // 0
+
+  // why was I not doing this before?  detects problem in/t0584.cc
+  if (!inTemplate && obj->type) {
+    checkNontemplateType(obj->type);
+  }
+
+  return true;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/integrity.h
===================================================================
--- vendor/elsa/current/elsa/integrity.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/integrity.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// integrity.h
+// procedures for checking the the AST is well-formed, for
+// various notions of well-formedness
+
+#ifndef INTEGRITY_H
+#define INTEGRITY_H
+
+#include "astvisit.h"        // ASTVisitorEx
+                    
+// integrity checks:
+//   - The AST must be unambiguous.
+//   - No dependent types appear in concrete code.
+class IntegrityVisitor : public ASTVisitorEx {
+private:     // funcs
+  void checkNontemplateType(Type *t);
+
+public:      // funcs
+  // ASTVisitorEx functions
+  virtual void foundAmbiguous(void *obj, void **ambig, char const *kind);
+
+  // ASTVisitor functions
+  virtual bool visitDeclarator(Declarator *obj);
+  virtual bool visitExpression(Expression *obj);
+};
+
+#endif // INTEGRITY_H

Added: vendor/elsa/current/elsa/interptest
===================================================================
--- vendor/elsa/current/elsa/interptest	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/interptest	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,112 @@
+#!/usr/bin/perl -w
+# -*-cperl-*-
+
+die "this script is not done";
+
+# A script for interpreting files as tests.  We implement a
+# general-purpose means for 1) asserting an embedded sentence to be
+# true about a file and 2) templatizing a file with an embedded diff
+# that is applied to the file before the assertion is run.  The
+# commands that embedd the assertion and diff each have a set of mode
+# names attached; when this script is run a mode is supplied and the
+# assertions and diff commands labelled with that mode are the only
+# ones honored.
+
+# More specifically, we implement the following features.  This script
+# takes as arguments a mode and a list of files.  Step 1) All of the
+# files on the command line to this script are processed to apply the
+# diff indicated by the mode.  Step 2) all of the assertions indicated
+# by the mode are run.
+#
+# During interpretation all lines ending in a suffix of the form
+#   // INTERP_*
+# are considered to be interpreter commands.  They are deleted from
+# the file before the file is saved at the end of step 1.
+#
+# Each command is annotated by a MODE_SET, which is a comma-separated
+# list of mode names; when the current mode is on that list then the
+# command is honored; otherwise it is ignored.
+#
+# Step 1) The file will be processed and all of the ADD(MODE) and
+# DEL(MODE) lines applied and the file FILE.SUFFIX will be saved to
+# FILE-MODE.SUFFIX.
+#
+# Step 2) INPUT=<filenames> COMMAND will be run in the shell, where
+# <filenames> is the list of files FILE-MODE.SUFFIX for each
+# FILE.SUFFIX in the input files to this script.  The test passes if
+# the return value is RESULT.
+
+# The commands are as follows.
+#
+# INTERP_PREFIX(FOO)
+# changes the INTERP prefix to FOO FOO_PREFIX command.  Read all the
+# rest of the rules accordingly.
+#
+# INTERP_ALSO(MODE_SET)FILE
+# also puts FILE on the list of files to be processed and then
+# included in the INPUT argument to the assertion commands run for
+# this mode.  The assertions in FILE are not run.
+#
+# INTERP_ASSERT(MODE_SET) RESULT=COMMAND
+# defines a test assertion.
+#
+# INTERP_ADD(MODE_SET)LINE
+# when mode is MODE then this line is added to the file at this
+# position; any text to the left of the command comment is retained.
+#
+# INTERP_DEL(MODE_SET)
+# when mode is MODE then this entire line is deleted, including the
+# text to the left of the command-comment.
+
+# ****
+my $mode;                       # the mode used to filter the commands
+my @infiles;                    # the input files
+my %infile2outfile;             # map input files to output files
+
+sub parse_command_line {
+  for my $arg(@ARGV) {
+    if ($arg=~m/^--mode=(.*)$/) {
+      $mode = $1;
+    } else {
+      push @infiles, $1;
+    }
+  }
+  die "you must specify a mode" unless defined $mode;
+}
+
+sub make_outfile_name {
+  my ($infile) = @_;
+  if ($infile =~ m/(^[^\.]*)(\..*)$/) {
+    my ($stem, $suffix) = ($1, $2);
+    return "$stem-$mode$suffix";
+  } else {
+    return "$infile-$mode";
+  }
+}
+
+# main ****
+
+# for each infile name, make the outfile name, filter the infile and
+# print it out to outfile; accumulate the assertions (commands and
+# results), and honor the add and del commands
+
+parse_command_line();
+
+# check for duplicate infile names, non-existant infiles, and
+# already-existant outfiles
+my %infilesset;
+my %outfileset;
+for my $infile (@infiles) {
+  die "duplicate infile name $infile" if $infilesset{$infile};
+  ++$infilesset{$infile};
+  die "no such infile $infile" unless -e $infile;
+
+  my $outfile = make_outfile_name($infile);
+  die "duplicate outfile name $outfile -- this shouldn't be possible" if $outfileset{$outfile};
+  ++$outfileset{$infile};
+  die "file already exists $outfile" if -e $outfile;
+}
+
+# for my $infile(@infiles) {
+#   die "" if -e $infilenew;
+# }

Added: vendor/elsa/current/elsa/iptparse.cc
===================================================================
--- vendor/elsa/current/elsa/iptparse.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/iptparse.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,198 @@
+// iptparse.cc
+// (some) code for iptparse.h
+
+#include "iptparse.h"      // this module
+#include "iptree.h"        // IPTree
+#include "autofile.h"      // AutoFILE
+#include "exc.h"           // xfatal
+
+#include <stdlib.h>        // rand()
+
+
+TokenType lookahead = TOK_EOF;
+
+
+// get the next token and stash it in 'lookahead'
+void getToken()
+{
+  lookahead = getNextToken();
+}
+ 
+
+// string representation of current token
+string tokenToString()
+{
+  if (lookahead == TOK_INTLIT) {
+    return stringc << "intlit(" << lexerSval << ")";
+  }
+  else {
+    static char const * const map[] = {
+      "EOF",
+      "INTLIT",
+      "COMMA",
+      "SEMICOLON"
+    };
+
+    xassert(TABLESIZE(map) == NUM_TOKENTYPES);
+    return string(map[lookahead]);
+  }
+}
+
+
+// report parse error at current token
+void parseError()
+{
+  xfatal("parse error at " << tokenToString());
+}
+
+
+// get token and expect it to be a specific kind
+void expect(TokenType t)
+{
+  getToken();
+  if (lookahead != t) {
+    parseError();
+  }
+}
+
+
+void parseBracePair(ArrayStack<Interval> &pairs)
+{
+  xassert(lookahead == TOK_INTLIT);
+  int lo = lexerSval;
+
+  expect(TOK_COMMA);
+
+  expect(TOK_INTLIT);
+  int hi = lexerSval;
+
+  expect(TOK_SEMICOLON);
+
+  pairs.push(Interval(lo, hi));
+}
+
+                              
+// return a random number in [0,n-1], uniformly distributed
+static int randomNumber(int n)
+{
+  // from rand() man page
+  return (int)((double)n*rand()/(RAND_MAX+1.0));
+}
+
+void shuffleRange(ArrayStack<Interval> &pairs, int lo, int hi)
+{
+  while (lo < hi) {
+    // exchange 'lo' with a random element above it
+    int other = lo+1+randomNumber(hi-lo);
+    
+    // should only be exchanging elements with equal size
+    xassert(pairs[lo].size() == pairs[other].size());
+                       
+    // swap
+    Interval tmp = pairs[lo];
+    pairs[lo] = pairs[other];
+    pairs[other] = tmp;
+    
+    lo++;
+  }
+}
+
+
+static int decSizeCompare(Interval const *a, Interval const *b)
+{
+  return b->size() - a->size();
+}
+
+IPTree *parseFile(rostring fname)
+{
+  AutoFILE fp(toCStr(fname), "r");
+  yyrestart(fp);
+
+  ArrayStack<Interval> pairs;
+
+  bool done = false;
+  while (!done) {
+    getToken();
+    switch (lookahead) {
+      case TOK_EOF:
+        done = true;
+        break;
+
+      case TOK_INTLIT:
+        parseBracePair(pairs);
+        break;
+
+      default:
+        parseError();
+    }
+  }
+
+  // sort the pairs by decreasing size
+  pairs.sort(decSizeCompare);
+
+  // randomize the order of elements with equal sizes
+  int lastSize = -1;
+  int lastSizeStart = -1;
+  int maxHi = 0;
+  int i;
+  for (i=0; i < pairs.length(); i++) {
+    // also calculate the maximum 'hi' value
+    if (pairs[i].hi > maxHi) {
+      maxHi = pairs[i].hi;
+    }
+
+    if (pairs[i].size() != lastSize) {
+      if (lastSize > 0) {
+        shuffleRange(pairs, lastSizeStart, i-1);
+      }
+
+      // new range of equisize intervals
+      lastSize = pairs[i].size();
+      lastSizeStart = i;
+    }
+  }
+
+  // last range
+  if (lastSize > 0) {
+    shuffleRange(pairs, lastSizeStart, i-1);
+  }
+
+  // make the tree
+  IPTree *tree = new IPTree(maxHi);
+
+  // now insert them in order
+  for (i=0; i < pairs.length(); i++) {
+    tree->insert(pairs[i].lo, pairs[i].hi);
+  }
+
+  return tree;
+}
+
+
+// --------------------- test code ---------------------
+#ifdef TEST_IPTPARSE
+
+#include "test.h"      // ARGS_MAIN
+
+void entry(int argc, char *argv[])
+{
+  xBase::logExceptions = false;
+
+  if (argc < 2) {
+    xbase(stringc << "usage: " << argv[0] << " foo.c.str [tree]");
+  }
+
+  IPTree *tree = parseFile(argv[1]);
+
+  if (argc >= 3) {
+    tree->gdb();
+  }
+
+  cout << "link chases: " << Node::linkChases << "\n";
+  
+  delete tree;
+}
+
+ARGS_MAIN
+
+#endif // TEST_IPTPARSE

Added: vendor/elsa/current/elsa/iptparse.h
===================================================================
--- vendor/elsa/current/elsa/iptparse.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/iptparse.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,35 @@
+// iptparse.h
+// interface to the interval partition tree parser
+
+#ifndef IPTPARSE_H
+#define IPTPARSE_H
+
+#include <stdio.h>    // FILE
+#include "str.h"      // rostring
+
+class IPTree;         // iptree.h
+
+// the lexer stashes lexed integer codes here
+extern int lexerSval;
+
+// token codes
+enum TokenType {
+  TOK_EOF=0,          // end of file
+  TOK_INTLIT,         // integer literal
+  TOK_COMMA,          // ","
+  TOK_SEMICOLON,      // ";"
+
+  NUM_TOKENTYPES
+};
+
+// call this to begin lexing (defined in iptparse.yy.cc)
+void yyrestart(FILE *input_file);
+
+// call this to get the next token (defined in iptparse.yy.cc)
+TokenType getNextToken();
+
+// parse a file into a given tree
+IPTree *parseFile(rostring fname);
+
+
+#endif // IPTPARSE_H

Added: vendor/elsa/current/elsa/iptparse.lex
===================================================================
--- vendor/elsa/current/elsa/iptparse.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/iptparse.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+/* iptparse.lex */
+/* lexer for iptree parser */
+
+
+/* ------------ C prelude ------------ */
+%{
+#include "iptparse.h"       // token definitions
+#include "exc.h"            // xfatal
+
+// this works around a problem with cygwin & fileno
+#define YY_NEVER_INTERACTIVE 1
+
+int lexerSval = 0;
+%}
+
+
+/* ------------ flex options ----------- */
+/* no wrapping is needed; setting this means we don't have to link with libfl.a */
+%option noyywrap
+
+/* don't use the default-echo rules */
+%option nodefault
+
+/* I don't call unput */
+%option nounput
+
+/* the scanner is never interactive */
+%option never-interactive
+
+
+/* -------------- token rules ------------ */
+%%
+
+  /* punctuation */
+","              { return TOK_COMMA; }
+";"              { return TOK_SEMICOLON; }
+
+  /* decimal integer literal */
+[0-9]+ {
+  lexerSval = atoi(yytext);
+  return TOK_INTLIT;
+}
+
+  /* whitespace; ignore */
+[ \t\n\f\v\r]+  {
+}
+
+  /* C++ comment */
+"//".*    {
+}
+
+.  {
+  xfatal("illegal character: `" << yytext[0] << "'");
+}
+
+<<EOF>> {
+  yyterminate();
+}
+
+
+%%
+/* ----------------- C epilogue --------------- */
+
+TokenType getNextToken()
+{
+  int code = yylex();
+  xassert(0 <= code && code < NUM_TOKENTYPES);
+  return (TokenType)code;
+}
+
+  /* EOF */

Added: vendor/elsa/current/elsa/iptree.cc
===================================================================
--- vendor/elsa/current/elsa/iptree.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/iptree.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,542 @@
+// iptree.cc
+// code for iptree.h
+
+#include "iptree.h"       // this module
+#include "autofile.h"     // AutoFILE
+#include "syserr.h"       // xsyserror
+#include "trace.h"        // TRACE
+
+
+// --------------------- Relevance ----------------------
+char const *toString(Relevance r)
+{
+  char const * const map[] = {
+    "R_IRRELEVANT_SIBS",
+    "R_IRRELEVANT",
+    "R_UNKNOWN",
+    "R_RELEVANT"
+  };
+
+  STATIC_ASSERT(TABLESIZE(map) == NUM_RELEVANCES);
+  xassert((unsigned)r < (unsigned)NUM_RELEVANCES);
+  return map[r];
+}
+
+
+// ------------------- VariantResults -------------------
+char const *toString(VariantResult r)
+{
+  char const * const map[] = {
+    "VR_UNKNOWN",
+    "VR_PASSED",
+    "VR_FAILED"
+  };
+
+  STATIC_ASSERT(TABLESIZE(map) == NUM_VRESULTS);
+  xassert((unsigned)r < (unsigned)NUM_VRESULTS);
+  return map[r];
+}
+
+
+void printBits(ArrayStack<char> const &bits)
+{
+  for (int i=0; i < bits.length(); i++) {
+    cout << (bits[i]? '1' : '0');
+  }
+}
+
+
+void iprintResults(VariantCursor p, ArrayStack<char> &bits)
+{
+  if (p->data) {
+    // print the result
+    cout << toString(p->data) << "  ";
+
+    // and the bitstring
+    printBits(bits);
+    cout << "\n";
+  }
+
+  if (p->zero) {
+    bits.push(0);
+    iprintResults(p->zero, bits);
+    bits.pop();
+  }
+
+  if (p->one) {
+    bits.push(1);
+    iprintResults(p->one, bits);
+    bits.pop();
+  }
+}
+
+
+void printResults(VariantResults &results)
+{
+  ArrayStack<char> bits;
+  VariantCursor p = results.getTop();
+
+  iprintResults(p, bits);
+}
+
+
+// ---------------------- Interval ----------------------
+string Interval::rangeString() const
+{
+  if (hi < INT_MAX) {
+    return stringc << "[" << lo << ", " << hi << "]";
+  }
+  else {
+    return stringc << "[" << lo << ", +inf)";
+  }
+}
+
+
+// ------------------------ Node ------------------------
+long Node::linkChases = 0;
+
+Node::Node(int lo, int hi)
+  : ival(lo, hi),
+    left(NULL),
+    right(NULL),
+    subintervals(NULL),
+    rel(R_UNKNOWN)
+{
+  xassert(lo <= hi);
+}
+
+Node::~Node()
+{
+  if (left) {
+    delete left;
+  }
+  if (right) {
+    delete right;
+  }
+  if (subintervals) {
+    delete subintervals;
+  }
+}
+
+
+bool Node::contains(Node const *n) const
+{
+  return ival.contains(n->ival);
+}
+
+
+bool Node::contains(int n) const
+{
+  return ival.contains(n);
+}
+
+
+int Node::getLeftEdge() const
+{
+  if (left) {
+    return left->getLeftEdge();
+  }
+  else {
+    return ival.lo;
+  }
+}
+
+int Node::getRightEdge() const
+{
+  if (right) {
+    return right->getRightEdge();
+  }
+  else {
+    return ival.hi;
+  }
+}
+
+
+void Node::insert(Node *n)
+{
+  if (n->ival < this->ival) {
+    // goes into left subtree
+    if (!left) {
+      left = n;
+    }
+    else {
+      linkChases++;
+      left->insert(n);
+    }
+    return;
+  }
+
+  if (n->ival > this->ival) {
+    // goes into right subtree
+    if (!right) {
+      right = n;
+    }
+    else {
+      linkChases++;
+      right->insert(n);
+    }
+    return;
+  }
+
+  if (this->contains(n)) {
+    // goes into subintervals
+    if (!subintervals) {
+      subintervals = n;
+    }
+    else {
+      subintervals->insert(n);
+    }
+    return;
+  }
+
+  xfatal("improper overlap: " << n->rangeString() <<
+         " and " << this->rangeString());
+}
+
+
+Node const *Node::queryC(int n) const
+{
+  xassert(contains(n));
+
+  // search among subintervals for containing node
+  Node const *sub = subintervals;
+  while (sub) {
+    if (sub->ival.contains(n)) {
+      return sub->queryC(n);
+    }
+    
+    if (n < sub->ival) {
+      sub = sub->left;
+    }
+    else {
+      xassert(n > sub->ival);
+      sub = sub->right;
+    }
+  }
+
+  // no subinterval contains it
+  return this;
+}
+
+
+int writeSegment(FILE *fp, GrowArray<char> const &source,
+                 int start, int len)
+{
+  xassert(len >= 0);
+  xassert(start >= 0);
+  xassert(start+len <= source.size());
+
+  fwrite(source.getArray()+start, 1, len, fp);
+  
+  return len;
+}
+
+
+
+
+// The following diagram depicts the situation when a node ("me") is
+// asked to print itself.  It is responsible for printing everything
+// from A (the left edge of the left sibling tree) to H (the right
+// edge of the right sibling tree).
+//                                                               .
+//                               me                              .
+//                        +---------------+                      .
+//                        |               |                      .
+//          left          |               |        right         .
+//        +--------+      |      sub      |     +---------+      .
+//        |        |      |     +--+      |     |         |      .
+//        |        |      |     |  |      |     |         |      .
+//       /|        |\     |    /|  |\     |    /|         |\     .
+//      / |        | \    |   / |  | \    |   / |         | \    .
+//      A            B    C   D      E    F   G             H    .
+//
+// This requires several steps:
+//   - A-B: ask 'left' to print itself
+//   - B-D: I do this
+//   - D-E: ask 'subintervals' to print itself
+//   - E-G: I do this
+//   - G-H: ask 'right' to print itself
+//
+// If 'rel' is R_IRRELEVANT_SIBS, print nothing.
+//
+// If 'left' is NULL, then A=B=C.
+// If 'right' is NULL, then F=G=H.
+//
+// If 'rel' is R_IRRELEVANT, omit C-F.
+//
+// If 'subintervals' is null, then I just print B-G.
+int Node::write(FILE *fp, GrowArray<char> const &source,
+                VariantCursor &cursor) const
+{
+  if (rel == R_IRRELEVANT_SIBS) {
+    // my entire range, from A to H, is cancelled
+    cursor = cursor->getZero();
+    return 0;
+  }
+  cursor = cursor->getOne();
+
+  // # of bytes printed so far
+  int ret = 0;
+
+  int B;
+  if (left) {
+    ret += left->write(fp, source, cursor);          // print A-B
+    B = left->getRightEdge();
+  }
+  else {
+    // so when I print B-D, I will actually print C-D
+    B = ival.lo-1;
+  }
+
+  int E;
+  if (rel > R_IRRELEVANT) {
+    cursor = cursor->getOne();
+    if (subintervals) {
+      int D = subintervals->getLeftEdge();
+      ret += writeSegment(fp, source, B+1, D-(B+1));   // print B-D
+      ret += subintervals->write(fp, source, cursor);  // print D-E
+      E = subintervals->getRightEdge();
+    }
+    else {
+      // so when I print E-G, I will actually print B-G
+      E = B;
+    }
+  }
+  else {
+    cursor = cursor->getZero();
+
+    // omit C-F
+    int C = ival.lo;
+    ret += writeSegment(fp, source, B+1, C-(B+1));   // print B-C
+    
+    // so when I print E-G, I will actually print F-G
+    E = ival.hi;
+  }
+
+  int G;
+  if (right) {
+    G = right->getLeftEdge();
+    ret += writeSegment(fp, source, E+1, G-(E+1));   // print E-G
+    ret += right->write(fp, source, cursor);         // print G-H
+  }
+  else {
+    G = ival.hi+1;
+    ret += writeSegment(fp, source, E+1, G-(E+1));   // print E-G
+  }
+  
+  return ret;
+}
+
+
+// recursively explore the sibling tree
+int Node::writeSubs(FILE *fp, GrowArray<char> const &source,
+                    VariantCursor &cursor, int &curOffset)
+{
+  xfailure("not used anymore");
+
+  // write left siblings
+  int ret = 0;
+  if (left) {
+    ret += left->writeSubs(fp, source, cursor, curOffset);
+  }
+
+  // write data preceding me
+  ret += writeSegment(fp, source, curOffset, ival.lo - curOffset);
+
+  // possibly write me
+  if (rel > R_IRRELEVANT) {
+    cursor = cursor->getOne();
+    ret += write(fp, source, cursor);
+  }
+  else {
+    cursor = cursor->getZero();
+  }
+  curOffset = ival.hi+1;
+
+  // write right siblings
+  if (right) {
+    ret += right->writeSubs(fp, source, cursor, curOffset);
+  }
+  
+  return ret;
+}
+
+
+static void indent(ostream &os, int ind)
+{
+  for (int i=0; i<ind; i++) {
+    os << ' ';
+  }
+}
+
+void Node::debugPrint(ostream &os, int ind) const
+{
+  indent(os, ind);
+  cout << rangeString() << " \t" << toString(rel) << "\n";
+
+  if (subintervals) {
+    subintervals->debugPrintSubs(os, ind+2);
+  }
+}
+
+void Node::debugPrintSubs(ostream &os, int ind) const
+{
+  // left siblings
+  if (left) {
+    left->debugPrintSubs(os, ind);
+  }
+            
+  // myself
+  debugPrint(os, ind);
+  
+  // right siblings
+  if (right) {
+    right->debugPrintSubs(os, ind);
+  }
+}
+
+
+// ------------------------ IPTree -----------------------
+IPTree::IPTree(int hi)
+  : top(NULL)
+{
+  top = new Node(0, hi);
+}
+
+IPTree::~IPTree()
+{
+  delete top;
+}
+
+
+Node *IPTree::insert(int lo, int hi)
+{ 
+  Node *n = new Node(lo, hi);
+  top->insert(n);
+  return n;
+}
+
+
+Node const *IPTree::queryC(int n) const
+{
+  if (!top || !top->contains(n)) {
+    return NULL;
+  }
+
+  return top->queryC(n);
+}
+
+
+int IPTree::write(rostring fname, GrowArray<char> const &source,
+                  VariantCursor &cursor) const
+{
+  AutoFILE fp(toCStr(fname), "w");
+  int ret = 0;
+
+  if (top->rel) {
+    cursor = cursor->getOne();
+    ret += top->write(fp, source, cursor);
+  }
+  else {
+    cursor = cursor->getZero();
+  }
+
+  return ret;
+}
+
+
+int IPTree::getLargestFiniteEndpoint()
+{
+  if (top->ival.hi < INT_MAX) {
+    return top->ival.hi;
+  }
+
+  Node *sub = top->subintervals;
+  if (!sub) {
+    return top->ival.lo;
+  }
+  
+  while (sub->right) {
+    sub = sub->right;
+  }
+
+  return sub->ival.hi;
+}
+
+
+void IPTree::gdb() const
+{
+  if (!top) {
+    cout << "(empty tree)\n";
+  }
+  else {
+    top->debugPrint(cout, 0);
+  }
+}
+
+
+// ---------------------- readFile -----------------------
+void readFile(rostring fname, GrowArray<char> &dest)
+{
+  AutoFILE fp(toCStr(fname), "r");
+
+  enum { SZ=4096 };
+  int curOffset = 0;
+
+  for (;;) {
+    dest.ensureIndexDoubler(curOffset+SZ);
+    int len = fread(dest.getArrayNC()+curOffset, 1, SZ, fp);
+    if (len < 0) {
+      xsyserror("read");
+    }
+    if (len == 0) {
+      break;
+    }
+
+    curOffset += len;
+  }
+  
+  // trim the array
+  dest.setSize(curOffset);
+}
+
+
+// ---------------------- test code ----------------------
+#ifdef TEST_IPTREE
+#include "test.h"        // USUAL_MAIN
+
+void entry()
+{
+  IPTree t(115);         // whole file
+
+  t.insert(0,9);         // prelude
+  t.insert(10,16);       // int g;
+  t.insert(17,23);       // int h;
+  t.insert(24,41);       // int bar(int,int);
+  t.insert(42,42);       // whitespace
+
+  t.insert(43,113);      // all of foo
+  t.insert(51,62);       // parameter list
+  t.insert(56,62);       // ", int y"
+
+  t.insert(69,75);       // "g += x;"
+  t.insert(71,74);       // "+= x"
+  t.insert(71,71);       // "+"
+
+  t.insert(79,92);       // "h = g + x + y";
+  t.insert(81,91);       // "= g + x + y"
+  t.insert(85,87);       // "+ x"
+  t.insert(89,91);       // "+ y"
+
+  t.insert(96,111);      // "return bar(2,3);"
+  t.insert(103,110);     // "bar(2,3)"
+  t.insert(107,109);     // "2,3"
+  t.insert(108,109);     // ",3"
+
+  t.gdb();
+}
+
+USUAL_MAIN
+
+#endif // TEST_IPTREE
+

Added: vendor/elsa/current/elsa/iptree.h
===================================================================
--- vendor/elsa/current/elsa/iptree.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/iptree.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,193 @@
+// iptree.h
+// interval partition tree
+
+#ifndef IPTREE_H
+#define IPTREE_H
+
+#include "objlist.h"        // ObjList
+#include "str.h"            // rostring
+#include "array.h"          // GrowArray
+#include "bitstrmap.h"      // BitStrMap
+
+#include <iostream.h>       // ostream
+#include <stdio.h>          // FILE
+#include <limits.h>         // INT_MAX
+
+
+// node relevance
+enum Relevance {
+  R_IRRELEVANT_SIBS,        // my siblings and I are all irrelevant
+  R_IRRELEVANT,             // was irrelevant at least once
+  R_UNKNOWN,                // never tested
+  R_RELEVANT,               // has been relevant every time tested
+  NUM_RELEVANCES
+};
+
+char const *toString(Relevance r);
+
+
+// result of applying the test to a variant
+enum VariantResult {
+  VR_UNKNOWN=0,             // never tried
+  VR_PASSED,                // test passed
+  VR_FAILED,                // test failed
+  NUM_VRESULTS
+};
+
+char const *toString(VariantResult r);
+
+
+// map a variant bitstring to its result code
+typedef BitStrMap<VariantResult> VariantResults;
+typedef VariantResults::Node *VariantCursor;
+
+// debugging: print the set of mapped bitvectors
+void printResults(VariantResults &results);
+
+
+class Interval {
+public:      // data
+  // interval endpoints, inclusive; hi can be INT_MAX
+  int lo, hi;
+
+public:      // funcs
+  Interval() : lo(0), hi(0) {}
+  Interval(int L, int H) : lo(L), hi(H) {}
+
+  Interval& operator= (Interval const &obj)
+    { lo=obj.lo; hi=obj.hi; return *this; }
+
+  // number of elements in the interval
+  int size() const
+    { return hi-lo+1; }
+
+  // interval comparison
+  bool contains(Interval const &obj) const
+    { return lo <= obj.lo && obj.hi <= hi; }
+  bool operator< (Interval const &obj) const
+    { return hi < obj.lo; }
+  bool operator> (Interval const &obj) const
+    { return lo > obj.hi; }
+
+  // integer comparison
+  bool contains(int n) const
+    { return lo <= n && n <= hi; }
+  bool operator< (int n) const
+    { return hi < n; }
+  bool operator> (int n) const
+    { return lo > n; }
+  friend bool operator< (int n, Interval const &obj)
+    { return n < obj.lo; }
+  friend bool operator> (int n, Interval const &obj)
+    { return n > obj.hi; }
+
+  // print the range as a string, like "[1, 2]"
+  string rangeString() const;
+};
+
+
+// node in the interval tree
+class Node {
+public:
+  // interval
+  Interval ival;
+
+  // binary search tree of siblings; this tree is not necessarily
+  // balanced, but the tree construction procedure has provisions to
+  // make balance reasonably likely (nullable owner)
+  Node *left, *right;
+
+  // subintervals contained within this one
+  Node *subintervals;
+
+  // state of search for minimal element
+  Relevance rel;
+
+  // # of times 'left' or 'right' is traversed during insert()
+  static long linkChases;
+
+private:     // funcs
+  int writeSubs(FILE *fp, GrowArray<char> const &source,
+                VariantCursor &cursor, int &curOffset);
+  void debugPrintSubs(ostream &os, int ind) const;
+
+public:      // funcs
+  Node(int lo, int hi);
+  ~Node();
+
+  // true if 'this' contains or equals 'n'
+  bool contains(Node const *n) const;
+
+  // true if 'this' contains the value 'n'
+  bool contains(int n) const;
+
+  // follow 'left' to the end, and get 'lo' there
+  int getLeftEdge() const;
+
+  // follow 'right' to end and get 'hi'
+  int getRightEdge() const;
+
+  // add 'n' somewhere in the subtree rooted at 'this'
+  void insert(Node *n);
+
+  // find the smallest interval containing 'n', which must at least
+  // be contained within 'this'
+  Node const *queryC(int n) const;
+  Node *query(int n) { return const_cast<Node*>(queryC(n)); }
+
+  // write this node's fragment from 'source' to 'fp', returning
+  // the # of bytes written
+  int write(FILE *fp, GrowArray<char> const &source,
+            VariantCursor &cursor) const;
+
+  // print the range as a string, like "[1, 2]"
+  string rangeString() const
+    { return ival.rangeString(); }
+
+  // print this subtree to the given stream at the given level
+  // of indentation
+  void debugPrint(ostream &os, int ind) const;
+};
+
+
+// interval partition tree
+class IPTree {
+private:     // data
+  // (owner) top of the tree
+  Node *top;
+
+public:      // funcs
+  IPTree(int hi);      // hi is 'hi' of root
+  ~IPTree();
+
+  Node *getTop() { return top; }
+
+  // add a new interval; must nest properly *inside* existing
+  // intervals (so must insert from largest to smallest)
+  Node *insert(int lo, int hi);
+
+  // find the smallest interval containing the given value, or NULL if
+  // it is outside all intervals
+  Node const *queryC(int n) const;
+  Node *query(int n) { return const_cast<Node*>(queryC(n)); }
+
+  // given an array of source characters, write to 'fname' a file
+  // consisting of all the intervals that are not irrelevant; the
+  // cursor is advanced to reflect the navigation path; return the
+  // # of bytes written
+  int write(rostring fname, GrowArray<char> const &source,
+            VariantCursor &cursor) const;
+                                 
+  // what is the largest endpoint, other than INT_MAX?
+  int getLargestFiniteEndpoint();
+
+  // debugging: print the tree to stdout
+  void gdb() const;
+};
+
+
+// read a file into memory
+void readFile(rostring fname, GrowArray<char> &dest);
+
+
+#endif // IPTREE_H

Added: vendor/elsa/current/elsa/kandr.ast
===================================================================
--- vendor/elsa/current/elsa/kandr.ast	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/kandr.ast	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// kandr.ast            see license.txt for copyright and terms of use
+// derived from oink.ast
+// nominal author: dsw
+
+// extension module to cc.ast; goes with kandr.gr
+
+verbatim {
+  #define KANDR_EXTENSION         // this extension module is active
+}
+
+class PQName {
+  // Used in D_func::traverse to traverse kandr_params
+  -> PQ_name {
+    // FakeList link; use 'setNext' to set 'next'
+    public PQ_name *next = NULL;
+    public void setNext(PQ_name *newNext);
+  }
+}
+
+class IDeclarator {
+  // retrieve the innermost D_func constructor
+  pure_virtual D_func *getD_func();
+
+  -> D_func(FakeList<PQ_name> *kAndR_params = NULL); // params if a K&R function
+}

Added: vendor/elsa/current/elsa/kandr.cc
===================================================================
--- vendor/elsa/current/elsa/kandr.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/kandr.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,150 @@
+// kandr.cc            see license.txt for copyright and terms of use
+// support routines for the K&R extension
+
+#include "kandr.h"          // this module
+#include "generic_aux.h"    // genericSetNext
+#include "cc_lang.h"        // CCLang
+
+
+// implemented in implint.cc
+bool filterOutImplIntFirstParam
+  (SourceLoc loc,
+   IDeclarator *base,
+   FakeList<ASTTypeId> *&params);
+
+
+// -------------------- AST extensions ---------------------
+D_func *D_name::getD_func() {return NULL;}
+D_func *D_pointer::getD_func() {return base->getD_func();}
+D_func *D_reference::getD_func() {return base->getD_func();}
+D_func *D_func::getD_func() {
+  // you have to be careful that there may be another one nested down
+  // inside if the user used this funky syntax:
+  // int (*oink2(x))(int)
+  D_func *df = base->getD_func();
+  if (df) return df;
+  else return this;
+}
+D_func *D_array::getD_func() {return base->getD_func();}
+D_func *D_bitfield::getD_func() {return NULL;}
+D_func *D_ptrToMember::getD_func() {return base->getD_func();}
+D_func *D_grouping::getD_func() {return base->getD_func();}
+
+
+void PQ_name::setNext(PQ_name *newNext)
+{
+  next = newNext;
+}
+
+
+// ---------------------- parsing support ---------------------
+// return a parameter AST list constructed as if the K&R-defined
+// function had been defined the usual way; NOTE: this imitates
+// nonterm(FakeList<ASTTypeId>*) ParameterDeclarationList in cc.gr
+// exactly because I didn't want to think hard about how to use
+// Scott's datastructures correctly as I wasted so much time on that
+// yesterday
+FakeList<ASTTypeId>* kAndR_makeParamList
+  (FakeList<PQ_name> *kAndR_params, PtrMap<const char, ASTTypeId> &declsForParams)
+{
+  if (!kAndR_params) return FakeList<ASTTypeId>::emptyList();
+  PQ_name *pqName = kAndR_params->first();
+  ASTTypeId *d = declsForParams.get(pqName->name);
+  // if it has no declaration then it is an int
+  if (!d) {
+    d = new ASTTypeId
+      (new TS_simple(pqName->loc, ST_INT),
+       new Declarator
+       (new D_name
+        (pqName->loc,
+         // I'll make a new PQ_name to be safe that we have no
+         // aliasing problems
+         new PQ_name(pqName->loc, pqName->name)),
+        NULL /*_init*/));
+  } else {
+    // mutate the location of the declaration to match that of the
+    // place where the variable is first mentioned in the list; this
+    // is only to allow cqual/tests/oldstyle2.c to pass
+    d->decl->decl->loc = pqName->loc;
+  }
+  FakeList<ASTTypeId> *list = kAndR_makeParamList(kAndR_params->butFirst(), declsForParams);
+  // FIX: why doesn't this segfault??; ah, because you can call
+  // methods on null pointers as long as they are not virtual
+  d->setNext(list->first());
+  return FakeList<ASTTypeId>::makeList(d);
+}
+
+// create a Function definition with K&R params
+Function *makeKandRdefn(SourceLoc loc, Declaration *rds, IDeclarator *id,
+                        S_compound *ds, S_compound *b)
+{
+  Function *ret = new Function (
+     rds->dflags,           // decl flags (static, extern, etc.)
+     rds->spec,             // type specifier for return value
+     new Declarator(id, NULL), // declarator with fn name, params
+     NULL,                  // ctor member inits
+     b,                     // function body statement
+     NULL                   // exception handlers
+     );
+  fixUpKandRFunctionDef(rds, id, ds);
+  return ret;
+}
+
+// convert ds to params and insert
+void fixUpKandRFunctionDef
+  (Declaration *rds, IDeclarator *id, S_compound *ds)
+{
+  // Find the declarations for these params
+  // S_compound(ASTList<Statement> stmts) for each name, build an
+  // ASTTypeId of the corresponding declarations.  Note that this
+  // may involve taking apart a declaration with multiple
+  // Declarator-s for a single DeclSpecifier.
+  PtrMap<const char, ASTTypeId> declsForParams;
+  FOREACH_ASTLIST_NC(Statement, ds->stmts, nameIter) {
+    S_decl *sdecl = nameIter.data()->asS_decl();
+    Declaration *declaration = dynamic_cast<Declaration*>(sdecl->decl);
+    xassert(declaration);
+    FAKELIST_FOREACH_NC(Declarator, declaration->decllist, dcltor) {
+      // clone TypeSpecifier and Declarator
+      ASTTypeId *atid = new ASTTypeId(declaration->spec->clone(), dcltor->clone());
+      StringRef name = dcltor->decl->getDeclaratorId()->getName();
+      declsForParams.add(name, atid);
+    }
+  }
+
+  // Find the place where the params we are building should go.
+  D_func *df = id->getD_func();
+  xassert(df);
+  xassert(!df->params);     //FakeList<ASTTypeId> *params
+
+  // Find the "parameter" list which is just the names, without
+  // types, "params" if a K&R function:
+  //   FakeList<PQ_name> *kAndR_params
+  // For each one, look up the declaration above and
+  // build a Parameter for it.
+  df->params = kAndR_makeParamList(df->kAndR_params, declsForParams);
+
+  // ****
+
+  rds->spec = NULL;           // stole it above (ownership transfer)
+  delete rds;                 // was just a carrier of dflags/spec
+}
+
+D_func *new_D_func_kandr
+  (CCLang &lang,
+   SourceLoc loc,
+   IDeclarator *base,
+   FakeList<ASTTypeId> *params,
+   CVFlags cv,
+   ExceptionSpec /*nullable*/ *exnSpec,
+   FakeList<PQ_name> *kAndR_params)
+{
+  if (lang.allowImplicitInt
+      && !filterOutImplIntFirstParam(loc, base, params)) {
+    return NULL;
+  }
+  return new D_func(loc, base, params, cv, exnSpec, kAndR_params);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/kandr.gr
===================================================================
--- vendor/elsa/current/elsa/kandr.gr	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/kandr.gr	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,429 @@
+// kandr.gr            see license.txt for copyright and terms of use
+// derived from oink.gr
+// nominal author: dsw
+
+// this is as extension module to cc.gr, to add support for
+// K&R extensions to the grammar
+
+
+// expected statistics
+option shift_reduce_conflicts 127;
+option reduce_reduce_conflicts 180;
+
+
+// this verbatim section is appended to the one in cc.gr
+verbatim {
+  #include "kandr.h"      // makeKandRdefn, etc.
+}
+
+
+// KandR stuff ****************************************************************
+
+// only allow K&R func defns at toplevel
+nonterm(TopForm*) Declaration {
+  -> k:KandRFunctionDefinition             { return new TF_func(loc, k); }
+  -> k:KandRFunctionDefinition_implInt     { return new TF_func(loc, k); }
+}
+
+nonterm(Function*) KandRFunctionDefinition {
+  // K&R function:
+
+  // return type        name/params
+  -> rds:DeclSpecifier  id:KandRDeclarator
+  //     parameters in K&R style
+         ds:KandRSimpleDeclarationSeq
+  //     body
+         b:FunctionBody
+    {
+      return makeKandRdefn(loc, rds, id, ds, b);
+    }
+}
+
+// split from above so ambiguity will bubble up to the Declaration level
+nonterm(Function*) KandRFunctionDefinition_implInt {
+  // no return type!      name/params
+  ->                      id:KandRDeclarator
+  //     parameters in K&R style
+         ds:KandRSimpleDeclarationSeq
+  //     body
+         b:FunctionBody
+    {
+      // FIX: otherwise this is a parse error; what should we do in
+      // that case?
+      xassert(lang.allowImplicitInt);
+
+      // the return type defaults to int
+      Declaration *rds = new Declaration(DF_NONE, new TS_simple(loc, ST_IMPLINT), NULL);
+      return makeKandRdefn(loc, rds, id, ds, b);
+    }
+
+  // one more, for "static" (etc.)
+  -> m:UberModifierSeq id:KandRDeclarator ds:KandRSimpleDeclarationSeq b:FunctionBody
+    {
+      xassert(lang.allowImplicitInt);
+      DeclFlags df = uberDeclFlags(m);
+      CVFlags cv = uberCVFlags(m);
+      Declaration *rds = new Declaration(df, new_TS_simple(loc, cv, ST_IMPLINT), NULL);
+      return makeKandRdefn(loc, rds, id, ds, b);
+    }
+}
+
+nonterm(S_compound*) KandRSimpleDeclarationSeq {
+  // don't allow empty, as the empty parameter list is also not
+  // allowed; Scott says to do it this way; I prevents an ambiguity
+  // with the usual C++ no-arg function declaration
+//    -> empty
+//         { return new S_compound(loc, NULL); }
+  -> s:KandRSimpleDeclaration
+    { S_compound *c = new S_compound(loc, NULL);
+      c->stmts.append(new S_decl(loc, s));
+      return c;
+    }
+  -> c:KandRSimpleDeclarationSeq s:KandRSimpleDeclaration
+       { c->stmts.append(new S_decl(loc, s)); return c; }
+}
+
+
+nonterm(Declaration*) KandRSimpleDeclaration {
+  // destructive action on 'spec'
+  //e.g.: int                x                  ;
+  -> spec:DeclSpecifier list:KandRInitDeclaratorList ";"
+       { spec->decllist = list; return spec; }
+}
+
+
+nonterm(FakeList<Declarator>*) KandRInitDeclaratorList {
+  -> d:KandRInitDeclarator
+       { return FakeList<Declarator>::makeList(d); }
+  -> d:KandRInitDeclarator "," list:KandRInitDeclaratorList
+       { d->setNext(list->first());
+         return FakeList<Declarator>::makeList(d); }
+}
+
+
+nonterm(Declarator*) KandRInitDeclarator {
+  // ambiguous:
+  //   int f(x *y);
+  // could be declaring a variable called "f" with ctor-initializer "(x*y)",
+  // or it could be declaring a function called "f" which accepts a pointer
+  // to an 'x' as a parameter
+  //
+  // another example:
+  //   int m(int (n));
+  // could be declaring a variable called "m" with ctor-initializer "int (n)"
+  // which itself is a call to the constructor for "int", or it could be
+  // declaring a function called "m" with an integer parameter called "n",
+  // the latter surrounded by a redundant set of parens
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  -> d:Declarator                       // (int)  x
+       { return new Declarator(d, NULL); }
+
+  // The whole point is to omit this possibility
+//    -> d:Declarator i:Initializer         // (int)  x = 5
+//         { return new Declarator(d, i); }
+}
+
+
+// for K&R function definitions
+nonterm(IDeclarator*) KandRDeclarator {
+  -> "*" cv:CVQualifierSeqOpt d:KandRDeclarator
+       { return new D_pointer(loc, cv, d); }
+  -> d:KandRDirectDeclarator
+       { return d; }
+}
+
+// for K&R function definitions
+nonterm(IDeclarator*) KandRDirectDeclarator {
+  fun keep(x) { return x!=NULL; }
+
+  // FIX: not sure I'm not ruling out something in the grammar that
+  // should be legal here
+//    -> n:IdExpression_no_colon_colon
+//         { return new D_name(loc, n); }
+
+  // function declarator; the return type comes from the type
+  // specifier that precedes this
+//    -> d:KandRDirectDeclarator    // name of function
+
+  // FIX: see note above
+  -> d:KandRIdExpression    // name of function
+         // Scott said don't allow the empty list
+     "(" kAndR_params:KandRIdentifierList ")"// parameters
+//       ql:QLiterals                      // qualifier literals
+//       cv:CVQualifierSeqOpt
+      { return new_D_func_kandr
+          (lang, 
+           loc,
+           d,
+           NULL/* no normal params*/,
+           CV_NONE /*cv*/,
+           NULL /*exception spec*/,
+           kAndR_params
+           );
+      }
+      
+  // sm: for in/c/k0003.c; the KandR declarator structure is
+  // pretty messed up, but when I made a few tweaks it introduced
+  // quite a few conflicts...
+  -> "(" d:KandRIdExpression ")"     // name of function, in parens
+         // Scott said don't allow the empty list
+     "(" kAndR_params:KandRIdentifierList ")"// parameters
+//       ql:QLiterals                      // qualifier literals
+//       cv:CVQualifierSeqOpt
+      { return new_D_func_kandr
+          (lang,
+           loc,
+           d,
+           NULL/* no normal params*/,
+           CV_NONE /*cv*/,
+           NULL /*exception spec*/,
+           kAndR_params
+           );
+      }
+
+  // function declarator; the return type comes from the type
+  // specifier that precedes this
+  -> d:KandRDirectDeclarator    // name of function
+     "(" params:ParameterDeclarationClause ")" // parameters
+//       cv:CVQualifierSeqOpt                      // optional "const"
+//       e:ExceptionSpecificationOpt               // optional "throw" clause
+    { return new_D_func_kandr
+        (lang,
+         loc,
+         d,
+         params,
+         CV_NONE,
+         NULL/*exception spec*/,
+         NULL/*kAndR_params*/
+         );
+    }
+
+  // sm: for in/c/k0009.c
+  -> d:KandRDirectDeclarator "[" sz:ConstantExpressionOpt "]"
+       { return new_D_array(loc, d, sz); }
+
+  // precedence grouping; must be recorded in the AST for disambiguation
+  -> "(" d:KandRDeclarator ")"
+       { return new D_grouping(loc, d); }
+}
+
+// FIX: see note above; not sure this is necessary nor that it is not
+// too strict
+nonterm(IDeclarator*) KandRIdExpression {
+  -> n:KandRIdentifier
+       { return new D_name(loc, n); }
+}
+
+//  nonterm(FakeList<StringRef>*) IdentifierListOpt {
+//    -> empty               { return FakeList<StringRef>::emptyList(); }
+//    -> il:IdentifierList   { return il; }
+//  }
+
+//  nonterm(FakeList<StringRef>*) IdentifierList {
+nonterm(FakeList<PQ_name>*) KandRIdentifierList {
+  -> i:KandRIdentifier
+       { return FakeList<PQ_name>::makeList(i); }
+  -> i:KandRIdentifier "," e:KandRIdentifierList
+       { i->setNext(e->first()); 
+         return FakeList<PQ_name>::makeList(i); }
+}
+
+
+nonterm(PQ_name*) KandRIdentifier {
+  -> i:Identifier { return new PQ_name(loc, i); }
+}
+
+// implicit-int ****************
+                            
+// modifiers that can precede a function decl/defn in C; note
+// that the only intersection with CDtorModifier is "inline"
+nonterm(UberModifiers) CFuncModifier_no_inline {
+  -> "static"                              { return UM_STATIC; }
+  -> "extern"                              { return UM_EXTERN; }
+  -> "const"                               { return UM_CONST; }
+  -> "volatile"                            { return UM_VOLATILE; }
+}
+
+nonterm(UberModifiers) CFuncModifier {
+  -> m:CFuncModifier_no_inline             { return m; }
+  -> "inline"                              { return UM_INLINE; }
+}
+
+nonterm(UberModifiers) CFuncModifierSeq {
+  -> m:CFuncModifier                       { return m; }
+  -> s:CFuncModifierSeq m:CFuncModifier    { return uberCombine(loc, s, m); }
+}
+
+nonterm(UberModifiers) CFuncModifierSeqOpt {
+  -> empty                                 { return UM_NONE; }
+  -> m:CFuncModifier                       { return m; }
+}
+
+
+// most instances of implicit-int in function definitions are
+// covered by the existing syntax for constructors; but if the
+// 'static' keyword is used, that isn't legal for ctors, so we
+// need a special rule
+nonterm(Function*) ImplIntFunctionDefinition {
+  // make it look like the existing ctor AST, since those get
+  // converted into implicit-int
+  -> m:CFuncModifier_no_inline d:Declarator b:FunctionBody
+       {
+         DeclFlags df = uberDeclFlags(m);
+         CVFlags cv = uberCVFlags(m);
+         return new Function(
+           df,                                // decl flags
+           new_TS_simple(loc, cv, ST_CDTOR),  // type specifier: ctor or dtor
+           new Declarator(d, NULL),           // declarator with fn name, params
+           NULL,                              // ctor member inits
+           b,                                 // function body statement
+           NULL                               // exception handlers
+         );
+       }
+
+  // in/k0006.c: need some more variants; I spell them out to avoid
+  // introducing too many conflicts
+  -> m1:CFuncModifier_no_inline m2:CFuncModifierSeq d:Declarator b:FunctionBody
+       {                              
+         UberModifiers m = uberCombine(loc, m1, m2);
+         DeclFlags df = uberDeclFlags(m);
+         CVFlags cv = uberCVFlags(m);
+         return new Function(
+           df,                                // decl flags
+           new_TS_simple(loc, cv, ST_CDTOR),  // type specifier: ctor or dtor
+           new Declarator(d, NULL),           // declarator with fn name, params
+           NULL,                              // ctor member inits
+           b,                                 // function body statement
+           NULL                               // exception handlers
+         );
+       }
+
+  // "inline" is the common prefix with CDtorModifierSeq; so a defn
+  // that begins with it will not cause a parser split until the next
+  // modifier is seen; if no modifier follows "inline", it will be
+  // parsed as a constructor, and later changed into implicit-int
+  -> "inline" m1:CFuncModifier_no_inline m2:CFuncModifierSeqOpt
+     d:Declarator b:FunctionBody
+       {
+         UberModifiers m = uberCombine(loc, m1, m2);
+         DeclFlags df = uberDeclFlags(m) | DF_INLINE;
+         CVFlags cv = uberCVFlags(m);
+         return new Function(
+           df,                                // decl flags
+           new_TS_simple(loc, cv, ST_CDTOR),  // type specifier: ctor or dtor
+           new Declarator(d, NULL),           // declarator with fn name, params
+           NULL,                              // ctor member inits
+           b,                                 // function body statement
+           NULL                               // exception handlers
+         );
+       }
+}
+
+nonterm(TopForm*) Declaration {
+  fun keep(x) { return x!=NULL; }
+
+  fun merge(L,R) { L->addAmbiguity(R); return L; }
+
+  // only allow implicit-int func defns at toplevel
+  -> f:ImplIntFunctionDefinition
+    { return new TF_func(loc, f); }
+
+  -> m1:UberModifierSeqOpt /*implicit-int*/ list:InitDeclaratorList ";"
+    {
+      if (!lang.allowImplicitInt) {
+        trace("cancel") << loc
+          << ": implicit-int top-level Declaration in non-implicit-int language\n";
+        return NULL;
+      }
+      return new TF_decl
+        (loc,
+         new Declaration(uberDeclFlags(m1), new TS_simple(loc, ST_IMPLINT), list));
+    }
+}
+
+
+nonterm(Declaration*) KandRSimpleDeclaration {
+  fun keep(x) { return x!=NULL; }
+
+  // I'm sure this production introduces an unhandled ambiguity,
+  // but I have not yet constructed an example...
+
+  // (in/c/dC0026.c)
+  -> "register" /*implicit-int*/ list:KandRInitDeclaratorList ";"
+     {
+       if (!lang.allowImplicitInt) {
+         trace("cancel") << loc
+           << ": implicit-int KandRSimpleDeclaration in non-implicit-int language\n";
+         return NULL;
+       }
+       return new Declaration(DF_REGISTER,
+                              new TS_simple(loc, ST_IMPLINT),
+                              list);
+     }
+}
+
+nonterm(Statement*) Statement {
+  fun keep(x) { return x!=NULL; }
+
+  -> m1:UberModifierSeq /*implicit-int*/ list:InitDeclaratorList ";"
+    {
+      if (!lang.allowImplicitInt) {
+        trace("cancel") << loc
+          << ": implicit-int statement-level Declaration in non-implicit-int language\n";
+        return NULL;
+      }
+      return new S_decl (loc,
+        new Declaration(uberDeclFlags(m1), new TS_simple(loc, ST_IMPLINT), list));
+    }
+}
+
+nonterm(ASTTypeId*) ParameterDeclaration {
+  fun keep(x) { return x!=NULL; }
+
+  -> /*implicit-int*/ d:UnqualifiedDeclarator
+    {
+      // if this isn't K&R C, throw it out
+      if (!lang.allowImplicitInt) {
+        trace("cancel") << loc
+          << ": implicit-int parameter definition in non-implicit-int language\n";
+        return NULL;
+      }
+      return new ASTTypeId
+        (new TS_simple(loc, ST_IMPLINT),
+         new Declarator(d, NULL /*init*/));
+    }
+
+  -> "register" /*implicit-int*/ d:UnqualifiedDeclarator
+    {
+      // if this isn't K&R C, throw it out
+      if (!lang.allowImplicitInt) {
+        trace("cancel") << loc
+          << ": implicit-int parameter definition in non-implicit-int language\n";
+        return NULL;
+      }
+      return new ASTTypeId
+        (new TS_simple(loc, ST_IMPLINT),
+         new Declarator(d, NULL /*init*/));
+    }
+}
+
+
+// ------ implicit int for cast expressions ------
+nonterm(Expression*) CastExpression {
+  -> "(" t:ImplicitIntTypeId ")" e:CastExpression
+       { return new E_cast(t, e); }
+}
+
+nonterm(TypeSpecifier*) ImplicitIntTypeSpecifier {
+  -> m:UberCVQualifierSeq
+       { UberModifiers k = uberCombine(loc, UM_INT, m);
+         return new_TS_simple(loc, uberCVFlags(m), uberSimpleType(loc, k)); }
+}
+
+nonterm(ASTTypeId*) ImplicitIntTypeId {
+  -> spec:ImplicitIntTypeSpecifier
+       { return new ASTTypeId(spec, new Declarator(new D_name(loc, NULL), NULL)); }
+}
+
+

Added: vendor/elsa/current/elsa/kandr.h
===================================================================
--- vendor/elsa/current/elsa/kandr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/kandr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// kandr.h
+// declarations of support functions for K&R parsing
+
+#ifndef KANDR_H
+#define KANDR_H
+
+#include "cc_ast.h"         // AST
+
+Function *makeKandRdefn(SourceLoc loc, Declaration *rds, IDeclarator *id,
+                        S_compound *ds, S_compound *b);
+void fixUpKandRFunctionDef
+  (Declaration *rds, IDeclarator *id, S_compound *ds);
+D_func *new_D_func_kandr
+  (CCLang &lang,
+   SourceLoc loc,
+   IDeclarator *base,
+   FakeList<ASTTypeId> *params,
+   CVFlags cv,
+   ExceptionSpec /*nullable*/ *exnSpec,
+   FakeList<PQ_name> *kAndR_params);
+
+#endif // KANDR_H

Added: vendor/elsa/current/elsa/lexer.cc
===================================================================
--- vendor/elsa/current/elsa/lexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/lexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,300 @@
+// lexer.cc            see license.txt for copyright and terms of use
+// code for lexer.h
+
+#include "lexer.h"       // this module
+#include "cc_lang.h"     // CCLang
+
+#include <ctype.h>       // isdigit
+#include <stdlib.h>      // atoi
+
+
+/*
+ * Note about nonseparating tokens and the 'checkForNonsep' function:
+ *
+ * To diagnose and report erroneous syntax like "0x5g", which would
+ * naively be parsed as "0x5" and "g" (two legal tokens), I divide
+ * all tokens into two classes: separating and nonseparating.
+ *
+ * Separating tokens are allowed to be adjacent to each other and
+ * to nonseparating tokens.  An example is "(".
+ *
+ * Nonseparating tokens are not allowed to be adjacent to each other.
+ * They must be separated by either whitespace, or at least one
+ * separating token.  The nonseparating tokens are identifiers,
+ * alphabetic keywords, and literals.  The lexer would of course never
+ * yield two adjacent keywords, due to maximal munch, but classifying
+ * such an event as an error is harmless.
+ *
+ * By keeping track of whether the last token yielded is separating or
+ * not, we'll see (e.g.) "0x5g" as two consecutive nonseparating tokens,
+ * and can report that as an error.
+ *
+ * The C++ standard is rather vague on this point as far as I can
+ * tell.  I haven't checked the C standard.  In the C++ standard,
+ * section 2.6 paragraph 1 states:
+ *
+ *  "There are five kinds of tokens: identifiers, keywords, literals,
+ *   operators, and other separators.  Blanks, horizontal and
+ *   vertical tabs, newlines, formfeeds, and comments (collectively,
+ *   "whitespace"), as described below, are ignored except as they
+ *   serve to separate tokens.  [Note: Some white space is required
+ *   to separate otherwise adjacent identifiers, keywords, numeric
+ *   literals, and alternative tokens containing alphabetic
+ *   characters.]"
+ *
+ * The fact that the restriction is stated only in a parenthetical note
+ * is of course nonideal.  I think the qualifier "numeric" on "literals"
+ * is a mistake, otherwise "a'b'" would be a legal token sequence.  I
+ * do not currently implement the "alternative tokens".
+ *
+ * Update: Mozilla includes things like "foo""bar", i.e. directly
+ * adjacent string literals.  Therefore I'm going to interpret (the
+ * note in) the standard literally, and take char and string literals
+ * to be separating.
+ */
+
+
+// -------------------- TokenType ---------------------
+// these aren't emitted into cc_tokens.cc because doing so would
+// make that output dependent on smbase/xassert.h
+char const *toString(TokenType type)
+{
+  xassert(NUM_TOKEN_TYPES == tokenNameTableSize);
+  xassert((unsigned)type < (unsigned)NUM_TOKEN_TYPES);
+  return tokenNameTable[type];
+}
+
+TokenFlag tokenFlags(TokenType type)
+{
+  xassert((unsigned)type < (unsigned)NUM_TOKEN_TYPES);
+  return (TokenFlag)tokenFlagTable[type];
+}
+
+
+// ------------------------ Lexer -------------------
+Lexer::Lexer(StringTable &s, CCLang &L, char const *fname)
+  : BaseLexer(s, fname),
+
+    prevIsNonsep(false),
+    prevHashLineFile(s.add(fname)),
+
+    lang(L)
+{
+  // prime this lexer with the first token
+  getTokenFunc()(this);
+}
+
+
+Lexer::Lexer(StringTable &s, CCLang &L, SourceLoc initLoc,
+             char const *buf, int len)
+  : BaseLexer(s, initLoc, buf, len),
+
+    prevIsNonsep(false),
+    prevHashLineFile(s.add(sourceLocManager->getFile(initLoc))),
+
+    lang(L)
+{
+  // do *not* prime the lexer; I think it is a mistake above, but
+  // am leaving it for now
+}
+
+
+Lexer::~Lexer()
+{}
+
+
+void Lexer::whitespace()
+{
+  BaseLexer::whitespace();
+
+  // various forms of whitespace can separate nonseparating tokens
+  prevIsNonsep = false;
+}
+
+
+// this, and 'svalTok', are out of line because I don't want the
+// yylex() function to be enormous; I want that to just have a bunch
+// of calls into these routines, which themselves can then have
+// plenty of things inlined into them
+int Lexer::tok(TokenType t)
+{
+  checkForNonsep(t);
+  updLoc();
+  sval = NULL_SVAL;     // catch mistaken uses of 'sval' for single-spelling tokens
+  return t;
+}
+
+
+int Lexer::svalTok(TokenType t)
+{
+  checkForNonsep(t);
+  updLoc();
+  sval = (SemanticValue)addString(yytext, yyleng);
+  return t;
+}
+
+
+int Lexer::alternateKeyword_tok(TokenType t)
+{
+  if (lang.isCplusplus) {
+    return tok(t);
+  }
+  else {
+    // in C mode, they are just identifiers
+    return svalTok(TOK_NAME);
+  }
+}
+
+
+// examples of recognized forms
+//   #line 4 "foo.cc"       // canonical form
+//   # 4 "foo.cc"           // "line" can be omitted
+//   # 4 "foo.cc" 1         // extra stuff is ignored
+//   # 4                    // omitted filename means "same as previous"
+void Lexer::parseHashLine(char *directive, int len)
+{
+  char *endp = directive+len;
+
+  directive++;        // skip "#"
+  if (*directive == 'l') {
+    directive += 4;   // skip "line"
+  }
+
+  // skip whitespace
+  while (*directive==' ' || *directive=='\t') {
+    directive++;
+  }
+
+  // parse the line number
+  if (!isdigit(*directive)) {
+    pp_err("malformed #line directive line number");
+    return;
+  }
+  int lineNum = atoi(directive);
+
+  // skip digits and whitespace
+  while (isdigit(*directive)) {
+    directive++;
+  }
+  while (*directive==' ' || *directive=='\t') {
+    directive++;
+  }
+
+  if (*directive == '\n') {
+    // no filename: use previous
+    srcFile->addHashLine(curLine, lineNum, prevHashLineFile);
+    return;
+  }
+
+  if (*directive != '\"') {
+    pp_err("#line directive missing leading quote on filename");
+    return;
+  }
+  directive++;
+
+  // look for trailing quote
+  char *q = directive;
+  while (q<endp && *q != '\"') {
+    q++;
+  }
+  if (*q != '\"') {
+    pp_err("#line directive missing trailing quote on filename");
+    return;
+  }
+
+  // temporarily write a NUL so we can make a StringRef
+  *q = 0;
+  StringRef fname = strtable.add(directive);
+  *q = '\"';
+
+  // remember this directive
+  srcFile->addHashLine(curLine, lineNum, fname);
+
+  // remember the filename for future #line directives that
+  // don't explicitly include one
+  prevHashLineFile = fname;
+}
+
+
+// preprocessing error: report the location information in the
+// preprocessed source, ignoring #line information
+void Lexer::pp_err(char const *msg)
+{
+  // print only line information, and subtract one because I account
+  // for whitespace (including the final newline) before processing it
+  errors++;
+  cerr << srcFile->name << ":" << (curLine-1) << ": error: " << msg << endl;
+}
+
+
+STATICDEF void Lexer::tokenFunc(LexerInterface *lex)
+{
+  Lexer *ths = static_cast<Lexer*>(lex);
+
+  // call into the flex lexer; this updates 'loc' and sets
+  // 'sval' as appropriate
+  ths->type = ths->yylex();
+}
+
+
+STATICDEF void Lexer::c_tokenFunc(LexerInterface *lex)
+{
+  // as above
+  Lexer *ths = static_cast<Lexer*>(lex);
+  ths->type = ths->yylex();
+
+  // map C++ keywords into identifiers
+  TokenType tt = (TokenType)(ths->type);
+  if (tokenFlags(tt) & TF_CPLUSPLUS) {
+    // create the lexeme corresponding to the token's spelling
+    StringRef str = ths->strtable.add(toString(tt));
+
+    // set the LexerInterface fields to yield the new token
+    ths->type = TOK_NAME;
+    ths->sval = (SemanticValue)str;
+  }
+}
+
+
+Lexer::NextTokenFunc Lexer::getTokenFunc() const
+{
+  if (lang.recognizeCppKeywords) {
+    // expected case, yield the normal tokenizer
+    return &Lexer::tokenFunc;
+  }
+  else {
+    // yield the tokenizer that maps C++ keywords into C keywords
+    return &Lexer::c_tokenFunc;
+  }
+}
+
+string Lexer::tokenDesc() const
+{
+  if (tokenFlags((TokenType)type) & TF_MULTISPELL) {
+    // for tokens with multiple spellings, decode 'sval' as a
+    // StringRef
+    //return string((StringRef)sval);
+    return stringc << toString((TokenType)type) << ": " << (StringRef)sval;
+  }
+  else {
+    // for all others, consult the static table
+    return string(toString((TokenType)type));
+  }
+}
+
+string Lexer::tokenKindDesc(int kind) const
+{
+  // static table only
+  return toString((TokenType)kind);
+}
+
+string Lexer::tokenKindDescV(int kind) const
+{
+  stringBuilder s;
+  s << toString((TokenType)kind)
+    << " (" << kind << ")";
+  return s;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/lexer.h
===================================================================
--- vendor/elsa/current/elsa/lexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/lexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,80 @@
+// lexer.h            see license.txt for copyright and terms of use
+// lexer for C and C++ source files
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "baselexer.h"      // BaseLexer
+#include "cc_tokens.h"      // TokenType
+
+// fwd decls
+class CCLang;               // cc_lang.h
+
+
+// bounds-checking functional interfaces to tables declared in cc_tokens.h
+char const *toString(TokenType type);
+TokenFlag tokenFlags(TokenType type);
+
+
+// lexer object
+class Lexer : public BaseLexer {
+private:    // data
+  bool prevIsNonsep;               // true if last-yielded token was nonseparating
+  StringRef prevHashLineFile;      // previously-seen #line directive filename
+
+public:     // data
+  CCLang &lang;                    // language options
+
+protected:  // funcs
+  // see comments at top of lexer.cc
+  void checkForNonsep(TokenType t) {
+    if (tokenFlags(t) & TF_NONSEPARATOR) {
+      if (prevIsNonsep) {
+        err("two adjacent nonseparating tokens");
+      }
+      prevIsNonsep = true;
+    }
+    else {
+      prevIsNonsep = false;
+    }
+  }
+
+  // consume whitespace
+  void whitespace();
+
+  // do everything for a single-spelling token
+  int tok(TokenType t);
+
+  // do everything for a multi-spelling token
+  int svalTok(TokenType t);
+
+  // C++ "alternate keyword" token
+  int alternateKeyword_tok(TokenType t);
+
+  // handle a #line directive
+  void parseHashLine(char *directive, int len);
+
+  // report an error in a preprocessing task
+  void pp_err(char const *msg);
+
+  FLEX_OUTPUT_METHOD_DECLS
+
+public:     // funcs
+  // make a lexer to scan the given file
+  Lexer(StringTable &strtable, CCLang &lang, char const *fname);
+  Lexer(StringTable &strtable, CCLang &lang, SourceLoc initLoc,
+        char const *buf, int len);
+  ~Lexer();
+
+  static void tokenFunc(LexerInterface *lex);
+  static void c_tokenFunc(LexerInterface *lex);
+
+  // LexerInterface funcs
+  virtual NextTokenFunc getTokenFunc() const;
+  virtual string tokenDesc() const;
+  virtual string tokenKindDesc(int kind) const;
+  string tokenKindDescV(int kind) const;
+};
+
+
+#endif // LEXER_H

Added: vendor/elsa/current/elsa/license.txt
===================================================================
--- vendor/elsa/current/elsa/license.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/license.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+The software in this directory is
+Copyright (c) 2002, Regents of the University of California
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above 
+      copyright notice, this list of conditions and the following 
+      disclaimer in the documentation and/or other materials provided 
+      with the distribution.
+
+    * Neither the name of the University of California, Berkeley nor 
+      the names of its contributors may be used to endorse or promote 
+      products derived from this software without specific prior 
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: vendor/elsa/current/elsa/lookupset.cc
===================================================================
--- vendor/elsa/current/elsa/lookupset.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/lookupset.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,263 @@
+// lookupset.cc
+// code for lookupset.h
+
+#include "lookupset.h"        // this module
+#include "variable.h"         // Variable, sameEntity
+#include "template.h"         // TemplateInfo
+#include "cc_flags.h"         // bitmapString
+
+
+char const * const lookupFlagNames[NUM_LOOKUPFLAGS] = {
+  "LF_INNER_ONLY",
+  "LF_ONLY_TYPES",
+  "LF_TYPENAME",
+  "LF_SKIP_CLASSES",
+  "LF_ONLY_NAMESPACES",
+  "LF_TYPES_NAMESPACES",
+  "LF_QUALIFIED",
+  "LF_TEMPL_PRIMARY",
+  "LF_FUNCTION_NAME",
+  "LF_DECLARATOR",
+  "LF_SELFNAME",
+  "LF_unused_value2",
+  "LF_TEMPL_PARAM",
+  "LF_SUPPRESS_ERROR",
+  "LF_SUPPRESS_NONEXIST",
+  "LF_IGNORE_USING",
+  "LF_NO_IMPL_THIS",
+  "LF_unused_value3",
+  "LF_QUERY_TAGS",
+  "LF_unused_value",
+  "LF_EXPECTING_TYPE",
+  "LF_EXPLICIT_INST",
+  "LF_ARG_DEP",
+  "LF_GET_SCOPE_ONLY",
+};
+
+
+string toString(LookupFlags f)
+{
+  // make sure I haven't added a flag without adding a string for it
+  xassert(declFlagNames[NUM_LOOKUPFLAGS-1] != NULL);
+
+  return bitmapString(f, lookupFlagNames, NUM_LOOKUPFLAGS, " ");
+}
+                                 
+// this exists in case gdb's overload resolution is broken (?)
+string toString_LF(LookupFlags f)
+{
+  return toString(f);
+}
+
+
+// vfilter: variable filter
+// implements variable-filtering aspect of the flags; the idea
+// is you never query 'variables' without wrapping the call
+// in a filter
+Variable *vfilter(Variable *v, LookupFlags flags)
+{
+  if (!v) return v;
+
+  if ((flags & LF_ONLY_TYPES) &&
+      !v->hasFlag(DF_TYPEDEF)) {
+    return NULL;
+  }
+
+  if ((flags & LF_ONLY_NAMESPACES) &&
+      !v->hasFlag(DF_NAMESPACE)) {
+    return NULL;
+  }
+
+  if ((flags & LF_TYPES_NAMESPACES) &&
+      !v->hasFlag(DF_TYPEDEF) &&
+      !v->hasFlag(DF_NAMESPACE)) {
+    return NULL;
+  }
+
+  if (!(flags & LF_SELFNAME) &&
+      v->hasFlag(DF_SELFNAME)) {
+    // the selfname is not visible b/c LF_SELFNAME not specified
+    return NULL;
+  }
+                                                        
+  if ((flags & LF_TEMPL_PARAM) &&
+      !v->isTemplateParam()) {
+    return NULL;
+  }
+
+  return v;
+}
+
+
+// --------------------- LookupSet ----------------------
+LookupSet::LookupSet()
+{}
+
+LookupSet::~LookupSet()
+{}
+
+
+LookupSet::LookupSet(LookupSet const &obj)
+{
+  copy(obj);
+}
+
+LookupSet& LookupSet::operator= (LookupSet const &obj)
+{
+  if (this != &obj) {
+    copy(obj);
+  }
+  return *this;
+}
+
+void LookupSet::copy(LookupSet const &obj)
+{
+  removeAll();
+  SObjList<Variable>::operator=(obj);
+}
+
+
+Variable *LookupSet::filter(Variable *v, LookupFlags flags)
+{
+  v = vfilter(v, flags);
+  if (v) {
+    adds(v);
+  }
+  return v;
+}
+
+
+void LookupSet::adds(Variable *v)
+{
+  if (v->isOverloaded()) {
+    SFOREACH_OBJLIST_NC(Variable, v->overload->set, iter) {
+      add(iter.data());
+    }
+  }
+  else {
+    add(v);
+  }
+}
+
+void LookupSet::add(Variable *v)
+{
+  // 2006-02-22: Trend-prof says this routine is exhibiting quadratic
+  // performance.  That is, not only is the algorithm obviously
+  // quadratic in the worst case, it's exhibiting that in the typical
+  // case too.  But the constant factor is reasonably small, and
+  // optimizing it is nontrivial, so for now I'll hold off.  If I can
+  // ever be convinced that 'sameEntity' is behaving correctly, then
+  // I'll consider adding a hash consistent with it.
+
+  // is 'v' already present?
+  SFOREACH_OBJLIST(Variable, *this, iter) {
+    if (sameEntity(v, iter.data())) {
+      return;      // already present
+    }
+  }
+
+  // not already present, add it
+  prepend(v);
+}
+
+
+void LookupSet::removeAllButOne()
+{
+  while (count() > 1) {
+    removeFirst();
+  }
+}
+
+
+void LookupSet::removeNonTemplates()
+{
+  SObjListMutator<Variable> mut(*this);
+  while (!mut.isDone()) {
+    Variable *v = mut.data();
+
+    if (v->isTemplate()) {
+      mut.adv();     // keep it
+      continue;
+    }
+    
+    // 2005-04-17: in/t0055.cc:  The context is a lookup that has
+    // template arguments.  It might be that we found a selfname in
+    // the scope of a template class instantiation; but if template
+    // args are used, then the user is intending to apply args to the
+    // original template.  (The code here is an approximation of what
+    // is specified in 14.6p2b.)
+    if (v->hasFlag(DF_SELFNAME)) {
+      // argh.. my selfnames do not have proper template info, so
+      // I have to go through the type (TODO: fix this)
+      if (v->type->isCompoundType()) {
+        CompoundType *ct = v->type->asCompoundType();
+        TemplateInfo *tinfo = ct->templateInfo();
+        if (tinfo != NULL &&
+            tinfo->isCompleteSpecOrInstantiation()) {
+          // replace 'v' with a pointer to the template primary
+          mut.dataRef() = tinfo->getPrimary()->var;
+          mut.adv();
+          continue;
+        }
+      }
+
+      // (in/t0501.cc)
+      else if (v->type->isPseudoInstantiation()) {
+        PseudoInstantiation *pi = v->type->asPseudoInstantiation();
+        mut.dataRef() = pi->primary->typedefVar;
+        mut.adv();
+        continue;
+      }
+
+      else {
+        xfailure("unexpected DF_SELFNAME variable type");
+      }
+    }
+
+    mut.remove();    // filter it out
+  }
+}
+
+
+string LookupSet::asString() const
+{
+  if (isEmpty()) {
+    return "";
+  }
+
+  // are all the names in the same scope?
+  Scope *scope = firstC()->scope;
+  SFOREACH_OBJLIST(Variable, *this, iter1) {
+    Variable const *v = iter1.data();
+
+    if (v->scope != scope) {
+      scope = NULL;
+    }
+  }
+
+  stringBuilder sb;
+
+  SFOREACH_OBJLIST(Variable, *this, iter2) {
+    Variable const *v = iter2.data();
+
+    sb << "  " << v->loc << ": ";
+    if (scope) {
+      sb << v->toString();      // all same scope, no need to prin it
+    }
+    else {
+      sb << v->toQualifiedString();
+    }
+    sb << "\n";
+  }
+
+  return sb;
+}
+
+
+void LookupSet::gdb() const
+{
+  cout << asString();
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/lookupset.h
===================================================================
--- vendor/elsa/current/elsa/lookupset.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/lookupset.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,102 @@
+// lookupset.h
+// LookupSet, a set of lookup candidates
+
+#ifndef LOOKUPSET_H
+#define LOOKUPSET_H
+
+#include "sobjlist.h"        // SObjList
+#include "str.h"             // string
+
+class Variable;              // variable.h
+
+
+// variable lookup sometimes has complicated exceptions or
+// special cases, so I'm folding lookup options into one value
+enum LookupFlags {
+  LF_NONE              = 0,
+  LF_INNER_ONLY        = 0x00000001,   // only look in the innermost scope
+  LF_ONLY_TYPES        = 0x00000002,   // ignore (skip over) non-type names
+  LF_TYPENAME          = 0x00000004,   // user used 'typename' keyword
+  LF_SKIP_CLASSES      = 0x00000008,   // skip class scopes
+  LF_ONLY_NAMESPACES   = 0x00000010,   // ignore non-namespace names
+  LF_TYPES_NAMESPACES  = 0x00000020,   // ignore non-type, non-namespace names
+  LF_QUALIFIED         = 0x00000040,   // context is a qualified lookup
+  LF_TEMPL_PRIMARY     = 0x00000080,   // return template primary rather than instantiating it
+  LF_FUNCTION_NAME     = 0x00000100,   // looking up the name at a function call site
+  LF_DECLARATOR        = 0x00000200,   // context is a declarator name lookup; for templates, this means to pick the primary or a specialization, but don't instantiate
+  LF_SELFNAME          = 0x00000400,   // the DF_SELFNAME is visible
+  LF_unused_value2     = 0x00000800,   // (available)
+  LF_TEMPL_PARAM       = 0x00001000,   // return only template parameter/argument names
+  LF_SUPPRESS_ERROR    = 0x00002000,   // during lookup, don't emit errors
+  LF_SUPPRESS_NONEXIST = 0x00004000,   // suppress "does not exist" errors
+  LF_IGNORE_USING      = 0x00008000,   // 3.4.2p3: ignore using-directives
+  LF_NO_IMPL_THIS      = 0x00010000,   // do not insert implicit 'this->'
+  LF_unused_value3     = 0x00020000,   // (available)
+  LF_QUERY_TAGS        = 0x00040000,   // look in Scope::typeTags instead of Scope::variables
+  LF_unused_value      = 0x00080000,   // (available for a new use)
+  LF_EXPECTING_TYPE    = 0x00100000,   // do not apply template args to a non-type
+  LF_EXPLICIT_INST     = 0x00200000,   // the context is a TF_explicitInst
+  LF_ARG_DEP           = 0x00400000,   // looking in argument-dependent "associated scopes"
+  LF_GET_SCOPE_ONLY    = 0x00800000,   // if looking up A::B::C, just look up A::B
+
+  // flag combination for looking up names that precede "::" (3.4.3p1);
+  // this is used for the new lookup mechanism (Env::lookupPQ, etc.)
+  LF_QUALIFIER_LOOKUP  = LF_TYPES_NAMESPACES | LF_SELFNAME,
+
+  LF_ALL_FLAGS         = 0x00FFFFFF,   // bitwise OR of all flags
+  NUM_LOOKUPFLAGS      = 24            // # of bits set to 1 in LF_ALL_FLAGS
+};
+
+extern char const * const lookupFlagNames[NUM_LOOKUPFLAGS];
+string toString(LookupFlags flags);
+string toString_LF(LookupFlags flags);
+
+ENUM_BITWISE_OPS(LookupFlags, LF_ALL_FLAGS)     // smbase/macros.h
+
+
+// filter a Variable w.r.t. a given set of flags, returning NULL
+// if the Variable does not pass through the filter  
+Variable *vfilter(Variable *v, LookupFlags flags);
+
+
+// set of lookup candidates; equivalence classes are as identified
+// by 'sameEntity' (declared in variable.h)
+class LookupSet : public SObjList<Variable> {
+private:     // disallowed
+  void operator== (LookupSet&);
+
+public:
+  LookupSet();
+  ~LookupSet();
+  
+  // copy list contents
+  LookupSet(LookupSet const &obj);
+  LookupSet& operator= (LookupSet const &obj);
+  void copy(LookupSet const &obj);
+
+  // like vfilter, but also accumulate the Variable in the set
+  Variable *filter(Variable *v, LookupFlags flags);
+
+  // add 'v' to a candidate set, such that the set has exactly one
+  // entry for each unique entity; this breaks apart 'v' if it is
+  // an overload set and enters each overloaded entity separately
+  void adds(Variable *v);
+
+  // same as above except add 'v' itself, ignoring whether it
+  // is an overload set
+  void add(Variable *v);
+  
+  // throw away all the entries except for one; this is used for
+  // error recovery
+  void removeAllButOne();
+  
+  // remove any non-templates from the set
+  void removeNonTemplates();
+  
+  // construct a candidate list, one per line, indented
+  string asString() const;
+  void gdb() const;
+};
+
+
+#endif // LOOKUPSET_H

Added: vendor/elsa/current/elsa/main.cc
===================================================================
--- vendor/elsa/current/elsa/main.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/main.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,808 @@
+// main.cc            see license.txt for copyright and terms of use
+// entry-point module for a program that parses C++
+
+#include <iostream.h>     // cout
+#include <stdlib.h>       // exit, getenv, abort
+#include <fstream.h>      // ofstream
+
+#include "trace.h"        // traceAddSys
+#include "parssppt.h"     // ParseTreeAndTokens, treeMain
+#include "srcloc.h"       // SourceLocManager
+#include "ckheap.h"       // malloc_stats
+#include "cc_env.h"       // Env
+#include "cc_ast.h"       // C++ AST (r)
+#include "cc_ast_aux.h"   // class LoweredASTVisitor
+#include "cc_lang.h"      // CCLang
+#include "parsetables.h"  // ParseTables
+#include "cc_print.h"     // PrintEnv
+#include "cc.gr.gen.h"    // CCParse
+#include "nonport.h"      // getMilliseconds
+#include "ptreenode.h"    // PTreeNode
+#include "ptreeact.h"     // ParseTreeLexer, ParseTreeActions
+#include "sprint.h"       // structurePrint
+#include "strtokp.h"      // StrtokParse
+#include "smregexp.h"     // regexpMatch
+#include "cc_elaborate.h" // ElabVisitor
+#include "integrity.h"    // IntegrityVisitor
+#include "xml_file_writer.h" // XmlFileWriter
+#include "xml_reader.h"   // xmlDanglingPointersAllowed
+#include "xml_do_read.h"  // xmlDoRead()
+#include "xml_type_writer.h" // XmlTypeWriter
+
+// little check: is it true that only global declarators
+// ever have Declarator::type != Declarator::var->type?
+// .. no, because it's true for class members too ..
+// .. it's also true of arrays declared [] but then inited ..
+// .. finally, it's true of parameters whose types get
+//    normalized as per cppstd 8.3.5 para 3; I didn't include
+//    that case below because there's no easy way to test for it ..
+// Intended to be used with LoweredASTVisitor
+class DeclTypeChecker : private ASTVisitor {
+public:
+  LoweredASTVisitor loweredVisitor; // use this as the argument for traverse()
+
+  int instances;
+
+public:
+  DeclTypeChecker()
+    : loweredVisitor(this)
+    , instances(0)
+  {}
+  virtual ~DeclTypeChecker() {}
+
+  virtual bool visitDeclarator(Declarator *obj);
+};
+
+bool DeclTypeChecker::visitDeclarator(Declarator *obj)
+{
+  if (obj->type != obj->var->type &&
+      !(obj->var->flags & (DF_GLOBAL | DF_MEMBER)) &&
+      !obj->type->isArrayType()) {
+    instances++;
+    cout << toString(obj->var->loc) << ": " << obj->var->name
+         << " has type != var->type, but is not global or member or array\n";
+  }
+  return true;
+}
+
+
+// this scans the AST for E_variables, and writes down the locations
+// to which they resolved; it's helpful for writing tests of name and
+// overload resolution
+class NameChecker : public ASTVisitor {
+public:
+  // accumulates the results
+  stringBuilder sb;
+
+public:
+  NameChecker() {}
+
+  virtual bool visitExpression(Expression *obj)
+  {
+    Variable *v = NULL;
+    if (obj->isE_variable()) {
+      v = obj->asE_variable()->var;
+    }
+    else if (obj->isE_fieldAcc()) {
+      v = obj->asE_fieldAcc()->field;
+    }
+
+    // this output format is designed to minimize the effect of
+    // changes to unrelated details
+    if (v
+        && !streq("__testOverload", v->name)
+        && !streq("dummy",          v->name)
+        && !streq("__other",        v->name) // "__other": for inserted elaboration code
+        && !streq("this",           v->name) // dsw: not sure why "this" is showing up
+        && !streq("operator=",      v->name) // an implicitly defined member of every class
+        && v->name[0]!='~'                   // don't print dtors
+        ) {
+      sb << " " << v->name << "=" << sourceLocManager->getLine(v->loc);
+    }
+
+    return true;
+  }
+};
+
+
+void if_malloc_stats()
+{
+  if (tracingSys("malloc_stats")) {
+    malloc_stats();
+  }
+}
+
+
+class SectionTimer {
+  long start;
+  long &elapsed;
+
+public:
+  SectionTimer(long &e)
+    : start(getMilliseconds()),
+      elapsed(e)
+  {}
+  ~SectionTimer()
+  {
+    elapsed += getMilliseconds() - start;
+  }
+};
+
+
+void handle_xBase(Env &env, xBase &x)
+{
+  // typically an assertion failure from the tchecker; catch it here
+  // so we can print the errors, and something about the location
+  env.errors.print(cout);
+  cout << x << endl;
+  cout << "Failure probably related to code near " << env.locStr() << endl;
+
+  // print all the locations on the scope stack; this is sometimes
+  // useful when the env.locStr refers to some template code that
+  // was instantiated from somewhere else
+  //
+  // (unfortunately, env.instantiationLocStack isn't an option b/c
+  // it will have been cleared by the automatic invocation of
+  // destructors unwinding the stack...)
+  cout << "current location stack:\n";
+  cout << env.locationStackString();
+
+  // I changed from using exit(4) here to using abort() because
+  // that way the multitest.pl script can distinguish them; the
+  // former is reserved for orderly exits, whereas signals (like
+  // SIGABRT) mean that something went really wrong
+  abort();
+}
+
+
+// this is a dumb way to organize argument processing...
+char *myProcessArgs(int argc, char **argv, char const *additionalInfo)
+{
+  // remember program name
+  char const *progName = argv[0];
+
+  // process args
+  while (argc >= 2) {
+    if (traceProcessArg(argc, argv)) {
+      continue;
+    }
+    else if (0==strcmp(argv[1], "-xc")) {
+      // treat this as a synonym for "-tr c_lang"
+      traceAddSys("c_lang");
+      argv++;
+      argc--;
+    }
+    else if (0==strcmp(argv[1], "-w")) {
+      // synonym for -tr nowarnings
+      traceAddSys("nowarnings");
+      argv++;
+      argc--;
+    }
+    else {
+      break;     // didn't find any more options
+    }
+  }
+
+  if (argc != 2) {
+    cout << "usage: " << progName << " [options] input-file\n"
+            "  options:\n"
+            "    -tr <flags>:       turn on given tracing flags (comma-separated)\n"
+         << (additionalInfo? additionalInfo : "");
+    exit(argc==1? 0 : 2);    // error if any args supplied
+  }
+
+  return argv[1];
+}
+
+
+void doit(int argc, char **argv)
+{
+  // I think this is more noise than signal at this point
+  xBase::logExceptions = false;
+
+  traceAddSys("progress");
+  //traceAddSys("parse-tree");
+
+  if_malloc_stats();
+
+  SourceLocManager mgr;
+
+  // string table for storing parse tree identifiers
+  StringTable strTable;
+
+  // parsing language options
+  CCLang lang;
+  lang.GNU_Cplusplus();
+
+
+  // ------------- process command-line arguments ---------
+  char const *inputFname = myProcessArgs
+    (argc, argv,
+     "\n"
+     "  general behavior flags:\n"
+     "    c_lang             use C language rules (default is C++)\n"
+     "    nohashline         ignore #line when reporting locations\n"
+     "\n"
+     "  options to stop after a certain stage:\n"
+     "    stopAfterParse     stop after parsing\n"
+     "    stopAfterTCheck    stop after typechecking\n"
+     "    stopAfterElab      stop after semantic elaboration\n"
+     "\n"
+     "  output options:\n"
+     "    parseTree          make a parse tree and print that, only\n"
+     "    printAST           print AST after parsing\n"
+     "    printTypedAST      print AST with type info\n"
+     "    printElabAST       print AST after semantic elaboration\n"
+     "    prettyPrint        echo input as pretty-printed C++\n"
+     "    xmlPrintAST        print AST as XML\n"
+     "\n"
+     "  debugging output:\n"
+     "    malloc_stats       print malloc stats every so often\n"
+     "    env                print as variables are added to the environment\n"
+     "    error              print as errors are accumulated\n"
+     "    overload           print details of overload resolution\n"
+     "\n"
+     "  (grep in source for \"trace\" to find more obscure flags)\n"
+     "");
+
+  if (tracingSys("printAsML")) {
+    Type::printAsML = true;
+  }
+
+  // FIX: dsw: couldn't we put dashes or something in here to break up
+  // the word?
+  if (tracingSys("nohashline")) {
+    sourceLocManager->useHashLines = false;
+  }
+
+  if (tracingSys("tolerateHashlineErrors")) {
+    sourceLocManager->tolerateHashlineErrors = true;
+  }
+
+  if (tracingSys("no-orig-offset")) {
+    sourceLocManager->useOriginalOffset = false;
+  }
+
+  if (tracingSys("ansi")) {
+    lang.ANSI_Cplusplus();
+  }
+
+  if (tracingSys("ansi_c")) {
+    lang.ANSI_C89();
+  }
+
+  if (tracingSys("ansi_c99")) {
+    lang.ANSI_C99();
+  }
+
+  if (tracingSys("c_lang")) {
+    lang.GNU_C();
+  }
+
+  if (tracingSys("gnu_c89")) {
+    lang.ANSI_C89();
+    lang.GNU_C_extensions();
+  }
+
+  if (tracingSys("gnu_kandr_c_lang")) {
+    lang.GNU_KandR_C();
+    #ifndef KANDR_EXTENSION
+      xfatal("gnu_kandr_c_lang option requires the K&R module (./configure -kandr=yes)");
+    #endif
+  }
+
+  if (tracingSys("gnu2_kandr_c_lang")) {
+    lang.GNU2_KandR_C();
+    #ifndef KANDR_EXTENSION
+      xfatal("gnu2_kandr_c_lang option requires the K&R module (./configure -kandr=yes)");
+    #endif
+  }
+
+  if (tracingSys("test_xfatal")) {
+    xfatal("this is a test error message");
+  }
+
+  if (tracingSys("msvcBugs")) {
+    lang.MSVC_bug_compatibility();
+  }
+
+  if (!tracingSys("nowarnings")) {
+    lang.enableAllWarnings();
+  }
+
+  if (tracingSys("templateDebug")) {
+    // predefined set of tracing flags I've been using while debugging
+    // the new templates implementation
+    traceAddSys("template");
+    traceAddSys("error");
+    traceAddSys("scope");
+    traceAddSys("templateParams");
+    traceAddSys("templateXfer");
+    traceAddSys("prettyPrint");
+    traceAddSys("xmlPrintAST");
+    traceAddSys("topform");
+  }
+
+  if (tracingSys("only_works_on_32bit") &&
+      sizeof(long) != 4) {
+    // we are running a regression test, and the testcase is known to
+    // fail due to dependence on architecture parameters, so skip it
+    cout << "skipping test b/c this is not a 32-bit architecture\n";
+    exit(0);
+  }
+
+  // dump out the lang settings if the user wants them
+  if (tracingSys("printLang")) {
+    cout << "language settings:\n";
+    cout << lang.toString();
+    cout << endl;
+  }
+  if (tracingSys("printTracers")) {
+    cout << "tracing flags:\n\t";
+    printTracers(std::cout, "\n\t");
+    cout << endl;
+  }
+
+  // --------------- parse --------------
+  TranslationUnit *unit;
+
+  // dsw: I needed this to persist past typechecking, so I moved it
+  // out here.  Feel free to refactor.
+  ArrayStack<Variable*> madeUpVariables;
+  ArrayStack<Variable*> builtinVars;
+
+  int parseWarnings = 0;
+  long parseTime = 0;
+  if (tracingSys("parseXml")) {
+    if (tracingSys("parseXml-no-danglingPointers")) {
+      xmlDanglingPointersAllowed = false;
+    }
+    unit = xmlDoRead(strTable, inputFname);
+    if (!unit) return;
+  }
+  else {
+    SectionTimer timer(parseTime);
+    SemanticValue treeTop;
+    ParseTreeAndTokens tree(lang, treeTop, strTable, inputFname);
+
+    // grab the lexer so we can check it for errors (damn this
+    // 'tree' thing is stupid..)
+    Lexer *lexer = dynamic_cast<Lexer*>(tree.lexer);
+    xassert(lexer);
+
+    CCParse *parseContext = new CCParse(strTable, lang);
+    tree.userAct = parseContext;
+
+    traceProgress(2) << "building parse tables from internal data\n";
+    ParseTables *tables = parseContext->makeTables();
+    tree.tables = tables;
+
+    maybeUseTrivialActions(tree);
+
+    if (tracingSys("parseTree")) {
+      // make some helpful aliases
+      LexerInterface *underLexer = tree.lexer;
+      UserActions *underAct = parseContext;
+
+      // replace the lexer and parser with parse-tree-building versions
+      tree.lexer = new ParseTreeLexer(underLexer, underAct);
+      tree.userAct = new ParseTreeActions(underAct, tables);
+
+      // 'underLexer' and 'tree.userAct' will be leaked.. oh well
+    }
+
+    if (!toplevelParse(tree, inputFname)) {
+      exit(2); // parse error
+    }
+
+    // check for parse errors detected by the context class
+    if (parseContext->errors || lexer->errors) {
+      exit(2);
+    }
+    parseWarnings = lexer->warnings + parseContext->warnings;
+
+    if (tracingSys("parseTree")) {
+      // the 'treeTop' is actually a PTreeNode pointer; print the
+      // tree and bail
+      PTreeNode *ptn = (PTreeNode*)treeTop;
+      ptn->printTree(cout, PTreeNode::PF_EXPAND);
+      return;
+    }
+
+    // treeTop is a TranslationUnit pointer
+    unit = (TranslationUnit*)treeTop;
+
+    //unit->debugPrint(cout, 0);
+
+    delete parseContext;
+    delete tables;
+  }
+
+  checkHeap();
+
+  // print abstract syntax tree
+  if (tracingSys("printAST")) {
+    unit->debugPrint(cout, 0);
+  }
+
+  //if (unit) {     // when "-tr trivialActions" it's NULL...
+  //  cout << "ambiguous nodes: " << numAmbiguousNodes(unit) << endl;
+  //}
+
+  if (tracingSys("stopAfterParse")) {
+    return;
+  }
+
+
+  // ---------------- typecheck -----------------
+  BasicTypeFactory tfac;
+  long tcheckTime = 0;
+  if (tracingSys("no-typecheck")) {
+    cout << "no-typecheck" << endl;
+  } else {
+    SectionTimer timer(tcheckTime);
+    Env env(strTable, lang, tfac, madeUpVariables, builtinVars, unit);
+    try {
+      env.tcheckTranslationUnit(unit);
+    }
+    catch (XUnimp &x) {
+      HANDLER();
+
+      // relay to handler in main()
+      cout << "in code near " << env.locStr() << ":\n";
+      throw;
+    }
+    catch (x_assert &x) {
+      HANDLER();
+
+      if (env.errors.hasFromNonDisambErrors()) {
+        if (tracingSys("expect_confused_bail")) {
+          cout << "got the expected confused/bail\n";
+          exit(0);
+        }
+
+        // The assertion failed only after we encountered and diagnosed
+        // at least one real error in the input file.  Therefore, the
+        // assertion might simply have been caused by a failure of the
+        // error recovery code to fully restore all invariants (which is
+        // often difficult).  So, we'll admit to being "confused", but
+        // not to the presence of a bug in Elsa (which is what a failed
+        // assertion otherwise nominally means).
+        //
+        // The error message is borrowed from gcc; I wouldn't be
+        // surprised to discover they use a similar technique to decide
+        // when to emit the same message.
+        //
+        // The reason I do not put the assertion failure message into
+        // this one is I don't want it showing up in the output where
+        // Delta might see it.  If I am intending to minimize an assertion
+        // failure, it's no good if Delta introduces an error.
+        env.error("confused by earlier errors, bailing out");
+        env.errors.print(cout);
+        exit(4);
+      }
+
+      if (tracingSys("expect_xfailure")) {
+        cout << "got the expected xfailure\n";
+        exit(0);
+      }
+
+      // if we don't have a basis for reducing severity, pass this on
+      // to the normal handler
+      handle_xBase(env, x);
+    }
+    catch (xBase &x) {
+      HANDLER();
+      handle_xBase(env, x);
+    }
+
+    int numErrors = env.errors.numErrors();
+    int numWarnings = env.errors.numWarnings() + parseWarnings;
+
+    // do this now so that 'printTypedAST' will include CFG info
+    #ifdef CFG_EXTENSION
+    // A possible TODO is to do this right after each function is type
+    // checked.  However, in the current design, that means physically
+    // inserting code into Function::tcheck (ifdef'd of course).  A way
+    // to do it better would be to have a general post-function-tcheck
+    // interface that analyses could hook in to.  That could be augmented
+    // by a parsing mode that parsed each function, analyzed it, and then
+    // immediately discarded its AST.
+    if (numErrors == 0) {
+      numErrors += computeUnitCFG(unit);
+    }
+    #endif // CFG_EXTENSION
+
+    // print abstract syntax tree annotated with types
+    if (tracingSys("printTypedAST")) {
+      unit->debugPrint(cout, 0);
+    }
+
+    // structural delta thing
+    if (tracingSys("structure")) {
+      structurePrint(unit);
+    }
+
+    if (numErrors==0 && tracingSys("secondTcheck")) {
+      // this is useful to measure the cost of disambiguation, since
+      // now the tree is entirely free of ambiguities
+      traceProgress() << "beginning second tcheck...\n";
+      Env env2(strTable, lang, tfac, madeUpVariables, builtinVars, unit);
+      unit->tcheck(env2);
+      traceProgress() << "end of second tcheck\n";
+    }
+
+    // print errors and warnings
+    env.errors.print(cout);
+
+    cout << "typechecking results:\n"
+         << "  errors:   " << numErrors << "\n"
+         << "  warnings: " << numWarnings << "\n";
+
+    if (numErrors != 0) {
+      exit(4);
+    }
+
+    // lookup diagnostic
+    if (env.collectLookupResults.length()) {
+      // scan AST
+      NameChecker nc;
+      nc.sb << "collectLookupResults";
+      unit->traverse(nc);
+
+      // compare to given text
+      if (streq(env.collectLookupResults, nc.sb)) {
+        // ok
+      }
+      else {
+        cout << "collectLookupResults do not match:\n"
+             << "  source: " << env.collectLookupResults << "\n"
+             << "  tcheck: " << nc.sb << "\n"
+             ;
+        exit(4);
+      }
+    }
+  }
+
+  // ---------------- integrity checking ----------------
+  long integrityTime = 0;
+  {
+    SectionTimer timer(integrityTime);
+
+    // check AST integrity
+    IntegrityVisitor ivis;
+    unit->traverse(ivis);
+
+    // check that the AST is a tree *and* that the lowered AST is a
+    // tree; only do this *after* confirming that tcheck finished
+    // without errors
+    if (tracingSys("treeCheck")) {
+      long start = getMilliseconds();
+      LoweredIsTreeVisitor treeCheckVisitor;
+      unit->traverse(treeCheckVisitor.loweredVisitor);
+      traceProgress() << "done with tree check 1 ("
+                      << (getMilliseconds() - start)
+                      << " ms)\n";
+    }
+
+    // check an expected property of the annotated AST
+    if (tracingSys("declTypeCheck") || getenv("declTypeCheck")) {
+      DeclTypeChecker vis;
+      unit->traverse(vis.loweredVisitor);
+      cout << "instances of type != var->type: " << vis.instances << endl;
+    }
+
+    if (tracingSys("stopAfterTCheck")) {
+      return;
+    }
+  }
+
+  // ----------------- elaboration ------------------
+  long elaborationTime = 0;
+  if (tracingSys("no-elaborate")) {
+    cout << "no-elaborate" << endl;
+  }
+  else {
+    SectionTimer timer(elaborationTime);
+
+    ElabVisitor vis(strTable, tfac, unit);
+
+    if (!lang.isCplusplus) {
+      // do only the C elaboration activities
+      vis.activities = EA_C_ACTIVITIES;
+    }
+
+    // if we are going to pretty print, then we need to retain defunct children
+    if (tracingSys("prettyPrint")
+        // dsw: I don't know if this is right, but printing the xml
+        // AST kind of resembles pretty-printing the AST; fix this if
+        // it is wrong
+        || tracingSys("xmlPrintAST")
+        ) {
+      vis.cloneDefunctChildren = true;
+    }
+
+    // do elaboration
+    unit->traverse(vis.loweredVisitor);
+
+    // print abstract syntax tree annotated with types
+    if (tracingSys("printElabAST")) {
+      unit->debugPrint(cout, 0);
+    }
+    if (tracingSys("stopAfterElab")) {
+      return;
+    }
+  }
+
+  // mark "real" (non-template) variables as such
+  if (!tracingSys("parseXml")) {
+    // mark "real" (non-template) variables as such
+    MarkRealVars markReal;
+    visitVarsF(builtinVars, markReal);
+    visitRealVarsF(unit, markReal);
+  }
+
+  // more integrity checking
+  {
+    SectionTimer timer(integrityTime);
+
+    // check that the AST is a tree *and* that the lowered AST is a
+    // tree (do this *after* elaboration!)
+    if (tracingSys("treeCheck")) {
+      long start = getMilliseconds();
+      LoweredIsTreeVisitor treeCheckVisitor;
+      unit->traverse(treeCheckVisitor.loweredVisitor);
+      traceProgress() << "done with tree check 2 ("
+                      << (getMilliseconds() - start)
+                      << " ms)\n";
+    }
+  }
+
+  // dsw: pretty printing
+  if (tracingSys("prettyPrint")) {
+    traceProgress() << "dsw pretty print...\n";
+    OStreamOutStream out0(cout);
+    CodeOutStream codeOut(out0);
+    CTypePrinter typePrinter;
+    PrintEnv env(typePrinter, &codeOut);
+    cout << "---- START ----" << endl;
+    cout << "// -*-c++-*-" << endl;
+    unit->print(env);
+    codeOut.finish();
+    cout << "---- STOP ----" << endl;
+    traceProgress() << "dsw pretty print... done\n";
+  }
+
+  // dsw: xml printing of the raw ast
+  if (tracingSys("xmlPrintAST")) {
+    traceProgress() << "dsw xml print...\n";
+    bool indent = tracingSys("xmlPrintAST-indent");
+    int depth = 0;              // shared depth counter between printers
+    cout << "---- START ----" << endl;
+
+    // serialize Files
+    IdentityManager idmgr;
+    XmlFileWriter fileXmlWriter(idmgr, &cout, depth, indent, NULL);
+    fileXmlWriter.toXml(sourceLocManager->serializationOnly_get_files());
+
+    // serialize AST and maybe Types
+    if (tracingSys("xmlPrintAST-types")) {
+      IdentityManager idmgr;
+      XmlTypeWriter xmlTypeVis( idmgr, (ASTVisitor*)NULL, &cout, depth, indent, NULL );
+      XmlTypeWriter_AstVisitor xmlVis_Types(xmlTypeVis, cout, depth, indent);
+      xmlTypeVis.astVisitor = &xmlVis_Types;
+      ASTVisitor *vis = &xmlVis_Types;
+      LoweredASTVisitor loweredXmlVis(&xmlVis_Types); // might not be used
+      if (tracingSys("xmlPrintAST-lowered")) {
+        vis = &loweredXmlVis;
+      }
+      unit->traverse(*vis);
+    } else {
+      IdentityManager idmgr;
+      XmlAstWriter_AstVisitor xmlVis(cout, idmgr, depth, indent);
+      ASTVisitor *vis = &xmlVis;
+      LoweredASTVisitor loweredXmlVis(&xmlVis); // might not be used
+      if (tracingSys("xmlPrintAST-lowered")) {
+        vis = &loweredXmlVis;
+      }
+      unit->traverse(*vis);
+    }
+
+    cout << endl;
+    cout << "---- STOP ----" << endl;
+    traceProgress() << "dsw xml print... done\n";
+  }
+
+  // test AST cloning
+  if (tracingSys("testClone")) {
+    TranslationUnit *u2 = unit->clone();
+
+    if (tracingSys("cloneAST")) {
+      cout << "------- cloned AST --------\n";
+      u2->debugPrint(cout, 0);
+    }
+
+    if (tracingSys("cloneCheck")) {
+      ArrayStack<Variable*> madeUpVariables2;
+      ArrayStack<Variable*> builtinVars2;
+      // dsw: I hope you intend that I should use the cloned TranslationUnit
+      Env env3(strTable, lang, tfac, madeUpVariables2, builtinVars2, u2);
+      u2->tcheck(env3);
+
+      if (tracingSys("cloneTypedAST")) {
+        cout << "------- cloned typed AST --------\n";
+        u2->debugPrint(cout, 0);
+      }
+
+      if (tracingSys("clonePrint")) {
+        OStreamOutStream out0(cout);
+        CodeOutStream codeOut(out0);
+        CTypePrinter typePrinter;
+        PrintEnv penv(typePrinter, &codeOut);
+        cout << "---- cloned pretty print ----" << endl;
+        u2->print(penv);
+        codeOut.finish();
+      }
+    }
+  }
+
+  // test debugPrint but send the output to /dev/null (basically just
+  // make sure it doesn't segfault or abort)
+  if (tracingSys("testDebugPrint")) {
+    ofstream devnull("/dev/null");
+    unit->debugPrint(devnull, 0);
+  }
+
+  cout << "parse=" << parseTime << "ms"
+       << " tcheck=" << tcheckTime << "ms"
+       << " integ=" << integrityTime << "ms"
+       << " elab=" << elaborationTime << "ms"
+       << "\n"
+       ;
+
+  //traceProgress() << "cleaning up...\n";
+
+  //malloc_stats();
+
+  // delete the tree
+  // (currently this doesn't do very much because FakeLists are
+  // non-owning, so I won't pretend it does)
+  //delete unit;
+
+  strTable.clear();
+
+  //checkHeap();
+  //malloc_stats();
+}
+
+int main(int argc, char **argv)
+{
+  try {
+    doit(argc, argv);
+  }
+  catch (XUnimp &x) {
+    HANDLER();
+    cout << x << endl;
+
+    // don't consider this the same as dying on an assertion failure;
+    // I want to have tests in regrtest that are "expected" to fail
+    // for the reason that they use unimplemented language features
+    return 10;
+  }
+  catch (XFatal &x) {
+    HANDLER();
+
+    // similar to XUnimp
+    cout << x << endl;
+    return 10;
+  }
+  catch (xBase &x) {
+    HANDLER();
+    cout << x << endl;
+    abort();
+  }
+
+  //malloc_stats();
+
+  return 0;
+}

Added: vendor/elsa/current/elsa/make-token-files
===================================================================
--- vendor/elsa/current/elsa/make-token-files	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/make-token-files	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,223 @@
+#!/usr/bin/perl -w
+# see usage string below
+
+use strict 'subs';
+
+sub usage {
+  print(<<"EOF");
+usage: $0 [-o outname] file.tok [extension.tok [...]]
+
+This script processes a master token description and produces several files:
+  - a .h file with the enumeration listing all the tokens
+  - a .cc file with a table of spellings, and table of flags
+  - a .ids file with grammar token names, ids, and aliases
+
+The filenames are named with the same base as the input .tok file,
+or with whatever base is specified with the -o option.
+EOF
+}
+
+$baseName = "";
+$myCommand = "$0 " . join(' ', @ARGV);
+
+while (@ARGV != 0 && $ARGV[0] =~ m/^-/) {
+  my $arg = $ARGV[0];
+  shift @ARGV;
+  if ($arg eq "-o") {
+    $baseName = $ARGV[0];
+    shift @ARGV;
+  }
+  else {
+    print("unknown option: $arg\n");
+    usage();
+    exit(2);
+  }
+}
+
+if (@ARGV < 1) {
+  usage();
+  exit(0);
+}
+
+$fname = $ARGV[0];
+
+if (!$baseName) {
+  $baseName = $fname;
+  $baseName =~ s|\.[^.]*$||;    # strip extension
+}
+
+# open the output files
+open(H, ">$baseName.h") or die("cannot open $baseName.h: $!\n");
+open(CC, ">$baseName.cc") or die("cannot open $baseName.cc: $!\n");
+open(IDS, ">$baseName.ids") or die("cannot open $baseName.ids: $!\n");
+
+
+# write the preambles
+
+$latch = "$baseName.h";
+$latch =~ tr|a-z./|A-Z__|;
+print H (<<"EOF");
+// $baseName.h
+// do not edit; this file automatically generated by
+//   $myCommand
+
+#ifndef $latch
+#define $latch
+
+// token flags
+enum TokenFlag {
+  TF_MULTISPELL   = 0x01,     // token has multiple spellings
+  TF_NONSEPARATOR = 0x02,     // token is a nonseparator
+  TF_CPLUSPLUS    = 0x04,     // token is a keyword in C++, but an identifier in C
+  ALL_TOKEN_FLAGS = 0x07      // bitwise OR of above
+};
+
+enum TokenType {
+EOF
+
+
+print CC (<<"EOF");
+// $baseName.cc
+// do not edit; this file automatically generated by
+//   $myCommand
+
+#include "$baseName.h"     // this module; defines TokenFlag
+
+char const * const tokenNameTable[] = {
+EOF
+
+# I'll have to accumulate the flags in a big list and then
+# emit them after I close the 'tokenNames' array
+ at flagsList = ();
+
+
+print IDS (<<"EOF");
+// $baseName.ids
+// do not edit; this file automatically generated by
+//   $myCommand
+
+// form:
+//   <code> : <name> [<alias>] ;
+
+EOF
+
+
+# process the input file(s), effectively a concatenation of all the
+# files supplied on the command line
+$nextId = 0;
+while (@ARGV > 0) {
+  $fname = $ARGV[0];
+  $lineNum = 0;
+  shift @ARGV;
+
+  # open the input file
+  open(IN, "<$fname") or die("cannot open $fname: $!\n");
+
+  # process it
+  while (defined($line = <IN>)) {
+    $lineNum++;
+
+    # blank lines and comment lines are copied to the output verbatim,
+    # once we've seen the first line which is neither
+    if ($line =~ m|^\s*$| or
+        $line =~ m|^\s*//|) {
+      if ($nextId) {
+        # indent unindented comments
+        if ($line =~ m|^//|) {
+          $line = "  " . $line;
+        }
+
+        print H ($line);
+        print CC ($line);
+        push @flagsList, $line;
+        print IDS ($line);
+      }
+      next;
+    }
+
+    # parse the line
+    chomp($line);
+    my ($enumerator, $spelling, $flags) =
+      ($line =~ m|^\s*([a-zA-Z_0-9]+),\s*(\"[^\"]*\")\s*,\s*:(.*)$|);
+
+    #print("enumerator: $enumerator\n");
+    #print("spelling:   $spelling\n");
+    #print("flags:      $flags\n");
+    #exit(0);
+
+    if (!defined($flags)) {
+      die("$fname:$lineNum: malformed line\n");
+    }
+
+    # parse the flags
+    $multiSpell = ($flags =~ m|m|);
+    $nonsep = ($flags =~ m|n|);
+    $cpp = ($flags =~ m|p|);
+
+    # emit to each file
+    print H ("  $enumerator,\n");
+    printf CC ("  %-40s // $enumerator\n", "$spelling,");
+
+    my @f = ("0");
+    if ($multiSpell) { push @f, "TF_MULTISPELL"; }
+    if ($nonsep)     { push @f, "TF_NONSEPARATOR"; }
+    if ($cpp)        { push @f, "TF_CPLUSPLUS"; }
+    push @flagsList, sprintf("  %-40s // $enumerator\n",
+                             join(' | ', @f) . ",");
+
+    printf IDS ("  %3d : %-30s %s;\n",
+                $nextId,
+                $enumerator,
+                ($multiSpell? "" : $spelling));
+
+    $nextId++;
+  }
+  
+  close(IN) or die;
+}
+
+
+# print the epilogues
+
+print H (<<"EOF");
+  NUM_TOKEN_TYPES
+
+};  // enum TokenType
+
+// map TokenType to its spelling or description
+extern char const * const tokenNameTable[];
+extern int const tokenNameTableSize;
+
+// map TokenType to a bitwise OR of TokenFlags
+extern unsigned char tokenFlagTable[];
+
+#endif // $latch
+EOF
+
+
+
+$flagsList = join('', @flagsList);
+print CC (<<"EOF");
+};  // tokenNameTable[]
+
+// this is provided to allow a consistency check between the generated
+// .h file and generated .cc file
+int const tokenNameTableSize =
+  sizeof(tokenNameTable) / sizeof(tokenNameTable[0]);
+
+
+unsigned char tokenFlagTable[] = {
+$flagsList
+};
+EOF
+
+
+# the IDS file has no epilogue
+
+
+# close the files
+close(H) or die;
+close(CC) or die;
+close(IDS) or die;
+
+exit(0);


Property changes on: vendor/elsa/current/elsa/make-token-files
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/mangle.cc
===================================================================
--- vendor/elsa/current/elsa/mangle.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/mangle.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,396 @@
+// mangle.cc
+// code for mangle.h
+// author: Daniel Wilkerson
+
+#include "mangle.h"     // this module
+#include "template.h"   // Type, TemplateInfo, etc.
+#include "variable.h"   // Variable
+#include "cc_print.h"   // PrintEnv
+    
+
+
+string mangleAtomic(AtomicType const *t)
+{
+  switch (t->getTag()) {
+  default: xfailure("bad tag");
+
+  case AtomicType::T_SIMPLE: {
+    SimpleType const *st = t->asSimpleTypeC();
+    return simpleTypeName(st->type);
+  }
+
+  case AtomicType::T_COMPOUND: {
+    CompoundType const *ct = t->asCompoundTypeC();
+
+    stringBuilder sb;
+
+    bool hasParams = ct->templateInfo() && ct->templateInfo()->params.isNotEmpty();
+    if (hasParams) {
+      sb << mangleTemplateParams(ct->templateInfo()) << " ";
+    }
+
+    if (!ct->templateInfo() || hasParams) {
+      // only say 'class' if this is like a class definition, or
+      // if we're not a template, since template instantiations
+      // usually don't include the keyword 'class' (this isn't perfect..
+      // I think I need more context)
+      sb << CompoundType::keywordName(ct->keyword) << " ";
+    }
+
+    // sm: I'm sure this is a bug; the class name is always part
+    // of the type...
+    // dsw: yup, it was a bug alright
+    //        if (!(tsf & TTS_CANON)) {
+    sb << (ct->name? ct->name : "/*anonymous*/");
+    //        }
+
+    // template arguments are now in the name
+    //if (templateInfo && templateInfo->specialArguments) {
+    //  sb << "<" << templateInfo->specialArgumentsRepr << ">";
+    //}
+
+    return sb;
+  }
+
+  case AtomicType::T_ENUM: {
+    EnumType const *et = t->asEnumTypeC(); // unused for the moment
+
+    stringBuilder sb;
+    sb << "enum ";
+      
+    // sm: again, to fail to include the name is a bug
+    // dsw: yup
+    //if (!(tsf & TTS_CANON)) {
+    sb << (et->name? et->name : "/*anonymous*/");
+    //}
+
+    return sb;
+  }
+
+  case AtomicType::T_TYPEVAR:
+    return string("TVAR");      // dsw: my replacement for an actual name
+      
+  case AtomicType::T_PSEUDOINSTANTIATION:
+    // sm: not clear what should happen here; I think in fact
+    // that pseudoinstantiations should not be "linker visible"
+    // so it won't matter
+    return t->toString();
+
+  case AtomicType:: T_DEPENDENTQTYPE:
+    // dsw: this is just a guess, but you never added this
+    return t->toString();
+  }
+}
+
+                              
+// cc_type.cc
+string cvToString(CVFlags cv);
+
+string mangle(Type const *t)
+{
+  // I'm pretty sure that it makes no sense to request a linker
+  // visible string (mangled name) for a type that contains template
+  // variables
+  //
+  // update: nope, a complete specialization contains type variables,
+  // but I suppose they got resolved as typedefs when the template
+  // scope provided binding for them; I'm too tired to think about
+  // this so I'll leave it for now; FIX: understand this.
+//    xassert(!t->containsVariables());
+  if (t->isCVAtomicType()) {
+    // special case a single atomic type, so as to avoid
+    // printing an extra space
+    CVAtomicType const *atomic = t->asCVAtomicTypeC();
+    return stringc
+      << mangleAtomic(atomic->atomic)
+      << cvToString(atomic->cv);
+  }
+  else {
+    return stringc << leftMangle(t) << rightMangle(t);
+  }
+}
+
+
+string leftMangle(Type const *t, bool innerParen)
+{
+  switch (t->getTag()) {
+    default: xfailure("bad tag");
+
+    case Type::T_ATOMIC: {
+      CVAtomicType const *at = t->asCVAtomicTypeC();
+
+      stringBuilder s;
+      s << mangleAtomic(at->atomic);
+      s << cvToString(at->cv);
+
+      // this is the only mandatory space in the entire syntax
+      // for declarations; it separates the type specifier from
+      // the declarator(s)
+      s << " ";
+
+      return s;
+    }
+
+    case Type::T_POINTER:
+    case Type::T_REFERENCE: {
+      Type *atType = t->getAtType();
+      CVFlags cv = t->getCVFlags();
+
+      stringBuilder s;
+      s << leftMangle(atType, false /*innerParen*/);
+      if (atType->isFunctionType() ||
+          atType->isArrayType()) {
+        s << "(";
+      }
+      s << (t->isPointerType()? "*" : "&");
+      if (cv) {
+        // 1/03/03: added this space so "Foo * const arf" prints right (t0012.cc)
+        s << cvToString(cv) << " ";
+      }
+      return s;
+    }
+    
+    case Type::T_FUNCTION: {
+      FunctionType const *ft = t->asFunctionTypeC();
+      
+      stringBuilder sb;
+
+      // FIX: FUNC TEMPLATE LOSS
+      // template parameters
+//        if (ft->templateInfo) {
+//          sb << mangleTemplateParams(ft->templateInfo) << " ";
+//        }
+
+      // return type and start of enclosing type's description
+      if (ft->flags & (/*FF_CONVERSION |*/ FF_CTOR | FF_DTOR)) {
+        // don't print the return type, it's implicit
+
+        // 7/18/03: changed so we print ret type for FF_CONVERSION,
+        // since otherwise I can't tell what it converts to!
+      }
+      else {
+        sb << leftMangle(ft->retType);
+      }
+
+      // NOTE: we do *not* propagate 'innerParen'!
+      if (innerParen ||
+          true /*(tsf & TTS_CANON)*/         // force innerParen for canonical type names
+          ) {
+        sb << "(";
+      }
+
+      return sb;
+    }
+
+    case Type::T_ARRAY: {
+      ArrayType const *at = t->asArrayTypeC();
+      
+      return leftMangle(at->eltType);
+    }
+
+    case Type::T_POINTERTOMEMBER: {
+      PointerToMemberType const *ptm = t->asPointerToMemberTypeC();
+
+      stringBuilder s;
+      s << leftMangle(ptm->atType, false /*innerParen*/);
+      s << " ";
+      if (ptm->atType->isFunctionType() ||
+          ptm->atType->isArrayType()) {
+        s << "(";
+      }
+      
+      // sm: the following line fails when the 'inClass' is
+      // a type variable
+      //s << ptm->inClass()->name << "::*";
+      // why was it not always just done like this?
+      s << mangleAtomic(ptm->inClassNAT) << "::*";
+
+      s << cvToString(ptm->cv);
+      return s;
+    }
+  }
+}
+
+
+string rightMangle(Type const *t, bool innerParen)
+{
+  switch (t->getTag()) {
+    default: xfailure("bad tag");
+
+    case Type::T_ATOMIC: {
+      //CVAtomicType const *at = t->asCVAtomicTypeC();    // unused
+      return "";
+    }
+
+    case Type::T_POINTER:
+    case Type::T_REFERENCE: {
+      Type *atType = t->getAtType();
+
+      stringBuilder s;
+      if (atType->isFunctionType() ||
+          atType->isArrayType()) {
+        s << ")";
+      }
+      s << rightMangle(atType, false /*innerParen*/);
+      return s;
+    }
+
+    case Type::T_FUNCTION: {
+      FunctionType const *ft = t->asFunctionTypeC();
+
+      // cqual qualifiers should not be part of the canonical type
+      // (you can't overload functions differing only in their cqual
+      // qualifiers), so I do not include the extra hooks for printing
+      // such information
+
+      // finish enclosing type
+      stringBuilder sb;
+      if (innerParen ||
+          true /*(tsf & TTS_CANON)*/         // force innerParen for canonical type names
+          ) {
+        sb << ")";
+      }
+
+      // arguments
+      sb << "(";
+      int ct=0;
+      SFOREACH_OBJLIST(Variable, ft->params, iter) {
+        ct++;
+        if (ft->isMethod() && ct==1) {
+          // don't actually print the first parameter;
+          // the 'm' stands for nonstatic member function
+          // sb << "/""*m: " << iter.data()->type->toString() << " *""/ ";
+	  // jk: we need this in order to not have the class name
+	  sb << "/""*m*""/ ";
+          continue;
+        }
+        if (ct >= 3 || (!ft->isMethod() && ct>=2)) {
+          sb << ", ";
+        }
+        sb << mangleVariable(iter.data());
+      }
+
+      if (ft->acceptsVarargs()) {
+        if (ct++ > 0) {
+          sb << ", ";
+        }
+        sb << "...";
+      }
+
+      sb << ")";
+
+      // right here is the boundary between what's normally printed
+      // by FunctionType::rightStringUpToQualifiers and
+      // FunctionType::rightStringAfterQualifiers
+
+      CVFlags cv = ft->getReceiverCV();
+      if (cv) {
+        sb << " " << ::toString(cv);
+      }
+
+      #if 0    // TTS_CANON disables
+      // exception specs
+      if (exnSpec && !(tsf & TTS_CANON)) {
+        sb << " throw(";
+        int ct=0;
+        SFOREACH_OBJLIST(Type, exnSpec->types, iter) {
+          if (ct++ > 0) {
+            sb << ", ";
+          }
+          sb << iter.data()->toString(tsf);
+        }
+        sb << ")";
+      }
+      #endif // 0
+
+      // hook for verifier syntax
+      //extraRightmostSyntax(sb, tsf);
+
+      // finish up the return type
+      sb << rightMangle(ft->retType);
+
+      return sb;
+    }
+
+    case Type::T_ARRAY: {
+      ArrayType const *at = t->asArrayTypeC();
+
+      stringBuilder sb;
+
+      if (at->hasSize()) {
+        sb << "[" << at->size << "]";
+      }
+      else {
+        sb << "[]";
+      }
+
+      sb << rightMangle(at->eltType);
+
+      return sb;
+    }
+
+    case Type::T_POINTERTOMEMBER: {
+      PointerToMemberType const *ptm = t->asPointerToMemberTypeC();
+
+      stringBuilder s;
+      if (ptm->atType->isFunctionType() ||
+          ptm->atType->isArrayType()) {
+        s << ")";
+      }
+      s << rightMangle(ptm->atType, false /*innerParen*/);
+      return s;
+    }
+  }
+}
+
+
+string mangleVariable(Variable const *v)
+{
+  stringBuilder sb;
+  if (v->type->isTypeVariable()) {
+    if (true /*tsf & TTS_CANON*/) {
+      sb << "TVAR";
+    } else {
+      // type variable's name, then the parameter's name
+      sb << v->type->asTypeVariable()->name << " " << v->name;
+    }
+  }
+  else {
+    sb << mangle(v->type);
+  }
+  
+  #if 0
+  if (value && (!(tsf & TTS_CANON))) {
+    sb << renderExpressionAsString(" = ", value);
+  }    
+  #endif // 0
+
+  return sb;
+}
+
+
+string mangleTemplateParams(TemplateInfo const *tp)
+{
+  stringBuilder sb;
+  sb << "template <";
+  int ct=0;
+  SFOREACH_OBJLIST(Variable, tp->params, iter) {
+    Variable const *p = iter.data();
+    if (ct++ > 0) {
+      sb << ", ";
+    }
+
+    if (p->type->isTypeVariable()) {
+      sb << "class " << p->type->asTypeVariable()->name;
+    }
+    else {
+      // non-type parameter
+      sb << mangleVariable(p);
+    }
+  }
+  sb << ">";
+  return sb;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/mangle.h
===================================================================
--- vendor/elsa/current/elsa/mangle.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/mangle.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// mangle.h
+// name mangling
+
+// For now, this is just a verson of Type::toString that does
+// not print parameter names.  It's a hack.
+
+// Eventually, it should:
+//   - mangle names compactly
+//   - demangle names back into types
+//   - support more than one algorithm (gcc's, for example) (?)
+
+
+#ifndef MANGLE_H
+#define MANGLE_H
+
+#include "str.h"             // string, stringBuilder
+#include "objlist.h"         // ObjList
+
+class Type;                  // cc_type.h
+class AtomicType;            // cc_type.h
+class Variable;              // variable.h
+class TemplateInfo;          // template.h
+class STemplateArgument;     // template.h
+
+
+// main entry point
+string mangle(Type const *t);
+
+
+// helpers
+string mangleAtomic(AtomicType const *t);
+string leftMangle(Type const *t, bool innerParen = true);
+string rightMangle(Type const *t, bool innerParen = true);
+string mangleVariable(Variable const *v);
+string mangleTemplateParams(TemplateInfo const *tp);
+
+
+#endif // MANGLE_H

Added: vendor/elsa/current/elsa/merge-lexer-exts.pl
===================================================================
--- vendor/elsa/current/elsa/merge-lexer-exts.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/merge-lexer-exts.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,58 @@
+#!/usr/bin/perl -w
+# merge a base flexer lexer description with zero or more extensions
+
+# TODO: I would like a feature where an extension can identify a
+# rule from the base that it would like to delete.  For example,
+# an extension might contain something like:
+#
+#   delete_rule "L"?{QUOTE}({STRCHAR}|{ESCAPE})*{QUOTE}
+#
+# and the effect would be to remove the entire rule+action:
+#
+#   "L"?{QUOTE}({STRCHAR}|{ESCAPE})*{QUOTE} {
+#     return svalTok(TOK_STRING_LITERAL);
+#   }
+#
+# by finding the pattern, then matching braces to find the action.
+#
+# It should be an error if the rule cannot be found, because in that
+# case it means the base specification has changed in a significant
+# way since the extension was written.
+
+
+use strict 'subs';
+
+if (@ARGV == 0) {
+  print(<<"EOF");
+usage: $0 base.lex [extension.lex [...]] >merged.lex
+EOF
+  exit(0);
+}
+
+$base = $ARGV[0];
+shift @ARGV;
+                     
+open(IN, "<$base") or die("cannot open $base: $!\n");
+while (defined($line = <IN>)) {
+  # re-echo all, including marker line, to allow composition via
+  # multiple runs
+  print($line);
+
+  if ($line =~ m/EXTENSION RULES GO HERE/) {
+    # insert all extension modules; insert in reverse order to
+    # preserve the idea that later files are extending earlier
+    # files, and the last-added extension should come first so
+    # it has total control
+    for ($i = @ARGV-1; $i >= 0; $i--) {
+      my $ext = $ARGV[$i];
+      open(EXT, "<$ext") or die("cannot open $ext: $!\n");
+      while (defined($extline = <EXT>)) {
+        print($extline);
+      }
+      close(EXT) or die;
+    }
+  }
+}
+
+close(IN) or die;
+exit(0);


Property changes on: vendor/elsa/current/elsa/merge-lexer-exts.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/mflags.h
===================================================================
--- vendor/elsa/current/elsa/mflags.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/mflags.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,143 @@
+// mflags.h
+// MatchFlags enumeration, so I can #include just that without
+// getting all of mtype.h
+
+#ifndef MFLAGS_H
+#define MFLAGS_H
+
+#include "macros.h"      // ENUM_BITWISE_OPS
+#include "str.h"         // string
+
+enum MatchFlags {
+  // complete equality; this is the default; note that we are
+  // checking for *type* equality, rather than equality of the
+  // syntax used to denote it, so we do *not* compare (e.g.)
+  // function parameter names or typedef usage
+  MF_NONE            = 0x0000,
+
+  // ----- basic behaviors -----
+  // when comparing function types, do not check whether the
+  // return types are equal
+  MF_IGNORE_RETURN   = 0x0001,
+
+  // when comparing function types, if one is a nonstatic member
+  // function and the other is not, then do not (necessarily)
+  // call them unequal
+  MF_STAT_EQ_NONSTAT = 0x0002,    // static can equal nonstatic
+
+  // when comparing function types, only compare the explicit
+  // (non-receiver) parameters; this does *not* imply
+  // MF_STAT_EQ_NONSTAT, nor MF_IGNORE_FUNC_CV
+  MF_IGNORE_IMPLICIT = 0x0004,
+
+  // In the C++ type system, cv qualifiers on parameters are not part
+  // of the type [8.3.5p3], so by default mtype ignores them.  If you
+  // set this flag, then they will *not* be ignored.  It is provided
+  // only for completeness; Elsa does not use it.
+  MF_RESPECT_PARAM_CV= 0x0008,
+
+  // ignore the topmost cv qualification of the two types compared
+  MF_IGNORE_TOP_CV   = 0x0010,
+
+  // when comparing function types, compare the exception specs;
+  // by default such specifications are not compared because the
+  // exception spec is not part of the "type" [8.3.5p4]
+  MF_COMPARE_EXN_SPEC= 0x0020,
+  
+  // allow the cv qualifications to differ up to the first type
+  // constructor that is not a pointer or pointer-to-member; this
+  // is cppstd 4.4 para 4 "similar"; implies MF_IGNORE_TOP_CV
+  MF_SIMILAR         = 0x0040,
+
+  // when the second type in the comparison is polymorphic (for
+  // built-in operators; this is not for templates), and the first
+  // type is in the set of types described, say they're equal;
+  // note that polymorhism-enabled comparisons therefore are not
+  // symmetric in their arguments
+  MF_POLYMORPHIC     = 0x0080,
+
+  // for use by the matchtype module: this flag means we are trying
+  // to deduce function template arguments, so the variations
+  // allowed in 14.8.2.1 are in effect (for the moment I don't know
+  // what propagation properties this flag should have)
+  MF_DEDUCTION       = 0x0100,
+
+  // this is another flag for MatchTypes, and it means that template
+  // parameters should be regarded as unification variables only if
+  // they are *not* associated with a specific template
+  MF_UNASSOC_TPARAMS = 0x0200,
+
+  // ignore the cv qualification on the array element, if the
+  // types being compared are arrays
+  MF_IGNORE_ELT_CV   = 0x0400,
+
+  // enable matching/substitution with template parameters
+  MF_MATCH           = 0x0800,
+
+  // do not allow new bindings to be created; but existing bindings
+  // can continue to be used
+  MF_NO_NEW_BINDINGS = 0x1000,
+
+  // when combined with MF_MATCH, it means we can bind variables in
+  // the pattern only to other variables in the "concrete" type, and
+  // that the binding function must be injective (no two pattern
+  // variables can be bound to the same concrete variable); this
+  // is used to compare two templatized signatures for equivalence
+  MF_ISOMORPHIC      = 0x2000,
+
+  // ignore the cv-flags on function types
+  MF_IGNORE_FUNC_CV  = 0x4000,
+
+  // ----- combined behaviors -----
+  // all flags set to 1
+  MF_ALL             = 0x7FFF,
+
+  // number of 1 bits in MF_ALL
+  MF_NUM_FLAGS       = 15,
+
+  // signature equivalence for the purpose of detecting whether
+  // two declarations refer to the same entity (as opposed to two
+  // overloaded entities)
+  MF_SIGNATURE       = (
+    MF_IGNORE_RETURN |       // can't overload on return type
+    MF_STAT_EQ_NONSTAT       // can't overload on static vs. nonstatic
+  ),
+
+  // ----- combinations used by the mtype implementation -----
+  // this is the set of flags that allow CV variance within the
+  // current type constructor
+  MF_OK_DIFFERENT_CV = (MF_IGNORE_TOP_CV | MF_SIMILAR),
+
+  // this is the set of flags that automatically propagate down
+  // the type tree equality checker; others are suppressed once
+  // the first type constructor looks at them
+  MF_PROP = (
+    MF_RESPECT_PARAM_CV |
+    MF_POLYMORPHIC      |
+    MF_UNASSOC_TPARAMS  |
+    MF_MATCH            |
+    MF_NO_NEW_BINDINGS  |
+    MF_ISOMORPHIC       
+    
+    // Note: MF_COMPARE_EXN_SPEC is *not* propagated.  It is used only
+    // when the compared types are FunctionTypes, to compare those
+    // toplevel exn specs, but any FunctionTypes appearing underneath
+    // are compared just as types (not objects), and hence their exn
+    // specs are irrelevant.
+  ),
+
+  // these flags are propagated below ptr and ptr-to-member
+  MF_PTR_PROP = (
+    MF_PROP            |
+    MF_SIMILAR         |
+    MF_DEDUCTION
+  )
+};
+
+ENUM_BITWISE_OPS(MatchFlags, MF_ALL)
+
+// defined in mtype.cc
+string toString(MatchFlags flags);
+
+
+#endif // MFLAGS_H

Added: vendor/elsa/current/elsa/mkdist
===================================================================
--- vendor/elsa/current/elsa/mkdist	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/mkdist	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,79 @@
+#!/bin/sh
+# make a tarball for distribution
+      
+# bail on error
+set -e
+
+# tarball dist name; e.g. elsa-2002.08.12
+distname=elsa-`date "+%Y.%m.%d"`
+echo $distname
+
+mkdir $distname || exit
+cd $distname || exit
+
+# main stuff
+export CVSROOT=":ext:scott at manju.cs.berkeley.edu:/home/cvs-repository"
+cvs export -D now smbase || exit
+cvs export -D now ast || exit
+cvs export -D now elkhound || exit
+cvs export -D now elsa || exit
+
+# toplevel files
+cp elsa/toplevel/* .
+
+# remove some files I don't want going into the external distribution
+rm elsa/mkdist
+rm -rf elsa/toplevel
+
+# generated docs; I have to run "make doc" myself in my own checked-out
+# versions before doing 'mkdist'
+cp -a ../../smbase/gendoc smbase || exit
+cp -a ../../ast/gendoc ast || exit
+cp -a ../../elkhound/gendoc elkhound || exit
+cp -a ../../elsa/gendoc elsa || exit
+
+# package it up
+cd ..
+targz $distname || exit
+rm -rf $distname
+
+if [ "$1" = "-notest" ]; then
+  echo "stopping without testing"
+  exit 0
+fi
+
+# test it
+untargz ${distname}.tar.gz
+cd ${distname}
+echo "building... (output in $distname/make.out)"
+./configure >make.out 2>&1
+make >>make.out 2>&1
+make check >>make.out 2>&1
+
+# make sure I can build the ocaml examples
+(cd elkhound/ocaml; make) >>make.out 2>&1
+
+# check for having run flex or bison
+# UPDATE: have to run flex b/c it's how lexical extensions are added..
+if egrep '^bison' make.out; then
+  echo "We ran bison during the build; that's bad!"
+  exit 2
+fi
+
+if egrep '^m4' make.out; then
+  echo "We ran m4 during the build; that's bad!"
+  exit 2
+fi
+
+# blow away the test directory
+if [ "$1" != "-keep" ]; then
+  cd ..
+  rm -rf $distname
+fi
+
+
+
+
+
+
+


Property changes on: vendor/elsa/current/elsa/mkdist
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/mtype.cc
===================================================================
--- vendor/elsa/current/elsa/mtype.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/mtype.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1330 @@
+// mtype.cc
+// code for mtype.h
+
+// 2005-08-03: This code is now exercised to 100% statement coverage,
+// except for the code that deals with MF_POLYMORPHIC and
+// MF_ISOMORPHIC and the places annotated with gcov-ignore or
+// gcov-begin/end-ignore, by in/t0511.cc.
+//
+// My plan is to re-do the coverage analysis using the entire test
+// suite once mtype is hooked up to the rest of the program as the
+// module to use for type comparison and matching.
+
+#include "mtype.h"       // this module
+#include "trace.h"       // tracingSys
+#include "cc_env.h"      // Env::applyArgumentMap
+
+
+string toString(MatchFlags flags)
+{
+  static char const * const map[] = {
+    "MF_IGNORE_RETURN",
+    "MF_STAT_EQ_NONSTAT",
+    "MF_IGNORE_IMPLICIT",
+    "MF_RESPECT_PARAM_CV",
+    "MF_IGNORE_TOP_CV",
+    "MF_COMPARE_EXN_SPEC",
+    "MF_SIMILAR",
+    "MF_POLYMORPHIC",
+    "MF_DEDUCTION",
+    "MF_UNASSOC_TPARAMS",
+    "MF_IGNORE_ELT_CV",
+    "MF_MATCH",
+    "MF_NO_NEW_BINDINGS",
+    "MF_ISOMORPHIC",
+    "MF_IGNORE_FUNC_CV",
+  };
+  STATIC_ASSERT(TABLESIZE(map) == MF_NUM_FLAGS);
+  return bitmapString(flags, map, MF_NUM_FLAGS, " ");
+}
+
+
+//-------------------------- Binding -------------------------
+string toString_or_CV_NONE(CVFlags cv)
+{
+  if (cv == CV_NONE) {
+    return "CV_NONE";
+  }
+  else {
+    return toString(cv);
+  }
+}
+
+
+bool IMType::Binding::operator== (Binding const &obj) const
+{
+  if (sarg.kind != obj.sarg.kind) {
+    return false;
+  }
+  
+  if (sarg.isType()) {
+    // somewhat complicated case: we need to make sure the types are
+    // the same, *ignoring* their cv-flags, and that the cv-flags in
+    // the Binding objects themselves *are* equal
+    return getType()->equals(obj.getType(), MF_IGNORE_TOP_CV) &&
+           cv == obj.cv;
+  }
+  else {
+    // easy, just STemplateArgument equality
+    return sarg.equals(obj.sarg);
+  }
+}
+
+
+string IMType::Binding::asString() const
+{
+  if (sarg.isType()) {
+    return stringc << getType()->toString() << " with "
+                   << toString_or_CV_NONE(cv);
+  }
+  else {
+    return sarg.toString();
+  }
+}
+
+
+// ------------------------- IMType -----------------------------
+IMType::IMType()
+  : bindings(),
+    env(NULL),
+    failedDueToDQT(false)
+{}
+
+IMType::~IMType()
+{}
+
+
+// --------------- IMType: AtomicType and subclasses ------------
+STATICDEF bool IMType::canUseAsVariable(Variable *var, MatchFlags flags)
+{
+  xassert(var);
+
+  if (!( flags & MF_MATCH )) {
+    // we're not using anything as a variable
+    return false;
+  }
+
+  if ((flags & MF_UNASSOC_TPARAMS) &&
+      var->getParameterizedEntity() != NULL) {
+    // we cannot use 'var' as a variable because, even though it is a
+    // template parameter, it is associated with a specific template
+    // and MF_UNASSOC_TPARAMS means we can only use *unassociated*
+    // variables as such
+    return false;
+  }
+
+  // no problem
+  return true;
+}
+
+
+bool IMType::imatchAtomicType(AtomicType const *conc, AtomicType const *pat, MatchFlags flags)
+{
+  if (conc == pat) {
+    return true;
+  }
+
+  if (pat->isTypeVariable() &&
+      canUseAsVariable(pat->asTypeVariableC()->typedefVar, flags)) {
+    return imatchAtomicTypeWithVariable(conc, pat->asTypeVariableC(), flags);
+  }
+
+  if (conc->getTag() != pat->getTag()) {
+    // match an instantiation with a PseudoInstantiation
+    if ((flags & MF_MATCH) &&
+        pat->isPseudoInstantiation() &&
+        conc->isCompoundType() &&
+        conc->asCompoundTypeC()->typedefVar->templateInfo() &&
+        conc->asCompoundTypeC()->typedefVar->templateInfo()->isCompleteSpecOrInstantiation()) {
+      TemplateInfo *concTI = conc->asCompoundTypeC()->typedefVar->templateInfo();
+      PseudoInstantiation const *patPI = pat->asPseudoInstantiationC();
+      
+      // these must be instantiations of the same primary
+      if (concTI->getPrimary() != patPI->primary->templateInfo()->getPrimary()) {
+        return false;
+      }
+      
+      // compare arguments; use the args to the primary, not the args to
+      // the partial spec (if any)
+      return imatchSTemplateArguments(concTI->getArgumentsToPrimary(),
+                                      patPI->args, flags);
+    }
+
+    return false;
+  }
+
+  // for the template-related types, we have some structural equality
+  switch (conc->getTag()) {
+    default: xfailure("bad tag");
+
+    case AtomicType::T_SIMPLE:
+    case AtomicType::T_COMPOUND:
+    case AtomicType::T_ENUM:
+      // non-template-related type, physical equality only
+      return false;
+
+    #define CASE(tag,type) \
+      case AtomicType::tag: return imatch##type(conc->as##type##C(), pat->as##type##C(), flags) /*user;*/
+    CASE(T_TYPEVAR, TypeVariable);
+    CASE(T_PSEUDOINSTANTIATION, PseudoInstantiation);
+    CASE(T_DEPENDENTQTYPE, DependentQType);
+    #undef CASE
+  }
+}
+
+
+bool IMType::imatchTypeVariable(TypeVariable const *conc, TypeVariable const *pat, MatchFlags flags)
+{
+  // 2005-03-03: Let's try saying that TypeVariables are equal if they
+  // are the same ordinal parameter of the same template.
+  Variable *cparam = conc->typedefVar;
+  Variable *pparam = pat->typedefVar;
+
+  return cparam->sameTemplateParameter(pparam);
+}
+
+
+bool IMType::imatchPseudoInstantiation(PseudoInstantiation const *conc,
+                                       PseudoInstantiation const *pat, MatchFlags flags)
+{
+  if (conc->primary != pat->primary) {
+    return false;
+  }
+
+  return imatchSTemplateArguments(conc->args, pat->args, flags);
+}
+
+
+bool IMType::imatchSTemplateArguments(ObjList<STemplateArgument> const &conc,
+                                      ObjList<STemplateArgument> const &pat,
+                                      MatchFlags flags)
+{
+  ObjListIter<STemplateArgument> concIter(conc);
+  ObjListIter<STemplateArgument> patIter(pat);
+
+  while (!concIter.isDone() && !patIter.isDone()) {
+    STemplateArgument const *csta = concIter.data();
+    STemplateArgument const *psta = patIter.data();
+    if (!imatchSTemplateArgument(csta, psta, flags)) {
+      return false;
+    }
+
+    concIter.adv();
+    patIter.adv();
+  }
+
+  return concIter.isDone() && patIter.isDone();
+}
+
+
+bool IMType::imatchSTemplateArgument(STemplateArgument const *conc,
+                                     STemplateArgument const *pat, MatchFlags flags)
+{
+  if (pat->kind == STemplateArgument::STA_DEPEXPR &&
+      pat->getDepExpr()->isE_variable() &&
+      canUseAsVariable(pat->getDepExpr()->asE_variable()->var, flags)) {
+    return imatchNontypeWithVariable(conc, pat->getDepExpr()->asE_variable(), flags);
+  }
+
+  if (conc->kind != pat->kind) {
+    return false;
+  }
+
+  switch (conc->kind) {
+    default: 
+      xfailure("bad or unimplemented STemplateArgument kind");
+
+    case STemplateArgument::STA_TYPE: {
+      // For convenience I have passed 'STemplateArgument' directly,
+      // but this module's usage of that structure is supposed to be
+      // consistent with it storing 'Type const *' instead of 'Type
+      // *', so this extraction is elaborated to make it clear we are
+      // pulling out const pointers.
+      Type const *ct = conc->getType();
+      Type const *pt = pat->getType();
+      return imatchType(ct, pt, flags);
+    }
+
+    case STemplateArgument::STA_INT:
+      return conc->getInt() == pat->getInt();
+      
+    case STemplateArgument::STA_ENUMERATOR:
+      return conc->getEnumerator() == pat->getEnumerator();
+
+    case STemplateArgument::STA_REFERENCE:
+      return conc->getReference() == pat->getReference();
+
+    case STemplateArgument::STA_POINTER:
+      return conc->getPointer() == pat->getPointer();
+
+    case STemplateArgument::STA_MEMBER:
+      return conc->getMember() == pat->getMember();
+
+    case STemplateArgument::STA_DEPEXPR:
+      return imatchExpression(conc->getDepExpr(), pat->getDepExpr(), flags);
+  }
+}
+
+
+bool IMType::imatchNontypeWithVariable(STemplateArgument const *conc,
+                                       E_variable *pat, MatchFlags flags)
+{
+  // 'conc' should be a nontype argument
+  if (!conc->isObject()) {
+    return false;
+  }
+
+  if (flags & MF_ISOMORPHIC) {
+    // check that we are only binding to a variable; ideally, this
+    // would only be an STA_DEPEXPR of an E_variable, but infelicities
+    // in other parts of the template-handling code can let this be
+    // an STA_REFERENCE of a Variable that is a template parameter..
+    // probably, that will be fixed at some point and the STA_REFERENCE
+    // possibility can be eliminated
+    if (conc->isDepExpr() &&
+        conc->getDepExpr()->isE_variable() &&
+        conc->getDepExpr()->asE_variable()->var->isTemplateParam()) {
+      // ok
+    }
+    else if (conc->kind == STemplateArgument::STA_REFERENCE &&
+             conc->getReference()->isTemplateParam()) {
+      // ok, sort of
+    }
+    else {
+      // not compatible with MF_ISOMORPHIC
+      return false;
+    }
+  }
+
+  StringRef vName = pat->name->getName();
+  Binding *binding = bindings.get(vName);
+  if (binding) {
+    // check that 'conc' and 'binding->sarg' are equal
+    return imatchSTemplateArgument(conc, &(binding->sarg), flags & ~MF_MATCH);
+  }
+  else {
+    if (flags & MF_NO_NEW_BINDINGS) {
+      return false;
+    }
+
+    // bind 'pat->name' to 'conc'
+    binding = new Binding;
+    binding->sarg = *conc;
+    return addBinding(vName, binding, flags);
+  }
+}
+
+
+bool IMType::addBinding(StringRef name, Binding * /*owner*/ value, MatchFlags flags)
+{
+  if (flags & MF_ISOMORPHIC) {
+    // is anything already bound to 'value'?
+    for (BindingMap::IterC iter(bindings); !iter.isDone(); iter.adv()) {
+      if (value->operator==(*(iter.value()))) {
+        // yes, something is already bound to it, which we cannot
+        // allow in MF_ISOMORPHIC mode
+        delete value;
+        return false;
+      }
+    }
+  }
+
+  bindings.add(name, value);
+  return true;
+}
+
+
+bool IMType::imatchDependentQType(DependentQType const *conc,
+                                  DependentQType const *pat, MatchFlags flags)
+{ 
+  // compare first components
+  if (!imatchAtomicType(conc->first, pat->first, flags)) {
+    return false;
+  }
+
+  // compare sequences of names as just that, names, since their
+  // interpretation depends on what type 'first' ends up being;
+  // I think this behavior is underspecified in the standard, but
+  // it is what gcc and icc seem to do
+  return imatchPQName(conc->rest, pat->rest, flags);
+}
+
+bool IMType::imatchPQName(PQName const *conc, PQName const *pat, MatchFlags flags)
+{
+  if (conc->kind() != pat->kind()) {
+    return false;
+  }
+
+  ASTSWITCH2C(PQName, conc, pat) {
+    // recursive case
+    ASTCASE2C(PQ_qualifier, cq, pq) {
+      // compare as names (i.e., syntactically)
+      if (cq->qualifier != pq->qualifier) {
+        return false;
+      }
+
+      // the template arguments can be compared semantically because
+      // the standard does specify that they are looked up in a
+      // context that is effectively independent of what appears to
+      // the left in the qualified name (cppstd 3.4.3.1p1b3)
+      if (!imatchSTemplateArguments(cq->sargs, pq->sargs, flags)) {
+        return false;
+      }
+
+      // continue down the chain
+      return imatchPQName(cq->rest, pq->rest, flags);
+    }
+
+    // base cases
+    ASTNEXT2C(PQ_name, cn, pn) {
+      // compare as names
+      return cn->name == pn->name;
+    }
+    ASTNEXT2C(PQ_operator, co, po) {
+      return co->o == po->o;      // gcov-ignore: can only match on types, and operators are not types
+    }
+    ASTNEXT2C(PQ_template, ct, pt) {
+      // like for PQ_qualifier, except there is no 'rest'
+      return ct->name == pt->name &&
+             imatchSTemplateArguments(ct->sargs, pt->sargs, flags);
+    }
+
+    ASTDEFAULT2C {
+      xfailure("bad kind");
+    }
+    ASTENDCASE2C
+  }
+}
+
+
+// -------------- IMType: Type and subclasses -------------
+bool IMType::imatchType(Type const *conc, Type const *pat, MatchFlags flags)
+{
+  if (pat->isReferenceType() &&         // if comparing reference
+      !conc->isReferenceType() &&       // to non-reference
+      (flags & MF_IGNORE_TOP_CV) &&     // at top of type
+      (flags & MF_DEDUCTION)) {         // during type deduction
+    // (in/t0549.cc) we got here because we just used a binding to
+    // come up with a reference type; without that, we would have stripped
+    // the reference-ness much earlier; but here we are, so strip it
+    pat = pat->asRvalC();
+  }
+
+  if (pat->isTypeVariable() &&
+      canUseAsVariable(pat->asTypeVariableC()->typedefVar, flags)) {
+    return imatchTypeWithVariable(conc, pat->asTypeVariableC(),
+                                  pat->getCVFlags(), flags);
+  }
+
+  if ((flags & MF_MATCH) &&
+      !(flags & MF_ISOMORPHIC) &&
+      pat->isCVAtomicType() &&
+      pat->asCVAtomicTypeC()->atomic->isDependentQType()) {
+    // must resolve a DQT to use it
+    return imatchTypeWithResolvedType(conc, pat, flags);
+  }
+
+  if (flags & MF_POLYMORPHIC) {
+    if (pat->isSimpleType()) {
+      SimpleTypeId objId = pat->asSimpleTypeC()->type;
+      if (ST_PROMOTED_INTEGRAL <= objId && objId <= ST_ANY_TYPE) {
+        return imatchTypeWithPolymorphic(conc, objId, flags);
+      }
+    }
+  }
+
+  // further comparison requires that the types have equal tags
+  Type::Tag tag = conc->getTag();
+  if (pat->getTag() != tag) {
+    return false;
+  }
+
+  switch (tag) {
+    default: xfailure("bad type tag");
+
+    #define CASE(tagName,typeName) \
+      case Type::tagName: return imatch##typeName(conc->as##typeName##C(), pat->as##typeName##C(), flags) /*user;*/
+    CASE(T_ATOMIC, CVAtomicType);
+    CASE(T_POINTER, PointerType);
+    CASE(T_REFERENCE, ReferenceType);
+    CASE(T_FUNCTION, FunctionType);
+    CASE(T_ARRAY, ArrayType);
+    CASE(T_POINTERTOMEMBER, PointerToMemberType);
+    #undef CASE
+  }
+}
+
+
+bool IMType::imatchTypeWithVariable(Type const *conc, TypeVariable const *pat,
+                                    CVFlags tvCV, MatchFlags flags)
+{
+  if ((flags & MF_ISOMORPHIC) &&
+      !conc->isTypeVariable()) {
+    return false;      // MF_ISOMORPHIC requires that we only bind to variables
+  }
+
+  StringRef tvName = pat->name;
+  Binding *binding = bindings.get(tvName);
+  if (binding) {
+    // 'tvName' is already bound; compare its current
+    // value (as modified by 'tvCV') against 'conc'
+    return equalWithAppliedCV(conc, binding, tvCV, flags);
+  }
+  else {
+    if (flags & MF_NO_NEW_BINDINGS) {
+      // new bindings are disallowed, so unbound variables in 'pat'
+      // cause failure
+      return false;
+    }
+
+    // bind 'tvName' to 'conc'; 'conc' should have cv-flags
+    // that are a superset of those in 'tvCV', and the
+    // type to which 'tvName' is bound should have the cv-flags
+    // in the difference between 'conc' and 'tvCV'
+    return addTypeBindingWithoutCV(tvName, conc, tvCV, flags);
+  }
+}
+
+
+bool IMType::imatchTypeWithResolvedType(Type const *conc, Type const *pat,
+                                        MatchFlags flags)
+{
+  // It would seem that I need an Env here so I can call
+  // applyArgumentMap.  If this assertion fails, it may be sufficient
+  // to change the MType constructor call to provide an Env; but be
+  // careful about the consequences to the constness of the interface.
+  if (!env) {
+    xfailure("in MF_MATCH mode, need to resolve a DQT, so need an Env...");
+  }
+
+  // this cast is justified by the private constructors of IMType
+  MType &mtype = static_cast<MType&>(*this);
+
+  // this cast is justified by the fact that applyArgumentMap is
+  // careful not to modify its argument; it accepts a non-const ptr
+  // only so that it can return it as non-const too (but I then
+  // store the result in the const 'resolvedType', so there isn't
+  // a loss of soundness there either)
+  Type *patNC = const_cast<Type*>(pat);
+
+  // The following call might need to query the bindings, and there
+  // is considerable difficulty involved in pushing a soundness
+  // argument through in the face of queried bindings.  So, I am
+  // forced to correlate the capacity to resolve DQTs with supporting
+  // the const interface.  That is why I have now removed setEnv().
+  xassert(mtype.getAllowNonConst());
+
+  Type const *resolvedType = env->applyArgumentMapToType_helper(mtype, patNC);
+  if (resolvedType) {
+    // take the resolved type and compare it directly to 'conc'
+    return imatchType(conc, resolvedType, flags & ~MF_MATCH);
+  }
+  else {
+    // failure to resolve, hence failure to match
+    failedDueToDQT = true;
+    return false;
+  }
+}
+
+
+// Typical scenario:
+//   conc is 'int const'
+//   binding is 'int'
+//   cv is 'const'
+// We want to compare the type denoted by 'conc' with the type denoted
+// by 'binding' with the qualifiers in 'cv' added to it at toplevel.
+bool IMType::equalWithAppliedCV(Type const *conc, Binding *binding, CVFlags cv, MatchFlags flags)
+{
+  // turn off type variable binding/substitution
+  flags &= ~MF_MATCH;
+
+  if (binding->sarg.isType()) {
+    Type const *t = binding->getType();
+
+    // cv-flags for 't' are ignored, replaced by the cv-flags stored
+    // in the 'binding' object
+    cv |= binding->cv;
+
+    return imatchTypeWithSpecifiedCV(conc, t, cv, flags);
+  }
+
+  if (binding->sarg.isAtomicType()) {
+    if (!conc->isCVAtomicType()) {
+      return false;
+    }
+
+    // compare the atomics
+    if (!imatchAtomicType(conc->asCVAtomicTypeC()->atomic,
+                          binding->sarg.getAtomicType(), flags)) {
+      return false;
+    }
+
+    // When a name is bound directly to an atomic type, it is compatible
+    // with any binding to a CVAtomicType for the same atomic; that is,
+    // it is compatible with any cv-qualified variant.  So, if we
+    // are paying attention to cv-flags at all, simply replace the
+    // original (AtomicType) binding with 'conc' (a CVAtomicType) and
+    // appropriate cv-flags.
+    if (!( flags & MF_OK_DIFFERENT_CV )) {
+      // The 'cv' flags supplied are subtracted from those in 'conc'.
+      CVFlags concCV = conc->getCVFlags();
+      if (concCV >= cv) {
+        // example:
+        //   conc = 'struct B volatile const'
+        //   binding = 'struct B'
+        //   cv = 'const'
+        // Since 'const' was supplied (e.g., "T const") with the type
+        // variable, we want to remove it from what we bind to, so here
+        // we will bind to 'struct B volatile' ('concCV' = 'volatile').
+        concCV = (concCV & ~cv);
+      }
+      else {
+        // example:
+        //   conc = 'struct B volatile'
+        //   binding = 'struct B'
+        //   cv = 'const'
+        // This means we are effectively comparing 'struct B volatile' to
+        // 'struct B volatile const' (the latter volatile arising because
+        // being directly bound to an atomic means we can add qualifiers),
+        // and these are not equal.
+        return false;
+      }
+
+      binding->setType(conc);
+      binding->cv = concCV;
+      return true;
+    }
+
+  }
+
+  // I *think* that the language rules that prevent same-named
+  // template params from nesting will have the effect of preventing
+  // this code from being reached, but if it turns out I am wrong, it
+  // should be safe to simply remove the assertion and return false.
+  xfailure("attempt to match a type with a variable bound to a non-type");
+
+  return false;      // gcov-ignore
+}
+
+bool IMType::imatchTypeWithSpecifiedCV(Type const *conc, Type const *pat, CVFlags cv, MatchFlags flags)
+{
+  // compare underlying types, ignoring first level of cv
+  return imatchCVFlags(conc->getCVFlags(), cv, flags) &&
+         imatchType(conc, pat, flags | MF_IGNORE_TOP_CV);
+}
+
+
+bool IMType::addTypeBindingWithoutCV(StringRef tvName, Type const *conc,
+                                     CVFlags tvcv, MatchFlags flags)
+{
+  CVFlags ccv = conc->getCVFlags();
+
+  if ((flags & MF_DEDUCTION) && (flags & MF_IGNORE_TOP_CV)) {
+    // trying to implement 14.8.2.1p2b3
+    ccv = CV_NONE;
+  }
+
+  if (tvcv & ~ccv) {
+    // the type variable was something like 'T const' but the concrete
+    // type does not have all of the cv-flags (e.g., just 'int', no
+    // 'const'); this means the match is a failure
+    if (flags & MF_DEDUCTION) {
+      // let it go anyway, as part of my poor approximationg of 14.8.2.1
+    }
+    else {
+      return false;
+    }
+  }
+
+  // 'tvName' will be bound to 'conc', except we will ignore the
+  // latter's cv flags
+  Binding *binding = new Binding;
+  binding->setType(conc);
+
+  // instead, compute the set of flags that are on 'conc' but not
+  // 'tvcv'; this will be the cv-flags of the type to which 'tvName'
+  // is bound
+  binding->cv = (ccv & ~tvcv);
+
+  // add the binding
+  return addBinding(tvName, binding, flags);
+}
+
+
+// check if 'conc' matches the "polymorphic" type family 'polyId'
+bool IMType::imatchTypeWithPolymorphic(Type const *conc, SimpleTypeId polyId,
+                                       MatchFlags flags)
+{
+  // check those that can match any type constructor
+  if (polyId == ST_ANY_TYPE) {
+    return true;
+  }
+
+  if (polyId == ST_ANY_NON_VOID) {
+    return !conc->isVoid();
+  }
+
+  if (polyId == ST_ANY_OBJ_TYPE) {
+    return !conc->isFunctionType() &&
+           !conc->isVoid();
+  }
+
+  // check those that only match atomics
+  if (conc->isSimpleType()) {
+    SimpleTypeId concId = conc->asSimpleTypeC()->type;
+    SimpleTypeFlags concFlags = simpleTypeInfo(concId).flags;
+
+    // see cppstd 13.6 para 2
+    if (polyId == ST_PROMOTED_INTEGRAL) {
+      return (concFlags & (STF_INTEGER | STF_PROM)) == (STF_INTEGER | STF_PROM);
+    }
+
+    if (polyId == ST_PROMOTED_ARITHMETIC) {
+      return (concFlags & (STF_INTEGER | STF_PROM)) == (STF_INTEGER | STF_PROM) ||
+             (concFlags & STF_FLOAT);      // need not be promoted!
+    }
+
+    if (polyId == ST_INTEGRAL) {
+      return (concFlags & STF_INTEGER) != 0;
+    }
+
+    if (polyId == ST_ARITHMETIC) {
+      return (concFlags & (STF_INTEGER | STF_FLOAT)) != 0;
+    }
+
+    if (polyId == ST_ARITHMETIC_NON_BOOL) {
+      return concId != ST_BOOL &&
+             (concFlags & (STF_INTEGER | STF_FLOAT)) != 0;
+    }
+  }
+
+  // polymorphic type failed to match
+  return false;
+}
+
+
+bool IMType::imatchAtomicTypeWithVariable(AtomicType const *conc,
+                                          TypeVariable const *pat,
+                                          MatchFlags flags)
+{
+  if ((flags & MF_ISOMORPHIC) &&
+      !conc->isTypeVariable()) {
+    return false;      // MF_ISOMORPHIC requires that we only bind to variables
+  }
+
+  StringRef tvName = pat->name;
+  Binding *binding = bindings.get(tvName);
+  if (binding) {
+    // 'tvName' is already bound; it should be bound to the same
+    // atomic as 'conc', possibly with some (extra, ignored) cv flags
+    if (binding->sarg.isType()) {
+      Type const *t = binding->getType();
+      if (t->isCVAtomicType()) {
+        return imatchAtomicType(conc, t->asCVAtomicTypeC()->atomic, flags & ~MF_MATCH);
+      }
+      else {
+        return false;
+      }
+    }
+    else if (binding->sarg.isAtomicType()) {
+      return imatchAtomicType(conc, binding->sarg.getAtomicType(), flags & ~MF_MATCH);
+    }
+    else {              // gcov-ignore: cannot be triggered, the error is
+      return false;     // gcov-ignore: diagnosed before mtype is entered 
+    }
+  }
+  else {
+    if (flags & MF_NO_NEW_BINDINGS) {
+      // new bindings are disallowed, so unbound variables in 'pat'
+      // cause failure
+      return false;
+    }
+
+    // bind 'tvName' to 'conc'
+    binding = new Binding;
+    binding->sarg.setAtomicType(conc);
+    return addBinding(tvName, binding, flags);
+  }
+}
+
+
+
+bool IMType::imatchCVAtomicType(CVAtomicType const *conc, CVAtomicType const *pat,
+                                MatchFlags flags)
+{
+  // compare cv-flags
+  return imatchCVFlags(conc->cv, pat->cv, flags) &&
+         imatchAtomicType(conc->atomic, pat->atomic, flags & MF_PROP);
+}
+
+  
+bool IMType::imatchCVFlags(CVFlags conc, CVFlags pat, MatchFlags flags)
+{
+  if (flags & MF_OK_DIFFERENT_CV) {
+    // anything goes
+    return true;
+  }
+  else if (flags & MF_DEDUCTION) {
+    // merely require that the pattern flags be a superset of
+    // the concrete flags (in/t0315.cc, in/t0348.cc)
+    //
+    // TODO: this is wrong, as it does not correctly implement
+    // 14.8.2.1; I am only implementing this because it emulates
+    // what matchtype does right now
+    if (pat >= conc) {
+      return true;
+    }
+    else {
+      return false;
+    }
+  }
+  else {
+    // require equality
+    return conc == pat;
+  }
+}
+
+
+bool IMType::imatchPointerType(PointerType const *conc, PointerType const *pat, MatchFlags flags)
+{
+  // note how MF_IGNORE_TOP_CV allows *this* type's cv flags to differ,
+  // but it's immediately suppressed once we go one level down; this
+  // behavior is repeated in all 'match' methods
+
+  return imatchCVFlags(conc->cv, pat->cv, flags) &&
+         imatchType(conc->atType, pat->atType, flags & MF_PTR_PROP);
+}
+
+
+bool IMType::imatchReferenceType(ReferenceType const *conc, ReferenceType const *pat, MatchFlags flags)
+{
+  if (flags & MF_DEDUCTION) {
+    // (in/t0114.cc, in/d0072.cc) allow pattern to be more cv-qualified;
+    // this only approximates 14.8.2.1, but emulates current matchtype
+    // behavior (actually, it emulates only the intended matchtype
+    // behavior; see comment added 2005-08-03 to MatchTypes::match_ref)
+    if (pat->atType->getCVFlags() >= conc->atType->getCVFlags()) {
+      // disable further comparison of these cv-flags
+      flags |= MF_IGNORE_TOP_CV;
+    }
+  }
+
+  return imatchType(conc->atType, pat->atType, flags & MF_PTR_PROP);
+}
+
+
+bool IMType::imatchFunctionType(FunctionType const *conc, FunctionType const *pat, MatchFlags flags)
+{
+  // I do not compare 'FunctionType::flags' explicitly since their
+  // meaning is generally a summary of other information, or of the
+  // name (which is irrelevant to the type)
+
+  if (!(flags & MF_IGNORE_RETURN)) {
+    // check return type
+    if (!imatchType(conc->retType, pat->retType, flags & MF_PROP)) {
+      return false;
+    }
+  }
+
+  if ((conc->flags | pat->flags) & FF_NO_PARAM_INFO) {
+    // at least one of the types does not have parameter info,
+    // so no further comparison is possible
+    return true;            // gcov-ignore: cannot trigger in C++ mode
+  }
+
+  if (!(flags & MF_STAT_EQ_NONSTAT)) {
+    // check that either both are nonstatic methods, or both are not
+    if (conc->isMethod() != pat->isMethod()) {
+      return false;
+    }
+  }
+
+  // check that both are variable-arg, or both are not
+  if (conc->acceptsVarargs() != pat->acceptsVarargs()) {
+    return false;
+  }
+
+  // check the parameter lists (do not mask with MF_PROP here,
+  // it happens inside 'imatchParameterLists')
+  if (!imatchParameterLists(conc, pat, flags)) {
+    return false;
+  }
+
+  if (flags & MF_COMPARE_EXN_SPEC) {
+    // check the exception specs
+    if (!imatchExceptionSpecs(conc, pat, flags & MF_PROP)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool IMType::imatchParameterLists(FunctionType const *conc, FunctionType const *pat,
+                                  MatchFlags flags)
+{
+  SObjListIter<Variable> concIter(conc->params);
+  SObjListIter<Variable> patIter(pat->params);
+
+  // skip the 'this' parameter(s) if desired, or if one has it
+  // but the other does not (can arise if MF_STAT_EQ_NONSTAT has
+  // been specified)
+  {
+    bool ignore = flags & MF_IGNORE_IMPLICIT;
+
+    bool cm = conc->isMethod();
+    CVFlags ccv = CV_NONE;
+
+    bool pm = pat->isMethod();
+    CVFlags pcv = CV_NONE;
+
+    if (cm) {
+      ccv = concIter.data()->type->asReferenceType()->atType->getCVFlags();
+      if (!pm || ignore) {
+        concIter.adv();
+      }
+    }
+
+    if (pm) {
+      pcv = patIter.data()->type->asReferenceType()->atType->getCVFlags();
+      if (!cm || ignore) {
+        patIter.adv();
+      }
+    }
+
+    if (flags & MF_IGNORE_FUNC_CV) {
+      // Ignore cv-flags.
+    }
+    else if ((flags & MF_STAT_EQ_NONSTAT) && (cm != pm)) {
+      // The functions differ in their staticness, and that is a
+      // difference that we have explicitly ignored.  In such a case,
+      // looking at the cv-flags would again expose the difference in
+      // staticness, so we don't.
+      //
+      // TODO: This feels wrong.  It seems like we should let the
+      // differing cv-flags imply disequality.  But the mechanism for
+      // determining signature equivalence when validating members of
+      // an overload set currently requires it; see in/t0121.cc for
+      // some examples of what this validation entails.  Probably if I
+      // rewrite that code (which was written before function cv-flag
+      // checking was separable from receiver object checking), then
+      // this ugly exception to an otherwise straightforward rule
+      // could be elimintated.
+    }
+    else {
+      // Note that if we didn't skip the receivers, their cv-flags will
+      // be compared again, below, but that should be harmless.
+      //
+      // Example of requiring cv-flag sensitivity: in/t0591.cc
+      //
+      if (ccv != pcv) {
+        return false;
+      }
+    }
+  }
+
+  // this takes care of imatchFunctionType's obligation to suppress
+  // non-propagated flags after consumption; it is masked *after*
+  // we check MF_IGNORE_IMPLICIT
+  flags &= MF_PROP;
+
+  // allow toplevel cv flags on parameters to differ
+  if (!( flags & MF_RESPECT_PARAM_CV )) {
+    flags |= MF_IGNORE_TOP_CV;
+  }
+
+  for (; !concIter.isDone() && !patIter.isDone();
+       concIter.adv(), patIter.adv()) {
+    // parameter names do not have to match, but
+    // the types do
+    if (imatchType(concIter.data()->type, patIter.data()->type, flags)) {
+      // ok
+    }
+    else {
+      return false;
+    }
+  }
+
+  return concIter.isDone() == patIter.isDone();
+}
+
+
+// almost identical code to the above.. list comparison is
+// always a pain..
+bool IMType::imatchExceptionSpecs(FunctionType const *conc, FunctionType const *pat, MatchFlags flags)
+{
+  if (conc->exnSpec==NULL && pat->exnSpec==NULL)  return true;
+  if (conc->exnSpec==NULL || pat->exnSpec==NULL)  return false;
+
+  // hmm.. this is going to end up requiring that exception specs
+  // be listed in the same order, whereas I think the semantics
+  // imply they're more like a set.. oh well
+  //
+  // but if they are a set, how the heck do you do matching?
+  // I think I see; the matching must have already led to effectively
+  // concrete types on both sides.  But, since I only see 'pat' as
+  // the pattern + substitutions, it would still be hard to figure
+  // out the correct correspondence for the set semantics.
+  
+  // this will at least ensure I do not derive any bindings from
+  // the attempt to compare exception specs
+  flags |= MF_NO_NEW_BINDINGS;
+
+  SObjListIter<Type> concIter(conc->exnSpec->types);
+  SObjListIter<Type> patIter(pat->exnSpec->types);
+  for (; !concIter.isDone() && !patIter.isDone();
+       concIter.adv(), patIter.adv()) {
+    if (imatchType(concIter.data(), patIter.data(), flags)) {
+      // ok
+    }
+    else {
+      return false;
+    }
+  }
+
+  return concIter.isDone() == patIter.isDone();
+}
+
+
+bool IMType::imatchArrayType(ArrayType const *conc, ArrayType const *pat, MatchFlags flags)
+{
+  // what flags to propagate?
+  MatchFlags propFlags = (flags & MF_PROP);
+
+  if (flags & MF_IGNORE_ELT_CV) {
+    if (conc->eltType->isArrayType()) {
+      // propagate the ignore-elt down through as many ArrayTypes
+      // as there are
+      propFlags |= MF_IGNORE_ELT_CV;
+    }
+    else {
+      // the next guy is the element type, ignore *his* cv only
+      propFlags |= MF_IGNORE_TOP_CV;
+    }
+  }
+
+  if (!( imatchType(conc->eltType, pat->eltType, propFlags) &&
+         conc->hasSize() == pat->hasSize() )) {
+    return false;
+  }
+
+  // TODO: At some point I will implement dependent-sized arrays
+  // (t0435.cc), at which point the size comparison code here will
+  // have to be generalized.
+
+  if (conc->hasSize()) {
+    return conc->size == pat->size;
+  }
+  else {
+    return true;
+  }
+}
+
+
+bool IMType::imatchPointerToMemberType(PointerToMemberType const *conc,
+                                       PointerToMemberType const *pat, MatchFlags flags)
+{
+  return imatchAtomicType(conc->inClassNAT, pat->inClassNAT, flags) &&
+         imatchCVFlags(conc->cv, pat->cv, flags) &&
+         imatchType(conc->atType, pat->atType, flags & MF_PTR_PROP);
+}
+
+
+// -------------------- IMType: Expression ---------------------
+// This is not full-featured matching as with types, rather this
+// is mostly just comparison for equality.
+bool IMType::imatchExpression(Expression const *conc, Expression const *pat, MatchFlags flags)
+{
+  if (conc->isE_grouping()) {
+    return imatchExpression(conc->asE_groupingC()->expr, pat, flags);
+  }
+  if (pat->isE_grouping()) {
+    return imatchExpression(conc, pat->asE_groupingC()->expr, flags);
+  }
+
+  if (conc->kind() != pat->kind()) {
+    return false;
+  }
+
+  // turn off variable matching for this part because expression
+  // comparison should be fairly literal
+  flags &= ~MF_MATCH;
+
+  ASTSWITCH2C(Expression, conc, pat) {
+    // only the expression constructors that yield integers and do not
+    // have side effects are allowed within type constructors, so that
+    // is all we deconstruct here
+    //
+    // TODO: should 65 and 'A' be regarded as equal here?  For now, I
+    // do not regard them as equivalent...
+    ASTCASE2C(E_boolLit, c, p) {
+      return c->b == p->b;
+    }
+    ASTNEXT2C(E_intLit, c, p) {
+      return c->i == p->i;
+    }
+    ASTNEXT2C(E_charLit, c, p) {
+      return c->c == p->c;
+    }
+    ASTNEXT2C(E_variable, c, p) {
+      if (c->var == p->var) {
+        return true;
+      }
+      if (c->var->isTemplateParam() &&
+          p->var->isTemplateParam()) {
+        // like for matchTypeVariable
+        return c->var->sameTemplateParameter(p->var);
+      }
+      return false;
+    }
+    ASTNEXT2C(E_sizeof, c, p) {
+      // like above: is sizeof(int) the same as 4?
+      return imatchExpression(c->expr, p->expr, flags);
+    }
+    ASTNEXT2C(E_unary, c, p) {
+      return c->op == p->op &&
+             imatchExpression(c->expr, p->expr, flags);
+    }
+    ASTNEXT2C(E_binary, c, p) {
+      return c->op == p->op &&
+             imatchExpression(c->e1, p->e1, flags) &&
+             imatchExpression(c->e2, p->e2, flags);
+    }
+    ASTNEXT2C(E_cast, c, p) {
+      return imatchType(c->ctype->getType(), p->ctype->getType(), flags) &&
+             imatchExpression(c->expr, p->expr, flags);
+    }
+    ASTNEXT2C(E_cond, c, p) {
+      return imatchExpression(c->cond, p->cond, flags) &&
+             imatchExpression(c->th, p->th, flags) &&
+             imatchExpression(c->el, p->el, flags);
+    }
+    ASTNEXT2C(E_sizeofType, c, p) {
+      return imatchType(c->atype->getType(), p->atype->getType(), flags);
+    }
+    ASTNEXT2C(E_keywordCast, c, p) {
+      return c->key == p->key &&
+             imatchType(c->ctype->getType(), p->ctype->getType(), flags) &&
+             imatchExpression(c->expr, p->expr, flags);
+    }
+    ASTDEFAULT2C {
+      // For expressions that are *not* const-eval'able, we can't get
+      // here because tcheck reports an error and bails before we get
+      // a chance.  So, the only way to trigger this code is to extend
+      // the constant-expression evaluator to handle a new form, and
+      // then fail to update the comparison code here to compare such
+      // forms with each other.
+      xfailure("some kind of expression is const-eval'able but mtype "
+               "does not know how to compare it");     // gcov-ignore
+    }
+    ASTENDCASE2C
+  }
+}
+
+
+// -------------------------- MType --------------------------
+MType::MType(bool allowNonConst_)
+  : allowNonConst(allowNonConst_)
+{}
+
+MType::~MType()
+{}
+
+
+MType::MType(Env &e)
+  : allowNonConst(true)
+{
+  env = &e;
+}
+
+
+bool MType::matchType(Type const *conc, Type const *pat, MatchFlags flags)
+{
+  // I can only uphold the promise of not modifying 'conc' and 'pat'
+  // if asked to when I was created.
+  xassert(!allowNonConst);
+
+  return commonMatchType(conc, pat, flags);
+}
+
+bool MType::matchTypeNC(Type *conc, Type *pat, MatchFlags flags)
+{
+  return commonMatchType(conc, pat, flags);
+}
+
+bool MType::commonMatchType(Type const *conc, Type const *pat, MatchFlags flags)
+{
+  // 14.8.2.1p2b3
+  if ((flags & MF_DEDUCTION) &&
+      !pat->isReferenceType()) {
+    flags |= MF_IGNORE_TOP_CV;
+  }
+
+  bool result = imatchType(conc, pat, flags);
+
+  #ifndef NDEBUG
+    static bool doTrace = tracingSys("mtype");
+    if (doTrace) {
+      ostream &os = trace("mtype");
+      os << "conc=`" << conc->toString()
+         << "' pat=`" << pat->toString()
+         << "' flags={" << toString(flags)
+         << "}; match=" << (result? "true" : "false")
+         ;
+         
+      if (failedDueToDQT) {
+        os << " (failedDueToDQT)";
+      }
+
+      if (result) {
+        os << bindingsToString();
+      }
+
+      os << endl;
+    }
+  #endif // NDEBUG
+
+  return result;
+}
+
+
+bool MType::matchSTemplateArguments(ObjList<STemplateArgument> const &conc,
+                                    ObjList<STemplateArgument> const &pat,
+                                    MatchFlags flags)
+{
+  xassert(!allowNonConst);
+
+  return commonMatchSTemplateArguments(conc, pat, flags);
+}
+
+bool MType::matchSTemplateArgumentsNC(ObjList<STemplateArgument> &conc,
+                                      ObjList<STemplateArgument> &pat,
+                                      MatchFlags flags)
+{
+  return commonMatchSTemplateArguments(conc, pat, flags);
+}
+
+bool MType::commonMatchSTemplateArguments(ObjList<STemplateArgument> const &conc,
+                                          ObjList<STemplateArgument> const &pat,
+                                          MatchFlags flags)
+{
+  bool result = imatchSTemplateArguments(conc, pat, flags);
+
+  #ifndef NDEBUG
+    static bool doTrace = tracingSys("mtype");
+    if (doTrace) {
+      ostream &os = trace("mtype");
+      os << "conc=" << sargsToString(conc)
+         << " pat=" << sargsToString(pat)
+         << " flags={" << toString(flags)
+         << "}; match=" << (result? "true" : "false")
+         ;
+
+      if (result) {
+        os << bindingsToString();
+      }
+
+      os << endl;
+    }
+  #endif // NDEBUG
+
+  return result;
+}
+
+
+bool MType::matchAtomicType(AtomicType const *conc, AtomicType const *pat,
+                            MatchFlags flags)
+{
+  xassert(!allowNonConst);
+  return imatchAtomicType(conc, pat, flags);
+}
+
+
+bool MType::matchSTemplateArgument(STemplateArgument const *conc,
+                                   STemplateArgument const *pat, MatchFlags flags)
+{
+  xassert(!allowNonConst);
+  return imatchSTemplateArgument(conc, pat, flags);
+}
+
+
+bool MType::matchExpression(Expression const *conc, Expression const *pat, MatchFlags flags)
+{
+  xassert(!allowNonConst);
+  return imatchExpression(conc, pat, flags);
+}
+
+
+string MType::bindingsToString() const
+{
+  // extract bindings
+  stringBuilder sb;
+  sb << "; bindings:";
+  for (BindingMap::IterC iter(bindings); !iter.isDone(); iter.adv()) {
+    sb << " \"" << iter.key() << "\"=`" << iter.value()->asString() << "'";
+  }
+  return sb;
+}
+
+
+int MType::getNumBindings() const
+{
+  return bindings.getNumEntries();
+}
+
+
+bool MType::isBound(StringRef name) const
+{
+  return !!bindings.getC(name);
+}
+
+
+STemplateArgument MType::getBoundValue(StringRef name, TypeFactory &tfac) const
+{
+  // you can't do this with the matcher that promises to
+  // only work with const pointers; this assertion provides
+  // the justification for the const_casts below
+  xassert(allowNonConst);
+
+  Binding const *b = bindings.getC(name);
+  if (!b) {
+    return STemplateArgument();
+  }
+
+  if (b->sarg.isAtomicType()) {
+    // the STA_ATOMIC kind is only for internal use by this module;
+    // we translate it into STA_TYPE for external use (but the caller
+    // has to provide a 'tfac' to allow the translation)
+    Type *t = tfac.makeCVAtomicType(
+      const_cast<AtomicType*>(b->sarg.getAtomicType()), CV_NONE);
+    return STemplateArgument(t);
+  }
+
+  if (b->sarg.isType()) {
+    // similarly, we have to combine the type in 'sarg' with 'cv'
+    // before exposing it to the user
+    Type *t = tfac.setQualifiers(SL_UNKNOWN, b->cv,
+                                 const_cast<Type*>(b->getType()), NULL /*syntax*/);
+    return STemplateArgument(t);
+  }
+
+  // other cases are already in the public format
+  return b->sarg;
+}
+
+
+void MType::setBoundValue(StringRef name, STemplateArgument const &value)
+{
+  xassert(value.hasValue());
+  
+  Binding *b = new Binding;
+  b->sarg = value;
+  if (value.isType()) {
+    b->cv = value.getType()->getCVFlags();
+  }
+
+  bindings.addReplace(name, b);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/mtype.h
===================================================================
--- vendor/elsa/current/elsa/mtype.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/mtype.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,240 @@
+// mtype.h
+// new implementation of type matcher
+
+// 2005-07-24: The plan for this module is it will eventually replace
+// the 'matchtype' module, and also Type::equals.  However, right now
+// it is still being put through its paces and so just exists on the
+// side as an auxiliary module, only reachable via the __test_mtype
+// internal testing hook function, exercised for the moment only by
+// in/t0511.cc.
+
+#ifndef MTYPE_H
+#define MTYPE_H
+
+#include "mflags.h"             // MatchFlags
+#include "objmap.h"             // ObjMap
+#include "cc_type.h"            // Type
+#include "cc_ast.h"             // C++ AST
+#include "template.h"           // STemplateArgument
+
+class Env;                      // cc_env.h
+
+class MType;                    // this file
+
+
+// Internal MType: the core of the MType implementation, separated
+// into its own class so that it cannot (easily, accidentally) use the
+// public MType interfaces.  Its directly-exposed interfaces ensure
+// constness of arguments, except that the exposed 'bindings' map can
+// be used for non-const access.  The MType class is responsible for
+// packaging this in a sound form.
+class IMType {
+protected:   // types
+  // A template variable binding.  A name can be bound to one of three
+  // things:
+  //   - a Type object and CVFlags to modify it
+  //   - an AtomicType object (with no cv)
+  //   - a non-type value given by 'sarg'
+  // The first two options are similar, differing only because it avoids
+  // having to wrap a Type object around an AtomicType object.
+  //
+  // Public clients don't have to know about this trickery though; as
+  // far as they are concerned, a name is simply bound to an
+  // STemplateArgument (though they have to pass a TypeFactory to
+  // allow the internal representation to be converted).
+  class Binding {
+  public:    // data
+    STemplateArgument sarg;     // most of the binding info
+    CVFlags cv;                 // if sarg.isType(), we are bound to the 'cv' version of it
+
+  public:
+    Binding() : sarg(), cv(CV_NONE) {}
+    Binding(Binding const &obj) : sarg(obj.sarg), cv(obj.cv) {}
+
+    bool operator== (Binding const &obj) const;
+
+    // Though I am using 'STemplateArgument', I want to treat its
+    // 'Type*' as being const.
+    void setType(Type const *t) { sarg.setType(const_cast<Type*>(t)); }
+    Type const *getType() const { return sarg.getType(); }
+                            
+    // debugging
+    string asString() const;
+  };
+
+protected:   // data
+  // set of bindings
+  typedef ObjMap<char const /*StringRef*/, Binding> BindingMap;
+  BindingMap bindings;
+  
+  // This is used to resolve DQTs during matching.  Originally I'd
+  // hoped to keep MType unaware of the environment, but this now
+  // seems unavoidable.  On the bright side, it means I can remove
+  // all PQName resolution code from MType, since Env can do that.
+  Env *env;                    // (nullable serf)
+
+public:      // data                    
+  // This is set to true if a failure to resolve a DQT is the cause of
+  // a match failure.  It starts as false, but once set to true, MType
+  // does not reset it, so it is up to the caller to reset this flag
+  // between queries when appropriate.
+  bool failedDueToDQT;
+
+protected:   // funcs
+  // ******************************************************************
+  // * NOTE: Do *not* simply make these entry points public.  If you  *
+  // * need to call one of these, make a public wrapper that consults *
+  // * 'allowNonConst' and uses TRACE("mtype") appropriately.         *
+  // ******************************************************************
+  static bool canUseAsVariable(Variable *var, MatchFlags flags);
+  bool imatchAtomicType(AtomicType const *conc, AtomicType const *pat, MatchFlags flags);
+  bool imatchTypeVariable(TypeVariable const *conc, TypeVariable const *pat, MatchFlags flags);
+  bool imatchPseudoInstantiation(PseudoInstantiation const *conc,
+                                       PseudoInstantiation const *pat, MatchFlags flags);
+  bool imatchSTemplateArguments(ObjList<STemplateArgument> const &conc,
+                               ObjList<STemplateArgument> const &pat,
+                               MatchFlags flags);
+  bool imatchSTemplateArgument(STemplateArgument const *conc,
+                                     STemplateArgument const *pat, MatchFlags flags);
+  bool imatchNontypeWithVariable(STemplateArgument const *conc,
+                                       E_variable *pat, MatchFlags flags);
+  bool addBinding(StringRef name, Binding * /*owner*/ value, MatchFlags flags);
+  bool imatchDependentQType(DependentQType const *conc,
+                                  DependentQType const *pat, MatchFlags flags);
+  bool imatchPQName(PQName const *conc, PQName const *pat, MatchFlags flags);
+  bool imatchType(Type const *conc, Type const *pat, MatchFlags flags);
+  bool imatchTypeWithVariable(Type const *conc, TypeVariable const *pat,
+                                    CVFlags tvCV, MatchFlags flags);
+  bool imatchTypeWithResolvedType(Type const *conc, Type const *pat,
+                                  MatchFlags flags);
+  bool imatchTypeWithDQT(Type const *conc, DependentQType const *pat,
+                         CVFlags patCV, MatchFlags flags);
+  bool equalWithAppliedCV(Type const *conc, Binding *binding, CVFlags cv, MatchFlags flags);
+  bool imatchTypeWithSpecifiedCV(Type const *conc, Type const *pat, CVFlags cv, MatchFlags flags);
+  bool addTypeBindingWithoutCV(StringRef tvName, Type const *conc,
+                               CVFlags tvcv, MatchFlags flags);
+  bool imatchTypeWithPolymorphic(Type const *conc, SimpleTypeId polyId, MatchFlags flags);
+  bool imatchAtomicTypeWithVariable(AtomicType const *conc,
+                                   TypeVariable const *pat,
+                                   MatchFlags flags);
+  bool imatchCVAtomicType(CVAtomicType const *conc, CVAtomicType const *pat, MatchFlags flags);
+  bool imatchCVFlags(CVFlags conc, CVFlags pat, MatchFlags flags);
+  bool imatchPointerType(PointerType const *conc, PointerType const *pat, MatchFlags flags);
+  bool imatchReferenceType(ReferenceType const *conc, ReferenceType const *pat, MatchFlags flags);
+  bool imatchFunctionType(FunctionType const *conc, FunctionType const *pat, MatchFlags flags);
+  bool imatchParameterLists(FunctionType const *conc, FunctionType const *pat,
+                                  MatchFlags flags);
+  bool imatchExceptionSpecs(FunctionType const *conc, FunctionType const *pat, MatchFlags flags);
+  bool imatchArrayType(ArrayType const *conc, ArrayType const *pat, MatchFlags flags);
+  bool imatchPointerToMemberType(PointerToMemberType const *conc,
+                                       PointerToMemberType const *pat, MatchFlags flags);
+  bool imatchExpression(Expression const *conc, Expression const *pat, MatchFlags flags);
+
+private:     // funcs
+  // the only allowed subclass is MType; this justifies a
+  // static_cast in mtype.cc
+  friend class MType;
+  IMType();
+  ~IMType();
+};
+
+
+// the public interface
+class MType : protected IMType {
+private:     // funcs
+  // This flag is true if the client is using the non-const interface.
+  //
+  // The idea is this module can support one of two modes
+  // w.r.t. constness:
+  //   1) The module promises not to modify any of its arguments.  The
+  //      client can use 'match', but cannot retrieve bindings (because
+  //      the bindings expose non-const access).
+  //      -> A possible future extension is to provide a binding query
+  //         interface that only exposes const access, but as that is
+  //         not needed right now, it is not provided.
+  //   2) The module makes no promises about modification.  The client
+  //      must use 'matchNC', and can query bindings freely.
+  // The private functions act as if the module is always in 'const' mode,
+  // that is, they promise to never modify the arguments; query is the
+  // one exception.
+  //
+  // The rationale for such deliberate treatment of 'const' is that I
+  // want to be able to use this module both for Type equality, which
+  // ought to be queryable with a const interface, and Type matching,
+  // which needs binding queries, which are at best inconvenient to
+  // provide with a const interface.
+  bool const allowNonConst;
+
+private:     // funcs
+  string bindingsToString() const;
+  bool commonMatchType(Type const *conc, Type const *pat, MatchFlags flags);
+  bool commonMatchSTemplateArguments(ObjList<STemplateArgument> const &conc,
+                                     ObjList<STemplateArgument> const &pat,
+                                     MatchFlags flags);
+
+public:      // funcs
+  // if 'allowNonConst' is false, const match* can be invoked;
+  // if 'allowNonConst' is true, 'getBoundValue' be invoked
+  MType(bool allowNonConst = false);
+  ~MType();
+
+  // This constructor sets 'allowNonConst' to true and also
+  // provides the 'env' for resolving DQTs.
+  MType(Env &env);
+
+  // so I can supply an Env even in const mode
+  //
+  // 2005-08-14: Can't allow this.  See imatchWithResolvedType.
+  // If you need to resolve DQTs, you have to allowNonConst, so
+  // the Env can/must be provided in the constructor call.
+  //void setEnv(Env *e) { env=e; }
+  
+  // what constness mode are we in?
+  bool getAllowNonConst() const { return allowNonConst; }
+
+  // Publish this member; see its comments above.
+  IMType::failedDueToDQT;
+
+  // ---- const match ----
+  // these functions can only be called if 'allowNonConst' is false
+
+  // return true if 'conc' is an instance of 'pat', in which case this
+  // object will have a record of the instantiation bindings; the
+  // const version can only be called when 'nonConst' is false
+  bool matchType(Type const *conc, Type const *pat, MatchFlags flags);
+  
+  // a few more
+  bool matchSTemplateArguments(ObjList<STemplateArgument> const &conc,
+                               ObjList<STemplateArgument> const &pat,
+                               MatchFlags flags);
+  bool matchAtomicType(AtomicType const *conc, AtomicType const *pat,
+                       MatchFlags flags);
+  bool matchSTemplateArgument(STemplateArgument const *conc,
+                              STemplateArgument const *pat, MatchFlags flags);
+  bool matchExpression(Expression const *conc, Expression const *pat, MatchFlags flags);
+
+  // ---- non-const match ----
+  // for now, only selected non-const entry points are provided
+  bool matchTypeNC(Type *conc, Type *pat, MatchFlags flags);
+  bool matchSTemplateArgumentsNC(ObjList<STemplateArgument> &conc,
+                                 ObjList<STemplateArgument> &pat,
+                                 MatchFlags flags);
+
+  // ---- query ----
+  // how many bindings are currently active?
+  int getNumBindings() const;
+
+  // returns true if 'name' is bound to something; this *can* be
+  // called even when 'allowNonConst' is false
+  bool isBound(StringRef name) const;
+
+  // get the binding for 'name', or return STA_NONE if none;
+  // 'allowNonConst' must be true
+  STemplateArgument getBoundValue(StringRef name, TypeFactory &tfac) const;
+
+  // set a binding; 'value' must not be STA_NONE
+  void setBoundValue(StringRef name, STemplateArgument const &value);
+};
+
+
+#endif // MTYPE_H

Added: vendor/elsa/current/elsa/multitest.pl
===================================================================
--- vendor/elsa/current/elsa/multitest.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/multitest.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,240 @@
+#!/usr/bin/perl -w
+# run a program on an input file, then (if the input has some
+# stylized comments) re-run, expecting an error
+
+use strict 'subs';
+use Config;
+
+$comment = "//";    # comment syntax
+$selectedError = "";
+$keepTemps = 0;
+$contin = 0;
+ at failures = ();     # if $contin, track which configurations failed
+
+$me = "multitest";
+
+while (@ARGV && $ARGV[0] =~ m/^-/) {
+  my $opt = $ARGV[0];
+  shift @ARGV;
+
+  if ($opt eq "-errnum") {
+    $selectedError = $ARGV[0];
+    shift @ARGV;
+    next;
+  }
+
+  if ($opt eq "-keep") {
+    $keepTemps = 1;
+    next;
+  }
+
+  if ($opt eq "-contin") {
+    $contin = 1;
+    next;
+  }
+
+  die("$me: unknown argument: $opt\n");
+}
+
+if (@ARGV < 2) {
+  print(<<"EOF");
+usage: $0 [options] program [args...] input.cc
+
+This will first invoke the command line as given, expecting that to
+succeed.  Then, it will scan input.cc (which must be the last argument
+on the command line) for any lines of the forms:
+
+  ${comment}ERROR(n): <some code>
+  <some code>     ${comment}ERRORIFMISSING(n):
+
+If it finds them, then for each such 'n' the lines ERROR(n) will be
+uncommented (and "ERROR(n)" removed), and lines ERRORIFMISSING(n)
+commented-out, and the original command executed again.  These
+additional runs should fail.
+
+options:
+  -errnum n     Only test ERROR(n) (does not test original).
+  -keep         Keep temporaries even when they succeed.
+EOF
+
+  exit(0);
+}
+
+
+# excerpt from perlipc man page
+defined $Config{sig_name} || die "No sigs?";
+$i = 0;
+foreach $name (split(' ', $Config{sig_name})) {
+  $signo{$name} = $i;
+  $signame[$i] = $name;
+  $i++;
+}
+
+$sigint = $signo{INT};
+$sigquit = $signo{QUIT};
+#print("sigint: $sigint\n");
+
+
+$fname = $ARGV[@ARGV - 1];
+#print("fname: $fname\n");
+
+($fnameBase, $fnameExt) = ($fname =~ m|^(.*)(\.[^./]*)$|);
+                                   #    bse ext
+if (!defined($fnameExt)) {
+  $fnameBase = $fname;
+  $fnameExt = "";     # no '.' present anywhere (after last '/')
+}
+
+# try once with no modifications
+if (!$selectedError) {
+  $code = mysystem(@ARGV);
+  if ($code != 0) {
+    failed("original", $code);
+  }
+}
+
+# bail, or if $contin, just keep track
+sub failed {
+  my ($config, $code) = @_;
+
+  if ($contin) {
+    push @failures, ($config);
+  }
+  else {
+    exit($code);
+  }
+}
+
+
+# read the input file
+open(IN, "<$fname") or die("can't open $fname: $!\n");
+ at lines = <IN>;
+close(IN) or die;
+
+# see what ERROR/ERRORIFMISSING lines are present
+%codes = ();
+foreach $line (@lines) {
+  my ($miss, $code) = ($line =~ m|${comment}ERROR(IFMISSING)?\((\d+)\):|);
+  if (defined($code)) {
+    $codes{$code} = 1;
+    $miss .= " ";     # pretend used
+  }
+}
+
+# get sorted keys
+ at allkeys = (sort {$a <=> $b} (keys %codes));
+$numkeys = @allkeys;
+if ($numkeys == 0) {
+  # no error tags
+  exit(0);
+}
+
+# consider each in turn
+$testedVariations = 0;
+foreach $selcode (@allkeys) {
+  if ($selectedError &&
+      $selectedError ne $selcode) {
+    next;
+  }
+  $testedVariations++;
+
+  print("-- selecting ERROR($selcode) --\n");
+
+  my $tempfname = "${fnameBase}.error${selcode}${fnameExt}";
+
+  # run through the lines in the file, generating a new file
+  # that has the selected lines uncommented
+  open(OUT, ">$tempfname") or die("can't create $tempfname: $!\n");
+  foreach $line (@lines) {
+    my ($miss, $code, $rest) =
+      ($line =~ m|${comment}ERROR(IFMISSING)?\((\d+)\):(.*)$|);
+      #                  miss          code    rest
+    if (defined($code) && $selcode == $code) {
+      if ($miss) {
+        # ERRORIFMISSING: we want to comment the whole line
+        print OUT ("${comment} $line");
+      }
+      else{
+        # ERROR: we want to uncomment what follows the "ERROR" marker
+        print OUT ($rest, "\n");
+      }
+    }
+    elsif ($line =~ m|collectLookupResults|) {
+      # comment-out this line in the error cases because if I do not
+      # then it will often lead to its own error, which would mask the
+      # one I am trying to verify
+      print OUT ("${comment} $line");
+    }
+    else {
+      print OUT ($line);         # emit as-is
+    }
+  }
+  close(OUT) or die;
+
+  # run the command on the new input file
+  @args = @ARGV;
+  $args[@ARGV - 1] = $tempfname;
+
+  #print("command: ", join(' ', @args), "\n");
+  $code = mysystem(@args);
+  if ($code == 0) {
+    print("ERROR($selcode): expected this to fail:\n",
+          "  ", join(' ', @args), "\n");
+    failed($selcode, 4);
+  }
+  else {
+    print("$selcode: failed as expected\n");
+    if (!$keepTemps) {
+      unlink($tempfname);
+    }
+  }
+}
+
+print("\n$me: ");
+
+if ($contin && @failures) {
+  print("failures: @failures\n");
+  exit(4);
+}
+elsif (!$selectedError) {
+  print("success: all $testedVariations variations failed as expected\n");
+}
+elsif ($testedVariations) {
+  print("success: error $selectedError failed as expected\n");
+}
+else {
+  print("nop: there is no error $selectedError in $fname\n");
+}
+
+exit(0);
+
+
+# like 'system', except return a proper exit code, and
+# propagate fatal signals (esp. ctrl-C)
+sub mysystem {
+  my @args = @_;
+
+  # dsw: when the test fails and it is not on the primary run, there
+  # is no output to allow you to easily reproduce the bug
+  print("running " . join(" ", @args), "\n");
+  my $code = system(@args);
+  if ($code == 0) { return $code; }
+
+  my $sig = $code & 127;
+  if ($sig != 0) {
+    if ($sig == $sigquit || $sig == $sigint) {
+      # subprocess died to user-originated signal; kill myself
+      # the same way
+      #print("killing myself with $sig\n");
+      kill $sig, $$;
+    }
+
+    # some other signal
+    die("child died with signal $signame[$sig]\n");
+  }
+
+  return $code >> 8;
+}
+
+
+# EOF


Property changes on: vendor/elsa/current/elsa/multitest.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/notopt.cc
===================================================================
--- vendor/elsa/current/elsa/notopt.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/notopt.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,75 @@
+// notopt.cc
+// little routines that GCC's optimizer barfs on (produces incorrect
+// code), so I separate them from the rest of the code (very annoying)
+
+#include "cc_env.h"    // Env
+#include "trace.h"     // TRACE
+
+// I am certain it is broken on gcc-2.95.3 on x86; maybe it
+// is ok on gcc-3, maybe not ...
+#if defined(__GNUC__) && __GNUC__<3 && defined(__OPTIMIZE__)
+  #error This module must be compiled with optimization turned off
+#endif
+
+
+// This is the main one that initially caused the problem.  With
+// -O2, an XTypeDeduction just flies right by the 'catch' as if
+// it weren't there.
+Type *Env::applyArgumentMapToType_helper(MType &map, Type *origSrc)
+{
+  try {
+    return applyArgumentMapToType(map, origSrc);
+  }
+  catch (XTypeDeduction &x) {
+    HANDLER();
+    TRACE("template", "failure to instantiate: " << x.why());
+    return NULL;
+  }
+}
+
+
+// This is the only other function that catches XTypeDeduction,
+// so I moved it out here too.
+STemplateArgument *Env::makeDefaultTemplateArgument
+  (Variable const *param, MType &map)
+{
+  // type parameter?
+  if (param->hasFlag(DF_TYPEDEF) &&
+      param->defaultParamType) {
+    // use 'param->defaultParamType', but push it through the map
+    // so it can refer to previous arguments 
+    try {
+      Type *t = applyArgumentMapToType(map, param->defaultParamType);
+      return new STemplateArgument(t);
+    }
+    catch (XTypeDeduction &x) {
+      HANDLER();
+      error(stringc << "could not evaluate default argument `"
+                    << param->defaultParamType->toString() 
+                    << "': " << x.why());
+      return NULL;
+    }
+  }
+  
+  // non-type parameter?
+  else if (!param->hasFlag(DF_TYPEDEF) &&
+           param->value) {
+    try {
+      STemplateArgument *ret = new STemplateArgument;
+      *ret = applyArgumentMapToExpression(map, param->value);
+      return ret;
+    }
+    catch (XTypeDeduction &x) {
+      HANDLER();
+      error(stringc << "could not evaluate default argument `"
+                    << param->value->exprToString() 
+                    << "': " << x.why());
+      return NULL;
+    }
+  }
+
+  return NULL;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/overload.cc
===================================================================
--- vendor/elsa/current/elsa/overload.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/overload.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2051 @@
+// overload.cc                       see license.txt for copyright and terms of use
+// code for overload.h
+
+// This module intends to implement the overload resolution procedure
+// described in cppstd clause 13.  However, there is a large gap
+// between the English description there and an implementation in
+// code, so it's likely there are omissions and deviations.
+
+#include "overload.h"      // this module
+#include "cc_env.h"        // Env
+#include "variable.h"      // Variable
+#include "cc_type.h"       // Type, etc.
+#include "trace.h"         // TRACE
+#include "typelistiter.h"  // TypeListIter
+#include "strtokp.h"       // StrtokParse
+#include "mtype.h"         // MType
+
+
+// ------------------- Candidate -------------------------
+Candidate::Candidate(Variable *v, Variable *instFrom0, int numArgs)
+  : var(v)
+  , instFrom(instFrom0)
+  , conversions(numArgs)
+{}
+
+Candidate::~Candidate()
+{}
+
+
+bool Candidate::hasAmbigConv() const
+{
+  for (int i=0; i < conversions.size(); i++) {
+    if (conversions[i].isAmbiguous()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+void Candidate::conversionDescriptions() const
+{
+  for (int i=0; i < conversions.size(); i++) {
+    OVERLOADTRACE(i << ": " << toString(conversions[i]));
+  }
+}
+
+
+Type *OverloadResolver::getReturnType(Candidate const *winner) const
+{
+  FunctionType *ft = winner->var->type->asFunctionType();
+  Type *retType = ft->retType;
+  if (!retType->isSimpleType()) {
+    return retType;      // easy
+  }
+
+  SimpleTypeId retId = retType->asSimpleTypeC()->type;
+  if (isConcreteSimpleType(retId)) {
+    return retType;      // also easy
+  }
+
+  // At this point, we do not have a concrete return type, but
+  // rather an algorithm for computing a return type given
+  // the types of the parameters.
+  //
+  // However, we also do not have easy access to the parameter types
+  // if they are polymorphic, which they must be for us to not have
+  // had a concrete type above.  What we have instead is the argument
+  // types and the conversion sequences that lead to the parameter
+  // types, so we need to use them to find the actual parameter types.
+
+  ArrayStack<Type*> concreteParamTypes;
+  int i = 0;
+  SFOREACH_OBJLIST(Variable, ft->params, paramIter) {
+    // get the polymorphic param type
+
+    // have:
+    Type *argType = args[i].type;                            // arg type
+    ImplicitConversion const &conv = winner->conversions[i]; // conversion
+    Type *paramType = paramIter.data()->type;    // param type, possibly polymorphic
+
+    // want: concrete parameter type
+    concreteParamTypes.push(conv.getConcreteDestType(env.tfac, argType, paramType));
+
+    i++;
+  }
+
+  // Ok!  Now we have some concrete parameter types, and can apply
+  // the algorithm specified by 'retId'.
+  switch (retId) {
+    // if this fails, we should have detected above that a concrete
+    // return type was available
+    default: xfailure("bad return type algorithm id");
+
+    // e.g.: T operator++ (VQ T&, int)
+    case ST_PRET_STRIP_REF: {
+      Type *vqT = concreteParamTypes[0]->getAtType();
+      return env.tfac.setQualifiers(SL_UNKNOWN, CV_NONE, vqT, NULL /*syntax*/);
+    }
+
+    // see ArrowStarCandidateSet::instantiateCandidate
+    case ST_PRET_PTM:
+      xfailure("ST_PRET_PTM is handled elsewhere");
+
+    // e.g. T& operator* (T*)
+    case ST_PRET_FIRST_PTR2REF: {
+      Type *T = concreteParamTypes[0]->getAtType();
+      return env.tfac.makeReferenceType(T);
+    }
+
+    // see E_binary::itcheck_x and resolveOverloadedBinaryOperator
+    case ST_PRET_SECOND_PTR2REF:
+      xfailure("ST_PRET_SECOND_PTR2REF is handled elsewhere");
+
+    // e.g.: LR operator* (L, R)
+    case ST_PRET_ARITH_CONV:
+      return usualArithmeticConversions(env.tfac,
+               concreteParamTypes[0], concreteParamTypes[1]);
+
+    // e.g.: L operator<< (L, R)
+    case ST_PRET_FIRST:
+      return concreteParamTypes[0];
+
+    // e.g.: T* operator+ (ptrdiff_t, T*)
+    case ST_PRET_SECOND:
+      return concreteParamTypes[1];
+  }
+}
+
+
+// ------------------ resolveOverload --------------------
+// prototypes
+int compareConversions(ArgumentInfo const &src,
+  ImplicitConversion const &left, Type const *leftDest,
+  ImplicitConversion const &right, Type const *rightDest);
+int compareStandardConversions
+  (ArgumentInfo const &leftSrc, StandardConversion left, Type const *leftDest,
+   ArgumentInfo const &rightSrc, StandardConversion right, Type const *rightDest);
+bool convertsPtrToBool(Type const *src, Type const *dest);
+bool isPointerToCompound(Type const *type, CompoundType const *&ct);
+bool isReferenceToCompound(Type const *type, CompoundType const *&ct);
+bool isPointerToCompoundMember(Type const *type, CompoundType const *&ct);
+bool isBelow(CompoundType const *low, CompoundType const *high);
+bool isProperSubpath(CompoundType const *LS, CompoundType const *LD,
+                     CompoundType const *RS, CompoundType const *RD);
+
+
+
+// this function can be used anyplace that there's only one list
+// of original candidate functions
+Variable *resolveOverload(
+  Env &env,
+  SourceLoc loc,
+  ErrorList * /*nullable*/ errors,
+  OverloadFlags flags,
+  SObjList<Variable> &varList,
+  PQName *finalName,
+  GrowArray<ArgumentInfo> &args,
+  bool &wasAmbig)
+{
+  OverloadResolver r(env, loc, errors, flags, finalName, args, varList.count());
+  r.processCandidates(varList);
+  return r.resolve(wasAmbig);
+}
+
+
+OverloadResolver::OverloadResolver
+  (Env &en, SourceLoc L, ErrorList *er,
+   OverloadFlags f,
+   PQName *finalName0,
+   GrowArray<ArgumentInfo> &a,
+   int numCand)
+  : env(en),
+    loc(L),
+    errors(er),
+    flags(f),
+    finalName(finalName0),
+    args(a),
+    finalDestType(NULL),
+    emptyCandidatesIsOk(false),
+
+    // this estimate does not have to be perfect; if it's high,
+    // then more space will be allocated than necessary; if it's
+    // low, then the 'candidates' array will have to be resized
+    // at some point; it's entirely a performance issue
+    candidates(numCand),
+    origCandidates(numCand)
+{
+  //overloadNesting++;
+
+  // part of 14.7.1 para 4: If any argument types is a reference to a
+  // template class instantiation, but the body has not been
+  // instantiated yet, instantiate it.
+  //
+  // Further, if an argument is (a reference to) a class type and that
+  // class has conversion operators that yield pointers or references
+  // to template class instnatiations, make sure *their* bodies are
+  // instantiated too.
+  //
+  // All this could conceivably be too much instantiation, as I could
+  // imagine that some of these don't necessarily "affect the
+  // semantics of the program"; but 14.7.1 para 5 goes on to say that
+  // even if you can do overload resolution without instantiating some
+  // class, it's ok to do so anyway.  Of course, this begs the
+  // question: exactly which classes are in their margin for error?
+  // Clearly they don't mean that all instantiations in the program
+  // are fair game (14.7.1 para 9), but they do not specify how
+  // tangentially related something must be to the overload resolution
+  // at hand before it's allowed to be instantiated...
+  //
+  // 9/22/04: As demonstrated by t0293.cc, we also need to instantiate
+  // classes mentioned by way of pointers (in addition to references),
+  // to enable derived-to-base conversions.
+  for (int i=0; i < args.size(); i++) {
+    Type *argType = a[i].type;
+    if (!argType) continue;
+
+    argType = argType->asRval();     // skip references
+    if (argType->isPointerType()) {  // skip pointers (9/22/04)
+      argType = argType->asPointerType()->atType;
+    }
+
+    if (argType->isCompoundType()) {
+      CompoundType *argCT = argType->asCompoundType();
+
+      // instantiate the argument class if necessary
+      env.ensureClassBodyInstantiated(argCT);
+
+      // iterate over the set of conversion operators
+      if (argCT->isComplete()) {      // non-instantiations can be incomplete here
+        SFOREACH_OBJLIST(Variable, argCT->conversionOperators, iter) {
+          Type *convType = iter.data()->type->asFunctionTypeC()->retType;
+
+          // we should only need to consider pointers or references;
+          // if 'convType' is itself an instantiation, it should have
+          // had its body instantiated when its containing class body
+          // was tchecked
+          if (convType->isPtrOrRef()) {
+            Type *convAtType = convType->getAtType();
+            if (convAtType->isCompoundType()) {
+              env.ensureClassBodyInstantiated(convAtType->asCompoundType());
+            }
+          }
+        }
+      }
+    }
+  }
+
+  printArgInfo();
+}
+
+
+void OverloadResolver::printArgInfo()
+{
+  IFDEBUG(
+    if (tracingSys("overload")) {
+      string info = argInfoString();
+
+      // it's a little inefficient to construct the string only to
+      // parse it at line boundaries, but I want the indentation to
+      // be a certain way, and this is only done in debug mode (and
+      // even then, only with the tracing flag enabled)
+      StrtokParse tok(info, "\n");
+      for (int i=0; i<tok; i++) {
+        overloadTrace() << tok[i] << "\n";
+      }
+    }
+  )
+}
+
+string OverloadResolver::argInfoString()
+{
+  stringBuilder sb;
+  sb << "arguments:\n";
+  for (int i=0; i < args.size(); i++) {
+    if (args[i].overloadSet.isEmpty() &&
+        !args[i].type) {
+      continue;      // don't print anything
+    }
+
+    sb << "  " << i << ": ";
+
+    if (args[i].overloadSet.isNotEmpty()) {
+      sb << "(13.4 set) ";
+      int ct=0;
+      SFOREACH_OBJLIST_NC(Variable, args[i].overloadSet, iter) {
+        if (ct++ > 0) {
+          sb << " or ";
+        }
+        sb << iter.data()->type->toString();
+      }
+    }
+    else {
+      sb << args[i].type->toString();
+    }
+
+    if (args[i].special) {
+      sb << " (" << toString(args[i].special) << ")";
+    }
+
+    sb << "\n";
+  }
+
+  return sb;
+}
+
+
+OverloadResolver::~OverloadResolver()
+{
+  //overloadNesting--;
+}
+
+
+void OverloadResolver::processCandidates(SObjList<Variable> &varList)
+{
+  SFOREACH_OBJLIST_NC(Variable, varList, iter) {
+    xassert(!(iter.data()->notQuantifiedOut()));
+    processCandidate(iter.data());
+  }
+}
+
+
+void OverloadResolver::addCandidate(Variable *var0, Variable *instFrom)
+{
+  xassert(var0);
+  Candidate *c = makeCandidate(var0, instFrom);
+  if (c) {
+    IFDEBUG( c->conversionDescriptions(); )
+    candidates.push(c);
+
+    // part of 14.7.1 para 4: If a candidate function parameter is
+    // (a reference to) a template class instantiation, force its body
+    // to be instantiated.
+    env.instantiateTemplatesInParams(var0->type->asFunctionType());
+  }
+  else {
+    OVERLOADTRACE("(not viable)");
+  }
+}
+
+void OverloadResolver::addTemplCandidate
+  (Variable *baseV, Variable *var0, ObjList<STemplateArgument> &sargs)
+{
+  Variable *var0inst =
+    env.instantiateFunctionTemplate
+    (env.loc(),
+     baseV,
+     sargs);
+  // quarl: for some reason adding ``xassert(var0inst != NULL)'' sometimes
+  // stops the segfault without throwing an assertion failure!
+  xassert(var0inst != NULL && "f1c15444-8783-4296-981f-e3908d7cb1b4");
+  xassert(var0inst->templateInfo()->isCompleteSpecOrInstantiation());
+
+  // try adding the candidate
+  addCandidate(var0inst, var0);
+}
+
+void OverloadResolver::processCandidate(Variable *v)
+{
+  OVERLOADINDTRACE("candidate: " << v->toString() <<
+                   " at " << toString(v->loc));
+
+  if ((flags & OF_NO_EXPLICIT) && v->hasFlag(DF_EXPLICIT)) {
+    // not a candidate, we're ignoring explicit constructors
+    OVERLOADTRACE("(not viable due to 'explicit')");
+    return;
+  }
+
+  if (!v->isTemplate(false /*considerInherited*/)) {
+    // 2005-02-18: Since reorganizing call site name lookup, I am now
+    // doing overload resolution among *instantiations*, rather than
+    // template primaries.
+    Variable *instFrom = NULL;
+    if (v->isInstantiation()) {
+      // what is it an instantiation of?
+      instFrom = v->templateInfo()->instantiationOf;
+      xassert(instFrom);
+
+      // do not consider members of template classes to be templates
+      // (in/t0269.cc)
+      if (!instFrom->isTemplate(false /*considerInherited*/)) {
+        instFrom = NULL;
+      }
+    }
+
+    addCandidate(v, instFrom);
+    return;
+  }
+
+  // Q: Can this point be reached?
+  //
+  // A: Yes, in/t0269.cc gets here.  E_constructor still does overload
+  // resolution with template primaries.  It's not clear whether that
+  // is a problem or not; it's a lot simpler than E_funCall.
+
+  // template function; we have to filter out all of the possible
+  // specializations and put them, together with the primary, into the
+  // candidates list
+  TemplateInfo *vTI = v->templateInfo();
+  xassert(vTI->isPrimary());
+
+  // get the semantic template arguments
+  ObjList<STemplateArgument> sargs;
+  {
+    InferArgFlags iflags = IA_NO_ERRORS;
+    if (flags & OF_METHODS) {
+      iflags |= IA_RECEIVER;
+    }
+
+    // (in/t0484.cc) an operator invocation site's LHS argument is the
+    // receiver when we are considering operators that are methods;
+    // but if the operator is a global function, then the LHS is not
+    // a receiver, but just an ordinary argument
+    if ((flags & OF_OPERATOR) && (v->type->asFunctionType()->isMethod())) {
+      iflags |= IA_RECEIVER;
+    }
+
+    // FIX: This is a bug!  If the args contain template parameters,
+    // they will be the wrong template parameters.
+    GrowArray<ArgumentInfo> &args0 = this->args;
+    // FIX: check there are no dependent types in the arguments
+    TypeListIter_GrowArray argListIter(args0);
+    MType match(env);
+    if (!env.getFuncTemplArgs(match, sargs, finalName, v, argListIter, iflags)) {
+      // something doesn't work about processing the template arguments
+      OVERLOADTRACE("(not viable because args to not match template params)");
+      return;
+    }
+  }
+
+  // FIX: the following is copied from Env::findMostSpecific(); it
+  // could be factored out and merged but adding to the list in the
+  // inner loop would be messy; you would have to make it an iterator
+  SFOREACH_OBJLIST_NC(Variable, vTI->specializations, iter) {
+    Variable *var0 = iter.data();
+    TemplateInfo *templInfo0 = var0->templateInfo();
+    xassert(templInfo0);      // should have templateness
+
+    // see if this candidate matches
+    MType match;
+    if (!match.matchSTemplateArguments(sargs, templInfo0->arguments, MF_MATCH)) {
+      // if not, skip it
+      continue;
+    }
+
+    addTemplCandidate(v, var0, sargs);
+  }
+
+  // add the primary also
+  addTemplCandidate(v, v, sargs);
+}
+
+
+void OverloadResolver::processPossiblyOverloadedVar(Variable *v)
+{
+  if (v->overload) {
+    processCandidates(v->overload->set);
+  }
+  else {
+    processCandidate(v);
+  }
+}
+
+
+void OverloadResolver::addAmbiguousBinaryCandidate(Variable *v)
+{
+  Candidate *c = new Candidate(v, NULL /*instFrom*/, 2);
+  c->conversions[0].addAmbig();
+  c->conversions[1].addAmbig();
+
+  OVERLOADINDTRACE("candidate: ambiguous-arguments placeholder");
+  IFDEBUG( c->conversionDescriptions(); )
+
+  candidates.push(c);
+}
+
+
+static EnumType *ifEnumType(Type *t)
+{
+  if (t && t->isCVAtomicType()) {
+    CVAtomicType *cvat = t->asCVAtomicType();
+    if (cvat->atomic->isEnumType()) {
+      return cvat->atomic->asEnumType();
+    }
+  }
+  return NULL;
+}
+
+static bool parameterAcceptsDirectly(EnumType *et, FunctionType *ft, int param)
+{
+  if (et &&
+      ft->params.count() > param) {
+    Type *paramType = ft->params.nth(param)->type;
+
+    // treat 'T&' the same as 'T'
+    paramType = paramType->asRval();
+
+    // get down to an enumtype
+    EnumType *paramEnumType = ifEnumType(paramType);
+
+    return paramEnumType && et->equals(paramEnumType);
+  }
+
+  return false;
+}
+
+void OverloadResolver::addUserOperatorCandidates
+  (Type * /*nullable*/ lhsType, Type * /*nullable*/ rhsType, StringRef opName)
+{
+  if (lhsType) {
+    lhsType = lhsType->asRval();
+  }
+  if (rhsType) {
+    rhsType = rhsType->asRval();
+  }
+
+  // member candidates
+  if (lhsType && lhsType->isCompoundType()) {
+    Variable *member = lhsType->asCompoundType()->lookupVariable(opName, env);
+    if (member) {
+      processPossiblyOverloadedVar(member);
+    }
+  }
+
+  // non-member candidates
+  LookupSet candidates;
+  {
+    // 13.3.1.2 para 3 bullet 2: "... all member functions are ignored."
+    LookupFlags flags = LF_SKIP_CLASSES;
+
+    // associated scopes lookup
+    ArrayStack<Type*> argTypes(2);
+    if (lhsType) {
+      argTypes.push(lhsType);
+    }
+    if (rhsType) {
+      argTypes.push(rhsType);
+    }
+    env.associatedScopeLookup(candidates, opName, argTypes, flags);
+
+    // ordinary lookup
+    {
+      Scope *dummy;
+      env.lookupVariable_set(candidates, opName, flags, dummy);
+    }
+
+    // filter candidates if no class-typed args
+    if ((lhsType && lhsType->isCompoundType()) ||
+        (rhsType && rhsType->isCompoundType())) {
+      // at least one arg is of class type; nothing special is done
+    }
+    else {
+      // no class-typed arguments; at least one must be enumeration type
+      // (otherwise operator overload resolution isn't done at all),
+      // and we require that every candidate explicitly accept one of
+      // the enumeration types
+      EnumType *et1 = ifEnumType(lhsType);
+      EnumType *et2 = ifEnumType(rhsType);
+
+      SObjListMutator<Variable> mut(candidates);
+      while (!mut.isDone()) {
+        FunctionType *ft = mut.data()->type->asFunctionType();
+
+        if (parameterAcceptsDirectly(et1, ft, 0) ||
+            parameterAcceptsDirectly(et2, ft, 1)) {
+          // ok, keep it
+          mut.adv();
+        }
+        else {
+          // drop it
+          mut.remove();
+        }
+      }
+    }
+  }
+
+  // process the resulting set
+  SFOREACH_OBJLIST_NC(Variable, candidates, iter) {
+    processCandidate(iter.data());
+  }
+}
+
+
+void OverloadResolver::addBuiltinUnaryCandidates(OverloadableOp op)
+{
+  ArrayStack<Variable*> &builtins = env.builtinUnaryOperator[op];
+  for (int i=0; i < builtins.length(); i++) {
+    processCandidate(builtins[i]);
+  }
+}
+
+
+void OverloadResolver::addBuiltinBinaryCandidates(OverloadableOp op,
+  ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo)
+{
+  ObjArrayStack<CandidateSet> &builtins = env.builtinBinaryOperator[op];
+  for (int i=0; i < builtins.length(); i++) {
+    builtins[i]->instantiateBinary(env, *this, op, lhsInfo, rhsInfo);
+  }
+}
+
+
+// this is a simple tournament, as suggested in footnote 123,
+// cppstd 13.3.3 para 2
+template <class RESOLVER, class CANDIDATE>
+CANDIDATE *tournament(RESOLVER &resolver, int low, int high, CANDIDATE *dummy)
+{
+  xassert(low <= high);         // Scott, you should catch this!
+
+  if (low == high) {
+    // only one candidate
+    return resolver.candidates[low];
+  }
+
+  // divide the pool in half and select a winner from each half
+  int mid = (low+high+1)/2;
+    // 1,3 -> 2
+    // 1,2 -> 2
+    // 2,3 -> 3
+  CANDIDATE *left = tournament(resolver, low, mid-1, dummy);
+  CANDIDATE *right = tournament(resolver, mid, high, dummy);
+
+  // compare the candidates to get one that is not worse than the other
+  int choice = resolver.compareCandidates(left, right);
+  if (choice <= 0) {
+    return left;    // left is better, or neither is better or worse
+  }
+  else {
+    return right;   // right is better
+  }
+}
+
+
+// tournament, plus final linear scan to ensure it's the best; the
+// dummy argument is just to instantiate the 'CANDIDATE' type
+template <class RESOLVER, class CANDIDATE>
+CANDIDATE *selectBestCandidate(RESOLVER &resolver, CANDIDATE *dummy)
+{
+  // dsw: I need this to be the semantics of this function, rather
+  // than an error; If you change it, change the class specialization
+  // resolution code also.
+  if (resolver.candidates.length() <= 0) {
+    return NULL;
+  }
+
+  // use a tournament to select a candidate that is not worse
+  // than any of those it faced
+  CANDIDATE *winner = tournament(resolver, 0, resolver.candidates.length()-1, dummy);
+
+  // now verify that the picked winner is in fact better than any
+  // of the other candidates (since the order is not necessarily linear)
+  for (int i=0; i < resolver.candidates.length(); i++) {
+    if (resolver.candidates[i] == winner) {
+      continue;    // skip it, no need to compare to itself
+    }
+
+    if (resolver.compareCandidates(winner, resolver.candidates[i]) == -1) {
+      // ok, it's better
+    }
+    else {
+      // not better, so there is no function that is better than
+      // all others
+      return NULL;
+    }
+  }
+
+  // 'winner' is indeed the winner
+  return winner;
+}
+
+
+// dsw: I put this here so that I didn't have to put the whole
+// selectBestCandidate() templatized function into overload.h
+Variable *selectBestCandidate_templCompoundType(TemplCandidates &resolver)
+{
+  Variable *dummy = NULL;
+    // dsw: this dummy idiom is dumb
+    // sm: horsepucky!
+
+  return selectBestCandidate(resolver, dummy);
+}
+
+
+Candidate const *OverloadResolver::resolveCandidate(bool &wasAmbig)
+{
+  wasAmbig = false;
+
+  if (candidates.isEmpty()) {
+    if (emptyCandidatesIsOk) {
+      return NULL;      // caller is prepared to deal with this
+    }
+
+    if (errors) {
+      // try to construct a meaningful error message; it does not
+      // end with a newline since the usual error reporting mechanism
+      // adds one
+      stringBuilder sb;
+      sb << "no viable candidate for "
+         << ((flags & OF_OPERATOR)? "operator; " : "function call; ")
+         << argInfoString();
+      if (origCandidates.length()) {
+        sb << " original candidates:";
+        for (int i=0; i<origCandidates.length(); i++) {
+          Variable *v = origCandidates[i];
+
+          // it might be nice to go further and explain why this
+          // candidate was not viable ...
+          sb << "\n  " << v->loc << ": " << v->toQualifiedString();
+        }
+      }
+      else {
+        sb << " (no original candidates)";
+      }
+
+      errors->addError(new ErrorMsg(loc, sb, EF_NONE));
+    }
+    OVERLOADTRACE("no viable candidates");
+    return NULL;
+  }
+
+  if (finalDestType) {
+    // include this in the diagnostic output so that I can tell
+    // when it will play a role in candidate comparison
+    OVERLOADTRACE("finalDestType: " << finalDestType->toString());
+  }
+
+  // use a tournament to select a candidate that is not worse
+  // than any of those it faced
+  Candidate const *winner = selectBestCandidate(*this, (Candidate const*)NULL);
+  if (!winner) {
+    // if any of the candidates contain variables, then this
+    // conclusion of ambiguity is suspect (in/t0573.cc)
+    for (int i=0; i<candidates.length(); i++) {
+      Variable *v = candidates[i]->var;
+      if (v->type->containsVariables()) {
+        goto ambig_bail;
+      }
+    }
+
+    if (errors) {
+      stringBuilder sb;
+      sb << "ambiguous overload; " << argInfoString() << " candidates:";
+      for (int i=0; i<candidates.length(); i++) {
+        Variable *v = candidates[i]->var;
+        sb << "\n  " << v->loc << ": " << v->toQualifiedString();
+      }
+      errors->addError(new ErrorMsg(loc, sb, EF_NONE));
+    }
+
+  ambig_bail:
+    OVERLOADTRACE("ambiguous overload");
+    wasAmbig = true;
+    return NULL;
+  }
+
+  OVERLOADTRACE(toString(loc)
+    << ": selected " << winner->var->toString()
+    << " at " << toString(winner->var->loc));
+
+  if (winner->hasAmbigConv()) {
+    // At least one of the conversions required for the winning candidate
+    // is ambiguous.  This might actually mean, had we run the algorithm
+    // as specified in the spec, that there's an ambiguity among the
+    // candidates, since I fold some of that into the selection of the
+    // conversion, for polymorphic built-in operator candidates.  Therefore,
+    // this situation should appear to the caller the same as when we
+    // definitely do have ambiguity among the candidates.
+    if (errors) {
+      errors->addError(new ErrorMsg(
+        loc, "ambiguous overload or ambiguous conversion", EF_NONE));
+    }
+    OVERLOADTRACE("ambiguous overload or ambiguous conversion");
+    wasAmbig = true;
+    return NULL;
+  }
+
+  return winner;
+}
+
+
+Variable *OverloadResolver::resolve(bool &wasAmbig)
+{
+  Candidate const *winner = resolveCandidate(wasAmbig);
+  if (!winner) {
+    return NULL;
+  }
+
+  // dsw: I've decided to agressively instantiate the template since
+  // everything downstream from here seems to assume that it has not
+  // gotten a template but a real variable with a real type etc.
+  // NOTE: if you do the optimization of instantiating only the
+  // function signatures and not the whole body then here is the place
+  // you would actually do the whole body instantiation; for now there
+  // is nothing to do here as it has already been done
+  //
+  // sm: TODO: Yes, we do need to delay instantiation until after
+  // overload resolution selects the function, as part of the delayed
+  // instantiation for class member functions.  See in/t0233.cc.
+  Variable *retV = winner->var;
+  if (winner->instFrom) {
+    // instantiation is now done during candidate processing
+    xassert(retV->templateInfo());
+    xassert(retV->templateInfo()->isCompleteSpecOrInstantiation());
+  } else {
+    // sm: in/t0411.cc causes this to fail, because we (correctly)
+    // do overload resolution while analyzing an uninstantiated
+    // template body, and the winner is a member of that template,
+    // so it *is* a template but is *not* instantiated from anything
+    //xassert(!retV->isTemplate());
+  }
+
+  return retV;
+}
+
+Variable *OverloadResolver::resolve()
+{
+  bool dummy;
+  return resolve(dummy);
+}
+
+
+// for each parameter, determine an ICS, and return the resulting
+// Candidate; return NULL if the function isn't viable; this
+// implements cppstd 13.3.2
+Candidate * /*owner*/ OverloadResolver::makeCandidate
+  (Variable *var, Variable *instFrom)
+{
+  origCandidates.push(var);
+  Owner<Candidate> c(new Candidate(var, instFrom, args.size()));
+
+  FunctionType *ft = var->type->asFunctionType();
+
+  // simultaneously iterate over parameters and arguments
+  SObjListIter<Variable> paramIter(ft->params);
+  int argIndex = 0;
+
+  // handle mismatches between presence of receiver and method-ness
+  if (flags & OF_METHODS) {      // receiver is present
+    if (!args[argIndex].type && ft->isMethod()) {
+      // no receiver object but function is a method: not viable
+      return NULL;
+    }
+    if (!ft->isMethod()) {
+      // no receiver parameter; leave the conversion as IC_NONE
+      argIndex++;       // do *not* advance 'paramIter'
+    }
+  }
+
+  for (; !paramIter.isDone() && argIndex < args.size();
+       paramIter.adv(), argIndex++) {
+    // address of overloaded function?
+    if (args[argIndex].overloadSet.isNotEmpty()) {
+      Variable *selVar =
+        env.pickMatchingOverloadedFunctionVar(args[argIndex].overloadSet,
+                                              paramIter.data()->type);
+      if (selVar) {
+        // just say it matches; we don't need to record *which* one was
+        // chosen, because that will happen later when the arguments are
+        // checked against the parameters of the chosen function
+        ImplicitConversion ics;
+        ics.addStdConv(SC_IDENTITY);
+        c->conversions[argIndex] = ics;
+
+        // go to next arg/param pair
+        continue;
+      }
+      else {
+        // whole thing not viable
+        return NULL;
+      }
+    }
+
+    bool destIsReceiver = argIndex==0 && ft->isMethod();
+
+    if (flags & OF_NO_USER) {
+      // only consider standard conversions
+      StandardConversion scs =
+        getStandardConversion(NULL /*errorMsg*/,
+                              args[argIndex].special, args[argIndex].type,
+                              paramIter.data()->type, destIsReceiver);
+      if (scs != SC_ERROR) {
+        ImplicitConversion ics;
+        ics.addStdConv(scs);
+        c->conversions[argIndex] = ics;
+      }
+      else {
+        return NULL;
+      }
+    }
+    else {
+      // consider both standard and user-defined
+      ImplicitConversion ics =
+        getImplicitConversion(env, args[argIndex].special, args[argIndex].type,
+                              paramIter.data()->type, destIsReceiver);
+      if (ics) {
+        c->conversions[argIndex] = ics;
+      }
+      else {
+        return NULL;           // no conversion sequence possible
+      }
+    }
+  }
+
+  // extra arguments?
+  if (argIndex < args.size()) {
+    if (ft->acceptsVarargs()) {
+      // fill remaining with IC_ELLIPSIS
+      ImplicitConversion ellipsis;
+      ellipsis.addEllipsisConv();
+      while (argIndex < args.size()) {
+        c->conversions[argIndex] = ellipsis;
+        argIndex++;
+      }
+    }
+    else {
+      // too few arguments, cannot form a conversion
+      return NULL;
+    }
+  }
+
+  // extra parameters?
+  if (!paramIter.isDone()) {
+    if (paramIter.data()->value) {
+      // the next parameter has a default value, which implies all
+      // subsequent parameters have default values as well; for
+      // purposes of overload resolution, we simply ignore the extra
+      // parameters [cppstd 13.3.2 para 2, third bullet]
+    }
+    else {
+      // no default value, argument must be supplied but is not,
+      // so cannot form a conversion
+      return NULL;
+    }
+  }
+
+  return c.xfr();
+}
+
+
+// 14.5.5.2 paras 3 and 4
+bool atLeastAsSpecializedAs(Env &env, Type *concrete, Type *pattern)
+{
+  // TODO: this isn't quite right:
+  //   - I use the return type regardless of whether this is
+  //     a template conversion function
+  //   - I don't do "argument deduction", I just match.  Maybe
+  //     that is equivalent?
+
+  MType match(env);
+  return match.matchTypeNC(concrete, pattern, MF_MATCH);
+}
+
+
+// compare overload candidates, returning:
+//   -1 if left is better
+//    0 if they are indistinguishable
+//   +1 if right is better
+// this is cppstd 13.3.3 para 1, second group of bullets
+int OverloadResolver::compareCandidates(Candidate const *left, Candidate const *right)
+{
+  // decision so far
+  int ret = 0;
+
+  // is exactly one candidate a built-in operator?
+  if ((int)left->var->hasFlag(DF_BUILTIN) +
+      (int)right->var->hasFlag(DF_BUILTIN) == 1) {
+    // 13.6 para 1 explains that if a user-written candidate and a
+    // built-in candidate have the same signature, then the built-in
+    // candidate is hidden; I implement this by saying that the
+    // user-written candidate always wins
+    if (left->var->type->equals(right->var->type, MF_IGNORE_RETURN)) {
+      // same signatures; who wins?
+      if (left->var->hasFlag(DF_BUILTIN)) {
+        return +1;     // right is user-written, it wins
+      }
+      else {
+        return -1;     // left is user-written, it wins
+      }
+    }
+  }
+
+  // iterate over parameters too, since we need to know the
+  // destination type in some cases
+  FunctionType const *leftFunc = left->var->type->asFunctionTypeC();
+  FunctionType const *rightFunc = right->var->type->asFunctionTypeC();
+  SObjListIter<Variable> leftParam(leftFunc->params);
+  SObjListIter<Variable> rightParam(rightFunc->params);
+
+  // argument index
+  int i = 0;
+
+  if (flags & OF_METHODS) {
+    if (!leftFunc->isMethod() || !rightFunc->isMethod()) {
+      // for nonmethods, the receiver param is ignored
+      i++;
+      if (leftFunc->isMethod()) {
+        leftParam.adv();
+      }
+      if (rightFunc->isMethod()) {
+        rightParam.adv();
+      }
+    }
+  }
+
+  // walk through list of arguments, comparing the conversions
+  for (; i < args.size(); i++) {
+    // get parameter types; they can be NULL if we walk off into the ellipsis
+    // of a variable-argument function
+    Type const *leftDest = NULL;
+    if (!leftParam.isDone()) {
+      leftDest = leftParam.data()->type;
+      leftParam.adv();
+    }
+    Type const *rightDest = NULL;
+    if (!rightParam.isDone()) {
+      rightDest = rightParam.data()->type;
+      rightParam.adv();
+    }
+
+    int choice = compareConversions(args[i], left->conversions[i], leftDest,
+                                             right->conversions[i], rightDest);
+    if (ret == 0) {
+      // no decision so far, fold in this comparison
+      ret = choice;
+    }
+    else if (choice == 0) {
+      // this comparison offers no information
+    }
+    else if (choice != ret) {
+      // this comparison disagrees with a previous comparison, which
+      // makes two candidates indistinguishable
+      return 0;
+    }
+  }
+
+  if (ret != 0) {
+    return ret;     // at least one of the comparisons is decisive
+  }
+
+  // the next comparison says that non-templates are better than
+  // template function *specializations*.. I'm not entirely sure
+  // what "specialization" means, whether it's something declared using
+  // the specialization syntax or just an instance of a template..
+  // I'm going to use the latter interpretation since I think it
+  // makes more sense
+  if (!left->instFrom && right->instFrom) {
+    return -1;     // left is non-template
+  } else if (left->instFrom && !right->instFrom) {
+    return +1;     // right is non-template
+  }
+
+  // next rule talks about comparing templates to find out which is
+  // more specialized
+  if (left->instFrom && right->instFrom) {
+    // sm: I think we just compare the candidates directly; there is
+    // no notion of partial specialization for function templates, so
+    // all the old stuff about primaries doesn't make sense
+
+    // this section implements cppstd 14.5.5.2
+
+    // NOTE: we use the instFrom field here instead of the var
+    Type *leftType = left->instFrom->type;
+    Type *rightType = right->instFrom->type;
+
+    // who is "at least as specialized" as who?
+    bool left_ALA = atLeastAsSpecializedAs(env, leftType, rightType);
+    bool right_ALA = atLeastAsSpecializedAs(env, rightType, leftType);
+    if (left_ALA && !right_ALA) {
+      // left is "more specialized"
+      return -1;
+    }
+    else if (!left_ALA && right_ALA) {
+      // right is "more specialized"
+      return +1;
+    }
+    else {
+      // fall through to remaining tests
+    }
+  }
+
+  // if we're doing "initialization by user-defined conversion", then
+  // look at the conversion sequences to the final destination type
+  if (finalDestType) {
+    StandardConversion leftSC = getStandardConversion(
+      NULL /*errorMsg*/, SE_NONE, leftFunc->retType, finalDestType);
+    StandardConversion rightSC = getStandardConversion(
+      NULL /*errorMsg*/, SE_NONE, rightFunc->retType, finalDestType);
+
+    ret = compareStandardConversions(
+      ArgumentInfo(SE_NONE, leftFunc->retType), leftSC, finalDestType,
+      ArgumentInfo(SE_NONE, rightFunc->retType), rightSC, finalDestType
+    );
+    if (ret != 0) {
+      return ret;
+    }
+  }
+
+  // no more rules remain, candidates are indistinguishable
+  return 0;
+}
+
+
+// compare two conversion sequences, returning the same choice code
+// as above; we need to know the source type and the destination types,
+// because some of the comparison criteria use them; this implements
+// cppstd 13.3.3.2
+int compareConversions(ArgumentInfo const &src,
+  ImplicitConversion const &left, Type const *leftDest,
+  ImplicitConversion const &right, Type const *rightDest)
+{
+  // para 2: choose based on what kind of conversion:
+  //   standard < user-defined/ambiguous < ellipsis
+  {
+    static int const map[ImplicitConversion::NUM_KINDS] = {
+      0,    // none
+      1,    // standard
+      2,    // user-defined
+      3,    // ellipsis
+      2     // ambiguous
+    };
+
+    int leftGroup = map[left.kind];
+    int rightGroup = map[right.kind];
+    xassert(leftGroup && rightGroup);   // make sure neither is IC_NONE
+
+    if (leftGroup < rightGroup) return -1;
+    if (rightGroup < leftGroup) return +1;
+  }
+
+  if (left.kind == ImplicitConversion::IC_AMBIGUOUS ||
+      right.kind == ImplicitConversion::IC_AMBIGUOUS) {
+    return 0;    // indistinguishable
+  }
+
+  // para 3: compare among same-kind conversions
+  xassert(left.kind == right.kind);
+
+  // para 3, bullet 1
+  if (left.kind == ImplicitConversion::IC_STANDARD) {
+    return compareStandardConversions(src, left.scs, leftDest,
+                                      src, right.scs, rightDest);
+  }
+
+  // para 3, bullet 2
+  if (left.kind == ImplicitConversion::IC_USER_DEFINED) {
+    if (left.user != right.user) {
+      // different conversion functions, incomparable
+      return 0;
+    }
+
+    // compare their second conversion sequences
+    ArgumentInfo src(SE_NONE, left.user->type->asFunctionTypeC()->retType);
+    return compareStandardConversions(src, left.scs2, leftDest,
+                                      src, right.scs2, rightDest);
+  }
+
+  // if ellipsis, no comparison
+  xassert(left.kind == ImplicitConversion::IC_ELLIPSIS);
+  return 0;
+}
+
+
+inline void swap(CompoundType const *&t1, CompoundType const *&t2)
+{
+  CompoundType const *temp = t1;
+  t1 = t2;
+  t2 = temp;
+}
+
+
+// this is a helper for 'compareStandardConversions'; it incorporates
+// the knowledge of having found two more cv flag pairs in a
+// simultaneous deconstruction of two types that are being compared;
+// ultimately it wants to set 'ret' to -1 if all the 'lcv's are
+// subsets of all the 'rcv's, and +1 if the subset goes the other way;
+// it returns 'true' if the subset relation does not hold
+static bool foldNextCVs(int &ret, CVFlags lcv, CVFlags rcv, int &skipCVs)
+{
+  if (skipCVs) {
+    skipCVs--;
+    return false;
+  }
+
+  if (lcv != rcv) {
+    if ((lcv & rcv) == lcv) {    // left is subset, => better
+      if (ret > 0) return true;  // but right was better previously, => no decision
+      ret = -1;
+    }
+    if ((lcv & rcv) == rcv) {    // right is subset, => better
+      if (ret < 0) return true;  // but left was better previously, => no decision
+      ret = +1;
+    }
+  }
+  return false;                  // no problem found
+}
+
+
+int compareStandardConversions
+  (ArgumentInfo const &leftSrc, StandardConversion left, Type const *leftDest,
+   ArgumentInfo const &rightSrc, StandardConversion right, Type const *rightDest)
+{
+  // if one standard conversion sequence is a proper subsequence of
+  // another, excluding SC_LVAL_TO_RVAL, then the smaller one is
+  // preferred
+  {
+    StandardConversion L = removeLval(left);
+    StandardConversion R = removeLval(right);
+    if (L != R) {
+      if (isSubsequenceOf(L, R)) return -1;
+      if (isSubsequenceOf(R, L)) return +1;
+    }
+  }
+
+  // compare ranks of conversions
+  SCRank leftRank = getRank(left);
+  SCRank rightRank = getRank(right);
+  if (leftRank < rightRank) return -1;
+  if (rightRank < leftRank) return +1;
+
+  // 13.3.3.2 para 4, bullet 1:
+  //   "A conversion that is not a conversion of a pointer, or pointer
+  //    to member, to bool is better than another conversion that is
+  //    such a conversion."
+  {
+    bool L = convertsPtrToBool(leftSrc.type, leftDest);
+    bool R = convertsPtrToBool(rightSrc.type, rightDest);
+    if (!L && R) return -1;
+    if (!R && L) return +1;
+  }
+
+  // hierarchy
+  // -------------
+  //   void           treated as a semantic super-root for this analysis
+  //     \            .
+  //      A           syntactic root, i.e. least-derived class of {A,B,C}
+  //       \          .
+  //        B         .
+  //         \        .
+  //          C       most-derived class of {A,B,C}
+  //
+  // (the analysis does allow for classes to appear in between these three)
+
+  // 13.3.3.2 para 4, bullet 2:
+  //   B* -> A*      is better than  B* -> void*
+  //   A* -> void*   is better than  B* -> void*
+  // 13.3.3.2 para 4, bullet 3:
+  //   C* -> B*      is better than  C* -> A*
+  //   C& -> B&      is better than  C& -> A&
+  //   B::* <- A::*  is better than  C::* <- A::*
+  //   C -> B        is better than  C -> A
+  //   B* -> A*      is better than  C* -> A*
+  //   B& -> A&      is better than  C& -> A&
+  //   C::* <- B::*  is better than  C::* <- A::*
+  //   B -> A        is better than  C -> A
+  //
+  // Q: what about cv flags?  for now I ignore them...
+  {
+    // first pass:  pointers, and references to pointers
+    // second pass: objects, and references to objects
+    // third pass:  pointers to members
+    for (int pass=1; pass <= 3; pass++) {
+      bool (*checkFunc)(Type const *type, CompoundType const *&ct) =
+        pass==1 ? &isPointerToCompound   :
+        pass==2 ? &isReferenceToCompound :
+                  &isPointerToCompoundMember;
+
+      // We're comparing conversions among pointers and references.
+      // Name the participating compound types according to this scheme:
+      //   left:  LS -> LD      (left source, left dest)
+      //   right: RS -> RD
+      CompoundType const *LS;
+      CompoundType const *LD;
+      CompoundType const *RS;
+      CompoundType const *RD;
+
+      // are the conversions of the right form?
+      if (checkFunc(leftSrc.type, LS) &&
+          checkFunc(leftDest, LD) &&
+          checkFunc(rightSrc.type, RS) &&
+          checkFunc(rightDest, RD)) {
+        // in pass 3, the paths go the opposite way, so just swap their ends
+        if (pass==3) {
+          swap(LS, LD);
+          swap(RS, RD);
+        }
+
+        // each of the "better than" checks above is really saying
+        // that if the paths between source and destination are
+        // in the "proper subpath" relation, then the shorter one is better
+        if (isProperSubpath(LS, LD, RS, RD)) return -1;
+        if (isProperSubpath(RS, RD, LS, LD)) return +1;
+      }
+    }
+  }
+
+  // 13.3.3.2 para 3, bullet 1, sub-bullets 3 and 4:
+  // if the conversions yield types that differ only in cv-qualification,
+  // then prefer the one with fewer such qualifiers (if one has fewer)
+  {
+    // preference so far
+    int ret = 0;
+
+    // will work through the type constructors simultaneously
+    Type const *L = leftDest;
+    Type const *R = rightDest;
+
+    // 2005-08-09 (in/t0530.cc): the very first cv-flags are
+    // irrelevant, because they come from parameter types, which are
+    // not part of the function type and therefore do not affect
+    // overload resolution
+    int skipCVs = 1;
+
+    // 2005-02-23: (in/t0395.cc) if 'L' and 'R' are pointers (either
+    // one is sufficient), then the comparison of this section requires
+    // that the conversions *differ* in group 3, otherwise they are
+    // indistinguishable
+    //
+    // 2005-04-15: (in/k0029.cc) it seems I want to regard them as
+    // indistinguishable if *neither* involved a qualification conversion
+    if (L->isPointerType() || R->isPointerType()) {
+      if (!(left & SC_GROUP_3_MASK) &&
+          !(right & SC_GROUP_3_MASK)) {
+        return 0;
+      }
+    }
+
+    // if one is a reference and the other is not, I don't see a basis
+    // for comparison in cppstd, so I skip the extra reference
+    //
+    // update: 13.3.3.2b.cc suggests that in fact cppstd intends
+    // 'int' and 'int const &' to be indistinguishable, so I *don't*
+    // strip extra references
+    #if 0   // I think this was wrong
+    if (L->isReference() && !R->isReference()) {
+      L = L->asRvalC();
+    }
+    else if (!L->isReference() && R->isReference()) {
+      R = R->asRvalC();
+    }
+    #endif // 0
+
+    // deconstruction loop
+    while (!L->isCVAtomicType() && !R->isCVAtomicType()) {
+      if (L->getTag() != R->getTag()) {
+        return 0;            // different types, can't compare
+      }
+
+      switch (L->getTag()) {
+        default: xfailure("bad tag");
+
+        case Type::T_POINTER:
+        case Type::T_REFERENCE: {
+          // assured by non-stackability of references
+          xassert(L->isPointerType() == R->isPointerType());
+
+          if (foldNextCVs(ret, L->getCVFlags(), R->getCVFlags(), skipCVs)) {
+            return 0;        // not subset, therefore no decision
+          }
+
+          L = L->getAtType();
+          R = R->getAtType();
+          break;
+        }
+
+        case Type::T_FUNCTION:
+        case Type::T_ARRAY:
+          if (L->equals(R)) {
+            return ret;      // decision so far is final
+          }
+          else {
+            return 0;        // different types, can't compare
+          }
+
+        case Type::T_POINTERTOMEMBER: {
+          PointerToMemberType const *lptm = L->asPointerToMemberTypeC();
+          PointerToMemberType const *rptm = R->asPointerToMemberTypeC();
+
+          if (foldNextCVs(ret, lptm->cv, rptm->cv, skipCVs)) {
+            return 0;        // not subset, therefore no decision
+          }
+
+          if (lptm->inClass() != rptm->inClass()) {
+            return 0;        // different types, can't compare
+          }
+
+          L = lptm->atType;
+          R = rptm->atType;
+          break;
+        }
+      }
+    }
+
+    if (!L->isCVAtomicType() || !R->isCVAtomicType()) {
+      return 0;              // different types, can't compare
+    }
+
+    // finally, inspect the leaves
+    CVAtomicType const *lat = L->asCVAtomicTypeC();
+    CVAtomicType const *rat = R->asCVAtomicTypeC();
+
+    if (foldNextCVs(ret, lat->cv, rat->cv, skipCVs)) {
+      return 0;              // not subset, therefore no decision
+    }
+
+    if (!lat->atomic->equals(rat->atomic)) {
+      return 0;              // different types, can't compare
+    }
+
+    // 'ret' is our final decision
+    return ret;
+  }
+}
+
+
+bool convertsPtrToBool(Type const *src, Type const *dest)
+{
+  // src was encountered to be NULL here after unimplemented: address of
+  // overloaded name, with a templatized element
+  xassert(src != NULL && "860cd085-9d59-4395-980c-d5f87bac7f5c");
+
+  // I believe this test is meant to transcend any reference bindings
+  src = src->asRvalC();
+  dest = dest->asRvalC();
+
+  if (!dest->isBool()) {
+    return false;
+  }
+
+  if (src->isPointerType() || src->isPointerToMemberType()) {
+    return true;
+  }
+
+  // (in/t0526.cc) it seems this also applies to types that get
+  // implicitly converted to pointers before being converted to bool
+  if (src->isArrayType() || src->isFunctionType()) {
+    return true;
+  }
+
+  return false;
+}
+
+
+// also allows void*, where 'void' is represented with
+// a NULL CompoundType
+bool isPointerToCompound(Type const *type, CompoundType const *&ct)
+{
+  type = type->asRvalC();
+
+  if (type->isPointerType()) {
+    type = type->asPointerTypeC()->atType;
+    if (type->isCompoundType()) {
+      ct = type->asCompoundTypeC();
+      return true;
+    }
+    if (type->isVoid()) {
+      ct = NULL;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+// allows both C& and C, returning C in 'ct'
+bool isReferenceToCompound(Type const *type, CompoundType const *&ct)
+{
+  type = type->asRvalC();
+
+  if (type->isCompoundType()) {
+    ct = type->asCompoundTypeC();
+    return true;
+  }
+
+  return false;
+}
+
+
+bool isPointerToCompoundMember(Type const *type, CompoundType const *&ct)
+{
+  type = type->asRvalC();
+
+  if (type->isPointerToMemberType()) {
+    ct = type->asPointerToMemberTypeC()->inClass();
+    return true;
+  }
+
+  return false;
+}
+
+
+// is 'low' below 'high' in the inheritance hierarchy?
+bool isBelow(CompoundType const *low, CompoundType const *high)
+{
+  return high==NULL ||
+         (low!=NULL && low->hasBaseClass(high));
+}
+
+
+// Is the path through the inheritance hierarchy from LS to LD a
+// proper sub-path (paths go up) of that from RS to RD?  In fact we
+// also require that one of the two endpoints coincide, since that's
+// the form of the rules given in 13.3.3.2 para 4.  Note that NULL is
+// the representation of 'void', treated as a superclass of
+// everything.
+bool isProperSubpath(CompoundType const *LS, CompoundType const *LD,
+                     CompoundType const *RS, CompoundType const *RD)
+{
+  if (LS == RS && LD == RD) return false;         // same path
+
+  if (!isBelow(LS, LD)) return false;             // LS -> LD not a path
+  if (!isBelow(RS, RD)) return false;             // RS -> RD not a path
+
+  if (LS == RS && isBelow(LD, RD)) {
+    // L and R start at the same place, but left ends lower
+    return true;
+  }
+
+  if (LD == RD && isBelow(RS, LS)) {
+    // L and R end at the same place, but right starts lower
+    return true;
+  }
+
+  return false;
+}
+
+
+// --------------------- ConversionResolver -----------------------
+bool isCompoundType_orConstRefTo(Type const *t)
+{
+  if (t->isCompoundType()) { return true; }
+
+  if (t->isReferenceType()) {
+    t = t->asReferenceTypeC()->atType;
+    return t->isConst() && t->isCompoundType();
+  }
+
+  return false;
+}
+
+ImplicitConversion getConversionOperator(
+  Env &env,
+  SourceLoc loc,
+  ErrorList * /*nullable*/ errors,
+  Type *srcClassType,
+  Type *destType
+) {
+  CompoundType *srcClass = srcClassType->asRval()->asCompoundType();
+
+  // in all cases, there is effectively one argument, the receiver
+  // object of type 'srcClass'
+  GrowArray<ArgumentInfo> args(1);
+  args[0] = ArgumentInfo(SE_NONE, srcClassType);
+
+  OVERLOADINDTRACE("converting " << srcClassType->toString() <<
+                   " to " << destType->toString());
+
+  // set up the resolver; since the only argument is the receiver
+  // object, user-defined conversions (for the receiver; of course
+  // user-defined conversions to the dest type are what are being
+  // considered by this function overall) should never enter the
+  // picture, but I'll supply OF_NO_USER just to be sure
+  OverloadResolver resolver(env, loc, errors, OF_NO_USER,
+                            // I assume conversion operators can't
+                            // have explicit template arguments
+                            NULL,
+                            args);
+
+  // get the conversion operators for the source class
+  SObjList<Variable> &ops = srcClass->conversionOperators;
+
+  // 13.3.1.4?
+  //
+  // 10/03/04: Allow conversion to 'T const &' for 'T' a class type
+  // as well (in/t0334.cc).
+  if (isCompoundType_orConstRefTo(destType)) {
+    CompoundType *destCT = destType->asRval()->asCompoundType();
+
+    // Where T is the destination class, "... [conversion operators
+    // that] yield a type whose cv-unqualified type is the same as T
+    // or is a derived class thereof are candidate functions.
+    // Conversion functions that return 'reference to T' return
+    // lvalues of type T and are therefore considered to yield T for
+    // this process of selecting candidate functions."
+    SFOREACH_OBJLIST_NC(Variable, ops, iter) {
+      Variable *v = iter.data();
+      Type *retType = v->type->asFunctionTypeC()->retType->asRval();
+      if (!retType->containsVariables()) {
+        // concrete type; easy case
+        if (retType->isCompoundType() &&
+            retType->asCompoundType()->hasBaseClass(destCT)) {
+          // it's a candidate
+          resolver.processCandidate(v);
+        }
+      }
+      else {
+        // (in/t0566.cc) templatized conversion operator; for now,
+        // ignore possibility of using derived class and just do
+        // direct matching
+        //
+        // TODO: accomodate derived-to-base conversion here too
+        MType match(env);
+        if (match.matchTypeNC(destType->asRval(), retType,
+                              MF_MATCH | MF_IGNORE_TOP_CV)) {
+          // use the bindings to instantiate the template
+          Variable *inst = env.instantiateFunctionTemplate(loc, v, match);
+          resolver.processCandidate(inst);
+        }
+      }
+    }
+  }
+
+  // 13.3.1.5?
+  else if (!destType->isReference()) {
+    // candidates added in this case are subject to an additional
+    // ranking criteria, namely that the ultimate destination type
+    // is significant (13.3.3 para 1 final bullet)
+    resolver.finalDestType = destType;
+
+    // Where T is the cv-unqualified destination type,
+    // "... [conversion operators that] yield type T or a type that
+    // can be converted to type T via a standard conversion sequence
+    // (13.3.3.1.1) are candidate functions.  Conversion functions
+    // that return a cv-qualified type are considered to yield the
+    // cv-unqualified version of that type for this process of
+    // selecting candidate functions.  Conversion functions that
+    // return 'reference to T' return lvalues of type T and are
+    // therefore considered to yield T for this process of selecting
+    // candidate functions."
+    SFOREACH_OBJLIST_NC(Variable, ops, iter) {
+      Variable *v = iter.data();
+      Type *retType = v->type->asFunctionType()->retType->asRval();
+      if (SC_ERROR!=getStandardConversion(NULL /*errorMsg*/,
+            SE_NONE, retType, destType)) {
+        // it's a candidate
+        resolver.processCandidate(v);
+      }
+    }
+  }
+
+  // must be 13.3.1.6
+  else {
+    // strip the reference
+    Type *underDestType = destType->asRval();
+
+    // Where the destination type is 'cv1 T &', "... [conversion
+    // operators that] yield type 'cv2 T2 &', where 'cv1 T' is
+    // reference-compatible (8.5.3) with 'cv2 T2', are
+    // candidate functions."
+    SFOREACH_OBJLIST_NC(Variable, ops, iter) {
+      Variable *v = iter.data();
+      Type *retType = v->type->asFunctionType()->retType;
+      if (retType->isReference()) {
+        retType = retType->asRval();     // strip the reference
+        if (isReferenceCompatibleWith(underDestType, retType)) {
+          // it's a candidate
+          resolver.processCandidate(v);
+        }
+      }
+    }
+  }
+
+  // pick the winner
+  bool wasAmbig;
+  Variable *winner = resolver.resolve(wasAmbig);
+
+  // return an IC with that winner
+  ImplicitConversion ic;
+  if (!winner) {
+    if (!wasAmbig) {
+      return ic;        // is IC_NONE
+    }
+    else {
+      ic.addAmbig();
+      return ic;
+    }
+  }
+
+  // compute the standard conversion that obtains the destination
+  // type, starting from what the conversion function yields
+  StandardConversion sc = getStandardConversion(
+    NULL /*errorMsg*/,
+    SE_NONE, winner->type->asFunctionType()->retType,   // conversion source
+    destType                                            // conversion dest
+  );
+
+  ic.addUserConv(SC_IDENTITY, winner, sc);
+  return ic;
+}
+
+
+
+// ------------------ LUB --------------------
+static CVFlags unionCV(CVFlags cv1, CVFlags cv2, bool &cvdiffers, bool toplevel)
+{
+  CVFlags cvu = cv1 | cv2;
+
+  // if underlying cv flags have already differed, then at this
+  // level we must have a 'const'
+  if (cvdiffers) {
+    if (toplevel) {
+      // once at toplevel, differences are irrelevant
+    }
+    else {
+      cvu |= CV_CONST;
+    }
+  }
+
+  // did this level witness a cv difference?
+  else if (cvu != cv1 || cvu != cv2) {
+    cvdiffers = true;
+  }
+
+  return cvu;
+}
+
+// must have already established similarity
+Type *similarLUB(Env &env, Type *t1, Type *t2, bool &cvdiffers, bool toplevel=false)
+{
+  // this analysis goes bottom-up, because if there are cv differences
+  // at a given level, then all levels above it must have CV_CONST in
+  // the LUB (otherwise t1 and t2 wouldn't be able to convert to it)
+
+  switch (t1->getTag()) {
+    default: xfailure("bad type code");
+
+    case Type::T_ATOMIC: {
+      CVAtomicType *at1 = t1->asCVAtomicType();
+      CVAtomicType *at2 = t2->asCVAtomicType();
+      CVFlags cvu = unionCV(at1->cv, at2->cv, cvdiffers, toplevel);
+      return env.tfac.makeCVAtomicType(at1->atomic, cvu);
+    }
+
+    case Type::T_POINTER: {
+      PointerType *pt1 = t1->asPointerType();
+      PointerType *pt2 = t2->asPointerType();
+      Type *under = similarLUB(env, pt1->atType, pt2->atType, cvdiffers);
+      CVFlags cvu = unionCV(pt1->cv, pt2->cv, cvdiffers, toplevel);
+      return env.tfac.makePointerType(cvu, under);
+    }
+
+    case Type::T_REFERENCE: {
+      ReferenceType *rt1 = t1->asReferenceType();
+      ReferenceType *rt2 = t2->asReferenceType();
+      Type *under = similarLUB(env, rt1->atType, rt2->atType, cvdiffers);
+      return env.tfac.makeReferenceType(under);
+    }
+
+    case Type::T_FUNCTION:
+    case Type::T_ARRAY:
+      // similarity implies equality, so LUB is t1==t2
+      return t1;
+
+    case Type::T_POINTERTOMEMBER: {
+      PointerToMemberType *pmt1 = t1->asPointerToMemberType();
+      PointerToMemberType *pmt2 = t2->asPointerToMemberType();
+      Type *under = similarLUB(env, pmt1->atType, pmt2->atType, cvdiffers);
+      CVFlags cvu = unionCV(pmt1->cv, pmt2->cv, cvdiffers, toplevel);
+      return env.tfac.makePointerToMemberType(pmt1->inClassNAT, cvu, under);
+    }
+  }
+}
+
+CompoundType *ifPtrToCompound(Type *t)
+{
+  if (t->isPointer()) {
+    PointerType *pt = t->asPointerType();
+    if (pt->atType->isCompoundType()) {
+      return pt->atType->asCompoundType();
+    }
+  }
+  return NULL;
+}
+
+bool isPointerToVoid(Type *t)
+{
+  return t->isPointerType() &&
+         t->getAtType()->isVoid();
+}
+
+CompoundType *ifPtrToMember(Type *t)
+{
+  if (t->isPointerToMemberType()) {
+    PointerToMemberType *ptm = t->asPointerToMemberType();
+    if (ptm->inClassNAT->isCompoundType()) {
+      return ptm->inClassNAT->asCompoundType();
+    }
+  }
+  return NULL;
+}
+
+// clear any toplevel cv-qualifications
+Type *cvUnqualified(Env &env, Type *t)
+{
+  return env.tfac.setQualifiers(SL_UNKNOWN, CV_NONE, t, NULL /*syntax*/);
+}
+
+Type *computeLUB(Env &env, Type *t1, Type *t2, bool &wasAmbig)
+{
+  wasAmbig = false;
+
+  // check for pointers-to-class first
+  {
+    CompoundType *ct1 = ifPtrToCompound(t1);
+    CompoundType *ct2 = ifPtrToCompound(t2);
+    CompoundType *lubCt = NULL;
+    if (ct1 && ct2) {
+      // get CV under the pointers
+      CVFlags cv1 = t1->asPointerType()->atType->getCVFlags();
+      CVFlags cv2 = t2->asPointerType()->atType->getCVFlags();
+
+      // union them (LUB in cv lattice)
+      CVFlags cvu = cv1 | cv2;
+
+      // find the LUB class, if any
+      lubCt = CompoundType::lub(ct1, ct2, wasAmbig);
+      Type *lubCtType;
+      if (!lubCt) {
+        if (wasAmbig) {
+          // no unique LUB
+          return NULL;
+        }
+        else {
+          // no class is the LUB, so use 'void'
+          lubCtType = env.tfac.getSimpleType(ST_VOID, cvu);
+        }
+      }
+      else {
+        // Now I want to make the type 'pointer to <cvu> <lubCt>', but
+        // I suspect I may frequently be able to re-use t1 or t2.
+        // Given the current fact that I don't deallocate types, that
+        // should be advantageous when possible.  Also, don't return
+        // a type with cv flags, since that messes up the instantiation
+        // of patterns.
+        if (ct1==lubCt && cv1==cvu && t1->getCVFlags()==CV_NONE) return t1;
+        if (ct2==lubCt && cv2==cvu && t2->getCVFlags()==CV_NONE) return t2;
+
+        // make a type from the class
+        lubCtType = env.tfac.makeCVAtomicType(lubCt, cvu);
+      }
+
+      return env.tfac.makePointerType(CV_NONE, lubCtType);
+    }
+  }
+
+  // convert ptr-to-non-class to void*?
+  if ((isPointerToVoid(t1) && t2->isPointerType()) ||
+      (isPointerToVoid(t2) && t1->isPointerType())) {
+    // since qualifier conversions can only add qualifiers, the LUB type
+    // must be a ptr-to-void with the union of the atType cv flags
+    CVFlags cv = t1->getAtType()->getCVFlags() | t2->getAtType()->getCVFlags();
+    return env.tfac.makePointerType(CV_NONE,
+      env.tfac.getSimpleType(ST_VOID, cv));
+  }
+
+  // TODO: I should check for pointer-to-members that are compatible
+  // by the existence of a greatest-upper-bound in the class hierarchy,
+  // for example:
+  //      A   B     .
+  //       \ /      .
+  //        C       .
+  // LUB(int A::*, int B::*) should be int C::*
+  //
+  // However, that's a bit of a pain to do, since it means maintaining
+  // the inverse of the 'hasBaseClass' relationship.  Also, I would not
+  // be able to follow the simple pattern used for pointer-to-class,
+  // since pointer-to-member can have multilevel cv qualification, so I
+  // need to flow into the general cv LUB analysis below.
+  //
+  // Since this situation should be extremely rare, I won't bother for
+  // now.  (See also convertibility.txt.)
+
+  // 2005-08-09: I managed to accidentally hack in/t0150.cc so that it
+  // exposes the need to at least check for direct descendant
+  // relationship with identical types, since GCC and ICC do so.
+  {
+    CompoundType *ct1 = ifPtrToMember(t1);
+    CompoundType *ct2 = ifPtrToMember(t2);
+    if (ct1 && ct2 && t1->getAtType()->equals(t2->getAtType())) {
+      if (ct1->hasBaseClass(ct2)) {
+        return cvUnqualified(env, t1);    // lower in the hierarchy
+      }
+      if (ct2->hasBaseClass(ct1)) {
+        return cvUnqualified(env, t2);
+      }
+    }
+  }
+
+  // ok, inheritance is irrelevant; I need to see if types
+  // are "similar" (4.4 para 4)
+  if (!t1->equals(t2, MF_SIMILAR)) {
+    // not similar to each other, so there's no type that is similar
+    // to both (similarity is an equivalence relation)
+    return NULL;
+  }
+
+  // ok, well, are they equal?  if so, then I don't have to make
+  // a new type object; NOTE: this allows identical enum arguments
+  // to yield out
+  if (t1->equals(t2, MF_IGNORE_TOP_CV)) {
+    // use 't1', but make sure we're not returning a cv-qualified type
+    return cvUnqualified(env, t1);
+  }
+
+  // not equal, but they *are* similar, so construct the lub type; for
+  // any pair of similar types, there is always a type to which both
+  // can be converted
+  bool cvdiffers = false;    // no difference recorded yet
+  return similarLUB(env, t1, t2, cvdiffers, true /*toplevel*/);
+}
+
+
+void test_computeLUB(Env &env, Type *t1, Type *t2, Type *answer, int code)
+{
+  // compute the LUB
+  bool wasAmbig;
+  Type *a = computeLUB(env, t1, t2, wasAmbig);
+
+  // did it do what we expected?
+  bool ok = false;
+  switch (code) {
+    default:
+      env.error("bad computeLUB code");
+      return;
+
+    case 0:
+      if (!a && !wasAmbig) {
+        ok = true;
+      }
+      break;
+
+    case 1:
+      if (a && a->equals(answer)) {
+        ok = true;
+      }
+      break;
+
+    case 2:
+      if (!a && wasAmbig) {
+        ok = true;
+      }
+      break;
+  }
+
+  static bool tracing = tracingSys("computeLUB");
+  if (!tracing && ok) {
+    return;
+  }
+
+  // describe the call
+  string call = stringc << "LUB(" << t1->toString()
+                        << ", " << t2->toString() << ")";
+
+  // expected result
+  string expect;
+  switch (code) {
+    case 0: expect = "fail"; break;
+    case 1: expect = stringc << "yield `" << answer->toString() << "'"; break;
+    case 2: expect = "fail with an ambiguity"; break;
+  }
+
+  // actual result
+  string actual;
+  if (a) {
+    actual = stringc << "yielded `" << a->toString() << "'";
+  }
+  else if (!wasAmbig) {
+    actual = "failed";
+  }
+  else {
+    actual = "failed with an ambiguity";
+  }
+
+  if (tracing) {
+    trace("computeLUB") << call << ": " << actual << "\n";
+  }
+
+  if (!ok) {
+    // synthesize complete message
+    env.error(stringc
+      << "I expected " << call
+      << " to " << expect
+      << ", but instead it " << actual);
+  }
+}
+
+
+// ------------------- InstCandidate ---------------
+InstCandidate::InstCandidate(Variable *p)
+  : primary(p),
+    sargs()
+{}
+
+InstCandidate::~InstCandidate()
+{}
+
+
+
+// ----------------- InstCandidateResolver ---------------
+InstCandidateResolver::InstCandidateResolver(Env &e)
+  : env(e),
+    candidates()
+{}
+
+InstCandidateResolver::~InstCandidateResolver()
+{}
+
+
+int InstCandidateResolver::compareCandidates(InstCandidate *left, InstCandidate *right)
+{
+  Type *leftType = left->primary->type;
+  Type *rightType = right->primary->type;
+
+  bool left_ALA = atLeastAsSpecializedAs(env, leftType, rightType);
+  bool right_ALA = atLeastAsSpecializedAs(env, rightType, leftType);
+  if (left_ALA && !right_ALA) {
+    // left is "more specialized"
+    return -1;
+  }
+  else if (!left_ALA && right_ALA) {
+    // right is "more specialized"
+    return +1;
+  }
+  else {
+    // no decision
+    return 0;
+  }
+}
+
+
+InstCandidate *InstCandidateResolver::selectBestCandidate()
+{
+  InstCandidate *dummy = 0;
+  return ::selectBestCandidate(*this, dummy);
+}
+
+
+// ----------------- debugging -------------------
+int overloadNesting = 0;
+
+ostream &overloadTrace()
+{
+  ostream &os = trace("overload");
+  for (int i=0; i<overloadNesting; i++) {
+    os << "  ";
+  }
+  return os;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/overload.h
===================================================================
--- vendor/elsa/current/elsa/overload.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/overload.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,330 @@
+// overload.h                       see license.txt for copyright and terms of use
+// implements C++ overload resolution
+// see cppstd section ("clause") 13
+
+#ifndef OVERLOAD_H
+#define OVERLOAD_H
+
+#include "sobjlist.h"      // SObjList
+#include "array.h"         // ArrayStack
+#include "implconv.h"      // ImplicitConversion, StandardConversion
+#include "srcloc.h"        // SourceLoc
+#include "cc_ast.h"        // PQName, ArgExpression, etc.
+#include "lookupset.h"     // LookupSet
+
+// fwds
+class Env;
+class Variable;
+class Type;
+class ErrorList;
+class TemplCandidates;
+
+
+// debugging output support
+extern int overloadNesting;      // overload resolutions ongoing
+
+// ostream with line prefix already printed
+ostream &overloadTrace();
+
+#ifndef NDEBUG
+  class OverloadIndTrace {
+  public:
+    OverloadIndTrace(char const *msg) {
+      overloadTrace() << msg << endl;
+      overloadNesting++;
+    }
+    ~OverloadIndTrace() {
+      overloadNesting--;
+    }
+  };
+
+  // print a message, indent, and at the end of this function,
+  // outdent automatically
+  #define OVERLOADINDTRACE(msg) \
+    OverloadIndTrace otrace(stringc << msg);
+
+  // just print a message at the current indentation
+  #define OVERLOADTRACE(msg) \
+    overloadTrace() << msg << endl
+
+#else
+  #define OVERLOADINDTRACE(msg) ((void)0)
+  #define OVERLOADTRACE(msg) ((void)0)
+#endif
+
+
+// information about an argument expression, for use with
+// overload resolution
+class ArgumentInfo {
+public:
+  SpecialExpr special;          // whether it's a special expression
+  Type *type;                   // type of argument
+
+  // NOTE: 'type' may be NULL if the argument corresponds to a
+  // receiver object but the function being invoked might be static
+  // and there is no receiver at the call site.
+
+  // if this is non-empty, then it means the argument is the name
+  // (or address of name) of an overloaded function, hence we must
+  // consider all the possible types; in this case, 'special' will
+  // be SE_NONE and 'type' will be NULL
+  LookupSet overloadSet;
+
+public:
+  ArgumentInfo()
+    : special(SE_NONE), type(NULL), overloadSet() {}
+  ArgumentInfo(SpecialExpr s, Type *t)
+    : special(s), type(t), overloadSet() {}
+  ArgumentInfo(LookupSet &set)
+    : special(SE_NONE), type(NULL), overloadSet(set) {}
+  ArgumentInfo(ArgumentInfo const &obj)
+    : DMEMB(special), DMEMB(type), DMEMB(overloadSet) {}
+  ArgumentInfo& operator= (ArgumentInfo const &obj)
+    { CMEMB(special); CMEMB(type); CMEMB(overloadSet); return *this; }
+};
+
+
+// used to pass info about all arguments
+typedef GrowArray<ArgumentInfo> ArgumentInfoArray;
+
+
+// information about a single overload possibility
+class Candidate {
+public:
+  // the candidate itself, with its type
+  Variable *var;
+
+  // if the candidate is actually an instantiation front for a
+  // template primary or partial specialization that is the real
+  // candidate, then that goes here
+  Variable *instFrom;
+
+  // list of conversions, one for each argument
+  GrowArray<ImplicitConversion> conversions;
+
+public:
+  // here, 'numArgs' is the number of actual arguments, *not* the
+  // number of parameters in var's function; it's passed so I know
+  // how big to make 'conversions'
+  Candidate(Variable *v, Variable *instFrom, int numArgs);
+  ~Candidate();
+
+  // true if one of the conversions is IC_AMBIGUOUS
+  bool hasAmbigConv() const;
+
+  // debugging
+  void conversionDescriptions() const;
+};
+
+
+// flags to control overload resolution
+enum OverloadFlags {
+  OF_NONE        = 0x00,           // nothing special
+  OF_NO_USER     = 0x01,           // don't consider user-defined conversions
+  OF_NO_EXPLICIT = 0x02,           // disregard DF_EXPLICIT Variables
+  
+  // this flag means the candidate set may contain a mix of static
+  // and nonstatic methods, and that resolution must explicitly
+  // account for the non-uniformity
+  OF_METHODS     = 0x04,
+  
+  // overload resolution is being done at an operator invocation site
+  OF_OPERATOR    = 0x08,
+
+  OF_ALL         = 0x0F,           // all flags
+};
+
+ENUM_BITWISE_OPS(OverloadFlags, OF_ALL);
+
+
+// this class implements a single overload resolution, exposing
+// a richer interface than the simple 'resolveOverload' call below
+class OverloadResolver {
+public:      // data
+  // same meaning as corresponding arguments to 'resolveOverload'
+  Env &env;
+  SourceLoc loc;
+  ErrorList * /*nullable*/ errors;
+  OverloadFlags flags;
+  PQName * /*nullable*/ finalName;
+  ArgumentInfoArray &args;
+  
+  // when non-NULL, this indicates the type of the expression
+  // that is being copy-initialized, and plays a role in selecting
+  // the best function (13.3.3, final bullet)
+  Type *finalDestType;
+
+  // when true, the lack of any viable candidates is *not*
+  // an error
+  bool emptyCandidatesIsOk;
+
+  // these are the "viable candidate functions" of the standard
+  ObjArrayStack<Candidate> candidates;
+  
+  // all candidates processed; used for error diagnosis
+  ArrayStack<Variable*> origCandidates;
+
+private:     // funcs
+  Candidate * /*owner*/ makeCandidate(Variable *var, Variable *instFrom);
+
+  // debugging, error diagnosis
+  void printArgInfo();
+  string argInfoString();
+
+public:      // funcs
+  OverloadResolver(Env &en, SourceLoc L, ErrorList *er,
+                   OverloadFlags f,
+                   PQName *finalName0,
+                   ArgumentInfoArray &a,
+                   int numCand = 10 /*estimate of # of candidates*/);
+  ~OverloadResolver();
+
+  // public so 'tournament' can use it
+  int compareCandidates(Candidate const *left, Candidate const *right);
+
+  // process a batch of candidate functions, adding the viable
+  // ones to the 'candidates' list
+  void addCandidate(Variable *var0, Variable *instFrom = NULL);
+  void addTemplCandidate(Variable *baseV, Variable *var0, ObjList<STemplateArgument> &sargs);
+  void processCandidates(SObjList<Variable> &varList);
+  void processCandidate(Variable *v);
+
+  // if 'v' has an overload set, then process that; otherwise, just
+  // process 'v' alone
+  void processPossiblyOverloadedVar(Variable *v);
+
+  // add a candidate that has two ambiguous user-defined conversions
+  // for its arguments to 'v'
+  void addAmbiguousBinaryCandidate(Variable *v);
+
+  // look up and process operator candidate functions, given the
+  // types of the arguments and the name of the operator
+  void addUserOperatorCandidates
+    (Type * /*nullable*/ lhsType, Type * /*nullable*/ rhsType, StringRef opName);
+
+  // instantiate built-in candidates
+  void addBuiltinUnaryCandidates(OverloadableOp op);
+  void addBuiltinBinaryCandidates(OverloadableOp op,
+    ArgumentInfo &lhsInfo, ArgumentInfo &rhsInfo);
+
+  // run the tournament to decide among the candidates; returns
+  // NULL if there is no clear winner
+  Variable *resolve(bool &wasAmbig);
+  Variable *resolve();     // ignore ambiguity info
+  
+  // slightly richer interface: return the complete Candidate,
+  // which contains the Variable, but also the conversions;
+  // NOTE: the candidate will disappear when '*this' does!
+  Candidate const * /*serf*/ resolveCandidate(bool &wasAmbig);
+  
+  // determine the return value of a candidate
+  Type *getReturnType(Candidate const *winner) const;
+};
+
+
+// dsw: not sure where this should go, but for now I'll put it here;
+// see the implementation for more notes
+Variable *selectBestCandidate_templCompoundType(TemplCandidates &resolver);
+
+
+// resolve the overloading, return the selected candidate; if nothing
+// matches or there's an ambiguity, adds an error to 'env' and returns
+// NULL
+Variable *resolveOverload(
+  Env &env,                        // environment in which to perform lookups
+  SourceLoc loc,                   // location for error reports
+  ErrorList * /*nullable*/ errors, // where to insert errors; if NULL, don't
+  OverloadFlags flags,             // various options
+  SObjList<Variable> &list,        // list of overloaded possibilities
+  PQName * /*nullable*/ finalName, // for any explicit template arguments; NULL for ctors
+  ArgumentInfoArray &args,         // list of argument types at the call site
+  bool &wasAmbig                   // returns as true if error due to ambiguity
+);
+
+
+// collect the set of conversion operators that 'ct' has; this
+// interface will change once I get a proper implementation of
+// conversion operator inheritance
+//void getConversionOperators(SObjList<Variable> &dest, Env &env,
+//                            CompoundType *ct);
+//
+// update: use 'ct->conversionOperators' instead
+
+
+// given an object of type 'srcClass', find a conversion operator
+// that will yield 'destType' (perhaps with an additional standard
+// conversion); for now, this function assumes the conversion
+// context is as in 13.3.1.{4,5,6}: copy-initialization by conversion
+// (NOTE: this does *not* try "converting constructors" of 'destType')
+ImplicitConversion getConversionOperator(
+  Env &env,
+  SourceLoc loc,
+  ErrorList * /*nullable*/ errors,
+  Type *srcClassType,      // must be a compound (or reference to one)
+  Type *destType
+);
+
+
+// least upper bound: given types T1 and T2, compute the unique type S
+// such that:
+//   (a) T1 and T2 can be standard-converted to S
+//   (b) for any other type S' != S that T1 and T2 can be
+//       standard-converted to, the conversion T1->S is better than
+//       T1->S' or T2->S is better than T2->S', and neither ->S
+//       conversion is worse than a ->S' conversion
+// if no type satisfies (a) and (b), return NULL; furthermore, if
+// a type satisfies (a) but not (b), then yield 'wasAmbig'
+//                 
+// NOTE: This only works for pointers, pointers-to-member, and enums.
+// If you give it some other types, it might return one of them, but
+// it might not actually be the the LUB.  This doesn't cause a problem
+// in my design because the output of computeLUB is always filtered to
+// ignore types that aren't one of those that work.
+Type *computeLUB(Env &env, Type *t1, Type *t2, bool &wasAmbig);
+
+// test vector for 'computeLUB'; code:
+//   0=fail
+//   1=success, should match 'answer'
+//   2=ambiguous
+void test_computeLUB(Env &env, Type *t1, Type *t2, Type *answer, int code);
+
+
+// When doing explicit instantiation of function templates, we collect
+// instantiation candidates and then select the most specific to
+// actually instantiate.
+class InstCandidate {
+public:
+  // the template to instantiate
+  Variable *primary;
+
+  // the arguments to apply to that template
+  ObjList<STemplateArgument> sargs;
+
+public:
+  InstCandidate(Variable *p);
+  ~InstCandidate();
+};
+
+// algorithm object to select the best from a set
+class InstCandidateResolver {
+public:
+  // needed to resolve DQTs...
+  Env &env;
+
+  // set of candidates
+  ObjArrayStack<InstCandidate> candidates;
+
+public:
+  InstCandidateResolver(Env &e);
+  ~InstCandidateResolver();
+
+  // for internal use by the tournament
+  int compareCandidates(InstCandidate *left, InstCandidate *right);
+
+  // public use: choose from 'candidates', or return NULL if the
+  // choice is ambiguous
+  InstCandidate *selectBestCandidate();
+};
+
+
+#endif // OVERLOAD_H

Added: vendor/elsa/current/elsa/packedword.h
===================================================================
--- vendor/elsa/current/elsa/packedword.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/packedword.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,69 @@
+// packedword.h            see license.txt for copyright and terms of use
+
+// quarl 2006-06-22
+//    PackedWord represents a single word (long for now; could be templatized)
+//    as a bit vector.  This allows packing multiple objects into a single
+//    word.
+
+#ifndef WORDPACK_H
+#define WORDPACK_H
+
+#include "xassert.h"
+
+class PackedWord {
+public:
+  typedef unsigned word;
+  enum { WORD_SIZE = 8*sizeof(word) };
+
+protected:
+  // bit vector from [0, WORD_SIZE)
+  word data;
+
+  static word mask(int begin, int end) {
+    return ((1<<(end-begin)) - 1) << begin;
+  }
+
+public:
+  PackedWord() : data(0) {}
+
+  // return data[begin, end)
+  //
+  // get(0, WORD_SIZE) == data
+  word get(int begin, int end) const {
+    word ret;
+    if (end == WORD_SIZE) {
+      // don't shift >> 32 cos it'd overflow
+      ret = data >> begin;
+    } else {
+      ret = (data & mask(0,end)) >> begin;
+    }
+    return ret;
+  }
+
+  void set(int begin, int end, word data0) {
+    xassert(begin < end && end <= WORD_SIZE);
+    // make sure data0 isn't too big
+    xassert((data0 & ~ mask(0,end-begin)) == 0);
+
+    // mask out old value
+    data = data & ~ mask(begin,end);
+
+    // add in new value
+    data = data | ( data0 << begin);
+  }
+};
+
+#define PACKEDWORD_DEF_GS(PW, N, T, B, E)                         \
+  T get##N() const {                                              \
+    return (T) PW.get(B, E);                                      \
+  }                                                               \
+  void set##N(T t) {                                              \
+    PW.set(B, E, (PackedWord::word) t);                           \
+  }
+
+#endif
+
+// Local Variables:
+// kc-compile-command-make: "make packedword_test && ./packedword_test"
+// End:
+

Added: vendor/elsa/current/elsa/packedword_test.cc
===================================================================
--- vendor/elsa/current/elsa/packedword_test.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/packedword_test.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,81 @@
+// packedword_test.cc            see license.txt for copyright and terms of use
+
+// quarl 2006-06-22
+//    test program for PackedWord.
+
+#include "packedword.h"
+#include "exc.h"
+
+class Foo {
+  PackedWord pw;
+  int a, b, c, d;
+
+  PACKEDWORD_DEF_GS(pw, A0, int, 0, 5)
+  PACKEDWORD_DEF_GS(pw, B0, int, 5, 20)
+  PACKEDWORD_DEF_GS(pw, C0, int, 20, 30)
+  PACKEDWORD_DEF_GS(pw, D0, int, 30, 32)
+
+  void check()
+  {
+    xassert(getA0() == a);
+    xassert(getB0() == b);
+    xassert(getC0() == c);
+    xassert(getD0() == d);
+  }
+
+public:
+  Foo() : a(0), b(0), c(0), d(0) {}
+  void setA(int a0) { setA0(a0); a = a0; check(); }
+  void setB(int b0) { setB0(b0); b = b0; check(); }
+  void setC(int c0) { setC0(c0); c = c0; check(); }
+  void setD(int d0) { setD0(d0); d = d0; check(); }
+};
+
+#define N(X) cout << "// " #X ";" << endl; X
+#define NE(X)                                                     \
+  cout << "// " #X ";" << endl;                                   \
+  clog << "Want exception: ";                                     \
+  try {                                                           \
+    X;                                                            \
+    cerr << "OOPS, expected assertion\n";                         \
+    return 1;                                                     \
+  } catch(...) {                                                  \
+    cout << "Good, got assertion.\n";                             \
+  }
+
+int main()
+{
+  N(Foo foo);
+  N(int A = (1<<5)-1);
+  N(int B = (1<<15)-1);
+  N(int C = (1<<10)-1);
+  N(int D = (1<<2)-1);
+  xassert(A == 31);
+
+  N(foo.setA( 1 ));
+  N(foo.setA( A ));
+
+  N(foo.setB( 0 ));
+  N(foo.setB( B ));
+  N(foo.setA( 0 ));
+  N(foo.setC( 0 ));
+  N(foo.setD( 0 ));
+  N(foo.setC( C ));
+  N(foo.setD( D ));
+  N(foo.setC( 0 ));
+  N(foo.setD( 0 ));
+
+  NE(foo.setA( A+1 ));
+  NE(foo.setB( B+1 ));
+  NE(foo.setC( C+1 ));
+  NE(foo.setD( D+1 ));
+
+  cout << "\n"
+       << "packedword_test: PASS.\n"
+       << flush;
+}
+
+// Local Variables:
+// kc-compile-command-make: "make packedword_test && ./packedword_test"
+// End:
+

Added: vendor/elsa/current/elsa/parssppt.cc
===================================================================
--- vendor/elsa/current/elsa/parssppt.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/parssppt.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,169 @@
+// parssppt.cc            see license.txt for copyright and terms of use
+// code for parssppt.h
+
+#include "parssppt.h"     // this module
+#include "glr.h"          // toplevelParse
+#include "trace.h"        // traceProcessArg
+#include "syserr.h"       // xsyserror
+
+#include <stdlib.h>       // exit
+
+
+// ---------------------- ParseTree --------------------
+ParseTreeAndTokens::ParseTreeAndTokens(CCLang &L, SemanticValue &top,
+                                       StringTable &extTable, char const *fname)
+  : treeTop(top),
+    lexer(new Lexer(extTable, L, fname)),
+    userAct(NULL),
+    tables(NULL)
+{}
+
+ParseTreeAndTokens::~ParseTreeAndTokens()
+{
+  delete lexer;
+}
+
+
+// ---------------------- other support funcs ------------------
+// process the input file, and yield a parse graph
+bool glrParseNamedFile(GLR &glr, LexerInterface &lexer, SemanticValue &treeTop,
+                       char const *inputFname)
+{
+  #if 0    // old
+  // do first phase lexer
+  traceProgress() << "lexical analysis...\n";
+  traceProgress(2) << "lexical analysis stage 1...\n";
+  Lexer1 lexer1(inputFname);
+  {
+    FILE *input = fopen(inputFname, "r");
+    if (!input) {
+      xsyserror("fopen", inputFname);
+    }
+
+    lexer1_lex(lexer1, input);
+    fclose(input);
+
+    if (lexer1.errors > 0) {
+      printf("L1: %d error(s)\n", lexer1.errors);
+      return false;
+    }
+  }
+
+  // do second phase lexer
+  traceProgress(2) << "lexical analysis stage 2...\n";
+  lexer2_lex(lexer2, lexer1, inputFname);
+
+  // parsing itself
+  lexer2.beginReading();
+  return glr.glrParse(lexer2, treeTop);
+  #endif // 0
+
+  PRETEND_USED(inputFname);     // stupid module..
+  return glr.glrParse(lexer, treeTop);
+}
+
+
+bool toplevelParse(ParseTreeAndTokens &ptree, char const *inputFname)
+{
+  // parse
+  xassert(ptree.userAct != NULL);    // must have been set by now
+  xassert(ptree.tables != NULL);
+
+  GLR glr(ptree.userAct, ptree.tables);
+
+  // parse input
+  return glrParseNamedFile(glr, *ptree.lexer, ptree.treeTop, inputFname);
+}
+
+
+// hack: need classifier to act like the one for Bison
+class SimpleActions : public TrivialUserActions {
+public:
+  virtual ReclassifyFunc getReclassifier();
+  static int reclassifyToken(UserActions *ths,
+    int oldTokenType, SemanticValue sval);
+};
+
+UserActions::ReclassifyFunc SimpleActions::getReclassifier()
+{
+  if (tracingSys("identityReclassify")) {
+    // don't reclassify anything
+    return &TrivialUserActions::reclassifyToken;
+  }
+  else {
+    // reclassify as if typedef's weren't possible
+    return &SimpleActions::reclassifyToken;
+  }
+}
+
+STATICDEF int SimpleActions::reclassifyToken(UserActions *, int type, SemanticValue)
+{
+  if (type == TOK_NAME) {
+    return TOK_VARIABLE_NAME;
+  }
+  else {
+    return type;
+  }
+}
+
+
+char *processArgs(int argc, char **argv, char const *additionalInfo) {
+  // remember program name
+  char const *progName = argv[0];
+
+  // process args
+  while (argc >= 2) {
+    if (traceProcessArg(argc, argv)) {
+      continue;
+    }
+#if 0
+    else if (streq(argv[1], "-sym") && argc >= 3) {
+      symOfInterestName = argv[2];
+      argc -= 2;
+      argv += 2;
+    }   
+#endif // 0
+    else {
+      break;     // didn't find any more options
+    }
+  }
+
+  if (argc != 2) {
+    cout << "usage: " << progName << " [options] input-file\n"
+//            "  env:\n"
+//            "    SYM_OF_INTEREST symbol to watch during analysis\n"
+            "  options:\n"
+            "    -tr <flags>:       turn on given tracing flags (comma-separated)\n"
+            //"    -sym <sym>: name the \"symbol of interest\"\n"
+//              "  useful tracing flags:\n"
+//              "    parse           print shift/reduce steps of parsing algorithm\n"
+//              "    grammar         echo the grammar\n"
+//              "    ambiguities     print ambiguities encountered during parsing\n"
+//              "    conflict        SLR(1) shift/reduce conflicts (fork points)\n"
+//              "    itemsets        print the sets-of-items DFA\n"
+//            "    ... the complete list is in parsgen.txt ...\n"
+         << (additionalInfo? additionalInfo : "");
+    exit(argc==1? 0 : 2);    // error if any args supplied
+  }
+
+  return argv[1];
+}
+
+void maybeUseTrivialActions(ParseTreeAndTokens &ptree) 
+{
+  if (tracingSys("trivialActions")) {
+    // replace current actions with trivial actions
+    //delete ptree.userAct;      // the caller does this
+    ptree.userAct = new SimpleActions;
+    cout << "using trivial (er, simple..) actions\n";
+  }
+}
+
+// useful for simple treewalkers
+bool treeMain(ParseTreeAndTokens &ptree, int argc, char **argv,
+              char const *additionalInfo)
+{
+  char const *positionalArg = processArgs(argc, argv, additionalInfo);
+  maybeUseTrivialActions(ptree);
+  return toplevelParse(ptree, positionalArg);
+}

Added: vendor/elsa/current/elsa/parssppt.h
===================================================================
--- vendor/elsa/current/elsa/parssppt.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/parssppt.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,73 @@
+// parssppt.h            see license.txt for copyright and terms of use
+// parser-support routines, for use at runtime while processing
+// the generated Parse tree
+//
+// this module is primarily for use with the C and C++ grammars,
+// but has been pressed into service for a few other uses too;
+// new grammars and parsers should probably not use this
+
+
+
+//                  alt.parssppt.die.die.die!
+
+// TODO:  This is a stupid module: ill-conceived, and awkward to use.
+// It either needs to be rewritten, or its functionality spread to
+// other modules.
+
+
+
+#ifndef PARSSPPT_H
+#define PARSSPPT_H
+
+#include "lexer.h"        // Lexer
+#include "useract.h"      // SemanticValue, UserAction
+
+class ParseTables;
+class GLR;
+class LexerInterface;
+
+
+// ----------------- helpers for analysis drivers ---------------
+// a self-contained parse tree (or parse DAG, as the case may be)
+class ParseTreeAndTokens {
+public:
+  // reference to place to store final semantic value
+  SemanticValue &treeTop;
+
+  // just replacing Lexer2 with Lexer for now..
+  LexerInterface *lexer;           // (owner)
+
+  // parse parameter
+  UserActions *userAct;            // (serf)
+
+  // parse tables (or NULL)
+  ParseTables *tables;             // (serf)
+
+public:
+  ParseTreeAndTokens(CCLang &lang, SemanticValue &top, StringTable &extTable,
+                     char const *inputFname);
+  ~ParseTreeAndTokens();
+};
+
+
+bool glrParseNamedFile(GLR &glr, LexerInterface &lexer, SemanticValue &treeTop,
+                       char const *inputFname);
+
+// dsw: what is this?
+//  // given grammar and input, yield a parse tree
+//  // returns false on error
+//  bool toplevelParse(ParseTreeAndTokens &ptree, char const *grammarFname,
+//                     char const *inputFname, char const *symOfInterestName);
+
+bool toplevelParse(ParseTreeAndTokens &ptree, char const *inputFname);
+
+char *processArgs(int argc, char **argv, char const *additionalInfo = NULL);
+
+void maybeUseTrivialActions(ParseTreeAndTokens &ptree);
+
+// useful for simple treewalkers; false on error
+bool treeMain(ParseTreeAndTokens &ptree, int argc, char **argv,
+              char const *additionalInfo = NULL);
+
+
+#endif // PARSSPPT_H

Added: vendor/elsa/current/elsa/regrtest
===================================================================
--- vendor/elsa/current/elsa/regrtest	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/regrtest	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1714 @@
+#!/bin/sh
+# regression tests
+
+# This file contains a list of tests that should be run in Elsa (via
+# ./ccparse) before each commit.  With the exception of a few stored
+# in the elsa/in/big directory, they should be short tests that can be
+# parsed and typechecked quickly.  When a big test fails (either one
+# that is in elsa/in/big, or some other external package), the failing
+# syntax should be isolated and added to this file.
+#
+# The basic procedure for adding tests is to find the section that has
+# tests for the language (C++, C, GNU extensions, etc.) the test uses,
+# and append a line of the form
+#
+#   testparse foo.cc
+#
+# where the name 'testparse' will depend on the section the test
+# appears in (because it selects the language).
+#
+# If the test is currently failing, but is intended to be fixed and
+# therefore eventually succeed, use
+#
+#   failparse foo.cc "give reason here"
+#
+# The "reason" string, ideally, should include (1) what response
+# ccparse gives (segfault, assertion failure, error message) and (2)
+# what kind of syntax characterizes the input (e.g., "template with
+# reference parameter").  The purpose of this string is to help me
+# prioritize which tests to fix first.
+#
+# If the test includes deliberately invalid syntax that elsa is
+# supposed to detect and reject, then include lines in the test case
+# of the form
+#
+#   //ERROR(n): some bad code;
+#
+# where 'n' is some number (like 1).  See multitest.pl for more
+# details.
+
+
+# default values for user parameters
+skip=0
+big=0
+contin=0
+
+# counters
+curtest=0
+success=0
+failure=0
+unexSuccess=0
+unexFailure=0
+skipdiagnose=0
+runOneTest=false
+
+usage() {
+cat <<EOF
+usage: $0 [options]
+  -skip <n>    skip the first <n> tests
+  -one <n>     run only test <n>
+  -big         run the big, timeconsuming tests
+  -contin      keep going even after a test fails (or succeeds) unexpectedly
+  -help        print this message
+EOF
+}
+
+# process args
+while [ "$1" != "" ]; do
+  case "$1" in
+    -skip)
+      shift
+      skip="$1"
+      ;;
+
+    -one)
+      shift
+      skip="$1"
+      runOneTest=true
+      ;;
+
+    -big)
+      big=1
+      ;;
+
+    -contin)
+      contin=1
+      ;;
+
+    -help)
+      usage
+      exit 0
+      ;;
+
+    *)
+      echo "unknown arg: $1"
+      usage
+      exit 2
+      ;;
+  esac
+
+  shift
+done
+
+# allow 'gmake' or whatever to be used instead of 'make'
+MAKE=${MAKE:-make}
+
+# clear the logfile
+logfile=regrtest.log
+rm -f $logfile
+
+# write something to terminal and log
+log() {
+  echo "$@"
+  echo "$@" >> $logfile
+}
+
+
+# run a single test, and bail if it fails
+runTest() {
+  if runTestInternal "$@"; then
+    true
+  else
+    if [ $contin = 0 ]; then
+      exit 2
+    fi
+  fi
+}
+
+# run a single test, and return 0 if it succeeds
+runTestInternal() {
+  result=0
+
+  if [ "$curtest" -lt "$skip" ]; then
+    echo "[$curtest]: skipping $*"
+  else
+    # print a visually distinctive banner
+    echo "------------ [$curtest] $* ------------"
+    ("$@")
+    result=$?
+    if [ $result -ne 0 ]; then
+      unexFailure=`expr $unexFailure + 1`
+      echo ""
+      log  "[$curtest] A regression test command failed:"
+      log  "  $*"
+    else
+      success=`expr $success + 1`
+    fi
+
+    if $runOneTest; then
+      # exit with code 0 if the test succeeded
+      exit `expr 1 - $success`
+    fi
+  fi
+
+  curtest=`expr $curtest + 1`
+  return $result
+}
+
+# run a big test, only if the user wants to
+bigTest() {
+  if [ $big = 1 ]; then
+    runTest "$@"
+  fi
+}
+
+# run a test that is expected to fail
+#
+# This is *not* intended for "here's a test that should fail", but
+# rather "here's a test that does fail right now, but we want to
+# eventually fix it".  The former can be handled using multitest.pl,
+# or a similar mechanism for inverting the test sense.
+failTest() {
+  reason="$1"
+  shift
+
+  if [ "$reason" = "" ]; then
+    echo "failTest $*: must supply a failure reason"
+    exit 4
+  fi
+
+  if [ "$curtest" -lt "$skip" ]; then
+    echo "[$curtest]: (fail) skipping $*"
+  else
+    echo "------------ [$curtest] (fail) $* ------------"
+    if "$@"; then
+      unexSuccess=`expr $unexSuccess + 1`
+      echo ""
+      log  "[$curtest] GOOD NEWS: A regression test that used to fail ($reason) now succeeds:"
+      log  "  $*"
+      if [ $contin = 0 ]; then
+        exit 2
+      fi
+    else
+      failure=`expr $failure + 1`
+      echo "Failed as expected: $reason"
+    fi
+
+    if $runOneTest; then
+      # exit with code 0 if the test failed
+      exit `expr 1 - $failure`
+    fi
+  fi
+
+  curtest=`expr $curtest + 1`
+}
+
+# run a failing big test
+bigFail() {
+  if [ $big = 1 ]; then
+    failTest "$@"
+  fi
+}
+
+# grep for lines containing both words, in first argument source file
+grepBoth() {
+  grep -w $2 $1 | grep -w $3
+}
+
+
+# ---------- test C++ parser ------------
+
+# by using shell functions we can make it easy to comment-out
+# or change to 'fail' status those tests that are not working at
+# some given time
+testparse() {
+  runTest perl ./multitest.pl ./ccparse in/$1
+}
+testparse_strict() {
+  # this is for tests that include things that should be diagnosed
+  # as errors, but (for the moment) require the "strict" flag for
+  # that to occur
+  #
+  # 2005-03-05: I am trying to move towards a state where 'strict'
+  # processing is *always* performed, so I am gradually adding
+  # _strict to certain tests that are or have been problematic;
+  # eventually I will remove _strict altogether and make that behavior
+  # be the default.
+  #
+  # 2005-03-09: The flag that "strict" used to control is now on
+  # by default, though it can be disabled with "-tr permissive".
+  # I will leave "testparse_strict", but not use it anymore.
+  runTest perl ./multitest.pl ./ccparse -tr strict in/$1
+}
+
+# run the parser with some specific tracing flag(s) added
+testparse_special() {
+  runTest perl ./multitest.pl ./ccparse -tr $1 in/$2
+}
+
+failparse() {
+  if [ "$2" = "" ]; then
+    echo "failparse $1: failparse takes two arguments"
+    exit 4
+  fi
+  failTest "$2" perl ./multitest.pl ./ccparse in/$1
+}
+
+failparse_special() {
+  if [ "$3" = "" ]; then
+    echo "failparse_special $2: failparse_special takes three arguments"
+    exit 4
+  fi
+  failTest "$3" perl ./multitest.pl ./ccparse -tr $1 in/$2
+}
+
+# ---- BEGIN: lots of tests ----
+# (this block of tests is parsed by another program, so should stick to
+# the uniform syntax below)
+testparse t0001.cc
+testparse t0002.cc
+testparse t0003.cc
+testparse t0004.cc
+testparse t0005.cc
+testparse t0006.cc
+testparse t0007.cc
+testparse t0008.cc
+testparse t0009.cc
+testparse t0010.cc
+testparse t0011.cc
+testparse t0012.cc
+testparse t0013.cc
+testparse t0014.cc
+testparse t0014a.cc
+testparse t0015.cc
+testparse t0016.cc
+testparse t0017.cc
+testparse t0018.cc
+testparse t0019.cc
+testparse t0020.cc
+testparse t0021.cc
+testparse t0022.cc
+testparse t0023.cc
+testparse t0024.cc
+testparse t0025.cc
+testparse t0026.cc
+testparse t0027.cc
+testparse t0028.cc
+testparse t0029.cc
+testparse t0030.cc
+testparse t0030a.cc
+testparse t0030b.cc
+testparse t0031.cc
+testparse t0032.cc
+testparse t0033.cc
+testparse t0034.cc
+testparse t0035.cc
+testparse t0036.cc
+testparse t0037.cc
+testparse t0038.cc
+testparse t0039.cc
+testparse t0040.cc
+testparse t0041.cc
+testparse t0042.cc
+testparse t0043.cc
+testparse t0044.cc
+testparse t0045.cc
+testparse t0046.cc
+testparse t0047.cc
+testparse t0048.cc
+testparse t0049.cc
+testparse t0050.cc
+testparse t0051.cc
+testparse t0052.cc
+testparse t0053.cc
+testparse t0054.cc
+testparse t0055.cc
+testparse t0056.cc
+testparse t0057.cc
+testparse t0058.cc
+testparse t0059.cc
+testparse t0060.cc
+testparse t0061.cc
+testparse t0062.cc
+testparse t0063.cc
+testparse t0064.cc
+testparse t0065.cc
+testparse t0066.cc
+testparse t0067.cc
+testparse t0068.cc
+testparse t0069.cc
+testparse t0070.cc
+testparse t0071.cc
+testparse t0072.cc
+testparse t0073.cc
+testparse t0074.cc
+testparse t0075.cc
+testparse t0076.cc
+testparse t0077.cc
+testparse t0078.cc
+testparse t0079.cc
+testparse t0080.cc
+testparse t0081.cc
+testparse t0082.cc
+testparse t0083.cc
+testparse t0084.cc
+testparse t0085.cc
+testparse t0086.cc
+testparse t0087.cc
+testparse t0088.cc
+testparse t0089.cc
+testparse t0090.cc
+testparse t0091.cc
+testparse t0092.cc
+testparse t0093.cc
+testparse t0094.cc
+testparse t0095.cc
+testparse t0096.cc
+testparse t0097.cc
+testparse t0098.cc
+testparse t0099.cc
+testparse t0100.cc
+testparse t0101.cc
+testparse t0102.cc
+testparse t0103.cc
+testparse t0104.cc
+testparse t0105.cc
+testparse t0106.cc
+testparse t0107.cc
+testparse t0108.cc
+testparse t0108b.cc
+testparse t0109.cc
+testparse t0110.cc
+testparse t0111.cc
+testparse t0112.cc
+testparse t0113.cc
+testparse t0114.cc
+testparse t0115.cc
+testparse t0116.cc
+testparse t0117.cc
+testparse t0118.cc
+testparse t0119.cc
+testparse t0120.cc
+testparse t0121.cc
+testparse t0122.cc
+testparse t0123.cc
+testparse t0124.cc
+testparse t0125.cc
+testparse t0126.cc
+testparse t0127.cc
+testparse t0128.cc
+testparse t0129.cc
+testparse t0130.cc
+testparse t0131.cc
+testparse t0132.cc
+testparse t0133.cc
+testparse t0134.cc
+testparse t0135.cc
+testparse t0136.cc
+testparse t0137.cc
+testparse t0138.cc
+testparse t0139.cc
+testparse t0140.cc
+testparse t0141.cc
+testparse t0142.cc
+testparse t0143.cc
+testparse t0144.cc
+testparse t0145.cc
+testparse t0146.cc
+testparse t0147.cc
+testparse t0148.cc
+testparse t0149.cc
+testparse t0150.cc
+testparse t0151.cc
+testparse t0152.cc
+testparse t0153.cc
+testparse t0154.cc
+testparse t0155.cc
+testparse t0156.cc
+testparse t0157.cc
+testparse t0158.cc
+testparse t0159.cc
+testparse t0160.cc
+testparse t0161.cc
+testparse t0162.cc
+testparse t0163.cc
+testparse t0164.cc
+testparse t0165.cc
+testparse t0166.cc
+testparse t0167.cc
+testparse t0168.cc
+testparse t0169.cc
+testparse t0170.cc
+testparse t0171.cc
+testparse t0172.cc
+testparse t0173.cc
+testparse t0174.cc
+testparse t0175.cc
+testparse t0176.cc
+testparse t0177.cc
+testparse t0178.cc
+testparse t0179.cc
+testparse t0180.cc
+testparse t0181.cc
+testparse t0182.cc
+testparse t0183.cc
+testparse t0184.cc
+testparse t0185.cc
+testparse t0186.cc
+testparse t0187.cc
+testparse t0188.cc
+testparse t0189.cc
+testparse t0190.cc
+testparse t0191.cc
+testparse t0192.cc # used to fail due to "forward template function"
+testparse t0193.cc
+testparse t0194.cc
+testparse t0195.cc
+testparse t0196.cc
+testparse t0197.cc
+testparse t0198.cc
+failparse t0199.cc "unimplemented: alpha conv + default arg"
+testparse t0200.cc
+testparse t0201.cc
+testparse t0202.cc
+testparse t0203.cc
+testparse t0204.cc
+testparse t0205.cc
+testparse t0206.cc
+testparse t0207.cc
+testparse t0208.cc
+testparse t0209.cc
+testparse t0210.cc
+testparse t0211.cc
+testparse t0212.cc
+testparse t0213.cc
+testparse t0214.cc
+# even g++ won't compile this; I'll bet not legal C++, so no point in testing it
+#failparse t0215.cc "(fill in a reason here)"
+testparse t0216.cc
+testparse t0217.cc
+testparse t0218.cc
+testparse t0219.cc
+testparse t0220.cc
+testparse t0221.cc
+testparse t0222.cc
+testparse t0223.cc
+testparse t0224.cc
+testparse t0225.cc
+testparse t0226.cc
+testparse t0227.cc
+testparse t0228.cc
+# tested below after I can query the gnu flag
+#testparse t0228b.cc
+testparse t0229.cc
+testparse t0230.cc
+testparse t0231.cc
+testparse t0232.cc
+testparse t0233.cc
+testparse t0234.cc
+testparse t0235.cc
+testparse t0236.cc
+testparse t0237.cc
+testparse t0238.cc
+testparse t0239.cc
+testparse t0240.cc
+testparse t0241.cc
+testparse t0242.cc
+testparse t0243.cc
+testparse t0244.cc
+testparse t0245.cc
+testparse t0246.cc
+testparse t0247.cc
+testparse t0248.cc
+testparse t0249.cc
+testparse t0250.cc
+testparse t0251.cc
+testparse t0252.cc
+testparse t0253.cc
+testparse t0254.cc
+testparse t0255.cc
+testparse t0256.cc
+testparse t0257.cc
+testparse t0258.cc
+testparse t0259.cc
+testparse t0260.cc
+testparse t0261.cc
+testparse t0262.cc
+testparse t0263.cc
+testparse t0264.cc
+testparse t0265.cc
+testparse t0266.cc
+# it's not clear whether t0267.cc is valid C++ or not, no point in testing it here
+testparse t0268a.cc
+testparse t0268.cc
+testparse t0269.cc
+testparse t0270.cc
+testparse t0271.cc
+testparse t0272.cc
+testparse t0273.cc
+testparse t0274.cc
+testparse t0275.cc
+testparse t0276.cc
+testparse t0277.cc
+testparse t0278.cc
+testparse_special eagerFBodyInst t0279.cc
+testparse t0280.cc
+testparse t0281.cc
+testparse t0282.cc
+testparse t0283.cc
+testparse t0284.cc
+testparse t0285.cc
+testparse t0286.cc
+testparse t0287.cc
+testparse t0288.cc
+testparse t0289.cc # "repeated using declarations"
+testparse t0290.cc
+testparse t0290a.cc
+testparse t0291.cc
+testparse t0292.cc
+testparse t0293.cc
+testparse t0294.cc
+testparse t0295.cc
+testparse t0296.cc
+testparse t0297.cc
+testparse t0298.cc
+testparse t0299.cc
+testparse t0300.cc
+testparse t0301.cc
+testparse t0302.cc
+testparse t0303.cc
+testparse t0304.cc
+testparse t0305.cc
+testparse t0306.cc
+testparse t0307.cc
+testparse t0308.cc
+testparse t0309.cc
+testparse t0310.cc
+testparse t0311.cc
+testparse t0312.cc
+testparse t0313.cc
+testparse t0314.cc
+testparse t0315.cc
+testparse t0316.cc
+testparse t0317.cc
+testparse t0318.cc
+testparse t0319.cc
+testparse t0320.cc
+testparse t0321.cc
+testparse t0322.cc
+testparse t0323.cc
+testparse t0324.cc
+testparse t0325.cc
+testparse t0326.cc
+testparse t0327.cc
+testparse t0328.cc
+testparse t0329.cc
+testparse t0330.cc
+testparse t0331.cc
+testparse t0332.cc
+testparse t0333.cc
+testparse t0334.cc
+testparse t0335.cc
+testparse t0336.cc
+testparse t0337.cc
+testparse t0338.cc
+testparse t0339.cc
+testparse t0340.cc
+testparse t0341.cc
+testparse t0342.cc
+testparse t0343.cc
+testparse t0344.cc
+testparse t0345.cc
+testparse t0346.cc
+testparse t0347.cc
+testparse t0348.cc
+testparse t0349.cc
+testparse t0350.cc
+testparse t0351.cc
+testparse t0352.cc
+testparse t0353.cc
+testparse t0354.cc
+testparse t0355.cc
+testparse t0356.cc
+testparse t0357.cc
+testparse t0358.cc
+testparse t0359.cc
+testparse t0360.cc
+
+# this tests that Elsa diagnoses erroneous input, but gcc accepts it,
+# so Elsa only rejects in ANSI mode
+testparse_special ansi t0361.cc
+
+testparse t0362.cc
+testparse t0363.cc
+testparse t0364.cc
+testparse t0365.cc
+testparse t0366.cc
+testparse t0367.cc
+testparse t0368.cc
+testparse t0369.cc
+testparse t0370.cc
+testparse t0371.cc
+testparse t0372.cc
+testparse t0373.cc
+testparse t0374.cc
+testparse t0375.cc
+testparse t0376.cc
+testparse t0377.cc
+testparse t0378.cc
+testparse t0379.cc
+testparse t0380.cc
+testparse t0381.cc
+testparse t0382.cc
+testparse t0383.cc
+testparse t0384.cc
+testparse t0385.cc
+testparse t0386.cc
+testparse t0387.cc
+testparse t0388.cc
+testparse t0389.cc
+testparse t0390.cc
+testparse t0391.cc
+testparse t0392.cc
+testparse t0393.cc
+testparse t0394.cc
+testparse t0395.cc
+testparse t0396.cc
+testparse t0397.cc
+testparse t0398.cc
+testparse t0399.cc
+testparse t0400.cc
+testparse t0401.cc
+testparse t0402.cc
+testparse t0403.cc
+testparse t0404.cc
+testparse t0405.cc
+testparse t0406.cc
+testparse t0407.cc
+testparse t0408.cc
+testparse t0409.cc
+testparse t0410.cc
+testparse t0411.cc
+testparse t0412.cc
+testparse t0413.cc
+testparse t0414.cc
+testparse t0415.cc
+testparse t0416.cc
+failparse t0417.cc "invalid template declarations are not rejected"
+testparse t0418.cc
+testparse t0419.cc
+testparse t0420.cc
+testparse t0421.cc
+testparse t0422a.cc
+testparse t0422.cc
+testparse t0423.cc
+testparse t0424.cc
+testparse t0425.cc
+testparse t0426.cc
+testparse t0427.cc
+testparse t0428.cc
+testparse t0429.cc
+testparse t0430.cc
+testparse t0431.cc
+testparse t0432.cc
+testparse t0433.cc
+testparse t0434.cc
+failparse t0435.cc "need for ArrayType with dependent size"
+failparse t0436.cc "pointer-to-member names processed in wrong order"
+testparse t0437.cc
+testparse t0438a.cc
+testparse t0438.cc
+failparse t0439.cc "default args in explicit spec"
+failparse t0440.cc "default args in explicit spec + DQTs"
+testparse t0441a.cc
+testparse t0441.cc
+testparse t0442.cc
+testparse t0443.cc
+testparse t0444.cc
+testparse t0445.cc
+testparse t0446.cc
+testparse t0447.cc
+testparse t0448.cc
+testparse t0449.cc
+testparse t0450.cc
+testparse t0451.cc
+testparse t0452.cc
+testparse t0453.cc
+testparse t0454.cc
+testparse t0455.cc
+testparse t0456.cc
+testparse t0457.cc
+testparse t0458.cc
+testparse t0459.cc
+testparse t0460.cc
+testparse t0461.cc
+testparse t0462.cc
+testparse t0463.cc
+failparse t0464.cc "ambiguous ExpressionList not disambiguated"
+failparse t0465.cc "ambiguous TemplateParameter, problem disambiguation declarations"
+failparse t0466.cc "ambiguous declaration"
+testparse t0467.cc
+testparse t0468.cc
+testparse t0469.cc
+testparse t0470.cc
+testparse t0471.cc
+failparse t0472.cc "failure to reject invalid code: friend name injection"
+testparse t0473.cc
+testparse t0474.cc
+testparse t0475.cc
+testparse t0476.cc
+testparse t0477.cc
+testparse t0478.cc
+testparse t0479.cc
+testparse t0480.cc
+testparse t0481.cc
+testparse t0482.cc
+testparse t0483.cc
+testparse t0484.cc
+testparse t0485.cc
+testparse t0486.cc
+testparse t0487.cc
+testparse t0487b.cc
+testparse t0488.cc
+testparse t0489.cc
+testparse t0490.cc
+testparse t0491.cc
+testparse t0492.cc
+testparse t0493.cc
+testparse t0494.cc
+testparse t0495.cc
+testparse t0496.cc
+testparse t0497.cc
+testparse t0498.cc
+testparse t0499.cc
+failparse t0500.cc "template template parameter"
+testparse t0501.cc
+testparse t0502.cc
+testparse t0503.cc
+testparse t0504.cc
+testparse t0505.cc
+testparse t0506.cc
+testparse t0507.cc
+testparse t0508.cc
+failparse t0509.cc "const-eval'able variable is actually reference templ arg"
+testparse t0510.cc
+testparse t0511.cc
+testparse t0512.cc
+testparse t0513.cc
+testparse t0514.cc
+testparse t0515.cc
+testparse t0516.cc
+testparse t0517.cc
+# t0518 through t0521 are tested below, outside the lots-of-tests section
+testparse t0522.cc
+testparse t0523.cc
+testparse t0524.cc
+testparse t0525.cc
+testparse t0526.cc
+testparse t0527.cc
+testparse t0528.cc
+testparse t0529.cc
+testparse t0530.cc
+testparse t0531.cc
+testparse t0532.cc
+testparse t0533.cc
+testparse t0534.cc
+testparse t0535.cc
+testparse t0536.cc
+testparse t0537.cc
+testparse t0538.cc
+# t0539 is more complicated, and is handled below
+testparse t0540.cc
+testparse t0541.cc
+testparse t0542.cc
+testparse t0543.cc
+testparse t0544.cc
+testparse t0545.cc
+testparse t0546.cc
+testparse t0547.cc
+testparse t0548.cc
+testparse t0549.cc
+testparse t0550.cc
+testparse t0551.cc
+testparse t0552.cc
+testparse t0553.cc
+failparse t0554.cc "instantiation of static data template members not implemented"
+testparse_special ansi t0555.cc
+failparse t0556.cc "problem parsing elaborated type of static data member template"
+testparse t0557.cc
+testparse t0558.cc
+testparse t0559.cc
+testparse t0560.cc
+testparse t0561.cc
+testparse t0562.cc
+testparse t0563.cc
+testparse t0564.cc
+failparse t0565.cc "unhandled MemberDeclaration ambiguity"
+testparse t0566.cc
+testparse t0567.cc
+testparse t0568.cc
+testparse t0569.cc
+testparse t0570.cc
+testparse t0571.cc
+testparse t0572.cc
+testparse t0573.cc
+testparse t0574.cc
+testparse t0575.cc
+testparse t0576.cc
+failparse t0577.cc "flawed abstract enumerator value processing"
+# t0578.cc is arguably valid code, but nobody can handle it
+failparse t0579.cc "tricky rules about enumerator types"
+failparse t0580.cc "use of enumerator in template-id for explicit specializiation"
+failparse t0581.cc "simpler dependent array bound problem"
+failparse t0582.cc "template array bound problem leads to crash"
+testparse t0583.cc
+testparse t0584.cc
+failparse t0585.cc "explicit invocation of dtor of template class"
+testparse t0586.cc
+failparse t0587.cc "conversion of static method of template to func ptr"
+testparse t0588.cc
+testparse t0589.cc
+testparse t0590.cc
+testparse t0591.cc
+
+# another set of tests, generally isolated by Daniel
+testparse d0001.cc
+testparse d0002.cc
+testparse d0003.cc
+testparse d0004.cc
+testparse d0005.cc
+testparse d0006.cc
+testparse d0007.cc
+testparse d0008.cc
+testparse d0009.cc
+testparse d0010.cc
+testparse d0011.cc
+testparse d0012.cc
+testparse d0013.cc
+testparse d0014.cc
+testparse d0015.cc
+testparse d0016.cc
+testparse d0017.cc
+testparse d0018.cc
+testparse d0019.cc
+testparse d0020.cc
+testparse d0021.cc
+testparse d0022.cc
+testparse d0023.cc
+testparse d0024.cc
+testparse d0025.cc
+testparse d0026.cc
+testparse d0027.cc
+testparse d0028.cc
+testparse d0029.cc
+# break
+testparse d0032.cc
+# break
+testparse d0034.cc
+testparse d0035.cc
+testparse d0036.cc
+testparse d0037.cc
+testparse d0038.cc
+testparse d0039.cc
+# d0040.cc and d0041.cc are illegal C++
+# d0042.cc through d0045.cc were less cleaned up versions of d0046.cc
+testparse d0046.cc
+testparse d0046elab.cc
+testparse d0047.cc
+testparse d0048.cc
+testparse d0048elab.cc
+testparse d0049.cc
+testparse d0050.cc
+testparse d0050elab.cc
+testparse d0051.cc
+testparse d0051elab.cc
+testparse d0052.cc
+testparse d0053.cc
+testparse d0054.cc
+testparse d0055.cc
+testparse d0056.cc
+testparse d0057.cc
+testparse d0058.cc
+testparse d0059.cc
+testparse d0060.cc
+testparse d0061.cc
+# these aren't valid C++, no point in testing
+#failparse d0062.cc "during type matching, recursion depth exceeded the limit"
+#failparse d0063.cc "during type matching, recursion depth exceeded the limit"
+testparse d0064.cc
+testparse d0065.cc
+testparse d0066.cc
+testparse d0067.cc
+testparse d0068.cc
+testparse d0069.cc
+testparse d0070.cc
+testparse d0071.cc
+testparse d0072.cc
+testparse d0073.cc
+testparse d0074.cc
+testparse d0075.cc
+testparse d0079.cc
+testparse d0080.cc # "inheriting from dependent qualified type"
+testparse d0084.cc
+
+# tests a rule enforced only in ANSI mode
+runTest perl ./multitest.pl ./ccparse -tr ansi in/d0087.cc
+
+testparse d0088.cc
+testparse d0089.cc
+testparse d0090.cc
+testparse d0091.cc
+testparse d0097.cc
+testparse d0098.cc
+testparse d0099.cc
+testparse d0100.cc
+testparse d0101.cc
+testparse d0102.cc
+testparse d0103.cc
+testparse d0104.cc
+testparse d0105.cc
+testparse d0106.cc
+testparse d0107.cc
+testparse d0108.cc
+testparse d0109.cc # "duplicate 'using' declaration"
+testparse d0110.cc # "class specialization without 'template' prefix?"
+testparse d0111.cc
+testparse d0112.cc # "gcc-2 bug"
+testparse d0113.cc
+testparse d0114.cc
+# sm: this is invalid input
+#failparse d0115.cc "gcc-2 bug: cannot find standard namespace"
+testparse d0116.cc
+testparse d0117.cc
+testparse d0118.cc
+testparse d0119.cc
+testparse d0120.cc
+testparse_special ansi d0121.cc
+# sm: this is invalid C++
+#failparse d0123.cc "from the kernel; works in C mode but in C++ mode can't convert void* to function pointer"
+testparse d0124.cc
+testparse d0125.cc # __builtin_va_copy
+testparse d0126.cc
+testparse_special treeCheck dk0127.cc #"a non-tree AST results: default param arg in template class inner class"
+
+# if the elaborateImplicitConversionArgToParam() check is turned on
+# for declarator initializers have to screen out types that
+# containsGeneralizedDependent()
+testparse d0128.cc
+
+# The implicit conversion of 0 to Foo(0) was not happennig in '?:'
+# expressions: "? Foo() : 0"
+testparse d0129.cc
+
+testparse k0001.cc #"left side of .* must be a class or reference to a class"
+testparse k0002.cc #"template function declared in another class (as a friend)"
+testparse k0003.cc #"template argument from static const member of template class"
+testparse k0004.cc #"non-typename template argument"
+testparse k0005.cc #"declaring a constructor with class name"
+testparse k0005a.cc #"declaring variables and member functions with class name"
+testparse k0006.cc #"error: E_alignofType is not constEval'able"
+testparse k0007.cc
+# renamed k0008.cc to gnu/g0022.cc because it is a GNU feature
+testparse k0009.cc #"clash between function and instantiated template parameter member"
+testparse_special only_works_on_32bit k0010.cc
+# quarl 2006-11-13
+#     k0010a.cc commented out for now since it passes on 64bit but fails on
+#     32bit; is the meaning of "only_works_on_32bit" inverted?
+#failparse_special only_works_on_32bit k0010a.cc "compile-time type size checking - long long"
+testparse k0011.cc
+testparse k0012.cc
+testparse k0013.cc #"cannot convert argument type `float (*)[4]' to parameter 1 type `float const (*)[4]'"
+testparse k0014.cc #"ambiguous lookup of base class constructor with constructor of same class with different template argument"
+testparse k0015.cc #"catch namespace_qualified::class_name"
+testparse k0016.cc #"explicit instantiation of template member function"
+testparse k0017.cc #"using namespace std' before 'namespace std"
+testparse k0018.cc #"member function taking an array argument with default value __null"
+testparse k0019.cc #"template parameters named for ctor/dtor"
+testparse k0020.cc #"deleting pointers of template-type"
+testparse k0021.cc #"calling a templated function pointer"
+testparse k0022.cc #"explicit instantiation of template loses original template parameter names"
+testparse k0023.cc #"typedef pointer to member function in template"
+testparse k0024.cc #"overloaded function resolution in an array"
+testparse k0025.cc #"fully-namespace-qualified base class initialization"
+testparse k0026.cc #"template argument default value from another template class"
+testparse k0027.cc #"reprSize of a sizeless array"
+
+# invalid
+#failparse k0028.cc "definition of member function declared in another namespace"
+
+testparse k0029.cc #'ambiguous overload "char* const*" vs "char const* const*"'
+testparse k0030.cc #'"and" and "or" keywords'
+testparse k0031.cc #"typedef used to declare a member function"
+testparse k0032.cc #"converting <integral>& to integral"
+testparse k0033.cc #"casting function pointer with throw() to/from no throw"
+
+# sm: invalid, strange gcc bug (not worth supporting, icc does not)
+#failparse k0034.cc "undefined instanceless unions repeating members"
+
+testparse k0035.cc #"ambiguous int+sizeof(struct{})"
+testparse k0036.cc #"taking the address of a string (?!)"
+testparse k0037.cc #"new array of pointers"
+testparse k0038.cc #"templatized struct as template parameter to function"
+testparse k0039.cc #"funky namespace resolution after 'using namespace'"
+testparse k0040.cc #"instantiating a template with unnamed template parameter"
+testparse k0041.cc #"inner struct defined inline in an inner struct not defined inline"
+testparse k0042.cc #"computed array size expression as an assignment"
+testparse k0043.cc #"voiding the result of a member call"
+
+# sm: this is not valid C++; perhaps we should keep a separate
+# set of tests of "legacy" C++ that worked in older gcc, just
+# in case we decide to support it at some point?
+#failparse k0044.cc "template super class member variable"
+
+testparse k0045.cc #"'operator delete' redeclared without throw()"
+testparse k0046.cc #"anonymous inline struct fields"
+testparse k0046a.cc #"anonymous struct fields in a union"
+testparse_special ansi k0046b.cc
+testparse k0047.cc #"template<T> operator T*"
+testparse k0048.cc #"re-declaration of template base-class member"
+testparse k0049.cc #"'restrict' as name"
+testparse k0050.cc #"definition of a function without 'const' on a basic type"
+testparse k0051.cc #"defining static-member array without array size"
+testparse k0052.cc #"operator& returning other pointer type"
+testparse k0053.cc #"calling a function with a pointer to an undefined template class"
+testparse k0054.cc #"constructor member initialization without namespace qualifier"
+
+# original was invalid; I have inverted the test's sense
+testparse k0055.cc #"using 'class' instead of 'typename' for template-class typedefs"
+
+testparse k0056.cc #"template friend function"
+testparse k0057.cc #"template friend function (2)"
+testparse k0058.cc #"converting to types from parameter templates"
+failparse k0059.cc "implicit type conversion in operator delete"
+failparse k0060.cc "disambiguated from multiple base class subobjects"
+failparse k0061.cc "multiple base classes instantiated from the same template class"
+# quarl 2006-05-28 k0062.cc passes on my machine, but not on Scott's ?!
+#failparse k0062.cc "template class with subclass whose member function with default argument is defined outside class"
+testparse k0063.cc #"class friend main"
+failparse k0064.cc "functions overloaded by number of template parameters"
+testparse k0065.cc "using incomplete class as default template argument"
+failparse k0066.cc "nested template class"
+failparse k0067.cc "constructor using volatile reference"
+failparse k0068.cc "explicitly named constructor"
+failparse k0008.cc "template parameterized by function pointer"
+failparse k0069.cc "friend class as template parameter"
+testparse k0070.cc #"scoping via template instantiation with all parameters defaulted"
+failparse k0071.cc "compound initializer for struct which was earlier forward-declared as class"
+failparse k0072.cc "template <class T> void foo(S1<T> s1, const typename T::T2 t2) {}"
+failparse k0073.cc "compound initializer for instantiated template struct"
+failparse k0074.cc "template unions"
+failparse k0075.cc "overloaded function involving function pointer in presence of template"
+failparse k0076.cc "attribute unused on struct parameter"
+failparse k0077.cc "template constructor instantiated using function type"
+failparse k0078.cc "array of function pointers initialized with template functions"
+failparse k0078a.cc "array of function pointers initialized with template functions (single item)"
+failparse k0079.cc "reference to reference used in inner class of template class"
+failparse k0080.cc "already implicitly instantiated"
+failparse k0081.cc "template instantiated through inferred type instantiating another template with default parameter depending on first template parameter"
+failparse k0082.cc "const register function parameter"
+failparse k0083.cc "friend template class declaration"
+failparse k0084.cc "complex literals"
+failparse k0085.cc "complex double * int"
+failparse k0086.cc "enable_if: template argument expressions"
+failparse k0087.cc 'implicit conversion to "bool const &" via "bool" via "operator bool"'
+testparse k0088.cc #"inferring const member function template parameter type"
+failparse k0089.cc "specialization of template function member"
+failparse k0090.cc "template specialization of array"
+failparse k0090a.cc "template specialization of array"
+failparse k0091.cc "template specialization with all default parameters"
+failparse k0092.cc "template-parameter-instantiated template class without 'typename' in constructor initializer"
+failparse k0093.cc "tertiary operator implicitly casting one pointer operand to bool"
+# This is a warning now instead of an error:
+#testparse k0094.cc #declared non-static, cannot re-declare as static
+failparse k0095.cc "templatized enum parameter"
+testparse k0096.cc "statement expression returning struct"
+testparse k0097.cc "function pointer template"
+failparse k0098.cc "ambiguous operator cast"
+failparse k0099.cc "partial specialization lookup"
+failparse k0100.cc "templatized template parameter list"
+testparse k0101.cc "typename ParameterDeclaration in TemplateParameterList"
+failparse k0102.cc "template parameter template-instantiated on another template parameter"
+testparse k0103.cc #"'duplicate definition' from 'using' declaration"
+testparse k0104.cc #"restrict reference"
+failparse k0105.cc "function pointer dependent type"
+failparse k0106.cc "anonymous struct in anonymous union"
+failparse k0107.cc "inline explicit instantiation"
+failparse k0108.cc "explicit instantiation of constructor"
+failparse k0109.cc "instantiating template member function"
+failparse k0110.cc "calling template dtor with template arguments"
+failparse k0111.cc "duplicate template specialization/definition of static data"
+testparse k0112.cc #"template instantiation with all default args"
+failparse k0113.cc "calling templatized operator-overloaded function"
+failparse k0114.cc "template parameterized on function (not function pointer)"
+failparse k0115.cc "using own member function"
+failparse k0116.cc "template parameter default instantiating template class"
+failparse k0117.cc "class templatized on int, copy constructor"
+testparse k0118.cc "typedef struct { } *foo"
+testparse k0119.cc "64-bit stuff"
+failparse k0120.cc "confusion between function template decl and return type"
+
+### </quarl-testcases-c++>
+
+failparse u0001.cc "template array size"
+
+# Simon sfg at cs
+testparse sg0001.cc # invoke dtor on const object
+
+# ---- END: lots of tests ----
+
+# this hacky variation of t0151.cc *does* work
+runTest perl ./multitest.pl ./five-errors in/t0151.cc
+
+# test some specialized error handling
+testparse_special expect_xfailure      t0518.cc
+testparse_special expect_confused_bail t0519.cc
+testparse_special expect_xfailure      t0520.cc
+testparse_special expect_confused_bail t0521.cc
+
+# test permissive-mode error diagnosis
+testparse_special permissive gnu/bugs/gb0005.cc
+testparse_special permissive gnu/bugs/gb0006.cc
+
+# t0539 has many variants; build them, then run them
+${MAKE:-make} -C in t0539 || exit
+testparse t0539_1.cc
+testparse t0539_2.cc
+testparse t0539_3.cc
+testparse t0539_4.cc
+testparse t0539_5.cc
+testparse t0539_6.cc
+testparse t0539_7.cc
+testparse t0539_8.cc
+testparse t0539_9.cc
+testparse t0539_10.cc
+testparse t0539_11.cc
+
+
+# examples from C++ standard
+#
+# a few examples have parts commented-out:
+#   7.3.3c.cc: nerfed because member templates aren't implemented
+#   7.3.3f.cc: "int i; int i;" is supposed to be allowed
+#   7.3.3k.cc: I don't detect a purported ambiguity
+#   7.3.4e.cc: major design flaw: cannot return sets from lookup functions
+#   (plus more from before I started maintaining this list ...)
+rm -f in/std/*.error*.cc
+for fn in in/std/*.cc; do
+  runTest perl ./multitest.pl ./ccparse -tr ansi "$fn"
+done
+
+# for the benefit of gcov
+runTest ./ccparse -tr printHierarchies,ansi in/std/3.4.5.cc
+
+# more in another (private) repository, if present
+if [ -f ../cppstdex/regrtest_inner ]; then
+  source ../cppstdex/regrtest_inner
+fi
+
+# is the gnu extension built?
+use_gnu=false
+if egrep "USE_GNU: +1" config.summary >/dev/null; then
+  use_gnu=true
+  echo "gnu extensions are enabled"
+else
+  echo "gnu extensions are not enabled"
+fi
+
+if $use_gnu; then
+  # test gnu extensions
+  testparse gnu/g0001.cc
+  testparse gnu/g0002.cc
+  testparse gnu/g0003.cc
+  testparse gnu/g0004.cc
+  testparse gnu/g0005.cc
+  testparse gnu/g0006.cc
+  testparse gnu/g0007.cc
+  testparse gnu/g0008.cc
+  # g0009.c is a C test
+  testparse gnu/g0010.cc
+  testparse gnu/g0011.cc
+  testparse gnu/g0012.cc
+  testparse gnu/g0013.cc
+  testparse gnu/g0014.cc
+  testparse gnu/g0015.cc
+  # g0016.cc is documentation, not a test
+  testparse gnu/g0017.cc
+  testparse gnu/g0018.cc
+  testparse gnu/g0019.cc
+  # g0020.cc is documentation
+  testparse gnu/g0021.cc
+  testparse gnu/g0022.cc #"addresses of labels and computed goto"
+  testparse gnu/g0023.cc
+  testparse gnu/g0024.cc
+  testparse gnu/g0025.cc
+  testparse gnu/g0026.cc
+  testparse gnu/g0027.cc
+  testparse gnu/g0028.cc
+  testparse gnu/g0029.cc
+  testparse gnu/g0030.cc
+  testparse gnu/g0031.cc
+  testparse gnu/g0032.cc
+  failparse gnu/g0033.cc "wrong typeof(array[]) semantics"
+
+  testparse gnu/t0124.cc
+  testparse gnu/t0125.cc
+  testparse gnu/t0127.cc
+  testparse gnu/t0128.cc
+  testparse gnu/t0129.cc
+  testparse gnu/t0130.cc
+  testparse gnu/t0131.cc
+  testparse gnu/t0132.cc
+
+  testparse gnu/d0076.cc
+  testparse gnu/d0078.cc
+  testparse gnu/d0081.cc
+  testparse gnu/d0082.cc
+  testparse gnu/d0085.cc
+  testparse gnu/d0086.cc
+  testparse gnu/d0089.cc
+  testparse gnu/d0092.cc
+  testparse gnu/d0093.cc
+  testparse gnu/d0094.cc
+
+  testparse gnu/bugs/gb0008.cc
+  testparse gnu/bugs/gb0009.cc
+  # gnu/bugs/gb0010.cc not supported
+  testparse gnu/bugs/gb0011.cc
+  testparse gnu/bugs/gb0012.cc
+
+  # test c99 extensions
+  for fn in in/c99/*.c; do
+    runTest ./ccparse -tr c_lang "$fn"
+  done
+
+  testparse gnu/k0001.cc #"({...}) cannot be empty"
+  testparse gnu/k0002.cc #"__builtin_va_*"
+  testparse gnu/k0003.cc #"gcc 3.4 __builtin_* math functions"
+  testparse gnu/k0004.cc #"operator <?"
+  testparse gnu/k0005.cc #"comparing long long to enum value"
+  testparse gnu/k0006.cc #"__offsetof__"
+  testparse gnu/k0006a.cc #"__builtin_offsetof"
+  failparse gnu/k0007.cc "__builtin_frame_address"
+  failparse gnu/k0008.c "declared extern inline, defined extern inline, defined non-extern-inline"
+  failparse gnu/k0009.cc "namespace attribute strong"
+  failparse gnu/k0010.c "nested K&R function"
+  testparse gnu/d0130.cc #"attributes on ctors and dtors"
+
+else # tests that only pass when not in gnu mode
+  testparse t0228b.cc
+
+fi   # end of 'if $use_gnu; then'
+
+# idempotency checks; known problems:
+#   27, 28: Templates not being printed correctly when the template
+#           arguments are used within the template.
+#   30: scope not printing.
+#   34: template arguments to a class, such as "A<T>", get printed as
+#       "template <class T> class A" instead
+#   35, 36: template <class ...> gets dropped
+#   t0033, t0105: trivial whitespace error prob due to elaboration modifying the ast
+# note that the 'sed' command includes a literal tab character..
+
+# template modifications broke pretty printing having to do with
+# templates
+#   26: "template<...>" prefix to function not printing, I think
+# UPDATE: seems to work now except that the instantiated function gets
+# printed which is not idempotent
+
+list=`echo "
+    t0001.cc
+    t0002.cc
+    t0003.cc
+    t0004.cc
+    t0005.cc
+    t0006.cc
+    t0007.cc
+    t0008.cc
+    t0009.cc
+    t0010.cc
+    t0011.cc
+    t0012.cc
+    t0013.cc
+    t0014.cc
+    t0014a.cc
+    t0015.cc
+    t0016.cc
+    t0017.cc
+    t0018.cc
+    t0019.cc
+    t0020.cc
+    t0021.cc
+    t0022.cc
+    t0023.cc
+    t0024.cc
+    t0025.cc
+    t0026.cc
+    t0027.cc
+    t0028.cc
+    t0029.cc
+    t0030.cc
+    t0030a.cc
+    t0030b.cc
+    t0031.cc
+    t0032.cc
+    t0033.cc
+    t0034.cc
+    t0035.cc
+    t0036.cc
+    t0037.cc
+    t0038.cc
+    t0039.cc
+    t0040.cc
+    t0041.cc
+    t0042.cc
+    t0043.cc
+    t0056.cc
+    t0093.cc
+    t0097.cc
+    t0100.cc
+    t0101.cc
+    t0102.cc
+    t0103.cc
+    t0106.cc
+    t0123.cc
+    k0121.cc
+    d0125.cc
+  " | xargs -n 1 | sed 's|^|in/|'`
+
+runTest perl ./idemcheck -d outdir $list
+
+# 2005-08-11: nerfed the GNU idemchecks.  They are failing now that I
+# have implemented the aggregate-type restriction for initializers,
+# and there's no easy solution.
+
+
+# test the parser in C mode
+testCparse() {
+  runTest perl ./multitest.pl ./ccparse -tr c_lang in/$1
+}
+testCparse_special() {
+  runTest perl ./multitest.pl ./ccparse -tr c_lang,$1 in/$2
+}
+failCparse() {
+  if [ "$2" = "" ]; then
+    echo "failparse $1: failparse takes two arguments"
+    exit 4
+  fi
+  failTest "$2" perl ./multitest.pl ./ccparse -tr c_lang in/$1
+}
+testCparse c/t0001.c
+testCparse c/t0002.c
+testCparse c/t0003.c
+testCparse c/t0004.c
+testCparse c/t0005.c
+testCparse c/t0006.c
+testCparse c/t0007.c
+testCparse c/t0008.c
+testCparse c/t0009.c
+testCparse c/t0010.c
+testCparse c/t0011.c
+testCparse c/t0012.c
+testCparse c/t0013.c
+testCparse c/t0014.c
+testCparse c/t0015.c
+testCparse c/t0016.c
+testCparse c/t0017.c
+testCparse c/t0018.c
+testCparse c/t0019.c
+
+# for gcov
+runTest perl ./multitest.pl ./ccparse -tr ansi_c99 in/c/t0020.c
+runTest perl ./multitest.pl ./ccparse -tr ansi_c,warnings in/c/t0021.c
+
+testCparse c/t0022.c
+failCparse c/t0023.c "unhandled KandRSimpleDeclaration ambiguity"
+testCparse c/t0024.c
+testCparse c/t0025.c
+testCparse c/t0026.c
+testCparse c/t0027.c
+
+testCparse gnu/d0096.c
+testCparse c/dC0010.c #"f(u8 register) doesn't parse"
+testCparse c/dC0011.c #"((size_t) &((struct scsi_cmnd *)0)->q) doesn't const eval"
+testCparse c/dC0012.c
+testCparse c/dC0013.c #"in C, a member with the same name as a type doesn't shadow the type"
+testCparse c/dC0017.c
+testCparse gnu/d0122.c
+testCparse c/d0124b.c
+
+# dsw: fix these
+testCparse c/dC0018.c # const-eval ambiguous expr
+testCparse c/dC0019.c # define a type in a 'sizeof' expression
+testCparse c/dC0020.c # define a type in a cast
+testCparse c/dC0021.c # C99 dynamic parameter array
+
+# dsw: perhaps we should change the implementation of reprSize()
+testCparse c/dC0022.c # sizeof dynamically-sized multidimensional array
+
+testCparse c/dC0023.c # "in gcc, in C mode, a foo and a struct foo are unrelated"
+
+# this is invalid code
+#
+# 2005-08-04: but if people keep feeding me this bug, I guess I will
+# shut up and accept it
+testCparse c/dC0024.c # "bizarreness with redundant and useless typedefs"
+
+testCparse c/dC0025.c # no-info-prototype of main(), then defn
+testCparse c/dC0026.c # implicit int in K&R decl
+testCparse_special gnu_c89 c/dC0027.c # "restrict in non-keyword role"
+testCparse c/dC0028.c # compound lit in ambiguous context
+testCparse_special gnu_c89 c/dC0029.c # "restrict in non-keyword role"
+
+testCparse gnu/dC0017.c # "__alignof__ arguments can be full expressions ??"
+testCparse c/dC0030.c # "template disambiguation code??"
+testCparse c/dC0031.c # "can't const-eval size of type that is an array with a dynamic size"
+testCparse c/dC0032.c # "open arrays not handled right"
+
+testparse_special ansi_c c/k0001.c #"typedef int fooint; typedef fooint long;"
+testCparse c/k0002.c #"attempt to create an object of incomplete class `S'"
+testCparse c/k0003.c #"old-style function decl with parentheses around func name"
+testCparse c/k0003a.c #"old-style function decl with parentheses around func name, returning a struct-typedef"
+testCparse c/k0004.c #'"merge nonterm MemberDeclaration"
+testCparse c/k0005.c #"multiply defined enum 'option'"
+testCparse c/k0006.c #"static inline function implicitly returning int"
+testCparse c/k0006a.c #"static inline function implicitly returning int, old-style param decl"
+testCparse c/k0011.c #"ambiguous s->z < 1 || 2 > (3)"
+testCparse c/k0007.c #"duplicate modifiers in C as warning, not error (?)"
+testCparse c/k0008.c #"function call vs type-cast ambiguity"
+testCparse c/k0009.c #"func returning array of function pointers with old-style parm list"
+testCparse c/k0010.c #"'and' keyword"
+testCparse c/k0012.c #return struct by value
+testCparse c/k0013.c #"enum variable declared earlier as int"
+testCparse c/k0014.c #"offsetof cannot be assumed to be 0 (evaluated e.g. in case labels)"
+testCparse c/k0015.c #"variable-sized character buffer in function-local struct using same name for size as a member variable and another variable in outside scope"
+testCparse c/k0016.c #"expression in compound initializer array index"
+failCparse c/k0017.c "E_fieldAcc is not constEval'able"
+
+### </quarl-testcases-c>
+
+# is K&R built?
+use_kandr=false
+if egrep "USE_KANDR: +1" config.summary >/dev/null; then
+  use_kandr=true
+  echo "K&R extensions are enabled"
+else
+  echo "K&R extensions are not enabled"
+fi
+
+if $use_kandr; then
+  # test the parser in C + K&R mode
+  testKANDRparse() {
+    runTest perl ./multitest.pl ./ccparse -tr gnu_kandr_c_lang in/$1
+  }
+  testKANDRparse kandr/t0001.c
+  testKANDRparse kandr/t0002.c
+  testKANDRparse kandr/t0003.c
+  testKANDRparse kandr/t0004.c
+fi
+
+
+# test GNU C
+if $use_gnu; then
+  testCparse gnu/g0009.c
+  testCparse gnu/d0083.c
+  testCparse gnu/t0126.c
+  testCparse gnu/d0095.c
+  testCparse gnu/c0001.c
+  testCparse gnu/c0002.c
+
+  testCparse gnu/dC0001.c # hex floating-point literals
+  testCparse gnu/dC0002.c # arrays of no length are assumed to have one element
+  testCparse gnu/dC0003.c # noInnerClasses: use a struct then define it but inside another
+  testCparse gnu/dC0004.c # can take address of const E_compoundLit
+  testCparse gnu/dC0005.c # extern inline functions
+  testCparse gnu/dC0006.c # more places where 0-length arrays are allowed
+  testCparse gnu/dC0007.c # case 1 ... 3:
+  testCparse gnu/dC0008.c # int a[] = { [1] 0 }; struct A a = { .x 8 };
+  testCparse gnu/dC0009.c # UCHAR8 SampleResolution:2 __attribute__ ((packed));
+  testCparse gnu/dC0014.c # "'u32 long off' doesn't parse"
+  testCparse gnu/dC0015.c # function scope structs can contain arrays of dynamic size
+  testCparse gnu/dC0016.c
+
+  # transparent unions
+  testCparse gnu/t0133.c
+  testCparse gnu/t0134.c
+
+  # These work, but for the wrong reason.  The transparent union attribute
+  # is dropped on the floor (bad) but then no argument checking is done
+  # so we don't notice the problem (double bad).  Oink would notice because
+  # the lack of normalization will cause problems.
+  testCparse gnu/t0135.c
+  testCparse gnu/t0136.c
+
+  # This is here just to document that Elsa does not diagnose something that
+  # gcc does.  However, it's so esoteric that I don't want to consider this
+  # even a "known bug" in Elsa, so it is commented out.
+  #failCparse gnu/t0137.c
+
+  # attribute tests
+  testCparse gnu/attr01.c
+  testCparse gnu/attr02.c
+  testCparse gnu/d0099.c
+
+  # asm tests
+  testCparse gnu/asm01.c
+
+  # gcc C-mode bugs
+  testCparse gnu/bugs/gb0001.c
+
+  # tests (primarily for __attribute__) from CIL
+  testcil() {
+    runTest ./ccparse -tr c_lang in/gnu/cil/$1
+  }
+  failcil() {
+    failTest "$2" ./ccparse -tr c_lang in/gnu/cil/$1
+  }
+
+  testcil align1.i
+  testcil align2.i
+  testcil attr2.i
+  testcil attr3.i
+  testcil attr4.i
+  testcil attr5.i
+  testcil attr6.i
+  testcil bind-zero.i
+  testcil combine_samefn_1.i
+
+  # I haven't researched the standard's opinion on this one, but
+  # I think it should be considered invalid input, because to do
+  # otherwise would be type-unsound!
+  failcil decl1.i "can add volatile later"
+
+  testcil enumattr.i
+  testcil globalprob.i
+  testcil init8.i
+  testcil invalredef.i
+  testcil mode_sizes.i
+  testcil regparm0.i
+  testcil rmtmps-attr.i
+  testcil rmtmps2.i
+  testcil sockaddr.i
+  testcil structattr.i
+  testcil structattr2.i
+  testcil structattr3.i
+  testcil transpunion.i
+  testcil typeof1.i #"ambiguous E_sizeofType"
+  testcil warnings-noreturn.i
+fi
+
+
+# msvc
+runTest ./ccparse -tr msvcBugs in/msvc/m0001.cc
+
+
+# final parser checks against the big files, since they've now become
+# my performance measurement files
+if $MAKE in/big; then
+
+testnsparse() {
+  runTest ./ccparse "$1"
+}
+failnsparse() {
+  failTest "$2" ./ccparse "$1"
+}
+
+if [ "$DISABLE_BIG_TESTS" = "" ]; then
+  # put shorter tests first
+  testnsparse in/big/nonport.i
+
+  testnsparse in/big/nsUnicodeToTeXCMRt1.i
+  testnsparse in/big/nsAtomTable.i
+  testnsparse in/big/nsSOAPPropertyBag.i
+  testnsparse in/big/nsCLiveconnectFactory.i
+  testnsparse in/big/nsHTMLEditRules.i
+  testnsparse in/big/nsMsgServiceProvider.i
+fi
+
+else
+  # Even though my in/big/gz/nsAtomTable.i.gz has the right md5sum,
+  # I can't convince gunzip to uncompress it under cygwin with text
+  # mounts (which it should be ignoring since it's getting the file
+  # contents via pipe, and ought to use O_BINARY anyway).
+  echo "Skipping large file tests because could not uncompress them."
+  echo "This may be due to a buggy cygwin gunzip."
+fi
+
+# final arithmetic to report result
+echo ""
+echo "use_gnu: $use_gnu"
+echo "use_kandr: $use_kandr"
+echo "Successful tests               :    $success"
+echo "Failed as expected (known bugs):    $failure"
+if [ $skipdiagnose -ne 0 ]; then
+  echo "Fail to diag. cppstdex errors  :    $skipdiagnose"
+fi
+if [ $contin = 1 ]; then
+  echo "Unexpected success:    $unexSuccess"
+  echo "Unexpected failure:    $unexFailure"
+  if [ -f "$logfile" ]; then
+    cat "$logfile"
+  fi
+fi
+
+
+######################################################################
+##
+## Top bugs affecting Debian packages
+##     See also:
+##       http://www.quarl.org/~quarl/debsec/output/status/elsa_1.errors
+##
+## 1. [k0105.cc] internal error: found dependent type `(dependent)' in non-template
+##   Seen 3466 times
+##   299 affected packages
+##   289 source packages
+##
+## 2. [k0059.cc] can only delete pointers, not `QGuardedPtr<class QPopupMenu /*anon*/>'
+##   Seen 149 times
+##   137 affected packages
+##   9 source packages
+##
+## 3. [k0075.cc] Assertion failed: argType != NULL && "52291632-1792-4e5c-b5b8-9e6240b75a91", file template.cc line 1346
+##   Seen 912 times
+##   70 affected packages
+##   32 source packages
+##
+## 4. [k0060.cc] field `KInetSocketAddress::d' ambiguously refers to elements of multiple base class subobjects
+##   Seen 69 times
+##   69 affected packages
+##   1 source packages
+##
+## 5. [k0064.cc] duplicate definition for `kRestoreMainWindows' of type `void ()()'; previous at [INPUT]
+##   Seen 1023 times
+##   59 affected packages
+##   55 source packages
+##
+## 6. [k0072.cc] Assertion failed: e != NULL && "ceae1527-94a7-480d-9134-5dbd8cbfb2aa", file cc.gr line 1240
+##   Seen 78 times
+##   16 affected packages
+##   5 source packages
+##
+## 7. [k0081.cc] could not evaluate default argument `iterator_traits<In /*anon*/>::value_type': attempt to extract member `value_type' from non-class `iterator_traits<In /*anon*/>'
+##   Seen 1101 times
+##   16 affected packages
+##   14 source packages
+##
+## 8. [k0086.cc] unimplemented: template.cc:4029: applyArgumentMap: dep-expr is not E_variable
+##   Seen 121 times
+##   15 affected packages
+##   16 source packages
+##
+## 9. [k0087.cc] no viable candidate for function call; arguments:
+##   Seen 153 times
+##   15 affected packages
+##   16 source packages
+##
+## 10. [gnu/k0006.cc] there is no function called `__offsetof__'
+##   Seen 364 times
+##   14 affected packages
+##   14 source packages
+##
+## 11. [k0100.cc] Assertion failed: unimplemented: templatized template parameter list (25eb7000-851c-4028-b762-4e365a5b10bf), file cc.gr line 2399
+##   Seen 402 times
+##   13 affected packages
+##   17 source packages
+##


Property changes on: vendor/elsa/current/elsa/regrtest
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/run-all3
===================================================================
--- vendor/elsa/current/elsa/run-all3	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/run-all3	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,24 @@
+#!/bin/sh
+# run elsa, gcc, icc
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 input.cc"
+  exit 0
+fi
+
+# grab extra arguments for elsa
+extra=""
+if [ "$1" = "-tr" ]; then
+  extra="-tr $2"
+  shift
+  shift
+fi
+
+echo "------------- icc -------------"
+./run-icc "$@"
+
+echo "------------- gcc -------------"
+./run-g++ "$@"
+
+echo "------------- elsa -------------"
+./ccparse $extra "$@"


Property changes on: vendor/elsa/current/elsa/run-all3
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/run-all3-multi
===================================================================
--- vendor/elsa/current/elsa/run-all3-multi	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/run-all3-multi	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+#!/bin/sh
+# run elsa, gcc, icc
+# 
+# each is run with multitest
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 input.cc"
+  exit 0
+fi
+
+# grab extra arguments for elsa
+extra=""
+if [ "$1" = "-tr" ]; then
+  extra="-tr $2"
+  shift
+  shift
+fi
+
+echo "------------- icc -------------"
+if ./multitest.pl ./run-icc "$@"; then
+  icc="ok"
+else
+  icc="fail"
+fi
+
+echo "------------- gcc -------------"
+if ./multitest.pl ./run-g++ "$@"; then
+  gcc="ok"
+else
+  gcc="fail"
+fi
+
+echo "------------- elsa -------------"
+if ./multitest.pl ./ccparse $extra "$@"; then
+  elsa="ok"
+else
+  elsa="fail"
+fi
+
+echo "icc: $icc  gcc: $gcc  elsa: $elsa"
+


Property changes on: vendor/elsa/current/elsa/run-all3-multi
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/run-delta-loop
===================================================================
--- vendor/elsa/current/elsa/run-delta-loop	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/run-delta-loop	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+#!/bin/sh
+# run delta in a loop to minimize tmp.i w.r.t. some message
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 message_regexp"
+  echo "  This minimizes tmp.i s.t. ccparse fails with an error"
+  echo "  that matches message_regexp"
+  exit 0
+fi
+
+export msg="$1"
+             
+delta=../delta/bin/multidelta
+if [ ! -x $delta ]; then
+  echo "error: can't run $delta"
+  exit 2
+fi
+
+$delta -level=0 ./test-for-error tmp.i || exit
+$delta -level=1 ./test-for-error tmp.i || exit
+
+$delta -level=0 ./test-for-error tmp.i || exit
+$delta -level=1 ./test-for-error tmp.i || exit
+$delta -level=2 ./test-for-error tmp.i || exit
+
+$delta -level=0 ./test-for-error tmp.i || exit
+$delta -level=1 ./test-for-error tmp.i || exit
+$delta -level=2 ./test-for-error tmp.i || exit
+$delta -level=3 ./test-for-error tmp.i || exit
+
+$delta -level=0 ./test-for-error tmp.i || exit
+$delta -level=1 ./test-for-error tmp.i || exit
+$delta -level=2 ./test-for-error tmp.i || exit
+$delta -level=3 ./test-for-error tmp.i || exit
+$delta -level=4 ./test-for-error tmp.i || exit
+
+$delta -level=0 ./test-for-error tmp.i || exit
+$delta -level=1 ./test-for-error tmp.i || exit
+$delta -level=2 ./test-for-error tmp.i || exit
+$delta -level=3 ./test-for-error tmp.i || exit
+$delta -level=4 ./test-for-error tmp.i || exit
+
+# note: sometimes this breaks the input by changing "> >" into ">>" ...
+# I don't know a good solution at this point, so I just fix them by
+# hand when it happens
+indent tmp.i || exit
+
+#$delta -nf ./test-for-error tmp.i || exit
+
+#indent tmp.i || exit


Property changes on: vendor/elsa/current/elsa/run-delta-loop
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/run-g++
===================================================================
--- vendor/elsa/current/elsa/run-g++	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/run-g++	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+#!/bin/sh
+# run g++ on an input to see if it accepts it
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 input.cc"
+  exit 0
+fi
+
+echo $HOME/opt/gcc-3.4.3/bin/g++ -o /dev/null -c -w -xc++ "$@"
+exec $HOME/opt/gcc-3.4.3/bin/g++ -o /dev/null -c -w -xc++ "$@"


Property changes on: vendor/elsa/current/elsa/run-g++
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/run-icc
===================================================================
--- vendor/elsa/current/elsa/run-icc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/run-icc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+#!/bin/sh
+# run icc on an input to see if it accepts it
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 input.cc"
+  exit 0
+fi
+
+echo source $HOME/opt/intel/bin/iccvars.sh
+source $HOME/opt/intel/bin/iccvars.sh
+
+echo $HOME/opt/intel/bin/icpc -o /dev/null -c -xc++ -w "$@"
+exec $HOME/opt/intel/bin/icpc -o /dev/null -c -xc++ -w "$@"


Property changes on: vendor/elsa/current/elsa/run-icc
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/semgrep.cc
===================================================================
--- vendor/elsa/current/elsa/semgrep.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/semgrep.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,170 @@
+// semgrep.cc
+// example Elsa application: semantic grep
+
+#include <iostream.h>     // cout
+#include <stdlib.h>       // exit, atoi
+
+#include "parssppt.h"     // ParseTreeAndTokens
+#include "srcloc.h"       // SourceLocManager
+#include "cc_env.h"       // Env
+#include "cc_ast.h"       // C++ AST (r)
+#include "cc_lang.h"      // CCLang
+#include "parsetables.h"  // ParseTables
+#include "cc.gr.gen.h"    // CCParse
+#include "strtokp.h"      // StrtokParse
+
+
+// ---------------------- GrepVisitor ------------------------
+class GrepVisitor : public ASTVisitor {
+public:      // data
+  // name of interest
+  string name;
+  int line;
+
+public:      // funcs
+  GrepVisitor(char const *n, int l)
+    : name(n),
+      line(l)
+  {}
+  virtual ~GrepVisitor() {}
+
+  bool matches(Variable *var);
+  void tryHit(Variable *var, SourceLoc refLoc, char const *use);
+
+  virtual bool visitExpression(Expression *obj);
+  virtual bool visitDeclarator(Declarator *obj);
+};
+
+
+bool GrepVisitor::matches(Variable *var)
+{
+  // compare line first for efficiency
+  return line == sourceLocManager->getLine(var->loc) &&
+         name.equals(var->name);
+}
+
+void GrepVisitor::tryHit(Variable *var, SourceLoc refLoc, char const *use)
+{
+  if (matches(var)) {
+    cout << toString(refLoc) << ": " << use << "\n";
+  }
+}
+
+
+bool GrepVisitor::visitExpression(Expression *obj)
+{
+  ASTSWITCH(Expression, obj) {
+    ASTCASE(E_variable, e) {
+      tryHit(e->var, e->name->loc, "use as variable");
+    }
+    ASTNEXT(E_fieldAcc, e) {
+      tryHit(e->field, e->fieldName->loc, "use as field");
+    }
+    ASTENDCASED
+  }
+
+  return true;
+}
+
+bool GrepVisitor::visitDeclarator(Declarator *obj)
+{
+  // would like to be able to tell if it's a definition ...
+  tryHit(obj->var, obj->decl->loc, "declaration");
+  return true;
+}
+
+
+// ---------------------- main -------------------------
+void doit(int argc, char **argv)
+{
+  xBase::logExceptions = false;
+
+  SourceLocManager mgr;
+  StringTable strTable;
+
+  // parsing language options
+  CCLang lang;
+  lang.GNU_Cplusplus();
+
+
+  // process command-line arguments
+  if (argc != 4) {
+    cout << "usage: " << argv[0] << " <name> <line> input.cc\n";
+    return;
+  }
+
+  GrepVisitor grepv(argv[1], atoi(argv[2]));
+  string inputFname = argv[3];
+
+  //cout << "grepping for " << grepv.name
+  //     << " on line " << grepv.line
+  //     << " in " << inputFname << "\n";
+
+  // parse+tcheck (TODO: make this more convenient)
+  TranslationUnit *unit;
+  {
+    SemanticValue treeTop;
+    ParseTreeAndTokens tree(lang, treeTop, strTable, inputFname.c_str());
+
+    // grab the lexer so we can check it for errors (damn this
+    // 'tree' thing is stupid..)
+    Lexer *lexer = dynamic_cast<Lexer*>(tree.lexer);
+    xassert(lexer);
+
+    CCParse *parseContext = new CCParse(strTable, lang);
+    tree.userAct = parseContext;
+
+    ParseTables *tables = parseContext->makeTables();
+    tree.tables = tables;
+
+    // parse
+    if (!toplevelParse(tree, inputFname.c_str())) {
+      exit(2); // parse error
+    }
+
+    // check for parse errors
+    if (parseContext->errors || lexer->errors) {
+      exit(2);
+    }
+
+    // treeTop is a TranslationUnit pointer
+    unit = (TranslationUnit*)treeTop;
+
+    delete parseContext;
+    delete tables;
+
+    // tcheck
+    BasicTypeFactory tfac;
+    ArrayStack<Variable*> madeUpVariables;
+    ArrayStack<Variable*> builtinVars;
+    Env env(strTable, lang, tfac, madeUpVariables, builtinVars, unit);
+    unit->tcheck(env);
+
+    int numErrors = env.errors.numErrors();
+    if (numErrors) {
+      env.errors.print(cerr);
+      cerr << numErrors << " errors\n";
+      exit(4);
+    }
+  }
+
+  // grep
+  unit->traverse(grepv);
+}
+
+int main(int argc, char **argv)
+{
+  try {
+    doit(argc, argv);
+  }
+  catch (xBase &x) {
+    HANDLER();
+    cout << x << endl;
+    abort();
+  }
+
+  return 0;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/serialno.cc
===================================================================
--- vendor/elsa/current/elsa/serialno.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/serialno.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,95 @@
+// serialno.cc
+// code for serialno.h
+
+#include "serialno.h"         // this module
+#include "trace.h"            // tracingSys
+#include "fstream.h"          // ifstream
+
+
+// -------------------- serial numbers ON --------------------
+#if USE_SERIAL_NUMBERS
+
+SerialBase::SerialBase()
+  : serialNumber(incSerialNumber())
+{}
+
+
+// I define this function so that even the copy ctor will get
+// and use a unique serial number
+SerialBase::SerialBase(SerialBase const &obj)
+  : serialNumber(incSerialNumber())
+{}
+
+
+SerialBase& SerialBase::operator= (SerialBase const &)
+{
+  // do *not* copy the serial number
+  return *this;
+}
+
+
+// FIX: given that I keep counting across multiple files now and given
+// that we will be analyizing huge inputs, it might help if this were
+// unsigned; then again, you couldn't catch a rollover
+int globalSerialNumber = 0;
+
+// initialize the global serial number; this is for multi-file
+// symmetry breaking
+class GlobalSerialNoInit {
+  char const * const filename;
+
+  public:
+  GlobalSerialNoInit(char const * const filename0)
+    : filename(filename0)
+  {
+    if (tracingSys("serialno-read")) {
+      try {
+        ifstream in(filename);
+        in >> globalSerialNumber;
+      } catch(...) {}
+    }
+    if (tracingSys("serialno-announce")) {
+      cout << "starting with globalSerialNumber " << globalSerialNumber << endl;
+    }
+  }
+
+  ~GlobalSerialNoInit() {
+    if (tracingSys("serialno-write")) {
+      ofstream out(filename);
+      out << globalSerialNumber << endl;
+    }
+    if (tracingSys("serialno-announce")) {
+      cout << "ending with globalSerialNumber " << globalSerialNumber << endl;
+    }
+  }
+};
+GlobalSerialNoInit gsnInit(".serialno"); // I need it to run at initialization time
+
+int incSerialNumber()
+{
+  // put the value into a local variable so that (at least when
+  // optimization is turned off) there is an easy name to use
+  // for conditional breakpoints
+  int sn = globalSerialNumber++;
+
+  // NOTE: put the breakpoint ABOVE the previous line, NOT HERE!
+  return sn;
+}
+
+void printSerialNo(stringBuilder &sb, char const *pre, int num, char const *post)
+{
+  if (tracingSys("serialNumbers")) {
+    sb << pre << num << post;
+  }
+}
+
+
+#endif // USE_SERIAL_NUMBERS
+
+
+
+// -------------------- serial numbers OFF --------------------
+// nothing..
+
+
+// EOF

Added: vendor/elsa/current/elsa/serialno.h
===================================================================
--- vendor/elsa/current/elsa/serialno.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/serialno.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,69 @@
+// serialno.h
+// object serial number
+
+// The idea here is that it's sometimes difficult during debugging to
+// keep track of the various objects (e.g. Types) floating around, and
+// virtual addresses are not so stable.  So, by turning on
+// USE_SERIAL_NUMBERS, every object will get a unique serial number,
+// and (some of) the print routines will print the number.  Normally
+// this should be off since it uses memory and makes the printouts
+// ugly.
+
+#ifndef SERIALNO_H
+#define SERIALNO_H
+
+#include "str.h"        // string
+
+// default to off; can turn on via "./configure -useSerialNumbers"
+#ifndef USE_SERIAL_NUMBERS
+  #define USE_SERIAL_NUMBERS 0
+#endif
+
+#ifdef USE_SERIAL_NUMBERS
+  #if USE_SERIAL_NUMBERS!=0 && USE_SERIAL_NUMBERS!=1
+    #error USE_SERIAL_NUMBERS defined but not 0 or 1
+  #endif
+#endif
+
+
+#if USE_SERIAL_NUMBERS
+
+  // base class for classes that want serial numbers to inherit
+  class SerialBase {
+  public:      // data
+    // unique across all objects
+    int serialNumber;
+
+  public:      // funcs
+    SerialBase();
+    SerialBase(SerialBase const &obj);
+    SerialBase& operator= (SerialBase const &obj);
+  };
+
+  #define INHERIT_SERIAL_BASE     : public SerialBase
+  #define INHERIT_SERIAL_BASE_AND : public SerialBase ,
+
+  // global counter, starts at 0
+  extern int globalSerialNumber;
+
+  // get the next serial number
+  int incSerialNumber();
+
+  // return a string with 'pre', then the number, then 'post'
+  //
+  // NOTE: Currently, the tracing flag "serialNumbers" must be set
+  // for the printouts to include the serial numbers.  (When it is
+  // not set, this function just returns "".)
+  void printSerialNo(stringBuilder &sb, char const *pre, int num, char const *post);
+
+#else // !USE_SERIAL_NUMBERS
+
+  // variations of above for use when serial numbers are disabled
+
+  #define INHERIT_SERIAL_BASE
+  #define INHERIT_SERIAL_BASE_AND :
+
+#endif // !USE_SERIAL_NUMBERS
+
+
+#endif // SERIALNO_H

Added: vendor/elsa/current/elsa/smin.cc
===================================================================
--- vendor/elsa/current/elsa/smin.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/smin.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,361 @@
+// smin.cc
+// structural minimizer
+
+#include "test.h"           // ARGS_MAIN
+#include "smin.h"           // this module
+#include "trace.h"          // TRACE_ARGS
+
+#include <stdlib.h>         // system
+#include <sys/types.h>      // ?
+#include <sys/wait.h>       // W* macros for interpreting exit status
+
+
+// ------------------ XCtrlC -------------------
+XCtrlC::XCtrlC()
+  : xBase("ctrl-c")
+{}
+
+XCtrlC::XCtrlC(XCtrlC const &obj)
+  : xBase(obj)
+{}
+
+XCtrlC::~XCtrlC()
+{}
+
+
+// ----------------- Minimizer -----------------
+Minimizer::Minimizer()
+  : sourceFname(),
+    testProg(),
+    source(10 /*hint*/),
+    tree(NULL),
+    results(),
+    passingTests(0),
+    failingTests(0),
+    cachedTests(0),
+    testInputSum(0)
+{}
+
+Minimizer::~Minimizer()
+{
+  if (tree) {
+    delete tree;
+  }
+}
+
+
+void setIrrelevant(IPTree &t, int offset)
+{
+  Node *n = t.query(offset);
+  if (n) {
+    n->rel = R_IRRELEVANT;
+  }
+}
+
+
+int system(rostring s)
+{
+  return system(toCStr(s));
+}
+
+
+VariantResult Minimizer::runTest()
+{
+  int code = system(stringc << testProg << " \'" << sourceFname << "\'");
+  if (WIFSIGNALED(code) && WTERMSIG(code) == SIGINT) {
+    XCtrlC x;
+    THROW(x);
+  }
+  
+  if (code == 0) {
+    cout << "p";
+    flush(cout);
+    passingTests++;
+    return VR_PASSED;
+  }
+  else {
+    cout << ".";
+    flush(cout);
+    failingTests++;
+    return VR_FAILED;
+  }
+}
+
+
+bool Minimizer::outerRunTest(int &size, Node *n, Relevance rel)
+{
+  // temporarily set n->rel
+  Relevance origRel = n->rel;
+  n->rel = rel;
+
+  VariantCursor cursor = write(size);
+  if (!cursor->data) {
+    // this variant has not already been tried, so test it
+    testInputSum += size;
+    try {
+      cursor->data = runTest();
+    }
+    catch (XCtrlC &) {
+      // restore the relevance guess
+      HANDLER();
+      n->rel = origRel;
+      throw;
+    }
+  }
+  else {
+    cout << "c";
+    flush(cout);
+    cachedTests++;
+  }
+
+  if (cursor->data == VR_PASSED) {
+    return true;
+  }
+  else {
+    xassert(cursor->data == VR_FAILED);
+
+    // 'n' seems to be relevant
+    n->rel = R_RELEVANT;
+
+    return false;
+  }
+}
+
+
+VariantCursor Minimizer::write(int &size)
+{
+  VariantCursor cursor = results.getTop();
+  size = tree->write(sourceFname, source, cursor);
+  return cursor;
+}
+
+
+void Minimizer::minimize()
+{
+  if (!tree->getTop()) {
+    return;
+  }
+
+  while (minimize(tree->getTop())) {
+    // keep going as long as progress is being made
+  }
+}
+
+
+bool Minimizer::minimize(Node *n)
+{
+  if (!n) {
+    // nothing to do
+    return false;
+  }
+
+  if (n->rel == R_IRRELEVANT_SIBS) {
+    // this node and siblings are already known to be irrelevant
+    return false;
+  }
+
+  if (n->rel == R_IRRELEVANT) {
+    // the node itself is irrelevant, but siblings are still in play
+    bool ret = false;
+    ret = minimize(n->right) || ret;
+    ret = minimize(n->left) || ret;
+    return ret;
+  }
+
+  Relevance origRel = n->rel;
+
+  // see if we can drop this node and its siblings
+  int size;
+  if (outerRunTest(size, n, R_IRRELEVANT_SIBS)) {
+    // we have made progress
+    cout << "\nred2: " << stringf("%10d", size) << " ";
+    flush(cout);
+    return true;
+  }
+
+  // for performance testing, would disable large-sections-first optimization
+  //origRel = R_RELEVANT;
+
+  if (origRel == R_UNKNOWN) {
+    // this is the first time this node has been tested, so do not
+    // test its children yet; instead wait for the next pass
+    //
+    // return 'true' to mean that we made progress in the sense of
+    // turning this node's 'rel' from R_UNKNOWN to R_RELEVANT, and
+    // consequently on the next pass we will investigate the
+    // children
+    return true;
+  }
+
+  // this node was tested at least once before, so now try dropping
+  // some of its children
+  xassert(origRel == R_RELEVANT);
+
+  // try children from right to left; here we are testing both
+  // siblings and subintervals, so as to leverage the existing tree
+  bool ret = false;
+  ret = minimize(n->right) || ret;
+
+  // try dropping my entire range, including the spaces outside
+  // any subintervals
+  if (outerRunTest(size, n, R_IRRELEVANT)) {
+    // we have made progress
+    cout << "\nred1: " << stringf("%10d", size) << " ";
+    flush(cout);
+    ret = true;
+  }
+  else {
+    // consider dropping subintervals
+    ret = minimize(n->subintervals) || ret;
+  }
+
+  ret = minimize(n->left) || ret;
+
+  return ret;
+}
+
+
+bool Minimizer::minimizeChildren(Node *sub)
+{
+  xfailure("not used right now");
+
+  bool ret = false;
+
+  // try minimizing later children first, with the idea that the
+  // static semantic dependencies are likely to go from later to
+  // earlier, hence we'd like to start dropping things at the
+  // end of the file first
+  if (sub->right) {
+    ret = minimizeChildren(sub->right) || ret;
+  }
+
+  // now try minimizing this child
+  ret = minimize(sub) || ret;
+
+  // and earlier children
+  if (sub->left) {
+    ret = minimizeChildren(sub->left) || ret;
+  }
+  
+  return ret;
+}
+
+
+void entry(int argc, char *argv[])
+{
+  xBase::logExceptions = false;
+  string progName = argv[0];
+  
+  TRACE_ARGS();
+
+  bool checktree = tracingSys("checktree");
+
+  if (checktree) {
+    if (argc != 3) {
+      cout << "usage: " << progName << " [options] foo.c foo.c.str\n";
+      return;
+    }
+  }
+  else {
+    if (argc != 4) {
+      cout << "usage: " << progName << " [options] foo.c foo.c.str ./test-program\n";
+      return;
+    }
+  }
+
+  Minimizer m;
+  m.sourceFname = argv[1];
+  string backupFname = stringc << m.sourceFname << ".bak";
+  string treeFname = argv[2];
+  if (!checktree) {
+    m.testProg = argv[3];
+  }
+
+  // back up the input
+  if (!checktree &&
+      0!=system(stringc << "cp \'" << m.sourceFname << "\' \'"
+                        << backupFname << "\'")) {
+    xfatal("failed to create " << backupFname);
+  }
+
+  // read the file into memory
+  readFile(m.sourceFname, m.source);
+
+  // build the interval partition tree
+  cout << "building interval partition tree\n";
+  m.tree = parseFile(treeFname);
+
+  // check that its size does not exceed the source file
+  {
+    int endpt = m.tree->getLargestFiniteEndpoint();
+    if (endpt >= m.source.size()) {
+      xfatal("the interval tree ends at " << endpt <<
+             ", but the file size is only " << m.source.size());
+    }
+  }
+
+  if (checktree) {
+    cout << "tree seems ok\n";
+    return;     // done
+  }
+
+  // generate the original input
+  int size;
+  VariantCursor cursor = m.write(size);
+  cout << "orig: " << stringf("%10d", size) << " ";
+  flush(cout);
+
+  // confirm it is the same as the given original
+  if (0!=system(stringc << "cmp -s \'" << m.sourceFname << "\' \'"
+                        << backupFname << "\'")) {
+    xfatal("failed to accurately re-create original source file");
+  }
+
+  try {
+    // confirm it passes the test
+    m.testInputSum += size;
+    cursor->data = m.runTest();
+    if (cursor->data == VR_PASSED) {
+      // yes
+    }
+    else {
+      // no
+      xfatal("original source file does not pass the test");
+    }
+  }
+  catch (XCtrlC &) {
+    HANDLER();
+    xfatal("exiting due to ctrl-c; input file is unchanged");
+  }
+
+  // begin trying lots of variants
+  try {
+    m.minimize();
+
+    cout << "\ndone!  writing minimized version to " << m.sourceFname << "\n";
+  }
+  catch (XCtrlC &) {
+    HANDLER();
+    cout << "\nuser pressed ctrl-c;\n";
+    cout << m.sourceFname << " will be left as the smallest variant that passed the test\n";
+  }
+
+  // write the final minimized version
+  cursor = m.write(size);
+  xassert(cursor->data == VR_PASSED);
+
+  cout << "passing=" << m.passingTests
+       << ", failing=" << m.failingTests
+       << ", total=" << (m.passingTests+m.failingTests)
+       << ", inputSum=" << m.testInputSum
+       << " (cached=" << m.cachedTests << ")"
+       << "\n";
+
+  // debugging stuff (interesting, but noisy)
+  if (tracingSys("dumpfinal")) {
+    m.tree->gdb();
+    printResults(m.results);
+  }
+}
+
+ARGS_MAIN

Added: vendor/elsa/current/elsa/smin.h
===================================================================
--- vendor/elsa/current/elsa/smin.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/smin.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,70 @@
+// smin.h
+// structural minimizer
+
+#ifndef SMIN_H
+#define SMIN_H
+
+#include "iptparse.h"       // parseFile
+#include "iptree.h"         // IPTree
+#include "exc.h"            // xBase
+
+
+// thrown when Ctrl-C pressed
+class XCtrlC : public xBase {
+public:
+  XCtrlC();
+  XCtrlC(XCtrlC const &obj);
+  ~XCtrlC();
+};
+
+
+
+class Minimizer {
+public:      // data
+  // filenames
+  string sourceFname;       // source file to minimize
+  string testProg;          // test program to run
+
+  // original contents of 'sourceFname;
+  GrowArray<char> source;
+  
+  // structural info about 'source'; must be set by client 
+  // (nullable owner)
+  IPTree *tree;
+  
+  // record of which variants have been tried
+  VariantResults results;
+  
+  // count of tests run
+  int passingTests;
+  int failingTests;
+  int cachedTests;
+  
+  // sum of the lengths of all inputs tested
+  long long testInputSum;
+
+private:     // funcs    
+  bool minimize(Node *n);
+  bool minimizeChildren(Node *sub);
+
+public:      // funcs
+  Minimizer();
+  ~Minimizer();
+
+  // run the test with the current contents of the source file
+  VariantResult runTest();
+
+  // write the variant corresponding to the current state of the tree
+  // nodes' relevance, and return a cursor denoting the bitstring for
+  // this variant; returns with 'size' set to size of written file
+  VariantCursor write(int &size);
+
+  // possibly use the cache; consider setting n->rel to 'ret';
+  // return true if the current variant passes
+  bool outerRunTest(int &size, Node *n, Relevance rel);
+
+  // kick off the minimizer
+  void minimize();
+};
+
+#endif // SMIN_H

Added: vendor/elsa/current/elsa/sprint.cc
===================================================================
--- vendor/elsa/current/elsa/sprint.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/sprint.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,129 @@
+// sprint.cc
+// code for sprint.h
+
+#include "sprint.h"     // this module
+
+
+void StructurePrinter::digStmt(Statement *s)
+{
+  // if this is a compound statement, traverse the elements;
+  // otherwise, skip it entirely
+  if (s->isS_compound()) {
+    S_compound *c = s->asS_compound();
+    FOREACH_ASTLIST_NC(Statement, c->stmts, iter) {
+      iter.data()->traverse(*this);
+    }
+  }
+}
+
+bool StructurePrinter::visitTopForm(TopForm *tf)
+{
+  in(tf->loc);
+
+  if (tf->isTF_func()) {
+    // dig down into the body, b/c I don't want an extra level for
+    // each function's body
+    digStmt(tf->asTF_func()->f->body);
+
+    out();
+
+    // do *not* now go into the children again
+    return false;
+  }
+  else {
+    // automatically traverse children for other kinds of topforms
+    return true;
+  }
+}
+
+bool StructurePrinter::visitStatement(Statement *s)
+{
+  in(s->loc);
+
+  ASTSWITCH(Statement, s) {
+    ASTCASE(S_label, sl)
+      digStmt(sl->s);
+
+    ASTNEXT(S_case, sc)
+      digStmt(sc->s);
+
+    ASTNEXT(S_default, sd)
+      digStmt(sd->s);
+
+    ASTNEXT(S_if, si)
+      digStmt(si->thenBranch);
+      if (si->elseBranch->loc > si->loc) {
+        digStmt(si->elseBranch);
+      }
+      else {
+        // the else branch wasn't syntactically present
+      }
+
+    ASTNEXT(S_switch, ss)
+      digStmt(ss->branches);
+
+    ASTNEXT(S_while, sw)
+      digStmt(sw->body);
+
+    ASTNEXT(S_doWhile, sd)
+      digStmt(sd->body);
+
+    ASTNEXT(S_for, sf)
+      digStmt(sf->body);
+
+    ASTDEFAULT
+      // those not listed above have their children automatically traversed
+      return true;
+      
+    ASTENDCASE
+  }
+
+  // those that *are* listed above have already handled children
+  out();
+  return false;
+}
+
+ostream &StructurePrinter::ind()
+{
+  for (int i=0; i < depth; i++) {
+    cout << "  ";
+  }
+  return cout;
+}
+
+bool StructurePrinter::in(SourceLoc loc)
+{
+  if (begin) {
+    // I'm first in my parent's list
+    cout << " {\n";
+  }
+
+  ind() << "begin=" << toString(loc);
+  depth++;
+  begin = true;
+  return true;    // visit children
+}
+
+void StructurePrinter::out()
+{
+  depth--;
+  if (begin) {
+    // no children
+    cout << "\n";
+  }
+  else {
+    // finish child list
+    ind() << "}\n";
+  }
+  begin = false;
+}
+
+
+void structurePrint(TranslationUnit *unit)
+{
+  StructurePrinter sp;
+  unit->traverse(sp);
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/sprint.h
===================================================================
--- vendor/elsa/current/elsa/sprint.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/sprint.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,54 @@
+// sprint.h
+// structure printer, for structural delta
+// this module is experimental
+
+#ifndef SPRINT_H
+#define SPRINT_H
+
+#include "cc_ast.h"     // C++ AST, visitor, etc.
+
+
+// walk the AST, printing info about syntactic and
+// static semantic structure
+// (sm: This should not inherit from LoweredASTVisitor.)
+// NOT Intended to be used with LoweredASTVisitor
+class StructurePrinter : public ASTVisitor {
+private:     // data
+  // current syntactic nesting level; 0 means toplevel
+  int depth;
+
+  // true if we just began the current nesting level
+  bool begin;
+
+  // for each depth level, at what char offset did the current
+  // entity begin?
+  //ArrayStack<int> begins;
+
+private:     // funcs
+  ostream &ind();
+  bool in(SourceLoc loc);
+  void out();
+  void digStmt(Statement *s);
+
+public:      // funcs
+  StructurePrinter()
+    : depth(0),
+      begin(false)
+  {
+    //begins.push(0);    // depth 0 starts at 0
+  }
+
+  virtual bool visitTopForm(TopForm *tf)      ;//{ return in(tf->loc); }
+  virtual void postvisitTopForm(TopForm*)     { out(); }
+  virtual bool visitStatement(Statement *s)   ;//{ return in(s->loc); }
+  virtual void postvisitStatement(Statement*) { out(); }
+  virtual bool visitMember(Member *m)         { return in(m->loc); }
+  virtual void postvisitMember(Member*)       { out(); }
+};
+  
+
+// convenient entry point
+void structurePrint(TranslationUnit *unit);
+
+
+#endif // SPRINT_H

Added: vendor/elsa/current/elsa/stdconv.cc
===================================================================
--- vendor/elsa/current/elsa/stdconv.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/stdconv.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1184 @@
+// stdconv.cc                       see license.txt for copyright and terms of use
+// code for stdconv.h
+
+#include "stdconv.h"      // this module
+#include "cc_type.h"      // Type
+#include "cc_env.h"       // Env
+#include "trace.h"        // tracingSys
+
+
+/*
+ * 2005-04-03: ARR_QUAL_CONV:
+ *
+ * It is possible to convert (say)
+ *
+ *   pointer to array of int
+ *
+ * to
+ *
+ *   pointer to array of const int
+ *
+ * because 3.9.3p5 apparently intends cv qualifiers on arrays and
+ * array elements to be interchangeable with respect to standard
+ * conversions.  See this post:
+ *
+ *   http://groups-beta.google.com/group/comp.std.c++/msg/1396c9ff05f4e86f?dmode=source
+ *
+ * So the strategy in this module (marked with "ARR_QUAL_CONV")
+ * is to "pull" qualifiers on array elements up to the level of
+ * the (outermost) ArrayType, as if they were attached to that
+ * object (only).  This is done primarily by 'getSrcCVFlags'.
+ */
+
+
+// ----------------------- StandardConversion -------------------
+string toString(StandardConversion c)
+{
+  stringBuilder sb;
+
+  if (c == SC_ERROR) {
+    return string("SC_ERROR");
+  }
+
+  if (c == SC_IDENTITY) {
+    return string("SC_IDENTITY");
+  }
+
+  #define CASE(label)                  \
+    case label:                        \
+      if (sb.length()) { sb << "|"; }  \
+      sb << #label;                    \
+      break;
+
+  switch (c & SC_GROUP_1_MASK) {
+    default: return stringc << "bad code: " << (int)c;
+    case SC_IDENTITY: break;
+    CASE(SC_LVAL_TO_RVAL)
+    CASE(SC_ARRAY_TO_PTR)
+    CASE(SC_FUNC_TO_PTR)
+  }
+
+  switch (c & SC_GROUP_3_MASK) {
+    default: return stringc << "bad code: " << (int)c;
+    case SC_IDENTITY: break;
+    CASE(SC_QUAL_CONV)
+  }
+
+  switch (c & SC_GROUP_2_MASK) {
+    default: return stringc << "bad code: " << (int)c;
+    case SC_IDENTITY: break;
+    CASE(SC_INT_PROM)
+    CASE(SC_FLOAT_PROM)
+    CASE(SC_INT_CONV)
+    CASE(SC_FLOAT_CONV)
+    CASE(SC_FLOAT_INT_CONV)
+    CASE(SC_PTR_CONV)
+    CASE(SC_PTR_MEMB_CONV)
+    CASE(SC_BOOL_CONV)
+  }
+
+  #undef CASE
+
+  if (c & ~(SC_GROUP_1_MASK | SC_GROUP_2_MASK | SC_GROUP_3_MASK)) {
+    return stringc << "bad code: " << (int)c;
+  }
+
+  return sb;
+}
+
+
+StandardConversion removeLval(StandardConversion scs)
+{
+  if ((scs & SC_GROUP_1_MASK) == SC_LVAL_TO_RVAL) {
+    // remove this transformation
+    return scs & (SC_GROUP_2_MASK | SC_GROUP_3_MASK);
+  }
+  else {
+    return scs;
+  }
+}
+
+
+bool isSubsequenceOf(StandardConversion left, StandardConversion right)
+{
+  StandardConversion L, R;
+  
+  L = left & SC_GROUP_1_MASK;                                   
+  R = right & SC_GROUP_1_MASK;
+  if (!( L == SC_IDENTITY || L == R )) {
+    return false;
+  }
+
+  L = left & SC_GROUP_2_MASK;
+  R = right & SC_GROUP_2_MASK;
+  if (!( L == SC_IDENTITY || L == R )) {
+    return false;
+  }
+
+  L = left & SC_GROUP_3_MASK;
+  R = right & SC_GROUP_3_MASK;
+  if (!( L == SC_IDENTITY || L == R )) {
+    return false;
+  }
+
+  return true;
+}
+
+
+// ---------------------------- SCRank ----------------------------
+// table 9
+SCRank getRank(StandardConversion scs)
+{
+  if ((scs & SC_GROUP_2_MASK) >= SC_INT_CONV) {
+    return SCR_CONVERSION;
+  }
+  
+  if (scs & SC_GROUP_2_MASK) {
+    return SCR_PROMOTION;
+  }
+  
+  return SCR_EXACT;
+}
+
+
+// --------------------- getStandardConversion --------------------
+bool isIntegerPromotion(AtomicType const *src, AtomicType const *dest);
+
+// int (including bitfield), bool, or enum
+bool isIntegerNumeric(Type const *t, SimpleType const *tSimple)
+{
+  if (tSimple) {
+    return isIntegerType(tSimple->type) ||
+           tSimple->type == ST_BOOL ||
+           tSimple->type == ST_PROMOTED_INTEGRAL;
+  }
+
+  // TODO: bitfields are also a valid integer conversion source,
+  // once I have an explicit representation for them
+
+  return t->isEnumType();
+}
+
+// any of above, or float
+bool isNumeric(Type const *t, SimpleType const *tSimple)
+{
+  return isIntegerNumeric(t, tSimple) ||
+         (tSimple && isFloatType(tSimple->type)) ||
+         (tSimple && tSimple->type == ST_PROMOTED_ARITHMETIC);
+}
+
+
+#if 0   // unused, but potentially useful at some point
+static char const *atomicName(AtomicType::Tag tag)
+{
+  switch (tag) {
+    default: xfailure("bad tag");
+    case AtomicType::T_SIMPLE:   return "simple";
+    case AtomicType::T_COMPOUND: return "compound";
+    case AtomicType::T_ENUM:     return "enum";
+    case AtomicType::T_TYPEVAR:  return "type variable";
+  }
+}
+#endif // 0
+
+static char const *ctorName(Type::Tag tag)
+{
+  switch (tag) {
+    default: xfailure("bad tag");
+    case Type::T_ATOMIC:          return "atomic";
+    case Type::T_POINTER:         return "pointer";
+    case Type::T_FUNCTION:        return "function";
+    case Type::T_ARRAY:           return "array";
+    case Type::T_POINTERTOMEMBER: return "ptr-to-member";
+  }
+}
+
+
+// implementation class
+class Conversion {
+public:
+  // original parameters to 'getStandardConversion'
+  string *errorMsg;
+  SpecialExpr srcSpecial;
+  Type const *src;
+  Type const *dest;
+  bool destIsReceiver;
+
+  // eventual return value
+  StandardConversion ret;
+
+  // when true, every destination pointer type constructor
+  // has had 'const' in its cv flags
+  bool destConst;
+
+  // count how many pointer or ptr-to-member type ctors we
+  // have stripped so far
+  int ptrCtorsStripped;
+
+public:
+  Conversion(string *e, SpecialExpr sp, Type const *s, Type const *d, bool dir)
+    : errorMsg(e),
+      srcSpecial(sp),
+      src(s),
+      dest(d),
+      destIsReceiver(dir),
+
+      ret(SC_IDENTITY),
+      destConst(true),
+      ptrCtorsStripped(0)
+  {}
+
+  StandardConversion error(char const *why);
+
+  bool stripPtrCtor(CVFlags scv, CVFlags dcv, bool isReference=false);
+};
+
+
+StandardConversion Conversion::error(char const *why)
+{
+  // 10/02/04: This is probably not the best way to handle this, but one
+  // problem with 'getStandardConversion' is if the source and destination
+  // are both references, it wants to pair those references up, but it is
+  // also possible to implicitly convert away the source reference and bind
+  // the dest reference, *if* the dest reference is a reference to const.
+  //
+  // So, if we are about to report an error (which is why we are in
+  // this function), and the dest is 'T const &', try again with a
+  // dest of just 'T'.
+  if (dest->isReference() &&
+      dest->getAtType()->isConst()) {
+    return getStandardConversion(errorMsg, srcSpecial, src, dest->getAtType(),
+                                 destIsReceiver);
+  }
+
+  if (errorMsg) {
+    *errorMsg = stringc
+      << "cannot convert `" << src->toString()
+      << "' to `" << dest->toString()
+      << "': " << why;
+  }
+  return ret = SC_ERROR;
+}
+
+
+// strip pointer constructors, update local state; return true
+// if we've encountered an error, in which case 'ret' is set
+// to the error code to return
+bool Conversion::stripPtrCtor(CVFlags scv, CVFlags dcv, bool isReference)
+{
+  if (scv != dcv) {
+    if (isReference) {
+      // Conversion from 'int &' to 'int const &' is equivalent to
+      // SC_LVAL_TO_RVAL, or so I'm led to believe by 13.3.3.2 para 3,
+      // second example.  13.3.3.1.4 para 5 talks about "reference-
+      // compatible with added qualification", but I don't then see
+      // a later discussion of what exactly this means.
+      //
+      // update: that term is defined in 8.5.3, and I now think that
+      // binding 'A&' to 'A const &' should be an SC_QUAL_CONV, just
+      // like with pointers...; moreover, I suspect that since
+      // SC_LVAL_TO_RVAL and SC_QUAL_CONV have the same *rank*, I'll
+      // still be able to pass 13.3.3.2 para 3 ex. 2
+      xassert(ret == SC_IDENTITY);     // shouldn't have had anything added yet
+      //ret |= SC_QUAL_CONV;
+      
+      // trying again.. 13.3.3.1.4 para 1
+      ret |= SC_IDENTITY;
+      
+      // old code; if ultimately this solution works, I'll drop the
+      // 'isReference' parameter to this function entirely...
+      //ret |= SC_LVAL_TO_RVAL;
+    }
+    else {
+      ret |= SC_QUAL_CONV;
+    }
+  }
+
+  if (scv & ~dcv) {
+    error("the source has some cv flag that the dest does not");
+    return true;
+  }
+
+  if (!destConst && (scv != dcv)) {
+    error("changed cv flags below non-const pointer");
+    return true;
+  }
+
+  if (!( dcv & CV_CONST )) {
+    destConst = false;
+  }
+
+  ptrCtorsStripped++;
+  return false;
+}
+
+
+// ARR_QUAL_CONV: Regard cv flags on an array element to be cv flags
+// on the array itself.  Dig down below arbitrarily many levels of
+// array to find the element.
+CVFlags getSrcCVFlags(Type const *src)
+{
+  if (src->isArrayType()) {
+    ArrayType const *at = src->asArrayTypeC();
+    return getSrcCVFlags(at->eltType);
+  }
+  else {
+    return src->getCVFlags();
+  }
+}
+
+
+// Below, each time I extract the CV flags from the 'dest' type,
+// I use this function.  Whenever 'dest' names a polymorphic type,
+// I pretend it has the same CV flags as the source so we don't
+// get spurious mismatches.
+CVFlags getDestCVFlags(Type const *dest, CVFlags srcCV)
+{
+  CVFlags destCV = getSrcCVFlags(dest);
+
+  // 9/23/04: If the destination type is polymorphic, then pretend
+  // the flags match.
+  if (dest->isSimpleType()) {
+    SimpleTypeId id = dest->asSimpleTypeC()->type;
+    if (id == ST_ANY_OBJ_TYPE ||
+        id == ST_ANY_NON_VOID ||
+        id == ST_ANY_TYPE) {
+      destCV = srcCV;
+    }
+  }
+
+  return destCV;
+}
+
+
+bool canConvertToBaseClass(Type const *src, Type const *dest, bool &ambig)
+{
+  if (!dest->isCompoundType()) {
+    return false;
+  }
+  CompoundType const *destCt = dest->asCompoundTypeC();
+
+  CompoundType const *srcCt = NULL;
+  if (src->isCompoundType()) {
+    srcCt = src->asCompoundTypeC();
+  }
+  else if (src->isPseudoInstantiation()) {
+    // (e.g. in/t0386.cc) conversion from pseudoinstantiation: can
+    // convert to any of the concrete bases
+    srcCt = src->asCVAtomicTypeC()->atomic->asPseudoInstantiationC()->primary;
+  }
+  else {
+    return false;
+  }
+
+  if (srcCt->hasStrictBaseClass(destCt)) {
+    ambig = !srcCt->hasUnambiguousBaseClass(destCt);
+    return true;
+  }
+
+  return false;
+}
+
+    
+// not sure if this is such a good idea..
+bool couldBeAnything(Type const *t)
+{
+  // PseudoInstantiation is left out because a PI has to be
+  // a class type
+  return t->isSimple(ST_DEPENDENT) ||
+         t->isTypeVariable() ||
+         t->isDependentQType();
+}
+
+
+// one of the goals of this function is to *not* construct any
+// intermediate Type objects; I should be able to do this computation
+// without allocating, and if I can then that avoids interaction
+// problems with Type annotation systems
+StandardConversion getStandardConversion
+  (string *errorMsg, SpecialExpr srcSpecial, Type const *src, Type const *dest,
+   bool destIsReceiver)
+{
+  Conversion conv(errorMsg, srcSpecial, src, dest, destIsReceiver);
+
+  // --------------- group 1 ----------------
+  if (src->isReference() &&
+      !src->asRvalC()->isFunctionType() &&
+      !src->asRvalC()->isArrayType() &&
+      !dest->isReference()) {
+    conv.ret |= SC_LVAL_TO_RVAL;
+
+    src = src->asReferenceTypeC()->atType;
+
+    // the src type must be complete for this conversion
+    if (src->isCompoundType() &&
+        src->asCompoundTypeC()->forward) {
+      return conv.error("type must be complete to strip '&'");
+    }
+
+    // am I supposed to check cv flags?
+  }
+  else if (!src->isReference() && dest->isReference()) {
+    // binding an (rvalue) object to a reference
+
+    if (!destIsReceiver) {
+      // are we trying to bind to a non-const reference?  if so,
+      // then we can't do it (cppstd 13.3.3.1.4 para 3)
+      ReferenceType const *destPT = dest->asReferenceTypeC();
+      if (!destPT->atType->isConst()) {
+        // can't form the conversion
+        return conv.error("attempt to bind an rvalue to a non-const reference");
+      }
+    }
+
+    // strip off the destination reference
+    dest = dest->asReferenceTypeC()->atType;
+    
+    // now, one final exception: ordinarily, there's no standard
+    // conversion from C to P (where C inherits from P); but it *is*
+    // legal to bind an rvalue of type C to a const reference to P
+    // (cppstd 13.3.3.1.4 para 1)
+    if (dest->isCompoundType() && 
+        src->isCompoundType() &&
+        src->asCompoundTypeC()->hasStrictBaseClass(dest->asCompoundTypeC())) {
+      // TODO: ambiguous? inaccessible?
+      return SC_PTR_CONV;     // "derived-to-base Conversion"
+    }
+  }
+  else if (src->asRvalC()->isArrayType() && dest->isPointer()) {
+    // 7/19/03: 'src' can be an lvalue (cppstd 4.2 para 1)
+
+    conv.ret |= SC_ARRAY_TO_PTR;
+
+    // note: even if we strip a reference here, we do not say it
+    // is SC_LVAL_TO_RVAL (why? because I can't represent that.. and
+    // I hope that that is right...)
+
+    src = src->asRvalC()->asArrayTypeC()->eltType;
+    dest = dest->asPointerTypeC()->atType;
+
+    // do one level of qualification conversion checking
+    CVFlags scv = getSrcCVFlags(src);
+    CVFlags dcv = getDestCVFlags(dest, scv);
+
+    if (srcSpecial == SE_STRINGLIT &&
+        scv == CV_CONST &&
+        dcv == CV_NONE) {
+      // special exception of 4.2 para 2: string literals can be
+      // converted to 'char*' (w/o 'const'); we'll already have
+      // converted 'char const []' to 'char const *', so this just
+      // adds the qualification conversion
+      //
+      // TODO: it might be nice to have a CCLang option to disable
+      // this, so that we could get soundness at the expense of
+      // compatibility with legacy code
+      conv.ret |= SC_QUAL_CONV;
+      scv = CV_NONE;   // avoid error in stripPtrCtor, below
+    }
+
+    if (conv.stripPtrCtor(scv, dcv))
+      { return conv.ret; }
+  }
+  else if (src->isFunctionType() && dest->isPointerType()) {
+    conv.ret |= SC_FUNC_TO_PTR;
+
+    dest = dest->asPointerTypeC()->atType;
+
+    CVFlags scv = getSrcCVFlags(src);
+    CVFlags dcv = getDestCVFlags(dest, scv);
+
+    if (conv.stripPtrCtor(scv, dcv))
+      { return conv.ret; }
+  }
+
+  // 9/25/04: conversions to bool that must be preceded by a
+  // group 1 conversion
+  if (dest->isBool()) {
+    // these conversions always yield 'true'.. I wonder if there
+    // is a good way to take advantage of that..
+    Type const *s = src->asRvalC();
+    if (s->isArrayType()) {
+      return conv.ret | SC_ARRAY_TO_PTR | SC_BOOL_CONV;
+    }
+    if (s->isFunctionType()) {
+      return conv.ret | SC_FUNC_TO_PTR | SC_BOOL_CONV;
+    }
+  }
+
+  // At this point, if the types are to be convertible, their
+  // constructed type structure must be isomorphic, possibly with the
+  // exception of cv flags and/or the containing class for member
+  // pointers.  The next phase checks the isomorphism and verifies
+  // that any difference in the cv flags is within the legal
+  // variations.
+
+  // ---------------- group 3 --------------------
+  // deconstruct the type constructors until at least one of them
+  // hits the leaf
+  while (!src->isCVAtomicType() &&
+         !dest->isCVAtomicType()) {
+    if (src->getTag() != dest->getTag()) {
+      // when PointerType and ReferenceType were unified, I had
+      // a slightly more informative message for one case
+      if (src->isPointerType() && dest->isReferenceType()) {
+        return conv.error("cannot convert rvalue to lvalue");
+      }
+      else {
+        return conv.error("different type constructors");
+      }
+    }
+
+    switch (src->getTag()) {
+      default: xfailure("bad type tag");
+
+      case Type::T_POINTER:
+      case Type::T_REFERENCE: {
+        bool isReference = (src->isReference());
+
+        src = src->getAtType();
+        dest = dest->getAtType();
+
+        // we look at the cv flags one level down because all of the
+        // rules in cppstd talk about things like "pointer to cv T",
+        // i.e. pairing the * with the cv one level down in their
+        // descriptive patterns
+        CVFlags srcCV = getSrcCVFlags(src);
+        CVFlags destCV = getDestCVFlags(dest, srcCV);
+        
+        if (conv.stripPtrCtor(srcCV, destCV, isReference))
+          { return conv.ret; }
+
+        break;
+      }
+
+      case Type::T_FUNCTION: {
+        // no variance is allowed whatsoever once we reach a function
+        // type, which is a little odd since I'd think it would be
+        // ok to pass
+        //   int (*)(Base*)
+        // where
+        //   int (*)(Derived*)
+        // is expected, but I don't see such a provision in cppstd
+        //
+        // 2005-04-15: Actually, 13.4p7 address this directly, and
+        // explains that it is indeed illegal.
+        //
+        // Also, 8.3.5p4 says that exception specs are irrelevant here,
+        // even though (again) there is a sound subtyping lattice.
+        if (src->equals(dest)) {
+          return conv.ret;
+        }
+        else {
+          return conv.error("unequal function types");
+        }
+      }
+
+      case Type::T_ARRAY: {
+        // like functions, no conversions are possible on array types,
+        // including (as far as I can see) converting
+        //   int[3]
+        // to
+        //   int[]
+        //
+        // ARR_QUAL_CONV: A qualification conversion is possible.  The
+        // element qualifier will already have been processed, so ignore
+        // it during equality checking.
+        if (src->equals(dest, MF_IGNORE_ELT_CV)) {
+          return conv.ret;
+        }
+        else {
+          return conv.error("unequal array types");
+        }
+      }
+
+      case Type::T_POINTERTOMEMBER: {
+        PointerToMemberType const *s = src->asPointerToMemberTypeC();
+        PointerToMemberType const *d = dest->asPointerToMemberTypeC();
+
+        if (s->inClass() != d->inClass()) {
+          if (conv.ptrCtorsStripped == 0) {
+            // opposite to first ptr ctor, we allow Base -> Derived
+            if (!d->inClass()->hasUnambiguousBaseClass(s->inClass())) {
+              return conv.error("src member's class is not an unambiguous "
+                                "base of dest member's class");
+            }
+            else if (d->inClass()->hasVirtualBase(s->inClass())) {
+              return conv.error("src member's class is a virtual base of "
+                                "dest member's class");
+            }
+            else {
+              // TODO: check accessibility.. this depends on the access privileges
+              // of the code we're in now..
+
+              // this is actually a group 2 conversion
+              conv.ret |= SC_PTR_MEMB_CONV;
+            }
+          }
+          else {
+            // after the first ctor, variance is not allowed
+            return conv.error("unequal member classes in ptr-to-member that "
+                              "is not the topmost type");
+          }
+        }
+
+        src = s->atType;
+        dest = d->atType;
+
+        CVFlags scv = getSrcCVFlags(src);
+        CVFlags dcv = getDestCVFlags(dest, scv);
+
+        if (conv.stripPtrCtor(scv, dcv))
+          { return conv.ret; }
+
+        // 10/08/04: (t0344.cc) For ptr-to-member where the member is
+        // a function, we need to ignore the receiver parameter.  So
+        // what follows is basically the T_FUNCTION case, above, but
+        // with a different EqFlags passed.
+        if (src->isFunctionType() && dest->isFunctionType()) {
+          if (src->equals(dest, MF_IGNORE_IMPLICIT)) {
+            return conv.ret;
+          }
+          else {
+            return conv.error("unequal function types");
+          }
+        }
+
+        break;
+      }
+    }
+  }
+
+  // ---------------- group 2 --------------
+
+  if (couldBeAnything(src) ||
+      couldBeAnything(dest)) {
+    // conversion could be as good as identity (in/t0572.cc)
+    return conv.ret;
+  }
+
+  // if I check equality here, will it mess anything up?
+  // no, looks ok; I'm going to try folding polymorphic
+  // checking into equality itself...
+  // 
+  // appears to work!  I'll tag the old stuff with "delete me"
+  // for the moment
+  if (src->equals(dest, MF_POLYMORPHIC)) {
+    return conv.ret;    // identical now
+  }
+
+  if (conv.ptrCtorsStripped == 1 &&
+      dest->isSimple(ST_VOID)) {
+    return conv.ret | SC_PTR_CONV;      // converting T* to void*
+  }
+
+  // if both types have not arrived at CVAtomic, then they
+  // are not convertible
+  if (!src->isCVAtomicType() ||
+      !dest->isCVAtomicType()) {
+    // exception: pointer -> bool
+    if (dest->isSimple(ST_BOOL) &&
+        (src->isPointerType() || src->isPointerToMemberType())) {
+      return conv.ret | SC_BOOL_CONV;
+    }
+
+    // exception: 0 -> (null) pointer
+    if (srcSpecial == SE_ZERO) {
+      if (dest->isPointerType()) {
+        return conv.ret | SC_PTR_CONV;
+      }
+      if (dest->isPointerToMemberType()) {
+        return conv.ret | SC_PTR_MEMB_CONV;
+      }
+    }
+
+    if (errorMsg) {
+      // if reporting, I go out of my way a bit here since I expect
+      // this to be a relatively common error and I'd like to provide
+      // as much information as will be useful
+      if (dest->isReference()) {
+        return conv.error("cannot convert rvalue to lvalue");
+      }
+
+      return conv.error(stringc
+        << "different type constructors, "
+        << ctorName(src->getTag()) << " vs. "
+        << ctorName(dest->getTag()));
+    }
+    else {
+      return SC_ERROR;     // for performance, don't make the string at all
+    }
+  }
+
+  // now we're down to atomics; we expect equality, but ignoring cv
+  // flags because they've already been handled
+
+  CVAtomicType const *s = src->asCVAtomicTypeC();
+  CVAtomicType const *d = dest->asCVAtomicTypeC();
+
+  if (conv.ptrCtorsStripped > 0) {
+    if (conv.ptrCtorsStripped == 1) {
+      bool ambig = false;
+      if (canConvertToBaseClass(src, dest, ambig)) {
+        if (ambig) {
+          return conv.error("base class is ambiguous");
+        }
+        // TODO: check accessibility.. this depends on the access privileges
+        // of the code we're in now..
+        return conv.ret | SC_PTR_CONV;      // converting Derived* to Base*
+      }
+    }
+
+    // since we stripped ptrs, final type must be equal
+    if (s->atomic->equals(d->atomic)) {
+      return conv.ret;
+    }
+    else {
+      // 9/25/04: (in/t0316.cc) I'm not sure where the best place to do
+      // this is, in part b/c I don't know what the real rule is.  This
+      // allows e.g. 'unsigned int &' to be passed where 'int const &'
+      // is expected.
+      if (conv.dest->isReference() &&
+          conv.dest->getAtType()->isConst()) {
+        // just strip the reference part of the dest; this is like binding
+        // the (const) reference, which is not an explicit part of the
+        // "conversion"
+        return getStandardConversion(errorMsg, srcSpecial, conv.src, 
+                                     conv.dest->asRvalC(), destIsReceiver);
+      }
+
+      return conv.error("incompatible atomic types");
+    }
+  }
+  else {
+    // further info on this: 13.3.3.1 para 6, excerpt:
+    //   "Any difference in top-level cv-qualification is
+    //    subsumed by the initialization and does not
+    //    constitute a conversion."
+
+    #if 0    // am I supposed to do any checking?
+    // I'm not perfectly clear on the checking I should do for
+    // the cv flags here.  lval-to-rval says that 'int const &'
+    // becomes 'int' whereas 'Foo const &' becomes 'Foo const'
+    if ((conv.ret & SC_LVAL_TO_RVAL) &&     // did we do lval-to-rval?
+        s->atomic->isSimpleType()) {        // were we a ref to simple?
+      // clear any 'const' on the source
+      scv &= ~CV_CONST;
+    }
+
+    if (scv != dcv) {
+      return conv.error("different cv flags (is this right?)");
+    }
+    #endif // 0
+  }
+
+  if (s->atomic->equals(d->atomic)) {
+    return conv.ret;    // identical now
+  }
+
+  SimpleType const *srcSimple = src->isSimpleType() ? src->asSimpleTypeC() : NULL;
+  SimpleType const *destSimple = dest->isSimpleType() ? dest->asSimpleTypeC() : NULL;
+
+  if (isIntegerPromotion(s->atomic, d->atomic)) {
+    return conv.ret | SC_INT_PROM;
+  }
+
+  if (srcSimple && srcSimple->type == ST_FLOAT &&
+      destSimple && destSimple->type == ST_DOUBLE) {
+    return conv.ret | SC_FLOAT_PROM;
+  }
+
+  // do this before checking for SC_INT_CONV, since a destination
+  // type of 'bool' is explicitly excluded by 4.7 para 4
+  if (isNumeric(src, srcSimple) &&
+      destSimple && destSimple->type == ST_BOOL) {
+    return conv.ret | SC_BOOL_CONV;
+  }
+
+  if (isIntegerNumeric(src, srcSimple) &&
+      destSimple && isIntegerType(destSimple->type)) {
+    return conv.ret | SC_INT_CONV;
+  }
+
+  bool srcFloat = srcSimple && isFloatType(srcSimple->type);
+  bool destFloat = destSimple && isFloatType(destSimple->type);
+  if (srcFloat && destFloat) {
+    return conv.ret | SC_FLOAT_CONV;
+  }
+
+  if (isNumeric(src, srcSimple) &&
+      isNumeric(dest, destSimple) &&
+      (srcFloat || destFloat)) {     // last test required if both are enums
+    return conv.ret | SC_FLOAT_INT_CONV;
+  }
+
+  // no more conversion possibilities remain; I don't print the
+  // atomic kinds, because the error is based on more than just
+  // the kinds; moreover, since I already know I didn't strip
+  // any ptr ctors, the full types should be easy to read
+  return conv.error("incompatible atomic types");
+}
+
+
+// This function implements Section 4.5, which contains
+// implementation-determined details.  Promotions are distinguished
+// from conversions in that they are preferred over conversions during
+// overload resolution.  Since this distinction is implementation-
+// dependent, I envision that users might replace this function with
+// an implementation that better suits them.
+//
+// NOTE:  One way to get a conservative analysis that never silently
+// chooses among potentially-ambiguous choices is to make this always
+// return false.
+//
+// Another idea:  It would be nice to have a set of tests such that
+// by running the tests one could determine what choices a given compiler
+// makes, so that this function could be modified accordingly to
+// imitate that behavior.
+bool isIntegerPromotion(AtomicType const *src, AtomicType const *dest)
+{
+  bool srcSimple = src->isSimpleType();
+  bool destSimple = dest->isSimpleType();
+
+  SimpleTypeId sid = srcSimple? src->asSimpleTypeC()->type : ST_ERROR;
+  SimpleTypeId did = destSimple? dest->asSimpleTypeC()->type : ST_ERROR;
+
+  if (did == ST_INT ||
+      did == ST_PROMOTED_INTEGRAL ||
+      did == ST_PROMOTED_ARITHMETIC) {
+    // paragraph 1: char/short -> int
+    // implementation choice: I assume char is 8 bits and short
+    // is 16 bits and int is 32 bits, so all map to 'int', as
+    // opposed to 'unsigned int'
+    if (sid == ST_CHAR ||
+        sid == ST_UNSIGNED_CHAR ||
+        sid == ST_SIGNED_CHAR ||
+        sid == ST_SHORT_INT ||
+        sid == ST_UNSIGNED_SHORT_INT) {
+      return true;
+    }
+
+    // paragraph 2: wchar_t/enum -> int
+    // implementation choice: I assume wchar_t and all enums fit into ints
+    if (sid == ST_WCHAR_T ||
+        src->isEnumType()) {
+      return true;
+    }
+
+    // TODO: paragraph 3: bitfields
+
+    // paragraph 4: bool -> int
+    if (sid == ST_BOOL) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+Type *makeSimpleType(TypeFactory &tfac, SimpleTypeId id)
+{
+  return tfac.getSimpleType(id);
+}
+
+Type *getConcreteDestType(TypeFactory &tfac, Type *srcType,
+                          StandardConversion sconv,
+                          SimpleTypeId destPolyType)
+{                 
+  // move 'srcType' closer to the actual dest type according to group 1
+  if (sconv & SC_LVAL_TO_RVAL) {
+    srcType = srcType->getAtType();
+    sconv &= ~SC_LVAL_TO_RVAL;
+  }
+  else {
+    // I don't think any other group 1 is possible when
+    // converting to a polymorphic type
+    xassert(!( sconv & SC_GROUP_1_MASK ));
+  }
+
+  // group 3: I believe this is impossible too
+  xassert(!( sconv & SC_GROUP_3_MASK ));
+
+  // so now we only have group 2 to deal with
+  xassert(sconv == (sconv & SC_GROUP_2_MASK));
+
+  // if no conversions remain, we're done
+  if (sconv == SC_IDENTITY) {
+    return srcType;
+  }
+
+  switch (destPolyType) {
+    // if this fails, the caller most likely failed to recognize
+    // that it could answer its question directly
+    default: xfailure("bad polymorphic type");
+
+    // the following includes some guesswork... there are probably
+    // bugs here; for now, I generally prefer to return something
+    // than to fail an assertion
+
+    case ST_PROMOTED_INTEGRAL:
+      // most likely SC_INT_PROM; I only promote to ST_INT
+      return makeSimpleType(tfac, ST_INT);
+
+    case ST_PROMOTED_ARITHMETIC:
+      if (sconv == SC_INT_PROM) {
+        return makeSimpleType(tfac, ST_INT);
+      }
+      else {
+        return makeSimpleType(tfac, ST_DOUBLE);
+      }
+
+    // not sure what conversions would be needed here..
+    case ST_INTEGRAL:
+    case ST_ARITHMETIC:
+    case ST_ARITHMETIC_NON_BOOL:
+      return makeSimpleType(tfac, ST_INT);
+
+    case ST_ANY_OBJ_TYPE:
+    case ST_ANY_NON_VOID:
+    case ST_ANY_TYPE:
+      // I really have no idea what could cause a conversion
+      // here, so I will go ahead and complain
+      xfailure("I don't think this is possible; conversion to very broad polymorphic type?");
+      return makeSimpleType(tfac, ST_INT);    // silence warning...
+  }
+}
+
+     
+void getIntegerStats(SimpleTypeId id, int &length, int &uns)
+{
+  switch (id) {
+    default: xfailure("bad id for getIntegerLength");
+
+    case ST_INT:                  length=0; uns=0; return;
+    case ST_UNSIGNED_INT:         length=0; uns=1; return;
+
+    case ST_LONG_INT:             length=1; uns=0; return;
+    case ST_UNSIGNED_LONG_INT:    length=1; uns=1; return;
+
+    case ST_LONG_LONG:            length=2; uns=0; return;
+    case ST_UNSIGNED_LONG_LONG:   length=2; uns=1; return;
+  }
+}
+
+
+// implemented below
+static SimpleTypeId uacHelper(SimpleTypeId leftId, SimpleTypeId rightId);
+
+// cppstd section 5 para 9
+// and C99 secton 6.3.1.8 para 1
+Type *usualArithmeticConversions(TypeFactory &tfac, Type *left, Type *right)
+{
+  if (left->isError()) { return left; }
+  if (right->isError()) { return right; }
+
+  // if either operand is of type long double, [return] long double
+  if (left->isSimple(ST_LONG_DOUBLE)) { return left; }
+  if (right->isSimple(ST_LONG_DOUBLE)) { return right; }
+
+  // similar for double
+  if (left->isSimple(ST_DOUBLE)) { return left; }
+  if (right->isSimple(ST_DOUBLE)) { return right; }
+
+  // and float
+  if (left->isSimple(ST_FLOAT)) { return left; }
+  if (right->isSimple(ST_FLOAT)) { return right; }
+
+  // now apply integral promotions (4.5)
+  SimpleTypeId leftId = applyIntegralPromotions(left);
+  SimpleTypeId rightId = applyIntegralPromotions(right);
+
+  // conversions on SimpleTypeIds
+  SimpleTypeId lubId = uacHelper(leftId, rightId);
+
+  // package it
+  return makeSimpleType(tfac, lubId);
+}
+
+SimpleTypeId usualArithmeticConversions(SimpleTypeId leftId, SimpleTypeId rightId)
+{
+  // same initial tests as above, but directly on the ids
+
+  // if either operand is of type long double, [return] long double
+  if (leftId == ST_LONG_DOUBLE) { return leftId; }
+  if (rightId == ST_LONG_DOUBLE) { return rightId; }
+
+  // similar for double
+  if (leftId == ST_DOUBLE) { return leftId; }
+  if (rightId == ST_DOUBLE) { return rightId; }
+
+  // and float
+  if (leftId == ST_FLOAT) { return leftId; }
+  if (rightId == ST_FLOAT) { return rightId; }
+
+  // now apply integral promotions (4.5)
+  leftId = applyIntegralPromotions(leftId);
+  rightId = applyIntegralPromotions(rightId);
+
+  // conversions on SimpleTypeIds
+  SimpleTypeId lubId = uacHelper(leftId, rightId);
+
+  return lubId;
+}
+
+static SimpleTypeId uacHelper(SimpleTypeId leftId, SimpleTypeId rightId)
+{
+  // At this point, both cppstd and C99 go into gory detail
+  // case-analyzing the types (which are both integral types at least
+  // 'int' or bigger/wider).  However, the effect of both analyses is
+  // to simply compute the least upper bound over the lattice of the
+  // "all values can be represented by" relation.  This relation
+  // is always an extension of the following minimal one:
+  //
+  //        long long       ------->    unsigned long long
+  //           ^                                ^
+  //           |                                |
+  //          long          ------->      unsigned long
+  //           ^                                ^
+  //           |                                |
+  //          int           ------->       unsigned int
+  //
+  // Additional implementation-specific edges may be added when the
+  // representation ranges allow.  For example if 'long' is 64 bits
+  // and 'unsigned int' is 32 bits, then there will be an edge from
+  // 'unsigned int' to 'long', and that edge participates in the
+  // least-upper-bound computation.  I play it conservative and
+  // compute my LUB over just the minimal one displayed above.
+
+  // mod out the length (C99 term: "conversion rank") and unsignedness
+  int leftLength, leftUns;
+  getIntegerStats(leftId, leftLength, leftUns);
+  int rightLength, rightUns;
+  getIntegerStats(rightId, rightLength, rightUns);
+
+  // least upper bound of a product lattice
+  int lubLength = max(leftLength, rightLength);
+  int lubUns = max(leftUns, rightUns);
+
+  // put them back together
+  static SimpleTypeId const map[3 /*length*/][2 /*unsignedness*/] = {
+    { ST_INT,           ST_UNSIGNED_INT },
+    { ST_LONG_INT,      ST_UNSIGNED_LONG_INT },
+    { ST_LONG_LONG,     ST_UNSIGNED_LONG_LONG }
+  };
+  SimpleTypeId lubId = map[lubLength][lubUns];
+  
+  return lubId;
+}
+
+
+// cppstd 4.5
+SimpleTypeId applyIntegralPromotions(Type *t)
+{
+  // since I only promote to 'int', this is easy
+
+  if (!t->isSimpleType()) {    // enumerations, mainly
+    return ST_INT;
+  }
+  SimpleTypeId id = t->asSimpleTypeC()->type;
+  
+  return applyIntegralPromotions(id);
+}
+
+SimpleTypeId applyIntegralPromotions(SimpleTypeId id)
+{
+  switch (id) {
+    case ST_CHAR:
+    case ST_SIGNED_CHAR:
+    case ST_UNSIGNED_CHAR:
+    case ST_SHORT_INT:
+    case ST_UNSIGNED_SHORT_INT:
+    case ST_WCHAR_T:
+    case ST_BOOL:
+      return ST_INT;    // promote smaller integer values
+
+    default:
+      return id;        // keep everything else
+  }
+}
+
+
+void test_getStandardConversion(
+  Env &env, SpecialExpr special, Type const *src, Type const *dest,
+  int expected)
+{
+  // run our function
+  string errorMsg;
+  StandardConversion actual = getStandardConversion(&errorMsg, special, src, dest);
+
+  // turn any resulting messags into warnings, so I can see their
+  // results without causing the final exit status to be nonzero
+  if (actual == SC_ERROR) {
+    env.warning(errorMsg);
+  }
+
+  // did the function do what we expected?
+  if (actual != expected) {
+    // no, explain the situation
+    env.error(stringc
+      << "getStandardConversion("
+      << toString(special) << ", `"
+      << src->toString() << "', `"
+      << dest->toString() << "') yielded "
+      << toString(actual) << ", but I expected "
+      << toString((StandardConversion)expected));
+  }
+  else if (tracingSys("gSC")) {
+    // make a warning to show what happened anyway
+    env.warning(stringc
+      << "getStandardConversion("
+      << toString(special) << ", `"
+      << src->toString() << "', `"
+      << dest->toString() << "') yielded "
+      << toString(actual));
+  }
+}
+
+
+// ------------------- reference-relatedness ------------------
+bool isReferenceRelatedTo(Type *t1, Type *t2)
+{
+  // ignoring toplevel cv-qualification, either t1 and t2 must be
+  // the same type, or they must be classes and t1 must be a base
+  // class of t2
+
+  // this sometimes ends up with t2 being polymorphic, so it goes first
+  if (t2->equals(t1, MF_IGNORE_TOP_CV | MF_POLYMORPHIC)) {
+    return true;
+  }
+  
+  // this implicitly skips toplevel cv
+  if (t1->isCompoundType() &&
+      t2->isCompoundType() &&
+      t2->asCompoundType()->hasBaseClass(t1->asCompoundType())) {
+    return true;
+  }
+
+  return false;
+}
+
+
+int referenceCompatibility(Type *t1, Type *t2)
+{
+  if (!isReferenceRelatedTo(t1, t2)) {
+    return 0;      // not even related
+  }
+
+  // get the toplevel cv flags
+  CVFlags cv1 = t1->getCVFlags();
+  CVFlags cv2 = t2->getCVFlags();
+
+  if (cv1 == cv2) {
+    return 2;      // exact match
+  }
+  
+  if (cv1 & cv2 == cv2) {
+    // cv1 is a superset
+    return 1;      // "compatible with added qualification"
+  }
+  
+  return 0;        // not compatible
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/stdconv.h
===================================================================
--- vendor/elsa/current/elsa/stdconv.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/stdconv.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,150 @@
+// stdconv.h                       see license.txt for copyright and terms of use
+// Standard Conversions, i.e. Section ("clause") 4 of cppstd
+
+// A Standard Conversion is one of a dozen or so type coercions
+// described in section 4 of cppstd.  A Standard Conversion Sequence
+// is up to three Standard Conversions, drawn from particular
+// subsets of such conversions, to be applied in sequence.
+
+// Standard Conversions are the kinds of conversions that can be
+// done implicitly (no explicit conversion or cast syntax), short
+// of user-defined constructors and conversions.
+
+// Note that in my system, there is nothing directly called an
+// "lvalue", rather there are simply references and non-references.
+
+#ifndef STDCONV_H
+#define STDCONV_H
+
+#include "macros.h"    // ENUM_BITWISE_AND,OR
+#include "str.h"       // string
+#include "cc_flags.h"  // SpecialExpr
+
+// fwd
+class Type;            // cc_type.h
+class Env;             // cc_env.h
+class TypeFactory;     // cc_type.h
+
+// The kinds of Standard Conversions.  Any given pair of convertible
+// types will be related by the conversions permitted as one or more
+// of the following kinds.  ORing together zero or one conversion from
+// each group yields a Standard Conversion Sequence.  The encoding is
+// designed to fit into a single byte so that CompressedImplicitConversion
+// can fit into 8 bytes (7/30/04: that class is now gone, but I still
+// like the tight encoding).
+enum StandardConversion {
+  SC_IDENTITY        = 0x00,  // types are identical
+
+  // conversion group 1 (comes first)
+  SC_LVAL_TO_RVAL    = 0x01,  // 4.1: int& -> int
+  SC_ARRAY_TO_PTR    = 0x02,  // 4.2: char[] -> char*
+  SC_FUNC_TO_PTR     = 0x03,  // 4.3: int ()(int) -> int (*)(int)
+  SC_GROUP_1_MASK    = 0x03,
+
+  // conversion group 3 (comes last conceptually)
+  SC_QUAL_CONV       = 0x04,  // 4.4: int* -> int const*
+  SC_GROUP_3_MASK    = 0x04,
+
+  // conversion group 2 (goes in the middle)
+  SC_INT_PROM        = 0x10,  // 4.5: int... -> int..., no info loss possible
+  SC_FLOAT_PROM      = 0x20,  // 4.6: float -> double, no info loss possible
+  SC_INT_CONV        = 0x30,  // 4.7: int... -> int..., info loss possible
+  SC_FLOAT_CONV      = 0x40,  // 4.8: float... -> float..., info loss possible
+  SC_FLOAT_INT_CONV  = 0x50,  // 4.9: int... <-> float..., info loss possible
+  SC_PTR_CONV        = 0x60,  // 4.10: 0 -> Foo*, Child* -> Parent*
+  SC_PTR_MEMB_CONV   = 0x70,  // 4.11: int Child::* -> int Parent::*
+  SC_BOOL_CONV       = 0x80,  // 4.12: various types <-> bool
+  SC_DERIVED_TO_BASE = 0x90,  // 13.3.3.1p6: Child -> Parent
+  SC_GROUP_2_MASK    = 0xF0,
+
+  SC_ERROR           = 0xFF,  // cannot convert
+};
+
+// for '&', one of the arguments should always be a mask
+ENUM_BITWISE_AND(StandardConversion)                    
+
+// for '|', some care should be taken to ensure you're not
+// ORing together nonzero elements from the same group
+ENUM_BITWISE_OR(StandardConversion)
+
+// allow creation of masks for turning off bits
+ENUM_BITWISE_NOT(StandardConversion, SC_ERROR);
+
+// render in C++ syntax as bitwise OR of the constants above
+string toString(StandardConversion c);
+
+
+// remove SC_LVAL_TO_RVAL from a conversion sequence
+StandardConversion removeLval(StandardConversion scs);
+
+// true if 'left' is a subsequence of 'right'
+bool isSubsequenceOf(StandardConversion left, StandardConversion right);
+
+
+// standard conversion rank, as classified by cppstd Table 9
+// (section 13.3.3.1.1 para 3)
+enum SCRank {
+  SCR_EXACT,
+  SCR_PROMOTION,
+  SCR_CONVERSION,
+  NUM_SCRANKS
+};
+
+SCRank getRank(StandardConversion scs);
+
+
+// given two types, determine the Standard Conversion Sequence,
+// if any, that will convert 'src' into 'dest'
+StandardConversion getStandardConversion(
+  string *errorMsg,    // if non-null, failed conversion sets error message
+  SpecialExpr special, // properties of the source expression
+  Type const *src,     // source type
+  Type const *dest,    // destination type
+  
+  // when the dest type is a method receiver ('this') parameter,
+  // it's allowable to bind an rvalue to a non-const reference
+  // (13.3.1 para 5 bullet 3)
+  bool destIsReceiver = false
+);
+
+
+// reverse-engineer a previous conversion that involved a
+// polymorphic destination type
+Type *getConcreteDestType(TypeFactory &tfac, Type *srcType,
+                          StandardConversion sconv,
+                          SimpleTypeId destPolyType);
+
+// cppstd section 5, para 9
+Type *usualArithmeticConversions(TypeFactory &tfac, Type *left, Type *right);
+SimpleTypeId usualArithmeticConversions(SimpleTypeId leftId, SimpleTypeId rightId);
+
+// cppstd 4.5
+SimpleTypeId applyIntegralPromotions(Type *t);
+SimpleTypeId applyIntegralPromotions(SimpleTypeId id);
+
+
+// testing interface, for use by the type checker
+void test_getStandardConversion(
+  Env &env, SpecialExpr special, Type const *src, Type const *dest,
+  int expected     // expected return value
+);
+
+
+// reference-relatedness (8.5.3 para 4)
+
+// "is t1 reference-related to t2?"  (both types have already had their
+// references stripped)  NOTE: this relation is *not* symmetric!
+bool isReferenceRelatedTo(Type *t1, Type *t2);
+
+// determine which of three reference-compatilibity conditions exist:
+//   0: not compatible
+//   1: compatible with added qualification
+//   2: compatible exactly
+int referenceCompatibility(Type *t1, Type *t2);
+
+// "is t1 reference-compatible (possibly with added qual) with t2?"
+inline bool isReferenceCompatibleWith(Type *t1, Type *t2)
+  { return referenceCompatibility(t1, t2) != 0; }
+
+  
+#endif // STDCONV_H

Added: vendor/elsa/current/elsa/strmap.h
===================================================================
--- vendor/elsa/current/elsa/strmap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/strmap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+// strmap.h
+// PtrMap using StringRef as key
+
+#ifndef STRMAP_H
+#define STRMAP_H
+
+#include "strtable.h"     // StringRef
+#include "ptrmap.h"       // PtrMap
+#include "strutil.h"      // qsortStringArray()
+
+// The 'KEY' argument to PtrMap is "char const" because it implicitly
+// adds a "*", so the actual key is "char const *", i.e. StringRef.
+// But note that the keys really have to be StringRef, not just any
+// char*, because PtrMap relies on the unique-representative property.
+template <class VALUE>
+class StringRefMap : public PtrMap<char const, VALUE> {
+  public:
+  // Iterate over the map in sorted order by the keys
+  class SortedKeyIter {
+  private:     // data
+    // underlying iterator state
+    StringRefMap<VALUE> const &map;
+    int keyIndex;
+    // dsw: I think it is a mistake to use getNumEntries() repeatedly
+    // instead of caching the value that it was at the time the
+    // iterator was constructed.  While we are still not thread-safe
+    // in the sense that an entry could be added or deleted, we could
+    // catch that, but we still do not want to separate the array of
+    // sortedKeys from its length as if these get out of synch this is
+    // an impossible bug to catch and a very low-level error.  Note
+    // that we still have a bit of a race condidition that numEntries
+    // is initialized before we iterate over the keys, but we are
+    // likely to catch that later.
+    int const numEntries;
+    char const **sortedKeys;    // array of strings
+
+  public:      // fucs
+    SortedKeyIter(StringRefMap<VALUE> const &map0)
+      : map(map0)
+      , keyIndex(0)
+      , numEntries(map.getNumEntries())
+      , sortedKeys(new char const *[numEntries])
+    {
+      int i = 0;
+      // delegate to the other Iter class
+      for(typename PtrMap<char const, VALUE>::Iter iter0(map); !iter0.isDone(); iter0.adv()) {
+//          xassert(i<numEntries);
+        sortedKeys[i++] = iter0.key();
+      }
+      xassert(numEntries == i);
+      qsortStringArray(sortedKeys, numEntries);
+    }
+    ~SortedKeyIter() {
+      delete [] sortedKeys;
+    }
+
+    bool isDone() const  { return keyIndex == numEntries; }
+    void adv()           { ++keyIndex; }
+
+    // return information about the currently-referenced table entry
+    char const *key() const {
+      char const *key0 = sortedKeys[keyIndex];
+      xassert(map.get(key0));
+      return key0;
+    }
+    VALUE *value() const { return map.get(key()); }
+  };
+  //   friend class SortedKeyIter;
+};
+
+#endif // STRMAP_H

Added: vendor/elsa/current/elsa/template.cc
===================================================================
--- vendor/elsa/current/elsa/template.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/template.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5132 @@
+// template.cc
+// template stuff implementation; code for template.h, and for
+// the template section of cc_env.h at the end of Env
+
+#include "template.h"      // this module
+#include "cc_env.h"        // also kind of this module
+#include "cc_print.h"      // CTypePrinter
+#include "trace.h"         // tracingSys
+#include "strtable.h"      // StringTable
+#include "cc_lang.h"       // CCLang
+#include "strutil.h"       // pluraln
+#include "overload.h"      // selectBestCandidate_templCompoundType
+#include "typelistiter.h"  // TypeListIter
+#include "cc_ast_aux.h"    // LoweredASTVisitor
+#include "mtype.h"         // MType
+#include "pair.h"          // pair
+
+
+void copyTemplateArgs(ObjList<STemplateArgument> &dest,
+                      ObjList<STemplateArgument> const &src)
+{
+  copyTemplateArgs(dest, objToSObjListC(src));
+}
+
+void copyTemplateArgs(ObjList<STemplateArgument> &dest,
+                      SObjList<STemplateArgument> const &src)
+{
+  if (dest.isEmpty()) {
+    // use prepend/reverse
+    SFOREACH_OBJLIST(STemplateArgument, src, iter) {
+      dest.prepend(new STemplateArgument(*(iter.data())));
+    }
+    dest.reverse();
+  }
+  else {
+    // just do the normal thing..
+    SFOREACH_OBJLIST(STemplateArgument, src, iter) {
+      dest.append(new STemplateArgument(*(iter.data())));
+    }
+  }
+}
+
+
+// Is it ok to call into these routines right now?  This is
+// part of a migration scheme, where dsw wants to ensure that
+// these routines aren't used in some contexts.
+static void checkOkToBeHere()
+{
+  if (!global_mayUseTypeAndVarToCString) {
+    xfailure("suspended during CTypePrinter::print");
+  }
+}
+
+
+// ------------------ TypeVariable ----------------
+TypeVariable::~TypeVariable()
+{}
+
+
+string TypeVariable::toCString() const
+{
+  checkOkToBeHere();
+
+  if (!name) {
+    return "/""*anon*/";
+  }
+
+  // use the "typename" syntax instead of "class", to distinguish
+  // this from an ordinary class, and because it's syntax which
+  // more properly suggests the ability to take on *any* type,
+  // not just those of classes
+  //
+  // but, the 'typename' syntax can only be used in some specialized
+  // circumstances.. so I'll suppress it in the general case and add
+  // it explicitly when printing the few constructs that allow it
+  //
+  // 8/09/04: sm: truncated down to just the name, since the extra
+  // clutter was annoying and not that helpful
+  return stringc //<< "/""*typevar"
+//                   << "typedefVar->serialNumber:"
+//                   << (typedefVar ? typedefVar->serialNumber : -1)
+                 //<< "*/"
+                 << name;
+}
+
+int TypeVariable::reprSize() const
+{
+  //xfailure("you can't ask a type variable for its size");
+
+  // this happens when we're typechecking a template class, without
+  // instantiating it, and we want to verify that some size expression
+  // is constant.. so make up a number
+  return 4;
+}
+
+
+void TypeVariable::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitAtomicType(this)) {
+    return;
+  }
+  vis.postvisitAtomicType(this);
+}
+
+
+bool TypeVariable::isAssociated() const
+{
+  return typedefVar->getParameterizedEntity() != NULL;
+}
+
+
+// -------------------- PseudoInstantiation ------------------
+PseudoInstantiation::PseudoInstantiation(CompoundType *p)
+  : NamedAtomicType(p? p->name : NULL),
+    primary(p),
+    args()        // empty initially
+{}
+
+PseudoInstantiation::~PseudoInstantiation()
+{}
+
+
+string PseudoInstantiation::toCString() const
+{
+  checkOkToBeHere();
+  return stringc << name << sargsToString(args);
+}
+
+int PseudoInstantiation::reprSize() const
+{
+  // it shouldn't matter what we say here, since the query will only
+  // be made in the context of checking (but not instantiating) a
+  // template definition body
+  return 4;
+}
+
+
+void PseudoInstantiation::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitAtomicType(this)) {
+    return;
+  }
+
+  primary->traverse(vis);
+
+  if (vis.visitPseudoInstantiation_args(args)) {
+    FOREACH_OBJLIST_NC(STemplateArgument, args, iter) {
+      STemplateArgument *arg = iter.data();
+      if (vis.visitPseudoInstantiation_args_item(arg)) {
+        arg->traverse(vis);
+        vis.postvisitPseudoInstantiation_args_item(arg);
+      }
+    }
+    vis.postvisitPseudoInstantiation_args(args);
+  }
+
+  vis.postvisitAtomicType(this);
+}
+
+
+// -------------------- DependentQType ------------------
+DependentQType::DependentQType(AtomicType *f)
+  : NamedAtomicType(NULL /*name*/),    // gets changed later
+    first(f),
+    rest()
+{}
+
+DependentQType::~DependentQType()
+{}
+
+
+bool dqt_toString_failWhenRestIsNull = false;
+string DependentQType::toCString() const
+{
+  checkOkToBeHere();
+  xassert(first);
+
+//   xassert(rest && "b6160580-54bb-4f08-a032-a69eb4791f3b");
+//   return stringc << first->toCString() << "::" << rest->toString();
+
+  // dsw: in Oink when I serialize and then de-serialize without the
+  // AST, these few links from the Typesystem into the AST are lost;
+  // therefore I need to allow them to be missing
+  if (dqt_toString_failWhenRestIsNull) {
+    xassert(rest && "b6160580-54bb-4f08-a032-a69eb4791f3b");
+  }
+  return stringc << first->toCString() << "::" << (rest ? rest->toString() : "<*unknown*>");
+}
+
+string DependentQType::toMLString() const
+{
+  return stringc << "dependentqtype-" << toCString();
+}
+
+int DependentQType::reprSize() const
+{
+  return 4;    // should not matter
+}
+
+
+void traverseTargs(TypeVisitor &vis, ObjList<STemplateArgument> &list)
+{
+  if (vis.visitDependentQTypePQTArgsList(list)) {
+    FOREACH_OBJLIST_NC(STemplateArgument, list, iter) {
+      STemplateArgument *sta = iter.data();
+      if (vis.visitDependentQTypePQTArgsList_item(sta)) {
+        sta->traverse(vis);
+        vis.postvisitDependentQTypePQTArgsList_item(sta);
+      }
+    }
+    vis.postvisitDependentQTypePQTArgsList(list);
+  }
+}
+
+void DependentQType::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitAtomicType(this)) {
+    return;
+  }
+
+  first->traverse(vis);
+
+  PQName *name = rest;
+  while (name->isPQ_qualifier()) {
+    PQ_qualifier *qual = name->asPQ_qualifier();
+
+    traverseTargs(vis, qual->sargs);
+    name = qual->rest;
+  }
+
+  if (name->isPQ_template()) {
+    traverseTargs(vis, name->asPQ_template()->sargs);
+  }
+
+  vis.postvisitAtomicType(this);
+}
+
+
+// ------------------ TemplateParams ---------------
+TemplateParams::TemplateParams(TemplateParams const &obj)
+  : params(obj.params)
+{}
+
+TemplateParams::~TemplateParams()
+{}
+
+
+string TemplateParams::paramsToCString() const
+{
+  return ::paramsToCString(params);
+}
+
+string paramsToCString(SObjList<Variable> const &params)
+{
+  stringBuilder sb;
+  sb << "template <";
+  int ct=0;
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    Variable const *p = iter.data();
+    if (ct++ > 0) {
+      sb << ", ";
+    }
+
+    if (p->isTemplateTypeParam()) {
+      if (p->name) {
+        sb << "class " << p->name;
+        StringRef tvName = p->type->asTypeVariable()->name;
+        if (tvName && tvName != p->name) {
+          // this should never happen, but if it does then I just want
+          // it to be visible, not (directly) cause a crash
+          sb << " /""* but type name is " << tvName << "! */";
+        }
+      }
+      else {
+        sb << "class /""*anon*/";
+      }
+    }
+    else {
+      // non-type parameter
+      sb << p->toCStringAsParameter();
+    }
+  }
+  sb << ">";
+  return sb;
+}
+
+
+string TemplateParams::paramsLikeArgsToString() const
+{
+  stringBuilder sb;
+  sb << "<";
+  int ct=0;
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    if (ct++) { sb << ", "; }
+    StringRef n = iter.data()->name;
+
+    if (n) {
+      sb << n;
+    }
+    else {
+      sb << "/""*anon*/";
+    }
+  }
+  sb << ">";
+  return sb;
+}
+
+
+// defined in cc_type.cc
+bool parameterListCtorSatisfies(TypePred &pred,
+                                SObjList<Variable> const &params);
+
+bool TemplateParams::anyParamCtorSatisfies(TypePred &pred) const
+{
+  return parameterListCtorSatisfies(pred, params);
+}
+
+
+// --------------- InheritedTemplateParams ---------------
+InheritedTemplateParams::InheritedTemplateParams(InheritedTemplateParams const &obj)
+  : TemplateParams(obj),
+    enclosing(obj.enclosing)
+{}
+
+InheritedTemplateParams::~InheritedTemplateParams()
+{}
+
+
+// ------------------ TemplateInfo -------------
+TemplateInfo::TemplateInfo(SourceLoc il, Variable *v)
+  : TemplateParams(),
+    var(NULL),
+    instantiationOf(NULL),
+    instantiations(),
+    specializationOf(NULL),
+    specializations(),
+    arguments(),
+    instLoc(il),
+    partialInstantiationOf(NULL),
+    partialInstantiations(),
+    argumentsToPrimary(),
+    defnScope(NULL),
+    definitionTemplateInfo(NULL),
+    instantiateBody(false),
+    instantiationDisallowed(false),
+    uninstantiatedDefaultArgs(0),
+    dependentBases()
+{
+  if (v) {
+    // this sets 'this->var' too
+    v->setTemplateInfo(this);
+  }
+}
+
+
+// this is called by Env::makeUsingAliasFor ..
+TemplateInfo::TemplateInfo(TemplateInfo const &obj)
+  : TemplateParams(obj),
+    var(NULL),                // caller must call Variable::setTemplateInfo
+    instantiationOf(NULL),
+    instantiations(obj.instantiations),      // suspicious... oh well
+    specializationOf(NULL),
+    specializations(obj.specializations),    // also suspicious
+    arguments(),                             // copied below
+    instLoc(obj.instLoc),
+    partialInstantiationOf(NULL),
+    partialInstantiations(),
+    argumentsToPrimary(),                    // copied below
+    defnScope(NULL),
+    definitionTemplateInfo(NULL),
+    instantiateBody(false),
+    uninstantiatedDefaultArgs(obj.uninstantiatedDefaultArgs),
+    dependentBases(obj.dependentBases)
+{
+  // inheritedParams
+  FOREACH_OBJLIST(InheritedTemplateParams, obj.inheritedParams, iter2) {
+    inheritedParams.prepend(new InheritedTemplateParams(*(iter2.data())));
+  }
+  inheritedParams.reverse();
+
+  // arguments
+  copyArguments(obj.arguments);
+
+  // argumentsToPrimary
+  copyTemplateArgs(argumentsToPrimary, objToSObjListC(obj.argumentsToPrimary));
+}
+
+
+TemplateInfo::~TemplateInfo()
+{
+  if (definitionTemplateInfo) {
+    delete definitionTemplateInfo;
+  }
+}
+
+
+TemplateThingKind TemplateInfo::getKind() const
+{
+  if (!instantiationOf && !specializationOf) {
+    if (!isPartialInstantiation()) {
+      xassert(arguments.isEmpty());
+    }
+    xassert(hasMainOrInheritedParameters());
+    return TTK_PRIMARY;
+  }
+
+  // specialization or instantiation
+  xassert(arguments.isNotEmpty());
+
+  if (specializationOf) {
+    return TTK_SPECIALIZATION;
+  }
+  else {
+    xassert(instantiationOf);
+    return TTK_INSTANTIATION;
+  }
+}
+
+
+bool TemplateInfo::isPartialSpec() const
+{
+  return isSpecialization() &&
+         hasParameters();
+}
+
+bool TemplateInfo::isCompleteSpec() const
+{
+  return isSpecialization() &&
+         !hasMainOrInheritedParameters();
+}
+
+
+bool TemplateInfo::isCompleteSpecOrInstantiation() const
+{
+  return isNotPrimary() &&
+         !hasMainOrInheritedParameters();
+}
+
+
+bool TemplateInfo::isInstOfPartialSpec() const
+{
+  return isInstantiation() &&
+         instantiationOf->templateInfo()->isPartialSpec();
+}
+
+
+// this is idempotent
+TemplateInfo const *TemplateInfo::getPrimaryC() const
+{
+  if (instantiationOf) {
+    return instantiationOf->templateInfo()->getPrimaryC();
+  }
+  else if (specializationOf) {
+    return specializationOf->templateInfo();     // always only one level
+  }
+  else {
+    return this;
+  }
+}
+
+
+void TemplateInfo::addToList(Variable *elt, SObjList<Variable> &children,
+                             Variable * const &parentPtr)
+{
+  // the key to this routine is casting away the constness of
+  // 'parentPtr'; it's the one routine entitled to do so
+  Variable * &parent = const_cast<Variable*&>(parentPtr);
+
+  // add to list, ensuring (if in debug mode) it isn't already there
+  xassertdb(!children.contains(elt));
+  children.append(elt);             // could use 'prepend' for performance..
+
+  // backpointer, ensuring we don't overwrite one
+  xassert(!parent);
+  xassert(this->var);
+  parent = this->var;
+}
+
+void TemplateInfo::addInstantiation(Variable *inst)
+{
+  addToList(inst, instantiations,
+            inst->templateInfo()->instantiationOf);
+}
+
+void TemplateInfo::addSpecialization(Variable *inst)
+{
+  addToList(inst, specializations,
+            inst->templateInfo()->specializationOf);
+}
+
+void TemplateInfo::addPartialInstantiation(Variable *pinst)
+{
+  addToList(pinst, partialInstantiations,
+            pinst->templateInfo()->partialInstantiationOf);
+}
+
+
+void TemplateInfo::changeToExplicitSpec()
+{
+  xassert(isInstantiation());
+
+  TemplateInfo *primary = getPrimary();
+
+  // remove myself from the primary's list of instantiations
+  primary->instantiations.removeItem(this->var);
+  const_cast<Variable*&>(instantiationOf) = NULL;
+
+  // add myself to the primary's list of explicit specs
+  primary->addSpecialization(this->var);
+
+  xassert(isCompleteSpec());
+}
+
+
+ObjList<STemplateArgument> &TemplateInfo::getArgumentsToPrimary()
+{
+  if (isInstOfPartialSpec()) {
+    return argumentsToPrimary;
+  }
+  else {
+    return arguments;
+  }
+}
+
+
+bool isomorphicArgumentLists(ObjList<STemplateArgument> const &list1,
+                             ObjList<STemplateArgument> const &list2)
+{
+  MType mtype;
+  return mtype.matchSTemplateArguments(list1, list2, MF_ISOMORPHIC|MF_MATCH);
+}
+
+bool TemplateInfo::isomorphicArguments(ObjList<STemplateArgument> const &list) const
+{
+  return isomorphicArgumentLists(arguments, list);
+}
+
+
+bool equalArgumentLists(ObjList<STemplateArgument> const &list1,
+                        ObjList<STemplateArgument> const &list2,
+                        MatchFlags mflags)
+{
+  MType mtype;
+  return mtype.matchSTemplateArguments(list1, list2, mflags);
+}
+
+bool TemplateInfo::equalArguments(ObjList<STemplateArgument> const &list,
+                                  MatchFlags mflags) const
+{
+  return equalArgumentLists(arguments, list, mflags);
+}
+
+
+bool TemplateInfo::argumentsContainTypeVariables() const
+{
+  FOREACH_OBJLIST(STemplateArgument, arguments, iter) {
+    STemplateArgument const *sta = iter.data();
+    if (sta->kind == STemplateArgument::STA_TYPE) {
+      if (sta->value.t->containsTypeVariables()) return true;
+    }
+    // FIX: do other kinds
+  }
+  return false;
+}
+
+
+bool TemplateInfo::argumentsContainVariables() const
+{
+  FOREACH_OBJLIST(STemplateArgument, arguments, iter) {
+    if (iter.data()->containsVariables()) return true;
+  }
+  return false;
+}
+
+
+bool TemplateInfo::hasParameters() const
+{
+  if (isPartialInstantiation()) {
+    return true;
+  }
+
+  // check params attached directly to this object
+  if (params.isNotEmpty()) {
+    return true;
+  }
+
+  return false;
+}
+
+int TemplateInfo::countInheritedParameters() const
+{
+  int ct=0;
+  FOREACH_OBJLIST(InheritedTemplateParams, inheritedParams, iter) {
+    ct += iter.data()->params.count();
+  }
+  return ct;
+}
+
+bool TemplateInfo::hasMainOrInheritedParameters() const
+{
+  return hasParameters() ||
+         hasInheritedParameters();
+}
+
+bool TemplateInfo::hasParametersEx(bool considerInherited) const
+{
+  return considerInherited?
+           hasMainOrInheritedParameters() :
+           hasParameters();
+}
+
+
+Variable *TemplateInfo::getSpecialization(ObjList<STemplateArgument> const &sargs)
+{
+  SFOREACH_OBJLIST_NC(Variable, specializations, iter) {
+    TemplateInfo *specTI = iter.data()->templateInfo();
+    if (isomorphicArgumentLists(specTI->arguments, sargs)) {
+      return iter.data();
+    }
+  }
+  return NULL;     // not found
+}
+
+
+bool TemplateInfo::hasSpecificParameter(Variable const *v) const
+{
+  // 'params'?
+  if (params.contains(v)) { return true; }
+
+  // inherited?
+  FOREACH_OBJLIST(InheritedTemplateParams, inheritedParams, iter) {
+    if (iter.data()->params.contains(v)) {
+      return true;
+    }
+  }
+
+  return false;     // 'v' does not appear in any parameter list
+}
+
+
+void TemplateInfo::copyArguments(ObjList<STemplateArgument> const &sargs)
+{
+  copyTemplateArgs(arguments, objToSObjListC(sargs));
+}
+
+void TemplateInfo::copyArguments(SObjList<STemplateArgument> const &sargs)
+{
+  copyTemplateArgs(arguments, sargs);
+}
+
+
+void TemplateInfo::prependArguments(ObjList<STemplateArgument> const &sargs)
+{
+  // save the existing arguments (if any)
+  ObjList<STemplateArgument> existing;
+  existing.concat(arguments);
+
+  // put the new ones in
+  copyTemplateArgs(arguments, objToSObjListC(sargs));
+
+  // put the old ones at the end
+  arguments.concat(existing);
+}
+
+
+string TemplateInfo::templateName() const
+{
+  if (isPrimary()) {
+    return stringc << var->fullyQualifiedName0()
+                   << paramsLikeArgsToString();
+  }
+
+  if (isSpecialization()) {
+    return stringc << var->fullyQualifiedName0()
+                   << sargsToString(arguments);
+  }
+
+  #if 0    // seems like this isn't needed anymore
+  // instantiation; but of the primary or of a specialization?
+  TemplateInfo *parentTI = instantiationOf->templateInfo();
+  if (parentTI->isPrimary()) {
+    return stringc << var->fullyQualifiedName()
+                   << sargsToString(arguments);
+  }
+  else {
+    // spec params + inst args, e.g. "A<T*><int>" to mean that
+    // this is an instantiation of spec "A<T*>" with args "<int>",
+    // i.e. original arguments "<int*>"
+    return stringc << var->fullyQualifiedName()
+                   << sargsToString(parentTI->arguments)
+                   << sargsToString(arguments);
+  }
+  #endif // 0
+
+  return var->fullyQualifiedName0();
+}
+
+
+void TemplateInfo::traverseArguments(TypeVisitor &vis)
+{
+  FOREACH_OBJLIST_NC(STemplateArgument, arguments, iter) {
+    iter.data()->traverse(vis);
+  }
+}
+
+
+void TemplateInfo::gdb()
+{
+  debugPrint(0);
+}
+
+
+void TemplateInfo::debugPrint(int depth, bool printPartialInsts)
+{
+  ind(cout, depth*2) << "TemplateInfo for "
+                     << (var? var->name : "(null var)") << " {" << endl;
+
+  depth++;
+
+  if (isPartialInstantiation()) {
+    // the template we are a partial instantiation of has all the
+    // parameter info, so print it; but then *it* better not turn
+    // around and print its partial instantiation list, otherwise we
+    // get an infinite loop!  (discovered the hard way...)
+    ind(cout, depth*2) << "partialInstantiatedFrom:\n";
+    partialInstantiationOf->templateInfo()->
+      debugPrint(depth+1, false /*printPartialInsts*/);
+  }
+
+  // inherited params
+  FOREACH_OBJLIST(InheritedTemplateParams, inheritedParams, iter) {
+    ind(cout, depth*2) << "inherited from " << iter.data()->enclosing->name
+                       << ": " << iter.data()->paramsToCString() << endl;
+  }
+
+  // my params
+  ind(cout, depth*2) << "params: " << paramsToCString() << endl;
+
+  ind(cout, depth*2) << "arguments:" << endl;
+  FOREACH_OBJLIST_NC(STemplateArgument, arguments, iter) {
+    iter.data()->debugPrint(depth+1);
+  }
+
+  ind(cout, depth*2) << "instantiations:" << endl;
+  depth++;
+  SFOREACH_OBJLIST_NC(Variable, instantiations, iter) {
+    Variable *var = iter.data();
+    ind(cout, depth*2) << var->type->toString() << endl;
+    var->templateInfo()->debugPrint(depth+1);
+  }
+  depth--;
+
+  if (printPartialInsts) {
+    ind(cout, depth*2) << "partial instantiations:" << endl;
+    depth++;
+    SFOREACH_OBJLIST_NC(Variable, partialInstantiations, iter) {
+      Variable *var = iter.data();
+      ind(cout, depth*2) << var->toString() << endl;
+      var->templateInfo()->debugPrint(depth+1);
+    }
+    depth--;
+  }
+
+  depth--;
+
+  ind(cout, depth*2) << "}" << endl;
+}
+
+
+// ------------------- STemplateArgument ---------------
+STemplateArgument::STemplateArgument(STemplateArgument const &obj)
+  : kind(obj.kind)
+{
+  if (kind == STA_TYPE) {
+    value.t = obj.value.t;
+  }
+  else if (kind == STA_INT) {
+    value.i = obj.value.i;
+  }
+  else {
+    value.v = obj.value.v;
+  }
+}
+
+
+STemplateArgument *STemplateArgument::shallowClone() const
+{
+  return new STemplateArgument(*this);
+}
+
+
+bool STemplateArgument::isObject() const
+{
+  switch (kind) {
+  default:
+    xfailure("illegal STemplateArgument kind"); break;
+
+  case STA_TYPE:                // type argument
+    return false;
+
+  case STA_INT:                 // int
+  case STA_ENUMERATOR:          // enumerator
+  case STA_REFERENCE:           // reference to global object
+  case STA_POINTER:             // pointer to global object
+  case STA_MEMBER:              // pointer to class member
+  case STA_DEPEXPR:             // value-dependent expr
+    return true;
+
+  case STA_TEMPLATE:            // template argument (not implemented)
+    return false;
+  }
+}
+
+
+bool STemplateArgument::isDependent() const
+{
+  if (isType()) {
+    // we don't (or shouldn't...) stack constructors on top of
+    // ST_DEPENDENT, so just check at the top level
+    //
+    // 8/10/04: I had simply been calling Type::isDependent, but that
+    // answers yes for type variables.  In the context in which I'm
+    // calling this, I am only interested in '<dependent>'.  I realize
+    // this is a bit of a non-orthogonality, but the fix isn't clear
+    // at the moment.
+    return getType()->isSimple(ST_DEPENDENT);
+  }
+  else if (kind == STA_DEPEXPR) {
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+
+bool STemplateArgument::equals(STemplateArgument const *obj,
+                               MatchFlags mflags) const
+{
+  MType mtype;
+  return mtype.matchSTemplateArgument(this, obj, mflags);
+}
+
+
+bool STemplateArgument::containsVariables(MType *map) const
+{
+  if (kind == STemplateArgument::STA_TYPE) {
+    if (value.t->containsVariables(map)) {
+      return true;
+    }
+  }
+  else if (kind == STA_DEPEXPR) {
+    // TODO: This is wrong because the variables might be bound
+    // in 'map'.  I think a reasonable solution would be to
+    // rehabilitate the TypeVisitor, and design a nice way for
+    // a TypeVisitor and an ASTVisitor to talk to each other.
+    return true;
+  }
+
+  return false;
+}
+
+
+bool STemplateArgument::isomorphic(STemplateArgument const *obj) const
+{
+  return equals(obj, MF_ISOMORPHIC|MF_MATCH);
+}
+
+
+void STemplateArgument::traverse(TypeVisitor &vis)
+{
+  if (!vis.visitSTemplateArgument(this)) {
+    return;
+  }
+
+  // dsw: WARNING: This partial implementation is a problem.  The
+  // cases that are not handled here are handled manually in
+  // cc_type_xml.cc.  If you add cases here you have to take them out
+  // there.
+  switch (kind) {
+    case STA_TYPE:
+      value.t->traverse(vis);
+      break;
+
+    case STA_DEPEXPR:
+      // TODO: at some point I will have to store actual expressions,
+      // and then I should traverse the expr
+      break;
+
+    default:
+      break;
+  }
+
+  vis.postvisitSTemplateArgument(this);
+}
+
+
+// NOTE: if you change this function, also change
+// printSTemplateArgument() in cc_print.cc
+string STemplateArgument::toString() const
+{
+  switch (kind) {
+    default: xfailure("bad kind");
+    case STA_NONE:      return string("STA_NONE");
+    case STA_TYPE: {
+      // NOTE: this code used to say this:
+      //   return value.t->toString();   // assume 'type' if no comment
+      //
+      // FIX: not sure if this is a bug but there is no abstract value
+      // lying around to be printed here so we just print what we
+      // have; enable the normal type printer temporarily in order to
+      // do this
+      Restorer<bool> res0(CTypePrinter::enabled, true);
+      CTypePrinter typePrinter0;
+      stringBuilder sb;
+      StringBuilderOutStream sbout0(sb);
+      typePrinter0.print(sbout0, value.t, "" /*do not print "anon"*/);
+      return sb;
+    }
+    case STA_INT:       return stringc << "/*int*/ " << value.i;
+    case STA_ENUMERATOR:return stringc << "/*enum*/ " << value.v->name;
+    case STA_REFERENCE: return stringc << "/*ref*/ " << value.v->name;
+    case STA_POINTER:   xassert(value.v && "ed1f952c-dbf5-41bf-9778-d5b0c0bda5af");
+                        return stringc << "/*ptr*/ &" << value.v->name;
+    case STA_MEMBER:    return stringc
+      << "/*member*/ &" << value.v->scope->curCompound->name
+      << "::" << value.v->name;
+    case STA_DEPEXPR:   return getDepExpr()->exprToString();
+    case STA_TEMPLATE:  return string("template (?)");
+    case STA_ATOMIC:    return value.at->toString();
+  }
+}
+
+
+void STemplateArgument::gdb()
+{
+  debugPrint(0);
+}
+
+
+void STemplateArgument::debugPrint(int depth)
+{
+  for (int i=0; i<depth; ++i) cout << "  ";
+  cout << "STemplateArgument: " << toString() << endl;
+}
+
+
+SObjList<STemplateArgument> *cloneSArgs(SObjList<STemplateArgument> &sargs)
+{
+  SObjList<STemplateArgument> *ret = new SObjList<STemplateArgument>();
+  SFOREACH_OBJLIST_NC(STemplateArgument, sargs, iter) {
+    ret->append(iter.data());
+  }
+  return ret;
+}
+
+
+string sargsToString(SObjList<STemplateArgument> const &list)
+{
+  SObjListIter<STemplateArgument> iter(list);
+  return sargsToString(iter);
+}
+
+string sargsToString(SObjListIter<STemplateArgument> &iter)
+{
+  stringBuilder sb;
+  sb << "<";
+
+  int ct=0;
+  for (; !iter.isDone(); iter.adv()) {
+    if (ct++ > 0) {
+      sb << ", ";
+    }
+    sb << iter.data()->toString();
+  }
+
+  if (sb[sb.length()-1] == '>') {
+    sb << " ";    // avoid creating ">>"
+  }
+  sb << ">";
+  return sb;
+}
+
+
+// return true if the semantic template arguments in 'args' are not
+// all concrete
+bool containsVariables(SObjList<STemplateArgument> const &args, MType *map)
+{
+  SFOREACH_OBJLIST(STemplateArgument, args, iter) {
+    if (iter.data()->containsVariables(map)) {
+      return true;
+    }
+  }
+  return false;     // all are concrete
+}
+
+bool containsVariables(ObjList<STemplateArgument> const &args, MType *map)
+{
+  return containsVariables(objToSObjListC(args), map);
+}
+
+
+bool hasDependentArgs(SObjList<STemplateArgument> const &args)
+{
+  SFOREACH_OBJLIST(STemplateArgument, args, iter) {
+    if (iter.data()->isDependent()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+char const *toString(STemplateArgument::Kind k)
+{
+  static char const * const map[] = {
+    "STA_NONE",
+    "STA_TYPE",
+    "STA_INT",
+    "STA_ENUMERATOR",
+    "STA_REFERENCE",
+    "STA_POINTER",
+    "STA_MEMBER",
+    "STA_DEPEXPR",
+    "STA_TEMPLATE",
+    "STA_ATOMIC",
+  };
+  STATIC_ASSERT(TABLESIZE(map) == STemplateArgument::NUM_STA_KINDS);
+  xassert((unsigned)k < (unsigned)STemplateArgument::NUM_STA_KINDS);
+  return map[k];
+}
+
+
+// ---------------------- TemplCandidates ------------------------
+STATICDEF
+TemplCandidates::STemplateArgsCmp TemplCandidates::compareSTemplateArgs
+  (STemplateArgument const *larg, STemplateArgument const *rarg)
+{
+  // handle cases like t0583.cc
+  if (larg->kind == STemplateArgument::STA_DEPEXPR ||
+      rarg->kind == STemplateArgument::STA_DEPEXPR) {
+    // In general I think the STemplateArgument scheme does not
+    // handle non-type params well.  The design in cpp_er.html
+    // looks much better; someday I should implement it.
+
+    if (larg->kind == STemplateArgument::STA_DEPEXPR &&
+        rarg->kind == STemplateArgument::STA_DEPEXPR) {
+      // no structural checks for expressions
+      return STAC_INCOMPARABLE;
+    }
+
+    if (larg->kind == STemplateArgument::STA_DEPEXPR) {
+      // assume that the RHS is more specialized
+      //
+      // TODO (admission): I should be checking that the RHS has a
+      // compatible type, is a non-type argument, etc.
+      return STAC_RIGHT_MORE_SPEC;
+    }
+    else {
+      // symmetric
+      return STAC_LEFT_MORE_SPEC;
+    }
+  }
+
+  // SGM 2006-05-26: I believe this assertion simply reflects that
+  // other cases are not handled, rather than being a precondition.
+  xassert(larg->kind == rarg->kind);
+
+  switch(larg->kind) {
+  default:
+    xfailure("bad/unexpected/unimplemented TemplateArgument kind");
+    break;
+
+  case STemplateArgument::STA_TYPE: // type argument
+    {
+    // check if left is at least as specific as right
+    bool leftAtLeastAsSpec;
+    {
+      MType match;
+      if (match.matchType(larg->value.t, rarg->value.t, MF_MATCH)) {
+        leftAtLeastAsSpec = true;
+      } else {
+        leftAtLeastAsSpec = false;
+      }
+    }
+    // check if right is at least as specific as left
+    bool rightAtLeastAsSpec;
+    {
+      MType match;
+      if (match.matchType(rarg->value.t, larg->value.t, MF_MATCH)) {
+        rightAtLeastAsSpec = true;
+      } else {
+        rightAtLeastAsSpec = false;
+      }
+    }
+
+    // change of basis matrix
+    if (leftAtLeastAsSpec) {
+      if (rightAtLeastAsSpec) {
+        return STAC_EQUAL;
+      } else {
+        return STAC_LEFT_MORE_SPEC;
+      }
+    } else {
+      if (rightAtLeastAsSpec) {
+        return STAC_RIGHT_MORE_SPEC;
+      } else {
+        return STAC_INCOMPARABLE;
+      }
+    }
+
+    }
+    break;
+
+  case STemplateArgument::STA_INT: // int or enum argument
+    if (larg->value.i == rarg->value.i) {
+      return STAC_EQUAL;
+    }
+    return STAC_INCOMPARABLE;
+    break;
+
+  case STemplateArgument::STA_ENUMERATOR: // reference to enumerator
+  case STemplateArgument::STA_REFERENCE: // reference to global object
+  case STemplateArgument::STA_POINTER: // pointer to global object
+  case STemplateArgument::STA_MEMBER: // pointer to class member
+    if (larg->value.v == rarg->value.v) {
+      return STAC_EQUAL;
+    }
+    return STAC_INCOMPARABLE;
+    break;
+  }
+}
+
+
+STATICDEF int TemplCandidates::compareCandidatesStatic
+  (TemplateInfo const *lti, TemplateInfo const *rti)
+{
+  // I do not even put the primary into the set so it should never
+  // show up.
+  xassert(lti->isNotPrimary());
+  xassert(rti->isNotPrimary());
+
+  // they should have the same primary
+  xassert(lti->getPrimaryC() == rti->getPrimaryC());
+
+  // they should always have the same number of arguments; the number
+  // of parameters is irrelevant
+  xassert(lti->arguments.count() == rti->arguments.count());
+
+  STemplateArgsCmp leaning = STAC_EQUAL;// which direction are we leaning?
+  // for each argument pairwise
+  ObjListIter<STemplateArgument> lIter(lti->arguments);
+  ObjListIter<STemplateArgument> rIter(rti->arguments);
+  for(;
+      !lIter.isDone();
+      lIter.adv(), rIter.adv()) {
+    STemplateArgument const *larg = lIter.data();
+    STemplateArgument const *rarg = rIter.data();
+    STemplateArgsCmp cmp = compareSTemplateArgs(larg, rarg);
+    switch(cmp) {
+    default: xfailure("illegal STemplateArgsCmp"); break;
+    case STAC_LEFT_MORE_SPEC:
+      if (leaning == STAC_EQUAL) {
+        leaning = STAC_LEFT_MORE_SPEC;
+      } else if (leaning == STAC_RIGHT_MORE_SPEC) {
+        leaning = STAC_INCOMPARABLE;
+      }
+      // left stays left and incomparable stays incomparable
+      break;
+    case STAC_RIGHT_MORE_SPEC:
+      if (leaning == STAC_EQUAL) {
+        leaning = STAC_RIGHT_MORE_SPEC;
+      } else if (leaning == STAC_LEFT_MORE_SPEC) {
+        leaning = STAC_INCOMPARABLE;
+      }
+      // right stays right and incomparable stays incomparable
+      break;
+    case STAC_EQUAL:
+      // all stay same
+      break;
+    case STAC_INCOMPARABLE:
+      leaning = STAC_INCOMPARABLE; // incomparable is an absorbing state
+    }
+  }
+  xassert(rIter.isDone());      // we checked they had the same number of arguments earlier
+
+  switch(leaning) {
+  default: xfailure("illegal STemplateArgsCmp"); break;
+  case STAC_LEFT_MORE_SPEC: return -1; break;
+  case STAC_RIGHT_MORE_SPEC: return 1; break;
+  case STAC_EQUAL:
+    // FIX: perhaps this should be a user error?
+    xfailure("Two template argument tuples are identical");
+    break;
+  case STAC_INCOMPARABLE: return 0; break;
+  }
+  xfailure("gcc can't tell that we can't get here");
+}
+
+
+int TemplCandidates::compareCandidates(Variable const *left, Variable const *right)
+{
+  TemplateInfo *lti = left->templateInfo();
+  xassert(lti);
+  TemplateInfo *rti = right->templateInfo();
+  xassert(rti);
+
+  return compareCandidatesStatic(lti, rti);
+}
+
+
+// ----------------------- Env ----------------------------
+// These are not all of Env's methods, just the ones declared in the
+// section for templates.
+
+
+bool Env::loadBindingsWithExplTemplArgs(Variable *var, ObjList<STemplateArgument> const &args,
+                                        MType &match, InferArgFlags iflags)
+{
+  xassert(var->templateInfo());
+  xassert(var->templateInfo()->isPrimary());
+
+  ObjListIter<STemplateArgument> argIter(args);
+  SObjListIterNC<Variable> paramIter(var->templateInfo()->params);
+  for (; !paramIter.isDone() && !argIter.isDone();
+       paramIter.adv(), argIter.adv()) {
+    Variable *param = paramIter.data();
+    STemplateArgument const *arg = argIter.data();
+
+    // is the parameter already bound?  this happens e.g. during
+    // explicit function instantiation, when the type of the function
+    // can be used to infer some/all of the template parameters
+    STemplateArgument existing = match.getBoundValue(param->name, tfac);
+
+    // if so, it should agree with the explicitly provided argument
+    if (existing.hasValue()) {
+      if (!existing.equals(*arg)) {
+        if (iflags & IA_REPORT_ERRORS) {
+          error(stringc << "for parameter `" << param->name
+                        << "', inferred argument `" << existing.toString()
+                        << "' does not match supplied argument `" << arg->toString()
+                        << "'");
+        }
+        return false;
+      }
+      else {
+        // no need to get down into the (rather messy...) binding code
+        // below
+        continue;
+      }
+    }
+
+    match.setBoundValue(param->name, *arg);
+  }
+  return true;
+}
+
+
+bool Env::inferTemplArgsFromFuncArgs
+  (Variable *var,
+   TypeListIter &argListIter,
+   MType &match,
+   InferArgFlags iflags)
+{
+  xassert(var->templateInfo());
+  xassert(var->templateInfo()->isPrimary());
+
+  // matching flags for this routine
+  MatchFlags mflags = MF_DEDUCTION | MF_MATCH;
+
+  TRACE("template", "deducing template arguments from function arguments");
+
+  // make a copy of the original bindings; this way I can tell if a
+  // parameter was made concrete just from the explicitly-provided
+  // arguments, as opposed to by additional deduced arguments
+  MType origMatch(match);
+
+  // if the caller has passed in information about the receiver object
+  // (so this function can work for nonstatic members), but the
+  // function here is not a method, we need to skip the receiver
+  FunctionType *funcType = var->type->asFunctionType();
+  if ((iflags & IA_RECEIVER) &&          // receiver passed
+      !funcType->isMethod()) {           // not a method
+    argListIter.adv();                   // skip receiver argument
+  }
+
+  // similarly, if the caller did *not* pass a receiver but this
+  // function has a receiver param, skip the param
+  SObjListIterNC<Variable> paramIter(funcType->params);
+  if (!(iflags & IA_RECEIVER) &&         // no receiver passed
+      funcType->isMethod()) {            // but is a method
+    paramIter.adv();                     // skip receiver parameter
+  }
+
+  // 2005-08-15: Previously, deduction was done by processing
+  // corresponding arguments and parameters from left to right,
+  // stopping on the first match failure.  However, 14.8.2.1 does not
+  // explicitly give an order, which suggests that implementations are
+  // required to (in effect) try all orders, and in fact 14.8.2.4p14
+  // example 2 requires an order other than left-to-right.
+  //
+  // So, I will do the following:
+  //   - Collect arg/param pairs in a worklist, initially in
+  //     left-to-right order.
+  //   - Draw pairs from the worklist and attempt to match.  If this
+  //     fails due to DQT problems, put the pair back in the list and
+  //     keep going.
+  //   - Keep trying until all worklist elements have been tried
+  //     without any intervening match successes.
+  //
+  // Tests: in/t0488.cc, in/t0570.cc.
+
+  // first, seed the worklist with arg/param pairs
+  typedef pair<Type* /*type*/, Variable* /*param*/> TypeParamPair;
+  ArrayStack<TypeParamPair> worklist(funcType->params.count());
+  for (; !paramIter.isDone() && !argListIter.isDone();
+       paramIter.adv(), argListIter.adv()) {
+    // 2005-08-09: If the parameter does not have any template
+    // parameters, after substitution of explicitly-provided
+    // arguments, then strict matching is not required so we skip it
+    // during template argument deduction.  [cppstd 14.8.1p4]
+    // (in/t0324.cc, in/t0534.cc)
+    Variable *param = paramIter.data();
+    if (!param->type->containsVariables(&origMatch)) {
+      // skip it; no deduction can occur, and any convertibility errors
+      // will be detected later
+      continue;
+    }
+
+    worklist.push(make_pair(argListIter.data(), param));
+  }
+
+  // worklist for next iteration
+  ArrayStack<TypeParamPair> nextWorklist(worklist.size());
+
+  // process it until fixpoint
+  while (worklist.length() != nextWorklist.length()) {
+    nextWorklist.empty();
+
+    for (int i=0; i < worklist.length(); i++) {
+      Variable *param = worklist[i].second;
+
+      Type *argType = worklist[i].first;
+      Type *paramType = param->type;
+
+      xassert(argType != NULL && "52291632-1792-4e5c-b5b8-9e6240b75a91");
+
+      // deduction does not take into account whether the argument
+      // is an lvalue, which in my system would mean it has
+      // reference type, so strip that
+      argType = argType->asRval();
+
+      // prior to calling into matchtype, normalize the parameter
+      // and argument types according to 14.8.2.1p2
+      if (!paramType->isReference()) {
+        if (argType->isArrayType()) {
+          // synthesize a pointer type to be used instead
+          ArrayType *at = argType->asArrayType();
+          argType = tfac.makePointerType(CV_NONE, at->eltType);
+        }
+        else if (argType->isFunctionType()) {
+          // use pointer type instead
+          argType = tfac.makePointerType(CV_NONE, argType);
+        }
+        else {
+          // final bullet says to ignore cv qualifications, but I think
+          // match_Type is already doing that (probably too liberally,
+          // but fixing match_Type is not on the agenda right now)
+        }
+      }
+
+      // final sentence of 14.8.2.1p2
+      paramType = paramType->asRval();
+
+      // "find template argument values that will make the deduced
+      // [parameter type] identical to ['argType']"
+      match.failedDueToDQT = false;
+      bool argUnifies = match.matchTypeNC(argType, paramType, mflags);
+
+      if (!argUnifies && match.failedDueToDQT) {
+        // this is the case where we put it back in the worklist
+        // to try again later
+        nextWorklist.push(worklist[i]);
+        continue;
+      }
+
+      if (!argUnifies) {
+        // cppstd 14.8.2.1 para 3 bullet 3: if 'paramType' is a
+        // template-id, then 'argType' can be derived from
+        // 'paramType'; assume that 'containsVariables' is
+        // sufficient evidence that 'paramType' is a template-id
+
+        // push past one level of pointerness too (part of bullet 3)
+        if (argType->isPointer() && paramType->isPointer()) {
+          argType = argType->getAtType();
+          paramType = paramType->getAtType();
+        }
+
+        if (argType->isCompoundType()) {
+          // get all the base classes
+          CompoundType *ct = argType->asCompoundType();
+          SObjList<BaseClassSubobj const> bases;
+          getSubobjects(bases, ct);
+          SFOREACH_OBJLIST(BaseClassSubobj const, bases, iter) {
+            BaseClassSubobj const *sub = iter.data();
+            if (sub->ct == ct) { continue; }      // already tried 'ct'
+
+            // attempt to match 'sub->ct' with 'paramType'
+            //
+            // TODO: There are two bugs here, due to allowing the
+            // effect of one match attempt to contaminate the next.
+            // First, if there are two base classes and the first
+            // does not match but the second does, when the first
+            // fails to match it may change the bindings in 'match'
+            // in such a way as to cause the second match to
+            // spuriously fail.  Second, cppstd says that we must
+            // report an error if more than one base class matches,
+            // but we will not be able to, since one successful
+            // match will (in all likelihood) modify the bindings so
+            // as to prevent the second match.  The solution is to
+            // save the current bindings before attempting a match,
+            // but MType does not currently support the needed
+            // push and pop of bindings.  Therefore I will just note
+            // the bugs and ignore them for now.
+            Type *t = env.makeType(sub->ct);    // leaked
+            if (match.matchTypeNC(t, paramType, mflags)) {
+              argUnifies = true;
+              break;
+            }
+          }
+        }
+
+        // did we find a match in the second attempt?
+        if (!argUnifies) {
+          if (iflags & IA_REPORT_ERRORS) {
+            // TODO: Somehow propagate this up to the user even during
+            // overload resolution (where IA_REPORT_ERRORS is not set)
+            // if resolution ultimately fails.
+            error(stringc << "during function template argument deduction: "
+                  << "argument `" << argType->toString() << "'"
+                  << " is incompatible with parameter `"
+                  << paramType->toString() << "'");
+          }
+          return false;
+        }
+      }
+    } // for(worklist)
+
+    // swap worklists
+    worklist.swapWith(nextWorklist);
+
+  } // while(changed)
+
+  return true;
+}
+
+
+bool Env::getFuncTemplArgs
+  (MType &match,
+   ObjList<STemplateArgument> &sargs,
+   PQName const *final,
+   Variable *var,
+   TypeListIter &argListIter,
+   InferArgFlags iflags)
+{
+  // 'final' might be NULL in the case of doing overload resolution
+  // for templatized ctors (that is, the ctor is templatized, but not
+  // necessarily the class)
+  if (final && final->isPQ_template()) {
+    if (!loadBindingsWithExplTemplArgs(var, final->asPQ_templateC()->sargs, match,
+                                       iflags)) {
+      return false;
+    }
+  }
+
+  if (!inferTemplArgsFromFuncArgs(var, argListIter, match, iflags)) {
+    return false;
+  }
+
+  // match -> sargs
+  return getArgumentsFromMatch(match, sargs, iflags, var);
+}
+
+bool Env::getArgumentsFromMatch
+  (MType &match, ObjList<STemplateArgument> &sargs,
+   InferArgFlags iflags, Variable *primary)
+{
+  TemplateInfo *ti = primary->templateInfo();
+  xassert(ti->isPrimary());
+
+  // put the bindings in a list in the right order
+  bool haveAllArgs = true;
+
+  // inherited params first
+  FOREACH_OBJLIST(InheritedTemplateParams, ti->inheritedParams, iter) {
+    getFuncTemplArgs_oneParamList(match, sargs, iflags, haveAllArgs,
+                                  iter.data()->params);
+  }
+
+  // then main params
+  getFuncTemplArgs_oneParamList(match, sargs, iflags, haveAllArgs,
+                                ti->params);
+
+  return haveAllArgs;
+}
+
+void Env::getFuncTemplArgs_oneParamList
+  (MType &match,
+   ObjList<STemplateArgument> &sargs,
+   InferArgFlags iflags,
+   bool &haveAllArgs,
+   //ObjListIter<STemplateArgument> &piArgIter,
+   SObjList<Variable> const &paramList)
+{
+  SFOREACH_OBJLIST(Variable, paramList, templPIter) {
+    Variable const *param = templPIter.data();
+
+    STemplateArgument sta = match.getBoundValue(param->name, tfac);
+
+    if (!sta.hasValue()) {
+      if (iflags & IA_REPORT_ERRORS) {
+        error(stringc << "arguments do not bind template parameter `"
+                      << templPIter.data()->name << "'");
+      }
+      haveAllArgs = false;
+    }
+    else {
+      // the 'sta' we have is owned by 'match' and will go away when
+      // it does; make a copy that 'sargs' can own
+      sargs.append(new STemplateArgument(sta));
+    }
+  }
+}
+
+
+Variable *Env::instantiateFunctionTemplate
+  (SourceLoc loc, Variable *primary, MType &match)
+{
+  // map 'match' to a list of semantic arguments
+  ObjList<STemplateArgument> sargs;
+  if (!getArgumentsFromMatch(match, sargs, IA_NO_ERRORS, primary)) {
+    return NULL;
+  }
+
+  // apply them to instantiate the template
+  return instantiateFunctionTemplate(loc, primary, sargs);
+}
+
+
+// this could be a template...
+void removeElementRange(SObjList<STemplateArgument> &list, int start, int num)
+{
+  SObjListMutator<STemplateArgument> mut(list);
+  while (start--) {
+    mut.adv();
+  }
+  while (num--) {
+    mut.remove();
+  }
+}
+
+
+// insert bindings into SK_TEMPLATE_ARG scopes, from template
+// parameters to concrete template arguments
+void Env::insertTemplateArgBindings
+  (Variable *baseV, SObjList<STemplateArgument> const &sargs)
+{
+  xassert(baseV);
+  TemplateInfo *baseVTI = baseV->templateInfo();
+
+  // begin iterating over arguments
+  SObjListIter<STemplateArgument> argIter(sargs);
+
+  // if 'baseV' is a partial instantiation, then it provides
+  // a block of arguments at the beginning, and then we use 'sargs'
+  SObjList<STemplateArgument> expandedSargs;
+  if (baseVTI->isPartialInstantiation()) {
+    // put 'sargs' in initially
+    expandedSargs = sargs;
+
+    // in/t0438a.cc: the partial instantiation chain may be longer
+    // than one element, so need a loop here
+    while (baseVTI->isPartialInstantiation()) {
+      // put partial inst args first
+      SObjList<STemplateArgument> const &piArgs =
+        objToSObjListC(baseVTI->arguments);
+      expandedSargs.prependAll(piArgs);
+
+      if (baseVTI->isPartialSpec()) {
+        // (in/t0504.cc) Oy, partial inst of partial spec.  I only
+        // want some of the args I just prepended, namely the ones
+        // that are *not* partial spec args.  So, remove the ones that
+        // are; they come after the partial inst args in 'piArgs'.
+        // (Disgusting hack.  It's a miracle it works at all.)
+        TemplateInfo *origTI = baseVTI->partialInstantiationOf->templateInfo();
+        int numPartialSpecArgs = origTI->arguments.count();
+        removeElementRange(expandedSargs, piArgs.count() - numPartialSpecArgs,
+                           numPartialSpecArgs);
+      }
+
+      // finally, set 'baseVTI' to point at the original template,
+      // since it has the parameter list for the definition
+      baseVTI = baseVTI->partialInstantiationOf->templateInfo();
+    }
+
+    // now, reset the iterator to walk the expanded list instead
+    argIter.reset(expandedSargs);
+  }
+
+  // does the definition parameter list differ from the declaration
+  // parameter list?
+  if (baseVTI->definitionTemplateInfo) {
+    // use the params from the definition instead
+    baseVTI = baseVTI->definitionTemplateInfo;
+  }
+
+  // first, apply them to the inherited parameters
+  FOREACH_OBJLIST(InheritedTemplateParams, baseVTI->inheritedParams, iter) {
+    InheritedTemplateParams const *inh = iter.data();
+
+    // create a scope to hold the bindings
+    Scope *s = enterScope(SK_TEMPLATE_ARGS, "inherited template argument bindings");
+
+    // insert them
+    insertTemplateArgBindings_oneParamList(s, baseV, argIter, inh->params);
+  }
+
+  // make a scope for the main template arguments; this one will be at
+  // the very top, though it will then be covered by the scope of the
+  // entity being instantiated (the caller does this)
+  Scope *argScope = enterScope(SK_TEMPLATE_ARGS, "main template argument bindings");
+
+  // then, bind "my" parameters
+  insertTemplateArgBindings_oneParamList(argScope, baseV, argIter, baseVTI->params);
+
+  if (!argIter.isDone()) {
+    error(stringc
+          << "too many template arguments to `" << baseV->name << "'", EF_STRONG);
+  }
+}
+
+// returns false if an error is detected
+bool Env::insertTemplateArgBindings_oneParamList
+  (Scope *scope, Variable *baseV, SObjListIter<STemplateArgument> &argIter,
+   SObjList<Variable> const &params)
+{
+  // accumulate type parameter bindings for cases like in/t0505.cc
+  // where later parameters refer to earlier parameters
+  //
+  // I'm not sure this is right; maybe I need to accumulate them
+  // across all the parameter lists?
+  MType typeBindings(true /*allowNonConst*/);
+
+  SObjListIter<Variable> paramIter(params);
+  while (!paramIter.isDone()) {
+    Variable const *param = paramIter.data();
+
+    // if we have exhaused the explicit arguments, use a NULL 'sarg'
+    // to indicate that we need to use the default arguments from
+    // 'param' (if available)
+    //
+    // 8/10/04: Default arguments are now handled elsewhere
+    // TODO: fully collapse this code to reflect that
+    xassert(!argIter.isDone());       // should not get here with too few args
+    STemplateArgument const *sarg = argIter.data();
+
+    if (sarg && sarg->isTemplate()) {
+      xfailure("Template template parameters are not implemented");
+    }
+
+
+    if (param->hasFlag(DF_TYPEDEF) &&
+        (!sarg || sarg->isType())) {
+      if (!sarg && !param->defaultParamType) {
+        error(stringc
+          << "too few template arguments to `" << baseV->name << "'");
+        return false;
+      }
+
+      // bind the type parameter to the type argument
+      Type *t = sarg? sarg->getType() : param->defaultParamType;
+      Variable *binding = makeVariable(param->loc, param->name, t,
+                                       DF_TYPEDEF | DF_TEMPL_PARAM | DF_BOUND_TPARAM);
+      addVariableToScope(scope, binding);
+
+      // remember them in 'typeBindings' too (for local use)
+      typeBindings.setBoundValue(param->name, *sarg);
+    }
+    else if (!param->hasFlag(DF_TYPEDEF) &&
+             (!sarg || sarg->isObject())) {
+      if (!sarg && !param->value) {
+        error(stringc
+          << "too few template arguments to `" << baseV->name << "'");
+        return false;
+      }
+
+      // TODO: verify that the argument in fact matches the parameter type
+
+      // bind the nontype parameter directly to the nontype expression;
+      // this will suffice for checking the template body, because I
+      // can const-eval the expression whenever it participates in
+      // type determination; the type must be made 'const' so that
+      // E_variable::constEval will believe it can evaluate it
+      Type *bindType = param->type->isReference()?
+        param->type :                 // reference: no need/desire to apply 'const'
+        tfac.applyCVToType(param->loc, CV_CONST,    // non-reference: apply 'const'
+                           param->type, NULL /*syntax*/);
+      bindType = applyArgumentMapToType(typeBindings, bindType);  // in/t0505.cc
+      Variable *binding = makeVariable(param->loc, param->name,
+                                       bindType, DF_TEMPL_PARAM | DF_BOUND_TPARAM);
+
+      // set 'bindings->value', in some cases creating AST
+      if (!sarg) {
+        binding->setValue(param->value);
+
+        // sm: the statement above seems reasonable, but I'm not at
+        // all convinced it's really right... has it been tcheck'd?
+        // has it been normalized?  are these things necessary?  so
+        // I'll wait for a testcase to remove this assertion... before
+        // this assertion *is* removed, someone should read over the
+        // applicable parts of cppstd
+        xunimp("default non-type argument");
+      }
+      switch (sarg->kind) {
+        // The following cases get progressively more difficult for
+        // an analysis to "see" what the actual template argument is.
+        // For example, in the first case, it sees something like:
+        //   int const I = 3;
+        // and const-eval'ing variables like 'I' is pretty routine.
+        // But for a pointer to member, it sees:
+        //   int A::*p const = &A::foo;
+        // and such constructs are unusual in ordinary code.  At some
+        // point I may need to implement a more aggressive
+        // substitution transformation, rather than relying on the
+        // indirection through the 'binding' variable.
+
+        case STemplateArgument::STA_INT: {
+          binding->setValue(build_E_intLit(sarg->getInt()));
+          break;
+        }
+        case STemplateArgument::STA_ENUMERATOR: {
+          binding->setValue(build_E_variable(sarg->getEnumerator()));
+          break;
+        }
+        case STemplateArgument::STA_REFERENCE: {
+          binding->setValue(build_E_variable(sarg->getReference()));
+          break;
+        }
+        case STemplateArgument::STA_POINTER: {
+          binding->setValue(build_E_addrOf(build_E_variable(sarg->getPointer())));
+          break;
+        }
+        case STemplateArgument::STA_MEMBER: {
+          binding->setValue(build_E_addrOf(build_E_variable(sarg->getMember())));
+          break;
+        }
+        case STemplateArgument::STA_DEPEXPR: {
+          binding->setValue(sarg->getDepExpr());
+          break;
+        }
+        default: {
+          xunimp("template template parameters");
+        }
+      }
+      xassert(binding->value);
+
+      if (param->type->containsGeneralizedDependent()) {
+        // (in/t0505.cc) the parameter type probably depends on
+        // parameters that have been bound earlier in the parameter
+        // list; but refining 'param->type' appropriately is not
+        // very convenient, so I'm just going to forego the check
+        //
+        // TODO: do it right, by building an MType
+        // and using applyArgumentMap
+      }
+      else if (binding->value->type->containsGeneralizedDependent()) {
+        // originally I added this to parallel the above case, but
+        // that was wrong, and now I have fixed default argument
+        // generation so this should never happen
+        xfailure("template argument is not concrete");
+      }
+      else {
+        // check that this argument is compatible with the parameter
+        // (TODO: this isn't exactly what 14.3.2p5 says)
+        string errorMsg;
+        if (SC_ERROR == getStandardConversion(&errorMsg,
+                                              binding->value->getSpecial(lang),
+                                              binding->value->type,
+                                              param->type,
+                                              false /*destIsReceiver*/)) {
+          error(errorMsg);
+        }
+      }
+
+      addVariableToScope(scope, binding);
+    }
+    else {
+      // mismatch between argument kind and parameter kind
+      char const *paramKind = param->hasFlag(DF_TYPEDEF)? "type" : "non-type";
+      // FIX: make a provision for template template parameters here
+      char const *argKind = sarg->isType()? "type" : "non-type";
+      error(stringc
+            << "`" << param->name << "' is a " << paramKind
+            << " parameter, but `" << sarg->toString() << "' is a "
+            << argKind << " argument", EF_STRONG);
+    }
+
+    paramIter.adv();
+    if (!argIter.isDone()) {
+      argIter.adv();
+    }
+  }
+
+  // having added the bindings, turn off name acceptance
+  scope->canAcceptNames = false;
+
+  xassert(paramIter.isDone());
+  return true;
+}
+
+void Env::insertTemplateArgBindings
+  (Variable *baseV, ObjList<STemplateArgument> const &sargs)
+{
+  insertTemplateArgBindings(baseV, objToSObjListC(sargs));
+}
+
+
+// reverse the effects of 'insertTemplateArgBindings'
+void Env::deleteTemplateArgBindings(Scope *limit)
+{
+  // just blow away template argument scopes on top
+  while (scope()->scopeKind == SK_TEMPLATE_ARGS &&
+         scope() != limit) {
+    exitScope(scope());
+  }
+}
+
+
+// The situation here is we have a partial specialization, for
+// example
+//
+//   template <class T, class U>
+//   class A<int, T*, U**> { ... }
+//
+// and we'd like to instantiate it with some concrete arguments.  What
+// we have is arguments that apply to the *primary*, for example
+//
+//   <int, float*, char***>
+//
+// and we want to derive the proper arguments to the partial spec,
+// namely
+//
+//   <float, char*>
+//
+// so we can pass these on to the instantiation routines.
+//
+// It's a bit odd to be doing this matching again, since to even
+// discover that the partial spec applied we would have already done
+// it once.  For now I'll let that be...
+void Env::mapPrimaryArgsToSpecArgs(
+  Variable *baseV,         // partial specialization
+  ObjList<STemplateArgument> &partialSpecArgs,       // dest. list
+  ObjList<STemplateArgument> &primaryArgs)           // source list
+{
+  // similar to Env::findMostSpecific, we need to match against the
+  // original's args if this is a partial instantiation (in/t0504.cc)
+  TemplateInfo *baseVTI = baseV->templateInfo();
+  TemplateInfo *matchTI = baseVTI;
+  if (baseVTI->isPartialInstantiation()) {
+    matchTI = baseVTI->partialInstantiationOf->templateInfo();
+  }
+
+  // execute the match to derive the bindings; we should not have
+  // gotten here if they do not unify
+  MType match(env);
+  bool matches = match.matchSTemplateArgumentsNC(primaryArgs, matchTI->arguments,
+                                                 MF_MATCH);
+  xassert(matches);
+
+  // Now the arguments are bound in 'bindings', for example
+  //
+  //   T |-> float
+  //   U |-> char
+  //
+  // We just need to run over the partial spec's parameters and
+  // build an argument corresponding to each parameter.
+
+  // first get args corresp. to inherited params
+  FOREACH_OBJLIST(InheritedTemplateParams, baseVTI->inheritedParams, iter) {
+    mapPrimaryArgsToSpecArgs_oneParamList(iter.data()->params, match, partialSpecArgs);
+  }
+
+  // then the main params
+  mapPrimaryArgsToSpecArgs_oneParamList(baseVTI->params, match, partialSpecArgs);
+}
+
+void Env::mapPrimaryArgsToSpecArgs_oneParamList(
+  SObjList<Variable> const &params,     // one arg per parameter
+  MType &match,                         // carries bindingsto use
+  ObjList<STemplateArgument> &partialSpecArgs)      // dest. list
+{
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    Variable const *param = iter.data();
+
+    STemplateArgument arg = match.getBoundValue(param->name, tfac);
+    if (!arg.hasValue()) {
+      error(stringc
+            << "during partial specialization parameter `" << param->name
+            << "' not bound in inferred bindings", EF_STRONG);
+      return;
+    }
+
+    partialSpecArgs.append(new STemplateArgument(arg));
+  }
+}
+
+
+// find most specific specialization that matches the given arguments
+Variable *Env::findMostSpecific
+  (Variable *baseV, ObjList<STemplateArgument> const &sargs)
+{
+  // baseV should be a template primary
+  TemplateInfo *baseVTI = baseV->templateInfo();
+  xassert(baseVTI->isPrimary());
+
+  // iterate through all of the specializations and build up a set of
+  // candidates
+  TemplCandidates templCandidates;
+  SFOREACH_OBJLIST_NC(Variable, baseVTI->specializations, iter) {
+    Variable *spec = iter.data();
+    TemplateInfo *specTI = spec->templateInfo();
+    xassert(specTI);        // should have templateness
+
+    // if 'specTI' is a partial instantiation, we want to match
+    // against the original argument list (in/t0504.cc)
+    TemplateInfo *matchTI = specTI;
+    if (specTI->isPartialInstantiation()) {
+      matchTI = specTI->partialInstantiationOf->templateInfo();
+    }
+
+    // see if this candidate matches
+    MType match;
+    if (match.matchSTemplateArguments(sargs, matchTI->arguments, MF_MATCH)) {
+      templCandidates.add(spec);
+    }
+  }
+
+  // there are no candidates so we just use the primary
+  if (templCandidates.candidates.isEmpty()) {
+    return baseV;
+  }
+
+  // there are candidates to try; select the best
+  Variable *bestV = selectBestCandidate_templCompoundType(templCandidates);
+
+  // if there is not best candidate, then the call is ambiguous and
+  // we should deal with that error
+  if (!bestV) {
+    // TODO: expand this error message
+    error(stringc << "ambiguous attempt to instantiate template", EF_STRONG);
+    return baseV;      // recovery: use the primary
+  }
+
+  // otherwise, use the best one
+  return bestV;
+}
+
+
+// remove scopes from the environment until the innermost
+// scope on the scope stack is the same one that the template
+// definition appeared in; template definitions can see names
+// visible from their defining scope only [cppstd 14.6 para 1]
+//
+// update: (e.g. t0188.cc) pop scopes until we reach one that
+// *contains* (or equals) the defining scope
+//
+// 4/20/04: Even more (e.g. t0204.cc), we need to push scopes
+// to dig back down to the defining scope.  So the picture now
+// looks like this:
+//
+//       global                   /---- this is "foundScope"
+//         |                     /
+//         namespace1           /   }
+//         | |                 /    }- 2. push these: "pushedScopes"
+//         | namespace11  <---/     }
+//         |   |
+//         |   template definition
+//         |
+//         namespace2               }
+//           |                      }- 1. pop these: "poppedScopes"
+//           namespace21            }
+//             |
+//             point of instantiation
+//
+// actually, it's *still* not right, because
+//   - this allows the instantiation to see names declared in
+//     'namespace11' that are below the template definition, and
+//   - it's entirely wrong for dependent names, a concept I
+//     largely ignore at this time
+// however, I await more examples before continuing to refine
+// my approximation to the extremely complex lookup rules
+void Env::prepArgScopeForTemlCloneTcheck
+  (ObjList<SavedScopePair> &poppedScopes, SObjList<Scope> &pushedScopes,
+   Scope *foundScope)
+{
+  xassert(foundScope);
+
+  // pop scope scopes
+  while (!scopes.firstC()->enclosesOrEq(foundScope)) {
+    Scope *s = scopes.first();
+    TRACE("scope", "prepArgScope: removing " << s->desc());
+    retractScope(s);
+
+    // do I need to save a delegation pointer?
+    SavedScopePair *ssp = new SavedScopePair(s);
+    if (s->hasDelegationPointer()) {
+      ssp->parameterizingScope = s->getAndNullifyDelegationPointer();
+      TRACE("scope", "prepArgScope: ... and saved delegation ptr " <<
+                     ssp->parameterizingScope->desc());
+    }
+
+    poppedScopes.prepend(ssp);
+    if (scopes.isEmpty()) {
+      xfailure("emptied scope stack searching for defining scope");
+    }
+  }
+
+  // make a list of the scopes to push; these form a path from our
+  // current scope to the 'foundScope'
+  Scope *s = foundScope;
+  while (s != scopes.firstC()) {
+    pushedScopes.prepend(s);
+    s = s->parentScope;
+    if (!s) {
+      if (scopes.firstC()->isGlobalScope()) {
+        // ok, hit the global scope in the traversal
+        break;
+      }
+      else {
+        xfailure("missed the current scope while searching up "
+                 "from the defining scope");
+      }
+    }
+  }
+
+  // now push them in list order, which means that 'foundScope'
+  // will be the last one to be pushed, and hence the innermost
+  // (I waited until now b/c this is the opposite order from the
+  // loop above that fills in 'pushedScopes')
+  SFOREACH_OBJLIST_NC(Scope, pushedScopes, iter) {
+    // Scope 'iter.data()' is now on both lists, but neither owns
+    // it; 'scopes' does not own Scopes that are named, as explained
+    // in the comments near its declaration (cc_env.h)
+    TRACE("scope", "prepArgScope: adding " << iter.data()->desc());
+    extendScope(iter.data());
+  }
+}
+
+
+void Env::unPrepArgScopeForTemlCloneTcheck
+  (ObjList<SavedScopePair> &poppedScopes, SObjList<Scope> &pushedScopes)
+{
+  // restore the original scope structure
+  pushedScopes.reverse();
+  while (pushedScopes.isNotEmpty()) {
+    Scope *s = pushedScopes.removeFirst();
+    TRACE("scope", "unPrepArgScope: removing " << s->desc());
+    retractScope(s);
+  }
+
+  // re-add the inner scopes removed above
+  while (poppedScopes.isNotEmpty()) {
+    SavedScopePair *ssp = poppedScopes.removeFirst();
+
+    // take out the scope and nullify it, effectively transferring ownership
+    Scope *s = ssp->scope;
+    ssp->scope = NULL;
+    TRACE("scope", "unPrepArgScope: adding " << s->desc());
+
+    // replace the parameterizingScope if needed
+    if (ssp->parameterizingScope) {
+      s->setDelegationPointer(ssp->parameterizingScope);
+      TRACE("scope", "... and restored delegation ptr " <<
+                     ssp->parameterizingScope->desc());
+    }
+
+    extendScope(s);
+    delete ssp;
+  }
+}
+
+
+// ---------------- default argument instantiation ----------------
+// find the D_func with parameters for 'func'
+D_func *getD_func(Function *func)
+{
+  // find innermost D_func
+  D_func *dfunc = NULL;
+  for (IDeclarator *d = func->nameAndParams->decl;
+       !d->isD_name();
+       d = d->getBase()) {
+    if (d->isD_func()) {
+      dfunc = d->asD_func();
+    }
+  }
+  xassert(dfunc);
+
+  return dfunc;
+}
+
+
+// Remove any default argument expressions from the parameters in
+// 'func'.  Later, as the default arguments are instantiated, we
+// will re-insert them.  That way we maintain the invariants that
+// (1) only tcheck'd syntax hangs off of a Function, and (2) the
+// Variable::value for a parameter is equal to the initializing
+// expression hanging off the associated Declarator.
+void removeDefaultArgs(Function *func)
+{
+  D_func *dfunc = getD_func(func);
+
+  // clean the default arguments (just leak them)
+  FAKELIST_FOREACH(ASTTypeId, dfunc->params, iter) {
+    iter->decl->init = NULL;
+  }
+}
+
+
+// Take all of the default argument expressions in 'primary', and
+// attach clones of them to 'inst'.  Also, take note in 'instTI' of
+// how many there are, so we know which ones are instantiated and
+// which ones are uninstantiated (initially, they are all
+// uninstantiated).
+void cloneDefaultArguments(Variable *inst, TemplateInfo *instTI,
+                           Variable *primary)
+{
+  FunctionType *instFt = inst->type->asFunctionType();
+  FunctionType *primaryFt = primary->type->asFunctionType();
+
+  SObjListIterNC<Variable> instParam(instFt->params);
+  SObjListIterNC<Variable> primaryParam(primaryFt->params);
+
+  for (; !instParam.isDone() && !primaryParam.isDone();
+       instParam.adv(), primaryParam.adv()) {
+    if (primaryParam.data()->value) {
+      instParam.data()->setValue(primaryParam.data()->value->clone());
+      instTI->uninstantiatedDefaultArgs++;
+    }
+    else {
+      // they are supposed to be contiguous at the end of the list, and
+      // prior tchecking should have ensured this
+      //
+      // actually, even if we reported the error, we might have
+      // continued to get here... what then?  not sure yet
+      xassert(instTI->uninstantiatedDefaultArgs == 0);
+    }
+  }
+
+  xassert(instParam.isDone() && primaryParam.isDone());
+}
+
+
+int countParamsWithDefaults(FunctionType *ft)
+{
+  int ret = 0;
+  SFOREACH_OBJLIST(Variable, ft->params, iter) {
+    if (iter.data()->value) {
+      ret++;
+    }
+  }
+  return ret;
+}
+
+
+// Given that all but 'instTI->uninstantiatedDefaultArgs' default args
+// have been instantiated, attach them to the function definition, if
+// there is one.
+void syncDefaultArgsWithDefinition(Variable *instV, TemplateInfo *instTI)
+{
+  // SGM 2006-09-17: I can't figure out why I wanted to do this in
+  // the first place.  The basic default-args design is:
+  //
+  // * The template primary has the default arg expression, but it has
+  // only been tchecked for parsing and non-depenendent lookup
+  // purposes.
+  //
+  // * When the template is instantiated, the entire primary's AST is
+  // cloned, so the default arg gets cloned too.  But it is still not
+  // fully tchecked.
+  //
+  // * When the default arg is needed (possibly right after
+  // instantiating), it is tchecked in place.  This is at the
+  // declaration site.
+  //
+  // I don't see where the definition gets involved in any of this,
+  // unless it is the only declaration, in which case there is still
+  // no need to explicitly sync b/c that is where the default args are
+  // already.
+  //
+  // Disabling this fixed in/dk0127.cc, which was failing because when
+  // the argument is copied below, I do not clone 'sem->value', but
+  // rather just build an IN_expr on top of it, which breaks the
+  // tree-ness property of the AST.  I wrote a few more tests in
+  // in/t0588.cc, but still can't find a reason to copy the args to
+  // the defn.
+  //
+  #if 0      // disabled; see comments above
+
+  if (!instV->funcDefn || !instTI->instantiateBody) {
+    return;
+  }
+
+  D_func *dfunc = getD_func(instV->funcDefn);
+
+  // iterate over both parameter lists (syntactic and semantic)
+  FakeList<ASTTypeId> *syntactic(dfunc->params);
+  SObjListIterNC<Variable> semantic(instV->type->asFunctionType()->params);
+  if (instV->type->asFunctionType()->isMethod()) {
+    semantic.adv();   // the receiver is never syntactically present
+  }
+
+  int skipped = 0;
+  for (; syntactic && !semantic.isDone();
+       syntactic = syntactic->butFirst(), semantic.adv()) {
+    Variable *sem = semantic.data();
+    if (!sem->value) {
+      continue;
+    }
+
+    if (skipped < instTI->uninstantiatedDefaultArgs) {
+      skipped++;
+      continue;
+    }
+
+    Declarator *d = syntactic->first()->decl;
+    if (d->init) {
+      continue;       // already transferred
+    }
+
+    // NOTE: This line is buggy, as it does not clone sem->value,
+    // which breaks the tree-ness of the AST.  Cloning it alone would
+    // not be enough, though, because the clone would need to be
+    // tchecked.  Anyway, I no longer remember why I wanted to do any
+    // of this, so the whole block of code is disabled.  See the
+    // comments above.
+    d->init = new IN_expr(sem->loc /* not perfect, but it will do */,
+                          sem->value);
+  }
+
+  // should end at the same time, except for possibly a trailing
+  // (singleton, really) 'void'-typed parameter
+  //
+  // could also be ST_ELLIPSIS (in/t0559.cc)
+  if (syntactic &&
+      (syntactic->first()->getType()->isVoid() ||
+       syntactic->first()->getType()->isSimple(ST_ELLIPSIS))) {
+    syntactic = syntactic->butFirst();
+  }
+  xassert(!syntactic && semantic.isDone());
+
+  #endif // 0
+}
+
+
+// cppstd 14.7.1 para 11
+//
+// 'neededDefaults' says how many default arguments were needed at
+// some call site.  We will use that to determine how many default
+// arguments need to be instantiated (which may be 0).
+void Env::instantiateDefaultArgs(Variable *instV, int neededDefaults)
+{
+  if (!instV->isInstantiation()) {
+    return;
+  }
+  TemplateInfo *instTI = instV->templateInfo();
+
+  if (instTI->uninstantiatedDefaultArgs == 0) {
+    return;       // nothing more we could instantiate anyway
+  }
+
+  // which parameters have default args?
+  FunctionType *ft = instV->type->asFunctionType();
+  int haveDefaults = 0;
+  int noDefaults = 0;
+  {
+    SFOREACH_OBJLIST(Variable, ft->params, iter) {
+      if (iter.data()->value) {
+        haveDefaults++;
+      }
+      else {
+        noDefaults++;
+      }
+    }
+  }
+  xassert(instTI->uninstantiatedDefaultArgs <= haveDefaults);
+
+  // expected scenario:
+  //                           <-- m ---><-- n --->
+  //                           <---uninstDefaults->
+  //                                     <--neededDefaults->
+  //   params:  0-------------|-----------------------------|
+  //            <-noDefaults-> <--------haveDefaults------->
+  //
+  // 'n' is the number of defaults to instantiate
+  int m = haveDefaults - neededDefaults;
+  int n = instTI->uninstantiatedDefaultArgs - m;
+  if (m < 0 || n <= 0) {
+    return;
+  }
+
+  TRACE("template", "instantiating " << pluraln(n, "argument") <<
+                    ", starting at arg " << (noDefaults+m) << ", in func decl: " <<
+                    instV->toQualifiedString());
+
+  // declScope: the scope where the function declaration appeared
+  Variable *baseV = instTI->instantiationOf;
+  #if 0      // seems to be wrong
+    Scope *declScope = baseV->scope;
+  #else      // fixes in/t0584.cc
+    Scope *declScope = instTI->var->scope;     // scope surrounding instantiation
+
+    // I suspect the reason I originally wrote 'baseV->scope' is I was
+    // thinking about template functions at global scope.  But for a
+    // member of a template class, I need to be pushing the template
+    // class instantiation scope, not the original template
+    // definition, because the latter has things like DQTs in it
+    // (look at gdbScopes() when this routine is running).
+    //
+    // Additional evidence to support this change comes from
+    // Env::instantiateFunctionBodyNow, from which much of the
+    // surrounding code here was copied, and uses defnScope (which is
+    // similar).
+  #endif
+  xassert(declScope);
+
+  // ------- BEGIN: duplicated from below -------
+  // isolate context
+  InstantiationContextIsolator isolator(*this, loc());
+
+  // set up the scopes in a way similar to how it was when the
+  // template definition was first seen
+  ObjList<SavedScopePair> poppedScopes;
+  SObjList<Scope> pushedScopes;
+  prepArgScopeForTemlCloneTcheck(poppedScopes, pushedScopes, declScope);
+
+  // bind the template arguments in scopes so that when we tcheck the
+  // body, lookup will find them
+  insertTemplateArgBindings(baseV, instTI->arguments);
+
+  // push the declaration scopes for inline definitions, since
+  // we don't get those from the declarator (that is in fact a
+  // mistake of the current implementation; eventually, we should
+  // 'pushDeclarationScopes' regardless of DF_INLINE_DEFN)
+  bool inlineDefn = instV->funcDefn &&
+                    (instV->funcDefn->dflags & DF_INLINE_DEFN);
+  if (inlineDefn) {
+    pushDeclarationScopes(instV, declScope);
+  }
+  // ------- END: duplicated from below -------
+
+  // tcheck some of the args
+  for (int i = noDefaults+m; i < noDefaults+n+m; i++) {
+    Variable *param = ft->params.nth(i);
+    if (param->value) {
+      // this dance is necessary because Variable::value is const,
+      // forcing updates to go through setValue
+      Expression *tmp = param->value;
+      tmp->tcheck(*this, tmp);
+      param->setValue(tmp);
+
+      instTI->uninstantiatedDefaultArgs--;
+    }
+    else {
+      // program is in error (e.g., default args not contiguous at the
+      // end), hopefully this has already been reported and we just
+      // skip it
+    }
+  }
+
+  // if there is an instantiated definition, attach the newly tcheck'd
+  // default arg exprs to it
+  syncDefaultArgsWithDefinition(instV, instTI);
+
+  // ------- BEGIN: duplicated from below -------
+  // remove the template argument scopes
+  deleteTemplateArgBindings();
+
+  if (inlineDefn) {
+    popDeclarationScopes(instV, declScope);
+  }
+
+  unPrepArgScopeForTemlCloneTcheck(poppedScopes, pushedScopes);
+  xassert(poppedScopes.isEmpty() && pushedScopes.isEmpty());
+  // ------- END: duplicated from below -------
+}
+
+
+// --------------- function template instantiation ------------
+// Get or create an instantiation Variable for a function template.
+// Note that this does *not* instantiate the function body; instead,
+// instantiateFunctionBody() has that responsibility.
+Variable *Env::instantiateFunctionTemplate
+  (SourceLoc loc,                              // location of instantiation request
+   Variable *primary,                          // template primary to instantiate
+   ObjList<STemplateArgument> const &sargs)    // arguments to apply to 'primary'
+{
+  // t0424.cc: if 'primary' is an alias, skip past it; aliases
+  // get to participate in overload resolution (i.e., *selecting*
+  // the function to invoke), but instantiation is always done
+  // with the real thing
+  primary = primary->skipAlias();
+
+  TemplateInfo *primaryTI = primary->templateInfo();
+  xassert(primaryTI->isPrimary());
+
+  // the arguments should be concrete
+  xassert(!containsVariables(sargs));
+
+  // look for a (complete) specialization that matches
+  Variable *spec = findCompleteSpecialization(primaryTI, sargs);
+  if (spec) {
+    return spec;      // use it
+  }
+
+  // look for an existing instantiation that has the right arguments
+  Variable *inst = findInstantiation(primaryTI, sargs);
+  if (inst) {
+    return inst;      // found it; that's all we need
+  }
+
+  // since we didn't find an existing instantiation, we have to make
+  // one from scratch
+  TRACE("template", "instantiating func decl: " <<
+                    primary->fullyQualifiedName0() << sargsToString(sargs));
+
+  // I don't need this, right?
+  // isolate context
+  //InstantiationContextIsolator isolator(*this, loc);
+
+  // bind the parameters in an STemplateArgumentMap
+  MType map(env);
+  bindParametersInMap(map, primaryTI, objToSObjListC(sargs));
+
+  // compute the type of the instantiation by applying 'map' to
+  // the templatized type
+  Type *instType = applyArgumentMapToType_helper(map, primary->type);
+  if (!instType) {
+    // caught XTypeDeduction
+
+    // unfortunately, the trace message gets split into two because
+    // neither place has all the context
+    TRACE("template", "^^^ failed to instantiate " <<
+                      primary->fullyQualifiedName0() << sargsToString(sargs));
+    return NULL;
+  }
+
+  // create the representative Variable
+  inst = makeInstantiationVariable(primary, instType);
+
+  // TODO: fold the following three activities into
+  // 'makeInstantiationVariable'
+
+  // annotate it with information about its templateness
+  TemplateInfo *instTI = new TemplateInfo(loc, inst);
+  instTI->copyArguments(sargs);
+
+  // insert into the instantiation list of the primary
+  primaryTI->addInstantiation(inst);
+
+  // this is an instantiation
+  xassert(instTI->isInstantiation());
+
+  // clone default argument expressions from the primary
+  cloneDefaultArguments(inst, instTI, primary);
+
+  return inst;
+}
+
+
+void Env::ensureFuncBodyTChecked(Variable *instV)
+{
+  if (!instV) {
+    return;      // error recovery
+  }
+  if (!instV->type->isFunctionType()) {
+    // I'm not sure what circumstances can cause this, but it used
+    // to be that all call sites to this function were guarded by
+    // this 'isFunctionType' check, so I pushed it inside
+    return;
+  }
+
+  TemplateInfo *instTI = instV->templateInfo();
+  if (!instTI) {
+    // not a template instantiation
+    return;
+  }
+  if (!instTI->isCompleteSpecOrInstantiation()) {
+    // not an instantiation; this might be because we're in
+    // the middle of tchecking a template definition, so we
+    // just used a function template primary sort of like
+    // a PseudoInstantiation; skip checking it
+    return;
+  }
+  if (instTI->instantiationDisallowed) {
+    // someone told us not to instantiate
+    return;
+  }
+  if (instTI->instantiateBody) {
+    // we've already seen this request, so either the function has
+    // already been instantiated, or else we haven't seen the
+    // definition yet so there's nothing we can do
+    return;
+  }
+
+  // acknowledge the request
+  instTI->instantiateBody = true;
+
+  // what template am I an instance of?
+  Variable *baseV = instTI->instantiationOf;
+  if (!baseV) {
+    // This happens for explicit complete specializations.  It's
+    // not clear whether such things should have templateInfos
+    // at all, but there seems little harm, so I'll just bail in
+    // that case
+    return;
+  }
+
+  // have we seen a definition of it?
+  if (!baseV->funcDefn) {
+    // nope, nothing we can do yet
+    TRACE("template", "want to instantiate func body: " <<
+                      instV->toQualifiedString() <<
+                      ", but cannot because have not seen defn");
+    return;
+  }
+
+  // ok, at this point we're committed to going ahead with
+  // instantiating the function body
+  instantiateFunctionBody(instV);
+}
+
+void Env::instantiateFunctionBody(Variable *instV)
+{
+  if (!doFunctionTemplateBodyInstantiation) {
+    TRACE("template", "NOT instantiating func body: " <<
+                      instV->toQualifiedString() <<
+                      " because body instantiation is disabled");
+    return;
+  }
+
+  if (delayFunctionInstantiation) {
+    TRACE("template", "delaying instantiating of: " << instV->toQualifiedString());
+    delayedFuncInsts.prepend(
+      new DelayedFuncInst(instV, instantiationLocStack, loc()));
+  }
+  else {
+    instantiateFunctionBodyNow(instV, loc());
+  }
+}
+
+void Env::instantiateFunctionBodyNow(Variable *instV, SourceLoc loc)
+{
+  TRACE("template", "instantiating func body: " << instV->toQualifiedString());
+
+  // reconstruct a few variables from above
+  TemplateInfo *instTI = instV->templateInfo();
+  Variable *baseV = instTI->instantiationOf;
+
+  // someone should have requested this
+  xassert(instTI->instantiateBody);
+
+  // isolate context
+  InstantiationContextIsolator isolator(*this, loc);
+
+  // defnScope: the scope where the function definition appeared.
+  Scope *defnScope;
+
+  // do we have a function definition already?
+  if (instV->funcDefn) {
+    // inline definition
+    defnScope = instTI->defnScope;
+  }
+  else {
+    // out-of-line definition; must clone the primary's definition
+    instV->funcDefn = baseV->funcDefn->clone();
+    defnScope = baseV->templateInfo()->defnScope;
+  }
+
+  // remove default argument expressions from the clone parameters
+  removeDefaultArgs(instV->funcDefn);
+
+  // set up the scopes in a way similar to how it was when the
+  // template definition was first seen
+  ObjList<SavedScopePair> poppedScopes;
+  SObjList<Scope> pushedScopes;
+  prepArgScopeForTemlCloneTcheck(poppedScopes, pushedScopes, defnScope);
+
+  // bind the template arguments in scopes so that when we tcheck the
+  // body, lookup will find them
+  insertTemplateArgBindings(baseV, instTI->arguments);
+
+  // push the declaration scopes for inline definitions, since
+  // we don't get those from the declarator (that is in fact a
+  // mistake of the current implementation; eventually, we should
+  // 'pushDeclarationScopes' regardless of DF_INLINE_DEFN)
+  if (instV->funcDefn->dflags & DF_INLINE_DEFN) {
+    pushDeclarationScopes(instV, defnScope);
+  }
+
+  // check the body, forcing it to use 'instV'
+  instV->funcDefn->tcheck(*this, instV);
+
+  // if we have already tcheck'd some default args, e.g., because we
+  // saw uses of the template before seeing the definition, transfer
+  // them over now
+  syncDefaultArgsWithDefinition(instV, instTI);
+
+  // remove the template argument scopes
+  deleteTemplateArgBindings();
+
+  if (instV->funcDefn->dflags & DF_INLINE_DEFN) {
+    popDeclarationScopes(instV, defnScope);
+  }
+
+  unPrepArgScopeForTemlCloneTcheck(poppedScopes, pushedScopes);
+  xassert(poppedScopes.isEmpty() && pushedScopes.isEmpty());
+}
+
+
+void Env::instantiateForwardFunctions(Variable *primary)
+{
+  if (!primary->templateInfo()) {
+    return;      // error recovery (t0275.cc)
+  }
+
+  SFOREACH_OBJLIST_NC(Variable, primary->templateInfo()->instantiations, iter) {
+    Variable *inst = iter.data();
+
+    if (inst->templateInfo()->instantiateBody) {
+      instantiateFunctionBody(inst);
+    }
+  }
+}
+
+
+// ----------------- class template instantiation -------------
+bool contains_STA_NONE(SObjList<STemplateArgument> const &args)
+{
+  SFOREACH_OBJLIST(STemplateArgument, args, iter) {
+    if (iter.data()->kind == STemplateArgument::STA_NONE) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// Get or create an instantiation Variable for a class template.
+// Note that this does *not* instantiate the class body; instead,
+// instantiateClassBody() has that responsibility.
+//
+// Return NULL if there is a problem with the arguments.
+Variable *Env::instantiateClassTemplate
+  (SourceLoc loc,                             // location of instantiation request
+   Variable *primary,                         // template primary to instantiate
+   SObjList<STemplateArgument> const &origPrimaryArgs)  // arguments to apply to 'primary'
+{
+  if (contains_STA_NONE(origPrimaryArgs)) {
+    return NULL;
+  }
+
+  // I really don't know what's the best place to do this, but I
+  // need it here so this is a start...
+  primary = primary->skipAlias();
+
+  TemplateInfo *primaryTI = primary->templateInfo();
+  xassert(primaryTI->isPrimary() && "60a04156-a119-4c6c-8c04-bca58e69dee1");
+
+  // the arguments should be concrete
+  xassert(!containsVariables(origPrimaryArgs));
+
+  // Augment the supplied arguments with defaults from the primary
+  // (note that defaults on a specialization are not used, and are
+  // consequently illegal [14.5.4 para 10]).
+  //
+  // This also checks whether the arguments match the parameters,
+  // and returns false if they do not.
+  ObjList<STemplateArgument> owningPrimaryArgs;
+  if (!supplyDefaultTemplateArguments(primaryTI, owningPrimaryArgs,
+                                      origPrimaryArgs)) {
+    return NULL;
+  }
+
+  // *still* should be concrete, even after supplying defaults
+  xassert(!containsVariables(owningPrimaryArgs));
+
+  // find the specialization that should be used (might turn
+  // out to be the primary; that's fine)
+  Variable *spec = findMostSpecific(primary, owningPrimaryArgs);
+  TemplateInfo *specTI = spec->templateInfo();
+  if (specTI->isCompleteSpec()) {
+    return spec;      // complete spec; good to go
+  }
+
+  // if this is a partial specialization, we need the arguments
+  // to be relative to the partial spec before we can look for
+  // the instantiation
+  ObjList<STemplateArgument> owningPartialSpecArgs;
+  if (spec != primary) {
+    xassertdb(specTI->isPartialSpec());
+    mapPrimaryArgsToSpecArgs(spec, owningPartialSpecArgs, owningPrimaryArgs);
+  }
+
+  // The code below wants to use SObjLists, and since they are happy
+  // accepting const versions, this is safe.  An alternative fix would
+  // be to push owningness down into those interfaces, but I'm getting
+  // tired of doing that ...
+  SObjList<STemplateArgument> const &primaryArgs =     // non-owning
+    objToSObjListC(owningPrimaryArgs);
+
+  // non-owning version of this too..
+  SObjList<STemplateArgument> const &partialSpecArgs =
+    objToSObjListC(owningPartialSpecArgs);
+
+  // look for an existing instantiation that has the right arguments
+  Variable *inst = spec==primary?
+    findInstantiation(specTI, owningPrimaryArgs) :
+    findInstantiation(specTI, owningPartialSpecArgs);
+  if (inst) {
+    return inst;      // found it; that's all we need
+  }
+
+  // since we didn't find an existing instantiation, we have to make
+  // one from scratch
+  if (spec==primary) {
+    TRACE("template", "instantiating class decl: " <<
+                      primary->fullyQualifiedName0() << sargsToString(primaryArgs));
+  }
+  else {
+    TRACE("template", "instantiating partial spec decl: " <<
+                      primary->fullyQualifiedName0() <<
+                      sargsToString(specTI->arguments) <<
+                      sargsToString(partialSpecArgs));
+  }
+
+  // create the CompoundType
+  CompoundType const *specCT = spec->type->asCompoundType();
+  CompoundType *instCT = tfac.makeCompoundType(specCT->keyword, specCT->name);
+  instCT->forward = true;
+  instCT->instName = str(stringc << specCT->name << sargsToString(primaryArgs));
+  instCT->parentScope = specCT->parentScope;
+
+  // wrap the compound in a regular type
+  Type *instType = makeType(instCT);
+
+  // create the representative Variable
+  inst = makeInstantiationVariable(spec, instType);
+
+  // this also functions as the implicit typedef for the class,
+  // though it is not entered into any scope
+  instCT->typedefVar = inst;
+
+  // also make the self-name, which *does* go into the scope
+  // (testcase: t0167.cc)
+  if (lang.compoundSelfName) {
+    Variable *self = makeVariable(loc, instCT->name, instType,
+                                  DF_TYPEDEF | DF_SELFNAME);
+    instCT->addUniqueVariable(self);
+    addedNewVariable(instCT, self);
+  }
+
+  // make a TemplateInfo for this instantiation
+  TemplateInfo *instTI = new TemplateInfo(loc, inst);
+
+  // fill in its arguments
+  instTI->copyArguments(spec==primary? primaryArgs : partialSpecArgs);
+
+  // if it is an instance of a partial spec, keep the primaryArgs too ...
+  if (spec!=primary) {
+    copyTemplateArgs(instTI->argumentsToPrimary, primaryArgs);
+  }
+
+  // attach it as an instance
+  specTI->addInstantiation(inst);
+
+  // this is an instantiation
+  xassert(instTI->isInstantiation());
+
+  return inst;
+}
+
+Variable *Env::instantiateClassTemplate
+  (SourceLoc loc,
+   Variable *primary,
+   ObjList<STemplateArgument> const &sargs)
+{
+  return instantiateClassTemplate(loc, primary, objToSObjListC(sargs));
+}
+
+
+// defined in cc_tcheck.cc
+void tcheckDeclaratorPQName(Env &env, ScopeSeq &qualifierScopes,
+                            PQName *name, LookupFlags lflags);
+
+
+void Env::instantiateClassBody(Variable *inst)
+{
+  TemplateInfo *instTI = inst->templateInfo();
+  CompoundType *instCT = inst->type->asCompoundType();
+  xassert(instCT->forward);     // otherwise already instantiated!
+
+  Variable *spec = instTI->instantiationOf;
+  TemplateInfo *specTI = spec->templateInfo();
+  CompoundType *specCT = spec->type->asCompoundType();
+
+  // used only if it turns out that 'specTI' is a partial instantiation
+  CompoundType *origCT = NULL;
+
+  TRACE("template", "instantiating " <<
+                    (specTI->isPrimary()? "class" : "partial spec") <<
+                    " body: " << instTI->templateName());
+
+  // defnScope: the scope where the class definition appeared
+  Scope *defnScope = NULL;
+
+  // do we have a function definition already?
+  if (instCT->syntax) {
+    // inline definition
+    defnScope = instTI->defnScope;
+  }
+  else if (specCT->syntax) {
+    // out-of-line definition; must clone the spec's definition
+    instCT->syntax = specCT->syntax->clone();
+    defnScope = specTI->defnScope;
+  }
+  else if (specTI->isPartialInstantiation()) {
+    // go look at the thing from which this was partial instantiated,
+    // in search of a definition (in/t0548.cc)
+    //
+    // TODO: This is an unfortunate hack.  I end up treating out-of-line
+    // definitions of member template classes quite differently from
+    // inline definitions of the same.  However, I didn't think about
+    // these issues when designing the template mechanism, and they just
+    // don't fit right.  At some point it would be good to reimplement
+    // the whole thing, taking this stuff into account.
+    TemplateInfo *origTI = specTI->partialInstantiationOf->templateInfo();
+    origCT = specTI->partialInstantiationOf->type->asCompoundType();
+    if (origCT->syntax) {
+      instCT->syntax = origCT->syntax->clone();
+      defnScope = origTI->defnScope;
+    }
+  }
+
+  if (!instCT->syntax) {
+    error(stringc << "attempt to instantiate `" << instTI->templateName()
+                  << "', but no definition has been provided for `"
+                  << specTI->templateName() << "'");
+    return;
+  }
+  xassert(defnScope);
+
+  // isolate context
+  InstantiationContextIsolator isolator(*this, loc());
+
+  // bind the template arguments in scopes so that when we tcheck the
+  // body, lookup will find them
+
+  // set up the scopes in a way similar to how it was when the
+  // template definition was first seen
+  ObjList<SavedScopePair> poppedScopes;
+  SObjList<Scope> pushedScopes;
+  prepArgScopeForTemlCloneTcheck(poppedScopes, pushedScopes, defnScope);
+
+  // bind the template arguments
+  insertTemplateArgBindings(spec, instTI->arguments);
+
+  // check the type tag, and push qualifier scopes
+  ScopeSeq qualifierScopes;
+  tcheckDeclaratorPQName(env, qualifierScopes, instCT->syntax->name, LF_DECLARATOR);
+
+  // the instantiation is will be complete; I think we must do this
+  // before checking into the compound to avoid repeatedly attempting
+  // to instantiate this class
+  instCT->forward = false;
+  instCT->syntax->ctype = instCT;
+
+  // check the class body, forcing it to use 'instCT'; don't check
+  // method bodies
+  {
+    Restorer<bool> r(checkFunctionBodies, false);
+    instCT->syntax->tcheckIntoCompound(*this, DF_NONE, instCT);
+  }
+
+  // Now, we've just tchecked the clone in an environment that
+  // makes all the type variables map to concrete types, so we
+  // now have a nice, ordinary, non-template class with a bunch
+  // of members.  But there is information stored in the
+  // original AST that needs to be transferred over to the
+  // clone, namely information about out-of-line definitions.
+  // We need both the Function pointers and the list of template
+  // params used at the definition site (since we have arguments
+  // but don't know what names to bind them to).  So, walk over
+  // both member lists, transferring information as necessary.
+  if (!origCT) {
+    transferTemplateMemberInfo(loc(), specCT->syntax, instCT->syntax,
+                               instTI->arguments);
+  }
+  else {
+    // this is the case above where we bypassed 'specCT', which is a
+    // partial instanitation; first combine the arguments from the
+    // partial inst with those from 'instTI'
+    ObjList<STemplateArgument> combinedArgs;
+    copyTemplateArgs(combinedArgs, specTI->arguments /*partial inst args*/);
+    copyTemplateArgs(combinedArgs, instTI->arguments);
+
+    // now transfer member info from the original
+    transferTemplateMemberInfo(loc(), origCT->syntax, instCT->syntax,
+                               combinedArgs);
+  }
+
+  // restore the scopes
+  env.retractScopeSeq(qualifierScopes);
+  deleteTemplateArgBindings();
+  unPrepArgScopeForTemlCloneTcheck(poppedScopes, pushedScopes);
+  xassert(poppedScopes.isEmpty() && pushedScopes.isEmpty());
+}
+
+
+// this is for 14.7.1 para 4, among other things
+void Env::ensureClassBodyInstantiated(CompoundType *ct)
+{
+  if (!ct->isComplete() && ct->isInstantiation()) {
+    Variable *inst = ct->typedefVar;
+
+    // 2005-04-17: in/k0053.cc: we would like to instantiate this
+    // template, but if there has not yet been a definition, then skip
+    // it (without error)
+    TemplateInfo *instTI = inst->templateInfo();
+    Variable *spec = instTI->instantiationOf;
+    CompoundType *specCT = spec->type->asCompoundType();
+    if (specCT->forward) {
+      TRACE("template", "would like to instantiate body of " <<
+                        instTI->templateName() <<
+                        ", but no template defn available");
+      return;
+    }
+
+    instantiateClassBody(inst);
+  }
+}
+
+// given a function type whose parameters are about to be considered
+// for various conversions, make sure that all relevant template
+// classes are instantiated
+void Env::instantiateTemplatesInParams(FunctionType *ft)
+{
+  SFOREACH_OBJLIST(Variable, ft->params, iter) {
+    Type *paramType = iter.data()->type;
+    if (paramType->asRval()->isCompoundType()) {
+      ensureClassBodyInstantiated(paramType->asRval()->asCompoundType());
+    }
+  }
+}
+
+
+void Env::instantiateForwardClasses(Variable *baseV)
+{
+  SFOREACH_OBJLIST_NC(Variable, baseV->templateInfo()->instantiations, iter) {
+    instantiateClassBody(iter.data());
+  }
+}
+
+
+// return false on error
+bool Env::supplyDefaultTemplateArguments
+  (TemplateInfo *primaryTI,
+   ObjList<STemplateArgument> &dest,          // arguments to use for instantiation
+   SObjList<STemplateArgument> const &src)    // arguments supplied by user
+{
+  // since default arguments can refer to earlier parameters,
+  // maintain a map of the arguments known so far
+  MType map(env);
+
+  // simultanously iterate over arguments and parameters, building
+  // 'dest' as we go
+  SObjListIter<Variable> paramIter(primaryTI->params);
+  SObjListIter<STemplateArgument> argIter(src);
+  while (!paramIter.isDone()) {
+    Variable const *param = paramIter.data();
+
+    STemplateArgument *arg = NULL;     // (owner)
+
+    // take argument from explicit list?
+    if (!argIter.isDone()) {
+      arg = argIter.data()->shallowClone();
+      argIter.adv();
+
+      // TODO: check that this argument matches the template parameter
+    }
+
+    // default?
+    else {
+      arg = makeDefaultTemplateArgument(paramIter.data(), map);
+      if (arg) {
+        TRACE("template", "supplied default argument `" <<
+                          arg->toString() << "' for param `" <<
+                          param->name << "'");
+      }
+    }
+
+    if (!arg) {
+      error(stringc << "no argument supplied for template parameter `"
+                    << param->name << "'");
+      return false;
+    }
+
+    // save this argument
+    dest.append(arg);
+    if (param->name) {
+      map.setBoundValue(param->name, *arg);
+    }
+
+    paramIter.adv();
+  }
+
+  if (!argIter.isDone()) {
+    error(stringc << "too many arguments supplied to template `"
+                  << primaryTI->templateName() << "'");
+    return false;
+  }
+
+  return true;
+}
+
+
+// moved Env::makeDefaultTemplateArgument into notopt.cc
+
+
+void Env::setSTemplArgFromExpr(STemplateArgument &sarg, Expression *expr)
+{
+  // see cppstd 14.3.2 para 1
+
+  if (expr->type->containsGeneralizedDependent()) {
+    // then certainly the value is dependent too, right?  in/k0003.cc
+    sarg.setDepExpr(expr);
+    return;
+  }
+
+  // TODO/BUG: I am basically saying that if a template argument can
+  // be const-eval'd, then it is an integer argument.  But it might be
+  // that the user is intending to pass a const-eval'able variable as
+  // a reference argument, in which case this code will do the wrong
+  // thing.  (in/t0509.cc)
+  //
+  // In general, this computation must also be told what type the
+  // corresponding template *parameter* has.
+
+  // (in/t0552.cc) maybe this is an enumerator?
+  if (expr->skipGroups()->isE_variable()) {
+    Variable *var = expr->skipGroups()->asE_variable()->var;
+    if (var && var->hasFlag(DF_ENUMERATOR)) {
+      sarg.setEnumerator(var);
+      return;
+    }
+  }
+
+  Type *rvalType = expr->type->asRval();
+  if (rvalType->isIntegerType() ||
+      rvalType->isBool() ||
+      rvalType->isEnumType()) {
+    // attempt to const-eval this expression
+    ConstEval cenv(env.dependentVar);
+    CValue val = expr->constEval(cenv);
+    if (val.isDependent()) {
+      sarg.setDepExpr(expr);
+    }
+    else if (val.isIntegral()) {
+      sarg.setInt(val.getIntegralValue());
+    }
+    else if (val.isError()) {
+      if (expr->type->isReference()) {
+        goto handle_reference;         // second chance
+      }
+      else {
+        env.error(stringc
+          << "cannot evaluate `" << expr->exprToString()
+          << "' as a template integer argument: " << *val.getWhy());
+        delete val.getWhy();
+      }
+    }
+    else {
+      xassert(val.isFloat());
+      env.error("cannot use float type as template argument");
+    }
+  }
+
+  else if (expr->type->isReference()) {
+  handle_reference:
+    if (expr->isE_variable()) {
+      // TODO: 14.3.2p1 says you can only use variables with
+      // external linkage
+      sarg.setReference(expr->asE_variable()->var);
+    }
+    else {
+      env.error(stringc
+        << "`" << expr->exprToString() << "' must be a simple variable "
+        << "for it to be a template reference argument");
+    }
+  }
+
+  else if (expr->type->isPointer()) {
+    if (expr->isE_addrOf() &&
+        expr->asE_addrOf()->expr->isE_variable()) {
+      // TODO: 14.3.2p1 says you can only use variables with
+      // external linkage
+      sarg.setPointer(expr->asE_addrOf()->expr->asE_variable()->var);
+    }
+    else if (expr->isE_variable() &&
+             expr->asE_variable()->var->isTemplateParam()) {
+      sarg.setPointer(expr->asE_variable()->var);
+    }
+    else {
+      // TODO: This is wrong; the '&' is optional for arrays.
+      env.error(stringc
+        << "`" << expr->exprToString() << " must be the address of a "
+        << "simple variable for it to be a template pointer argument");
+    }
+  }
+
+  else if (expr->type->isFunctionType()) {
+    // implicitly take its address [14.3.2p5b4] (in/t0561.cc)
+    if (expr->isE_variable()) {
+      // TODO: 14.3.2p1 says you can only use functions with
+      // external linkage
+      sarg.setPointer(expr->asE_variable()->var);
+    }
+    else {
+      env.error(stringc
+        << "`" << expr->exprToString() << " must be the name of a "
+        << "function for it to be a template pointer argument");
+    }
+  }
+
+  else if (expr->type->isPointerToMemberType()) {
+    // this check is identical to the case above, but combined with
+    // the inferred type it checks for a different syntax
+    if (expr->isE_addrOf() &&
+        expr->asE_addrOf()->expr->isE_variable()) {
+      sarg.setMember(expr->asE_addrOf()->expr->asE_variable()->var);
+    }
+    else {
+      env.error(stringc
+        << "`" << expr->exprToString() << " must be the address of a "
+        << "class member for it to be a template pointer argument");
+    }
+  }
+
+  else {
+    env.error(expr->type, stringc
+      << "`" << expr->exprToString() << "' has type `"
+      << expr->type->toString() << "' but that's not an allowable "
+      << "type for a non-type template argument");
+  }
+}
+
+
+// This function is intended to do what the above would do if given
+// an E_variable wrapped around this 'var', except it cannot tolerate
+// yielding a dependent expression.
+STemplateArgument Env::variableToSTemplateArgument(Variable *var)
+{
+  STemplateArgument ret;
+
+  // try to evaluate to an integer
+  ConstEval cenv(env.dependentVar);
+  CValue val = cenv.evaluateVariable(var);
+  if (val.isIntegral()) {
+    ret.setInt(val.getIntegralValue());
+  }
+  else {
+    // just assume it's a reference; this is wrong, like above, because
+    // we really should be taking into account the parameter type
+    ret.setReference(var);
+  }
+
+  return ret;
+}
+
+
+// 2005-08-12: After considerable struggles to get out-of-line defns
+// of member template classes to work (and even that is just working
+// in some simple cases that I happen to test), I now realize that the
+// idea of transferring member info is fundamentally flawed.
+//
+// Rather than "pushing" information down to the members, I should
+// always "pull" it from the container when needed.  That is, rather
+// than making the data complicated, I should put the complication
+// into the queries.
+//
+// The reason is (in retrospect) obvious: data is shared across all
+// contexts, whereas queries are context-sensitive.  It's easy to make
+// adjustments to queries to compensate for this or that wrinkle, but
+// anytime I change the data invariants I have to consider all queries
+// simultaneously.  In practice, this often means several cycles of
+// trying things and running through the regressions to see what
+// breaks.  It's inefficient and unsatisfying.
+//
+// So what I should do at some point is simplify the data design so
+// that it records the minimum amount of information needed to support
+// the queries.  When I see a definition of something previously
+// declared, connect them, but then rely on users of the declaration
+// to indirect through it to find the definition, rather than eagerly
+// propagating the definition to the users (primarily, members of
+// instantiations).
+
+
+// transfer template info from members of 'source' to corresp.
+// members of 'dest'; 'dest' is a clone of 'source'
+//
+// see comments above
+void Env::transferTemplateMemberInfo
+  (SourceLoc instLoc, TS_classSpec *source,
+   TS_classSpec *dest, ObjList<STemplateArgument> const &sargs)
+{
+  // simultanous iteration
+  ASTListIterNC<Member> srcIter(source->members->list);
+  ASTListIterNC<Member> destIter(dest->members->list);
+
+  for (; !srcIter.isDone() && !destIter.isDone();
+         srcIter.adv(), destIter.adv()) {
+    if (srcIter.data()->isMR_decl()) {
+      Declaration *srcDecl = srcIter.data()->asMR_decl()->d;
+      Declaration *destDecl = destIter.data()->asMR_decl()->d;
+
+      if (srcDecl->dflags & DF_FRIEND) {
+        continue;     // skip whole declaration for friends (t0262.cc)
+      }
+
+      // associate the type specifiers
+      transferTemplateMemberInfo_typeSpec(instLoc, srcDecl->spec, source->ctype,
+                                          destDecl->spec, sargs);
+
+      // simultanously iterate over the declarators
+      FakeList<Declarator> *srcDeclarators = srcDecl->decllist;
+      FakeList<Declarator> *destDeclarators = destDecl->decllist;
+
+      for (; srcDeclarators->isNotEmpty() && destDeclarators->isNotEmpty();
+             srcDeclarators = srcDeclarators->butFirst(),
+             destDeclarators = destDeclarators->butFirst()) {
+        Variable *srcVar = srcDeclarators->first()->var;
+        Variable *destVar = destDeclarators->first()->var;
+
+        // transfer info for member functions and static data
+        //
+        // 2005-08-13: Ouch!  It turns out I really haven't
+        // implemented instantiation of static data members of class
+        // templates at all, so the required data structures are
+        // simply not present to let me fix in/t0554.cc, which
+        // requires (among other things) turning on the 'isStatic'
+        // possibility below.
+        //
+        // TODO: Implement instantiation of static data members.
+        if (!srcVar->isType()) {
+          if (srcVar->type->isFunctionType() /*|| srcVar->isStatic()*/) {
+            // srcVar -> destVar
+            transferTemplateMemberInfo_one(instLoc, srcVar, destVar, sargs);
+          }
+        }
+      }
+      xassert(srcDeclarators->isEmpty() && destDeclarators->isEmpty());
+    }
+
+    else if (srcIter.data()->isMR_func()) {
+      if (srcIter.data()->asMR_func()->f->dflags & DF_FRIEND) {
+        // skip these.. apparently I do not have TemplateInfos on
+        // them, which might itself be a mistake, but since that's the
+        // case right now, must do this here (t0558.cc)
+        continue;
+      }
+
+      Variable *srcVar = srcIter.data()->asMR_func()->f->nameAndParams->var;
+      Variable *destVar = destIter.data()->asMR_func()->f->nameAndParams->var;
+
+      transferTemplateMemberInfo_one(instLoc, srcVar, destVar, sargs);
+
+      // the instance 'destVar' needs to have a 'defnScope'; it didn't
+      // get set earlier b/c at the time the declaration was tchecked,
+      // the Function didn't know it was an instantiation (but why is
+      // that?)
+      TemplateInfo *destTI = destVar->templateInfo();
+      if (!destTI->defnScope) {
+        destTI->defnScope = destVar->scope;
+        xassert(destTI->defnScope);
+
+        // arg.. I keep pushing this around.. maybe new strategy:
+        // set defnScope and funcDefn at same time?
+        destVar->funcDefn = destIter.data()->asMR_func()->f;
+      }
+      else {
+        // this happens when 'destVar' is actually a partial instantiation,
+        // so the scope was set by transferTemplateMemberInfo_membert
+        // when ..._one delegated to it
+        xassert(destTI->isPartialInstantiation());
+      }
+    }
+
+    else if (srcIter.data()->isMR_template()) {
+      TemplateDeclaration *srcTDecl = srcIter.data()->asMR_template()->d;
+      TemplateDeclaration *destTDecl = destIter.data()->asMR_template()->d;
+
+      // I've decided that member templates should just be treated as
+      // primaries in their own right, right no relation to the
+      // "original" definition, hence no action is needed!
+      //
+      // ah, but there is still the need to xfer the funcDefn, and to
+      // find the instantiations later, for out-of-line defns, plus they
+      // need to remember the template arguments.  so, I'm introducing
+      // the notion of "partial instantiation"
+
+      if (srcTDecl->isTD_decl()) {
+        TypeSpecifier *srcSpec = srcTDecl->asTD_decl()->d->spec;
+        if (srcSpec->isTS_classSpec() || srcSpec->isTS_elaborated()) {
+          // old TD_class behavior
+          transferTemplateMemberInfo_typeSpec(instLoc,
+            srcSpec, source->ctype,
+            destTDecl->asTD_decl()->d->spec, sargs);
+        }
+        else if (srcTDecl->asTD_decl()->d->dflags & DF_FRIEND) {
+          // (k0056.cc) source declaration is a friend... I *think* I
+          // just want to ignore it here... if I don't, then the
+          // member transfer logic gets confused by the fact that the
+          // presence and checkedness of the definition is independent
+          // of this template class's state (because the friend is not
+          // actually a memebr)
+        }
+        else {
+          // old TD_proto behavior
+          Variable *srcVar = srcTDecl->asTD_decl()->d->decllist->first()->var;
+          Variable *destVar = destTDecl->asTD_decl()->d->decllist->first()->var;
+
+          transferTemplateMemberInfo_membert(instLoc, srcVar, destVar, sargs);
+        }
+      }
+
+      else if (srcTDecl->isTD_func()) {
+        Variable *srcVar = srcTDecl->asTD_func()->f->nameAndParams->var;
+        Variable *destVar = destTDecl->asTD_func()->f->nameAndParams->var;
+
+        transferTemplateMemberInfo_membert(instLoc, srcVar, destVar, sargs);
+      }
+
+      else if (srcTDecl->isTD_tmember()) {
+        // not sure if this would even parse... if it does I don't
+        // know what it might mean
+        error("more than one template <...> declaration inside a class body?");
+      }
+
+      else {
+        xfailure("unknown TemplateDeclaration kind");
+      }
+    }
+
+    else {
+      // other kinds of member decls: don't need to do anything
+    }
+  }
+
+  // one is clone of the other, so same length lists
+  xassert(srcIter.isDone() && destIter.isDone());
+}
+
+
+// transfer specifier info, particularly for nested class or
+// member template classes
+void Env::transferTemplateMemberInfo_typeSpec
+  (SourceLoc instLoc, TypeSpecifier *srcTS, CompoundType *sourceCT,
+   TypeSpecifier *destTS, ObjList<STemplateArgument> const &sargs)
+{
+  if (srcTS->isTS_elaborated()) {
+    Variable *srcVar = srcTS->asTS_elaborated()->atype->typedefVar;
+    Variable *destVar = destTS->asTS_elaborated()->atype->typedefVar;
+
+    if (srcVar->scope == sourceCT) {
+      // just a forward decl, do the one element
+      transferTemplateMemberInfo_one(instLoc, srcVar, destVar, sargs);
+    }
+    else {
+      // this isn't a declaration of a type that is a member of the
+      // relevant template, it is just a reference to some other type;
+      // ignore it
+    }
+  }
+
+  else if (srcTS->isTS_classSpec()) {
+    TS_classSpec *srcCS = srcTS->asTS_classSpec();
+    TS_classSpec *destCS = destTS->asTS_classSpec();
+
+    // connect the classes themselves
+    transferTemplateMemberInfo_one(instLoc,
+      srcCS->ctype->typedefVar,
+      destCS->ctype->typedefVar, sargs);
+
+    // connect their members
+    transferTemplateMemberInfo(instLoc, srcCS, destCS, sargs);
+  }
+
+  else {
+    // other kinds of type specifiers: don't need to do anything
+  }
+}
+
+
+// transfer template information from primary 'srcVar' to
+// instantiation 'destVar'
+void Env::transferTemplateMemberInfo_one
+  (SourceLoc instLoc, Variable *srcVar, Variable *destVar,
+   ObjList<STemplateArgument> const &sargs)
+{
+  xassert(srcVar != destVar);
+
+  // bit of a hack: if 'destVar' already has templateInfo, then it's
+  // because it is a member template (or a member of a member
+  // template), and we got here by recursively calling
+  // 'transferTemplateMemberInfo'; call the member template handler
+  // instead
+  if (destVar->templateInfo()) {
+    transferTemplateMemberInfo_membert(instLoc, srcVar, destVar, sargs);
+    return;
+  }
+
+  TRACE("templateXfer", "associated primary " << srcVar->toQualifiedString()
+                     << " with inst " << destVar->toQualifiedString());
+
+  // make the TemplateInfo for this member instantiation
+  TemplateInfo *destTI = new TemplateInfo(instLoc);
+
+  // copy arguments into 'destTI'
+  destTI->copyArguments(sargs);
+
+  // attach 'destTI' to 'destVar'
+  destVar->setTemplateInfo(destTI);
+
+  // 'destVar' is an instantiation of 'srcVar' with 'sargs'
+  TemplateInfo *srcTI = srcVar->templateInfo();
+  xassert(srcTI);
+  srcTI->addInstantiation(destVar);
+
+  // set 'destTI->uninstantiatedDefaultArgs'
+  if (destVar->type->isFunctionType()) {
+    destTI->uninstantiatedDefaultArgs =
+      countParamsWithDefaults(destVar->type->asFunctionType());
+  }
+}
+
+
+// this is for member templates ("membert")
+void Env::transferTemplateMemberInfo_membert
+  (SourceLoc instLoc, Variable *srcVar, Variable *destVar,
+   ObjList<STemplateArgument> const &sargs)
+{
+  // what follows is a modified version of 'transferTemplateMemberInfo_one'
+
+  // 'destVar' is a partial instantiation of 'srcVar' with 'args'
+  TemplateInfo *srcTI = srcVar->templateInfo();
+  xassert(srcTI);
+  TemplateInfo *destTI = destVar->templateInfo();
+  xassert(destTI);
+
+  if (destTI->isInstantiation() || destTI->isPartialInstantiation()) {
+    // The relevant info has already been transferred.  This happens
+    // for example when an inner class is declared and then defined,
+    // when we see it for the second time.
+    return;
+  }
+
+  // 2005-06-09: (in/t0504.cc) prepend instead of copy, because 'destTI'
+  // might be a partial instantiation (and therefore already has some
+  // arguments), and we want 'sargs' to be regarded as the arguments to
+  // its containing template
+  destTI->prependArguments(sargs);
+
+  srcTI->addPartialInstantiation(destVar);
+
+  // should not have already checked this member's body even if
+  // it has an inline definition
+  xassert(!destVar->funcDefn);
+
+  // does the source have a definition?
+  if (srcVar->funcDefn) {
+    // give the definition to the dest too
+    destVar->funcDefn = srcVar->funcDefn;
+
+    // is it inline?
+    if (srcVar->scope == srcTI->defnScope) {
+      // then the dest's defnScope should be similarly arranged
+      destTI->defnScope = destVar->scope;
+    }
+    else {
+      // for out of line, the defn scopes of src and dest are the same
+      destTI->defnScope = srcTI->defnScope;
+    }
+  }
+
+  // 2005-08-12: I started to do some analogous stuff for class
+  // templates, including making a copy of CompoundType::syntax, but
+  // that isn't right b/c those can't be shared since they are
+  // supposed to be tcheck'd before transferring member info.
+  //
+  // That, and I am *really* confused right now.  How the hell does
+  // any of this work?
+
+  // do this last so I have full info to print for 'destVar'
+  TRACE("templateXfer", "associated primary " << srcVar->toQualifiedString()
+                     << " with partial inst " << destVar->toQualifiedString());
+}
+
+
+// given a name that was found without qualifiers or template arguments,
+// see if we're currently inside the scope of a template definition
+// with that name
+CompoundType *Env::findEnclosingTemplateCalled(StringRef name)
+{
+  FOREACH_OBJLIST(Scope, scopes, iter) {
+    Scope const *s = iter.data();
+
+    if (s->curCompound &&
+        s->curCompound->templateInfo() &&
+        s->curCompound->name == name) {
+      return s->curCompound;
+    }
+  }
+  return NULL;     // not found
+}
+
+
+// we (may) have just encountered some syntax which declares
+// some template parameters, but found that the declaration
+// matches a prior declaration with (possibly) some other template
+// parameters; verify that they match (or complain), and then
+// discard the ones stored in the environment (if any)
+//
+// return false if there is some problem, true if it's all ok
+// (however, this value is ignored at the moment)
+bool Env::verifyCompatibleTemplateParameters(Scope *scope, CompoundType *prior)
+{
+  bool hasParams = scope->isTemplateParamScope();
+  if (hasParams && scope->parameterizedEntity) {
+    // (in/t0191.cc) already parameterized.. let's pretend we didn't
+    // see them (I suspect there is a deeper problem here, but maybe
+    // this hack will work for the moment)
+    hasParams = false;
+  }
+
+  if (!hasParams && !prior->isTemplate()) {
+    // neither talks about templates, forget the whole thing
+    return true;
+  }
+
+  // before going further, associate the scope's parameters
+  // so that happens regardless of the decision here
+  if (hasParams) {
+    scope->setParameterizedEntity(prior->typedefVar);
+  }
+
+  if (!hasParams && prior->isTemplate()) {
+    error(stringc
+      << "prior declaration of " << prior->keywordAndName()
+      << " at " << prior->typedefVar->loc
+      << " was templatized with parameters "
+      << prior->templateInfo()->paramsToCString()
+      << " but the this one is not templatized",
+      EF_DISAMBIGUATES);
+    return false;
+  }
+
+  if (hasParams &&
+      scope->templateParams.isNotEmpty() &&      // t0252.cc
+      !prior->isTemplate()) {
+    if (prior->isInstantiation()) {
+      // in/t0510.cc: 'prior' is an instantiation, so the parameters
+      // were referring to the template primary
+      prior = prior->templateInfo()->getPrimary()->var->type->asCompoundType();
+    }
+    else {
+      error(stringc
+        << "prior declaration of " << prior->keywordAndName()
+        << " at " << prior->typedefVar->loc
+        << " was not templatized, but this one is, with parameters "
+        << paramsToCString(scope->templateParams),
+        EF_DISAMBIGUATES);
+      return false;
+    }
+  }
+
+  // now we know both declarations have template parameters;
+  // check them for naming equivalent types
+  //
+  // furthermore, fix the names in 'prior' in case they differ
+  // with those of 'scope->curTemplateParams'
+  //
+  // even more, merge their default arguments
+  TemplateInfo *priorTI = prior->templateInfo();
+  if (!mergeParameterLists(prior->typedefVar,
+                           priorTI->params,            // dest
+                           scope->templateParams)) {   // src
+    return false;
+  }
+
+  // furthermore, do the same for inherited parameters (this
+  // appears to be the nominal intent of mergeTemplateInfos(),
+  // but that function is never called...) (in/t0441.cc)
+  //
+  // this will walk the list of inherited parameter lists in 'prior'
+  ObjListIterNC<InheritedTemplateParams> inhParamIter(priorTI->inheritedParams);
+
+  // this is clumsy; I have 'scope', but I need to find it in
+  // the scope stack so I can look at the ones that precede it
+  SObjList<Scope const> paramScopes;
+  {
+    ObjListIter<Scope> scopeIter(this->scopes);
+    while (scopeIter.data() != scope) {
+      scopeIter.adv();
+    }
+    scopeIter.adv();
+
+    // I want to compare 'inhParamIter' to the parameter scopes above
+    // 'scope'; except they're in the opposite orders, so first collect
+    // and reverse the scopes
+    for (; !scopeIter.isDone(); scopeIter.adv()) {
+      if (scopeIter.data()->isTemplateParamScope()) {
+        paramScopes.prepend(scopeIter.data());
+      }
+    }
+  }
+  SObjListIter<Scope const> scopeIter(paramScopes);
+
+  // merge corresponding parameter lists
+  while (!inhParamIter.isDone() && !scopeIter.isDone()) {
+    if (!mergeParameterLists(prior->typedefVar,
+                             inhParamIter.data()->params,         // dest
+                             scopeIter.data()->templateParams)) { // src
+      return false;
+    }
+
+    inhParamIter.adv();
+    scopeIter.adv();
+  }
+
+  // should end at same time
+  if (!inhParamIter.isDone() || !scopeIter.isDone()) {
+    // TODO: expand this message
+    env.error(stringc << "wrong # of template param lists in declaration of "
+                      << prior->name);
+  }
+
+  return true;
+}
+
+
+// context: I have previously seen a (forward) template
+// declaration, such as
+//   template <class S> class C;             // dest
+//                   ^
+// and I want to modify it to use the same names as another
+// declaration later on, e.g.
+//   template <class T> class C { ... };     // src
+//                   ^
+// since in fact I am about to discard the parameters that
+// come from 'src' and simply keep using the ones from
+// 'dest' for future operations, including processing the
+// template definition associated with 'src'
+bool Env::mergeParameterLists(Variable *prior,
+                              SObjList<Variable> &destParams,
+                              SObjList<Variable> const &srcParams)
+{
+  // if 'prior' is actually a definition, then don't make any changes
+  bool priorIsDefn = !prior->type->asCompoundType()->forward;
+
+  TRACE("templateParams", "mergeParameterLists: prior=" << prior->name
+    << ", dest=" << paramsToCString(destParams)
+    << ", src=" << paramsToCString(srcParams)
+    << ", priorIsDefn=" << priorIsDefn);
+
+  // keep track of whether I've made any naming changes
+  // (alpha conversions)
+  bool anyNameChanges = false;
+
+  SObjListMutator<Variable> destIter(destParams);
+  SObjListIter<Variable> srcIter(srcParams);
+  for (; !destIter.isDone() && !srcIter.isDone();
+       destIter.adv(), srcIter.adv()) {
+    Variable *dest = destIter.data();
+    Variable const *src = srcIter.data();
+
+    // are the types equivalent?
+    if (!equalOrIsomorphic(dest->type, src->type)) {
+      error(stringc
+        << "prior declaration of " << prior->toString()
+        << " at " << prior->loc
+        << " was templatized with parameter `"
+        << dest->name << "' of type `" << dest->type->toString()
+        << "' but this one has parameter `"
+        << src->name << "' of type `" << src->type->toString()
+        << "', and these are not equivalent",
+        EF_DISAMBIGUATES);
+      return false;
+    }
+
+    // what's up with their default arguments?
+    if (dest->value && src->value) {
+      // this message could be expanded...
+      error("cannot specify default value of template parameter more than once");
+      return false;
+    }
+
+    // there is a subtle problem if the prior declaration has a
+    // default value which refers to an earlier template parameter,
+    // but the name of that parameter has been changed
+    if (anyNameChanges &&              // earlier param changed
+        dest->value) {                 // prior has a value
+      // leave it as a to-do for now; a proper implementation should
+      // remember the name substitutions done so far, and apply them
+      // inside the expression for 'dest->value'
+      xunimp("alpha conversion inside default values"
+             " (workaround: use consistent names in template parameter lists)");
+    }
+
+    // merge their default values
+    if (src->value && !dest->value) {
+      dest->setValue(src->value);
+    }
+
+    // do they use the same name?
+    if (!priorIsDefn &&
+        dest->name != src->name) {
+      // make the names the same
+      TRACE("templateParams", "changing parameter " << dest->name
+        << " to " << src->name);
+      anyNameChanges = true;
+
+      // Make a new Variable to hold the modified parameter.  I'm not
+      // sure this is the right thing to do, b/c I'm concerned about
+      // the fact that the original decl will be pointing at the old
+      // Variable, but if I modify it in place I've got the problem
+      // that the template params for a class are shared by all its
+      // members, so I'd be changing all the members' params too.
+      // Perhaps it's ok to make a few copies of template parameter
+      // Variables, as they are somehow less concrete than the other
+      // named entities...
+      Variable *v = makeVariable(dest->loc, src->name, src->type, dest->flags);
+
+      // copy a few other fields, including default value
+      v->setValue(dest->value);
+      v->defaultParamType = dest->defaultParamType;
+      v->scope = dest->scope;
+      v->setScopeKind(dest->getScopeKind());
+
+      // replace the old with the new
+      destIter.dataRef() = v;
+    }
+  }
+
+  if (srcIter.isDone() && destIter.isDone()) {
+    return true;   // ok
+  }
+  else {
+    error(stringc
+      << "prior declaration of " << prior->toString()
+      << " at " << prior->loc
+      << " was templatized with "
+      << pluraln(destParams.count(), "parameter")
+      << ", but this one has "
+      << pluraln(srcParams.count(), "parameter"),
+      EF_DISAMBIGUATES);
+    return false;
+  }
+}
+
+
+// 2005-08-12: There are no call sites for this function.  There is
+// now code at the end of verifyCompatibleTemplateParameters that does
+// essentially the same thing.  However, I will leave this here
+// because this code looks cleaner, and it is possible that at some
+// point I will discover how to plug this function in to the design,
+// thereby letting me delete the mess in the other function.
+bool Env::mergeTemplateInfos(Variable *prior, TemplateInfo *dest,
+                             TemplateInfo const *src)
+{
+  bool ok = mergeParameterLists(prior, dest->params, src->params);
+
+  // sync up the inherited parameters too
+  ObjListIterNC<InheritedTemplateParams> destIter(dest->inheritedParams);
+  ObjListIter<InheritedTemplateParams> srcIter(src->inheritedParams);
+
+  for (; !destIter.isDone() && !srcIter.isDone();
+         destIter.adv(), srcIter.adv()) {
+    if (!mergeParameterLists(prior, destIter.data()->params, srcIter.data()->params)) {
+      ok = false;
+    }
+  }
+
+  if (!destIter.isDone() || !srcIter.isDone()) {
+    // TODO: expand this error message
+    error("differing number of template parameter lists");
+    ok = false;
+  }
+
+  return ok;
+}
+
+
+// ------------ BEGIN: applyArgumentMap -------------
+// The algorithm in this section is doing what is specified by
+// 14.8.2p2b3, substitution of template arguments for template
+// parameters in a type.  'src' is the type containing references
+// to the parameters, 'map' binds parameters to arguments, and
+// the return value is the type with substitutions performed.
+Type *Env::applyArgumentMapToType(MType &map, Type *origSrc)
+{
+  xassert(origSrc && "6ccc991e-bd8a-47d8-8f5c-e75d7065a29d");
+
+  // my intent is to not modify 'origSrc', so I will use 'src', except
+  // when I decide to return what I already have, in which case I will
+  // use 'origSrc'
+  Type const *src = origSrc;
+
+  switch (src->getTag()) {
+    default: xfailure("bad tag");
+
+    case Type::T_ATOMIC: {
+      CVAtomicType const *scat = src->asCVAtomicTypeC();
+      Type *ret = applyArgumentMapToAtomicType(map, scat->atomic, scat->cv);
+      if (!ret) {
+        return origSrc;      // use original
+      }
+      else {
+        return ret;
+      }
+    }
+
+    case Type::T_POINTER: {
+      PointerType const *spt = src->asPointerTypeC();
+      return tfac.makePointerType(spt->cv,
+        applyArgumentMapToType(map, spt->atType));
+    }
+
+    case Type::T_REFERENCE: {
+      ReferenceType const *srt = src->asReferenceTypeC();
+      return tfac.makeReferenceType(applyArgumentMapToType(map, srt->atType));
+    }
+
+    case Type::T_FUNCTION: {
+      FunctionType const *sft = src->asFunctionTypeC();
+      FunctionType *rft = tfac.makeFunctionType(applyArgumentMapToType(map, sft->retType));
+
+      // copy parameters
+      int ct=0;
+      SFOREACH_OBJLIST(Variable, sft->params, iter) {
+        ct++;
+        Variable const *sp = iter.data();
+
+        // result parameter type
+        Type *rpt;
+        if (sft->isMethod() && ct==1) {
+          rpt = applyArgumentMapToReceiverType(map, sp->type);
+        }
+        else {
+          rpt = applyArgumentMapToType(map, sp->type);
+        }
+
+        Variable *rp = makeVariable(sp->loc, sp->name, rpt, sp->flags);
+
+        if (sp->value) {
+          // TODO: I should be substituting the template parameters
+          // in the default argument too... but for now I will just
+          // use it without modification
+          rp->setValue(sp->value);
+        }
+
+        rft->addParam(rp);
+      }
+      doneParams(rft);
+
+      rft->flags = sft->flags;
+
+      if (rft->exnSpec) {
+        // TODO: this
+        //
+        // Note: According to 14.8.2p2b3, if mapping the exception types
+        // leads to a failure, that is only diagnosed when the function
+        // *definition* is instantiated.  Thus, my tentative plan here is
+        // to attempt to do the map here, and if it fails, store ST_ERROR.
+        // Later, if/when I instantate the definition, check for ST_ERROR
+        // and diagnose it then (hmm, by then I will have lost the error
+        // message itself ...).
+        xunimp("applyArgumentMap: exception spec");
+      }
+
+      return rft;
+    }
+
+    case Type::T_ARRAY: {
+      ArrayType const *sat = src->asArrayTypeC();
+      return tfac.makeArrayType(applyArgumentMapToType(map, sat->eltType), sat->size);
+    }
+
+    case Type::T_POINTERTOMEMBER: {
+      PointerToMemberType const *spmt = src->asPointerToMemberTypeC();
+
+      // slightly tricky mapping the 'inClassNAT' since we need to make
+      // sure the mapped version is still a NamedAtomicType
+      Type *retInClassNAT =
+        applyArgumentMapToAtomicType(map, spmt->inClassNAT, CV_NONE);
+      if (!retInClassNAT) {
+        // use original 'spmt->inClassNAT'
+        return tfac.makePointerToMemberType
+          (spmt->inClassNAT,
+           spmt->cv,
+           applyArgumentMapToType(map, spmt->atType));
+      }
+      else if (!retInClassNAT->isCompoundType()) {
+        // 14.8.2p2b3.6
+        xTypeDeduction(stringc
+          << "during construction of pointer-to-member, type `"
+          << retInClassNAT->toString() << "' is not a class");
+      }
+      else {
+        return tfac.makePointerToMemberType
+          (retInClassNAT->asCompoundType(),
+           spmt->cv,
+           applyArgumentMapToType(map, spmt->atType));
+      }
+    }
+  }
+}
+
+Type *Env::applyArgumentMapToAtomicType
+  (MType &map, AtomicType *origSrc, CVFlags srcCV)
+{
+  AtomicType const *src = origSrc;
+
+  if (src->isTypeVariable()) {
+    TypeVariable const *stv = src->asTypeVariableC();
+
+    STemplateArgument replacement = map.getBoundValue(stv->name, tfac);
+    if (!replacement.hasValue()) {
+      // I can trigger these when there is a preceding error;
+      // an example is in/t0517.cc error 1
+      xTypeDeduction(stringc << "the type name `"
+                             << stv->name << "' is not bound");
+    }
+    else if (!replacement.isType()) {
+      xTypeDeduction(stringc << "the type name `"
+                             << stv->name << "' is bound to a non-type argument");
+    }
+
+    // take what we got and apply the cv-flags that were associated
+    // with the type variable, e.g. "T const" -> "int const"
+    return applyArgumentMap_applyCV(srcCV, replacement.getType());
+  }
+
+  else if (src->isPseudoInstantiation()) {
+    PseudoInstantiation const *spi = src->asPseudoInstantiationC();
+
+    // build a concrete argument list, so we can make a real instantiation
+    ObjList<STemplateArgument> args;
+    applyArgumentMapToTemplateArgs(map, args, spi->args);
+
+    // instantiate the class with our newly-created arguments
+    Variable *instClass = instantiateClassTemplate_or_PI(spi->primary, args);
+    if (!instClass) {
+      instClass = errorVar;    // error already reported; this is recovery
+    }
+
+    // apply the cv-flags and return it
+    return applyArgumentMap_applyCV(srcCV, instClass->type);
+  }
+
+  else if (src->isDependentQType()) {     // e.g. in/t0506.cc
+    DependentQType const *sdqt = src->asDependentQTypeC();
+
+    // resolve 'first' (this unfortunately wraps the result in an
+    // extraneous CVAtomicType)
+    AtomicType *retFirst =
+      applyArgumentMapToAtomicType(map, sdqt->first, CV_NONE)->
+        asCVAtomicType()->atomic;
+    if (!retFirst->isCompoundType()) {
+      // 14.8.2p2b3.3
+      xTypeDeduction(stringc
+        << "attempt to extract member `" << sdqt->rest->toString()
+        << "' from non-class `" << retFirst->toString() << "'");
+    }
+
+    // resolve 'first'::'rest'
+    return applyArgumentMap_applyCV(srcCV,
+             applyArgumentMapToQualifiedType(map, retFirst->asCompoundType(),
+                                             sdqt->rest));
+  }
+
+  else {
+    // all others do not refer to type variables; returning NULL
+    // here means to use the original unchanged
+    return NULL;
+  }
+}
+
+Type *Env::applyArgumentMap_applyCV(CVFlags cv, Type *type)
+{
+  if (type->isReferenceType()) {
+    // apparently, since 14.8.1p2 doesn't explicitly prohibit
+    // attempting to cv-qualify a reference, it is allowed
+    // (in/t0549.cc)
+    return type;
+  }
+
+  Type *ret = tfac.applyCVToType(SL_UNKNOWN, cv,
+                                 type, NULL /*syntax*/);
+  if (!ret) {
+    // 14.8.2p2b3.9
+    //
+    // This might be wrong, since b3.9 discusses cv-qualification of
+    // functions, but applyCVToType also does not like
+    // cv-qualification of arrays.  Who should push the
+    // cv-qualification down?  I'm thinking it should be applyCV...
+    xTypeDeduction(stringc << "type `" << type->toString()
+                           << "' cannot be cv-qualified");
+  }
+  else {
+    return ret;     // good to go
+  }
+}
+
+// Apply 'map' to 'origSrc', where 'origSrc' is playing the role of a
+// receiver object parameter type.
+//
+// This is a special case because Elsa represents the cv-flags on a
+// function type by applying them to the receiver object type.
+// However, when template arguments are supplied, if I'm not careful,
+// then the cv-flags might be affected by applying the binding.  But
+// that would be wrong; C++ does not provide any mechanism to abstract
+// the cv-flags of function types.
+//
+// Example (in/t0589.cc):
+//
+//   template <class T>
+//   int f(int (T::*)(T &));
+//
+// The correct type of f<S const> is:
+// 
+//   int ()(int (S::*)(S const &))
+//
+// but blind substitution in the Elsa representation would yield:
+//
+//   int ()(int (S::*)(S const &) const)
+//                                ^^^^^ oops
+//
+// So, what we're going to do in this function is apply the map, but
+// force the final cv-flags under the reference to be unchanged.
+//
+// The underlying reason for these shenanigans is that Elsa (as a
+// general architectural principle) moves from syntactic to semantic
+// representations of types as early as possible (that is also the
+// reason it boils away typedefs early, though that decision may need
+// to be revisited).  Since cv-flags on functions have the effect of
+// cv-qualifying the receiver, Elsa puts them there, hence analyses do
+// not need to handle them specially.  But because application of
+// template arguments is specified in the C++ standard in terms of
+// type syntax, I need to (in this one instance) pull them off to
+// treat them specially.
+//
+Type *Env::applyArgumentMapToReceiverType(MType &map, Type *origSrc)
+{             
+  Type const *src = origSrc;
+                                  
+  // The receiver object type is always a reference
+  xassert(src->isReferenceType());
+  
+  // Get the cv-flags on the type under the reference; these are
+  // actually the cv-flags for the function type this parameter is
+  // contained in (or at least, that is how they would be rendered
+  // syntactically).
+  Type *srcAtType = src->asReferenceTypeC()->atType;
+  CVFlags origCVFlags = srcAtType->getCVFlags();
+  
+  // Now apply the map as usual.
+  Type *destAtType = applyArgumentMapToType(map, srcAtType);
+  if (destAtType == srcAtType) {
+    return origSrc;     // no changes at all
+  }
+  
+  // Now get a version of 'destAtType' whose cv-qualifiers are the
+  // same as 'origCVFlags'.
+  destAtType = tfac.setQualifiers(SL_UNKNOWN, origCVFlags, destAtType,
+                                  NULL /*syntax*/);
+
+  // Finally, package it up as a ReferenceType again
+  return tfac.makeReferenceType(destAtType);
+}
+
+
+void Env::applyArgumentMapToTemplateArgs
+  (MType &map, ObjList<STemplateArgument> &dest,
+                               ObjList<STemplateArgument> const &srcArgs)
+{
+  xassert(dest.isEmpty());     // for prepend+reverse
+
+  FOREACH_OBJLIST(STemplateArgument, srcArgs, iter) {
+    STemplateArgument const *sta = iter.data();
+    if (sta->isType()) {
+      STemplateArgument *rta = new STemplateArgument;
+      rta->setType(applyArgumentMapToType(map, sta->getType()));
+      dest.prepend(rta);
+    }
+    else if (sta->isDepExpr()) {
+      STemplateArgument replacement =
+        applyArgumentMapToExpression(map, sta->getDepExpr());
+      dest.prepend(replacement.shallowClone());
+    }
+    else {
+      // assume any other kind does not need to be mapped
+      dest.prepend(sta->shallowClone());
+    }
+  }
+
+  dest.reverse();
+}
+
+
+STemplateArgument Env::applyArgumentMapToExpression
+  (MType &map, Expression *e)
+{
+  // hack: just try evaluating it first; this will only work if
+  // the expression is entirely non-dependent (in/t0287.cc)
+  STemplateArgument ret;
+  setSTemplArgFromExpr(ret, e);
+  if (!ret.isDepExpr()) {
+    return ret;     // good to go
+  }
+
+  // TODO: I think the right way to do this is to use the
+  // constant-evaluator (which setSTemplArgFromExpr uses
+  // internally), modified to use 'map'
+
+  if (!e->isE_variable()) {
+    // example: Foo<T::x + 1>, where T maps to some class 'C' that
+    // has an integer constant 'x'
+    //
+    // TODO: my plan is to invoke the constant-expression
+    // evaluator, modified to accept 'map' so it knows how to
+    // handle template parameters
+    xunimp("applyArgumentMap: dep-expr is not E_variable");
+  }
+  E_variable *evar = e->asE_variable();
+
+  if (evar->var->isTemplateParam()) {
+    // name refers directly to a template parameter
+    xassert(evar->name->isPQ_name());     // no qualifiers
+    ret = map.getBoundValue(evar->var->name, tfac);
+    xassert(ret.hasValue()                // map should bind it
+            && "64103c40-efae-4068-b4b1-5492a549b00c");
+  }
+  else {
+    // name must refer to a qualified name involving the template
+    // parameter
+    xassert(evar->var == dependentVar);
+    xassert(evar->name->isPQ_qualifier());
+    ret = applyArgumentMapToQualifiedName(map, evar->name->asPQ_qualifier());
+    if (!ret.hasValue()) {
+      // couldn't resolve; just package up as dependent name again (in/t0543.cc)
+      ret.setDepExpr(e);
+    }
+  }
+
+  if (!ret.isObject()) {
+    xTypeDeduction(stringc
+      << "the name `" << evar->name->toString()
+      << "' should be bound to an object argument");
+  }
+
+  return ret;
+}
+
+
+// resolve 'qual' using 'map'
+STemplateArgument Env::applyArgumentMapToQualifiedName
+  (MType &map, PQ_qualifier *qual)
+{
+  // we need to know what the qualifier (ignoring template
+  // args) refers to
+  xassert(qual->qualifierVar);
+
+  // combine with template args to yield a scope that we
+  // can use to look up subsequent components of the name
+  Scope *firstScope;
+  if (qual->sargs.isEmpty()) {
+    // no template arguments, so the qualifier variable
+    // should be directly usable
+    firstScope = qual->qualifierVar->getDenotedScope();
+  }
+  else {
+    // apply the map to the arguments, then use them to
+    // instantiate the class
+    firstScope = applyArgumentMap_instClass(map, qual->qualifierVar, qual->sargs);
+    if (!firstScope) {
+      return STemplateArgument();     // keep pushing back to caller...
+    }
+  }
+
+  // interpret the rest of the name w.r.t. the computed scope
+  return applyArgumentMapToPQName(map, firstScope, qual->rest);
+}
+
+// map 'sargs', apply them to 'primary', yield result as a Scope
+CompoundType *Env::applyArgumentMap_instClass
+  (MType &map, Variable *primary,
+   ObjList<STemplateArgument> const &sargs)
+{
+  // should be a template class
+  xassert(primary->isTemplateClass(false /*considerInherited*/));
+
+  // map the template arguments
+  ObjList<STemplateArgument> mappedArgs;
+  applyArgumentMapToTemplateArgs(map, mappedArgs, sargs);
+
+  if (containsVariables(mappedArgs)) {
+    return NULL;     // caller must deal with this
+  }
+
+  // instantiate the template with the arguments
+  Variable *inst =
+    instantiateClassTemplate(loc(), primary, mappedArgs);
+  xassert(inst);     // can this fail?
+
+  return inst->type->asCompoundType();
+}
+
+// resolve 'name', which is qualified with 'scope', using 'map'
+STemplateArgument Env::applyArgumentMapToPQName
+  (MType &map, Scope *scope, PQName *name)
+{
+  if (scope->curCompound) {
+    applyArgumentMap_ensureComplete(scope->curCompound);
+  }
+
+  // lookups are by qualification with 'scope', and should not need
+  // using-edge traversal (as it happens, LF_IGNORE_USING makes
+  // LF_QUALIFIED irrelevant, but it is an accurate description of the
+  // lookup context so I keep it)
+  LookupFlags lflags = LF_QUALIFIED | LF_IGNORE_USING;
+
+  // take apart the name; this isn't shared with other code that
+  // does similar things because of the presence of 'map' ...
+  if (name->isPQ_name()) {
+    // lookup in 'scope'
+    LookupSet set;
+    scope->lookup(set, name->getName(), NULL /*env*/, lflags);
+    if (set.isEmpty()) {
+      xTypeDeduction(stringc << "failed to find `" << name->getName()
+                             << "' in " << scope->scopeName());
+    }
+    else if (set.count() != 1) {
+      // in principle I think this is legal, but would be rather difficult
+      // to implement, since it means tracking down the expected type of
+      // the parameter...
+      xunimp("overloaded function name used as template argument in unusual circumstance");
+    }
+
+    return variableToSTemplateArgument(set.first());
+  }
+
+  else if (name->isPQ_operator()) {
+    // can this happen?
+    xfailure("applyArgumentMap: operator name as dependent expr?");
+  }
+
+  else if (name->isPQ_template()) {
+    // NOTE: This code has not been tested.  I'm being a bit lazy
+    // right now, and it would be pretty unusual (something like using
+    // a qualified name of a member template function as a non-type
+    // argument to a template).
+
+    PQ_template *templ = name->asPQ_template();
+
+    lflags |= LF_TEMPL_PRIMARY;
+    Variable *v = scope->lookup_one(templ->name, NULL /*env*/, lflags);
+    if (!v) {
+      xTypeDeduction(stringc << "failed to find `" << templ->name
+                             << "' in " << scope->scopeName());
+    }
+    if (!v->isTemplateClass(false /*considerInherited*/)) {
+      xTypeDeduction(stringc << "`" << templ->name << "' in "
+                             << scope->scopeName() << " is not a template class");
+    }
+
+    // apply the arguments
+    CompoundType *ct = applyArgumentMap_instClass(map, v, templ->sargs);
+    if (!ct) {
+      return STemplateArgument();    // ...
+    }
+
+    // wrap in an STemplateArgument
+    STemplateArgument ret;
+    ret.setType(ct->typedefVar->type);
+    return ret;
+  }
+
+  else {
+    xassert(name->isPQ_qualifier());
+    PQ_qualifier *qual = name->asPQ_qualifier();
+
+    lflags |= LF_TEMPL_PRIMARY | LF_TYPES_NAMESPACES;
+    Variable *q = scope->lookup_one(qual->qualifier, NULL /*env*/, lflags);
+    if (!q) {
+      xTypeDeduction(stringc << "failed to find `" << qual->qualifier
+                             << "' in " << scope->scopeName());
+    }
+    if (!q->type->isCompoundType()) {
+      xTypeDeduction(stringc << "`" << qual->qualifier << "' in "
+                             << scope->scopeName() << " is not a class");
+    }
+
+    if (qual->sargs.isEmpty() && !q->isTemplate(false /*considerInherited*/)) {
+      // use 'q' as a scope to process the rest
+      return applyArgumentMapToPQName(map, q->getDenotedScope(), qual->rest);
+    }
+    else if (!qual->sargs.isEmpty() && q->isTemplate(false /*considerInherited*/)) {
+      // apply the arguments to obtain a scope, and then use that
+      Scope *s = applyArgumentMap_instClass(map, q, qual->sargs);
+      if (!s) {
+        return STemplateArgument();    // ...
+      }
+      return applyArgumentMapToPQName(map, s, qual->rest);
+    }
+    else {
+      xTypeDeduction(stringc
+        << "mismatch between template-ness and argument application for `"
+        << qual->qualifier << "' in " << scope->scopeName());
+      return STemplateArgument();    // silence warning
+    }
+  }
+}
+
+void Env::applyArgumentMap_ensureComplete(CompoundType *ct)
+{
+  // instantiate if necessary
+  ensureClassBodyInstantiated(ct);
+
+  // if the class is still incomplete (because the definition was
+  // not available), I say it's another case like those mentioned
+  // in 14.8.2p2b3, even though it isn't explicitly among them
+  if (ct->forward) {
+    xTypeDeduction(stringc
+      << "attempt to access member of `" << ct->instName
+      << "' but no definition has been seen");
+  }
+}
+
+
+
+// We are trying to resolve 'ct'::'name', but 'name' might refer to
+// type variables bound only in 'map'.
+//
+// This code is somewhat related to Env::resolveDQTs, but that
+// function looks for bindings in the environment, and is in general a
+// bit of a hack.  The code here is more principled, and does its work
+// without using the environment.
+//
+// 2005-08-07: There is some overlap between this function and
+// applyArgumentMapToQualifiedName.  Essentially, the former is for
+// names of types and the latter for names of non-types.  However,
+// those tasks are not sufficiently different to warrant two
+// completely separate mechanisms.  Collapsing them is a TODO.
+Type *Env::applyArgumentMapToQualifiedType
+  (MType &map, CompoundType *ct, PQName *name)
+{
+  applyArgumentMap_ensureComplete(ct);
+
+  // similar to above
+  LookupFlags lflags = LF_QUALIFIED | LF_IGNORE_USING;
+
+  if (name->isPQ_name() || name->isPQ_operator()) {
+    // ordinary lookup will suffice
+    Variable *var = ct->lookup_one(name->getName(), NULL /*env*/, lflags);
+    if (!var || !var->isType()) {
+      xTypeDeduction(stringc << "no such type: " << ct->name
+                             << "::" << name->toString());
+    }
+    else {
+      return var->type;
+    }
+  }
+
+  // PQ_qualifier or PQ_template; get name and args
+  StringRef memberName;
+  ObjList<STemplateArgument> *srcArgs;
+  if (name->isPQ_template()) {
+    PQ_template *pqt = name->asPQ_template();
+    memberName = pqt->name;
+    srcArgs = &(pqt->sargs);
+  }
+  else {
+    PQ_qualifier *pqq = name->asPQ_qualifier();
+    memberName = pqq->qualifier;
+    srcArgs = &(pqq->sargs);
+  }
+  xassert(memberName);     // can't refer to anon member in DQT
+
+  // lookup the name portion
+  Variable *qualVar = ct->lookup_one(memberName, NULL /*env*/,
+                                     lflags | LF_TEMPL_PRIMARY);
+  if (!qualVar || !qualVar->type->isCompoundType()) {
+    xTypeDeduction(stringc << "no such member class: " << ct->name
+                           << memberName);
+  }
+
+  bool argsProvided = !srcArgs->isEmpty();
+  bool isTemplate = qualVar->isTemplateClass(false /*considerInherited*/);
+
+  if (argsProvided && isTemplate) {
+    // resolve the template arguments using 'map'
+    ObjList<STemplateArgument> args;
+    applyArgumentMapToTemplateArgs(map, args, *srcArgs);
+
+    // instantiate the template with the arguments
+    qualVar = instantiateClassTemplate(loc(), qualVar, args);
+    if (!qualVar) {
+      return env.errorType();    // error already reported
+    }
+  }
+  else if (!argsProvided && isTemplate) {
+    xTypeDeduction(stringc << "member " << ct->name << "::" << memberName
+                           << " is a template, but template args were not provided");
+  }
+  else if (argsProvided && !isTemplate) {
+    xTypeDeduction(stringc << "member " << ct->name << "::" << memberName
+                           << " is not a template, but template args were provided");
+  }
+
+  if (name->isPQ_template()) {
+    // we're done; package up the answer
+    //
+    // 2005-08-07: Why the heck to I apply CV_NONE?  Why not just
+    // return inst->type directly?
+    return tfac.applyCVToType(SL_UNKNOWN, CV_NONE,
+                              qualVar->type, NULL /*syntax*/);
+  }
+  else {
+    // recursively continue deconstructing 'name'
+    return applyArgumentMapToQualifiedType(map, qualVar->type->asCompoundType(),
+                                           name->asPQ_qualifier()->rest);
+  }
+}
+// ------------ END: applyArgumentMap -------------
+
+
+Variable *Env::findCompleteSpecialization(TemplateInfo *tinfo,
+                                          ObjList<STemplateArgument> const &sargs)
+{
+  SFOREACH_OBJLIST_NC(Variable, tinfo->specializations, iter) {
+    TemplateInfo *instTI = iter.data()->templateInfo();
+    if (instTI->isomorphicArguments(sargs)) {
+      return iter.data();      // found it
+    }
+  }
+  return NULL;                 // not found
+}
+
+
+Variable *Env::findInstantiation(TemplateInfo *tinfo,
+                                 ObjList<STemplateArgument> const &sargs)
+{
+  if (tinfo->isCompleteSpec()) {
+    xassertdb(tinfo->isomorphicArguments(sargs));
+    return tinfo->var;
+  }
+
+  SFOREACH_OBJLIST_NC(Variable, tinfo->instantiations, iter) {
+    TemplateInfo *instTI = iter.data()->templateInfo();
+    if (instTI->isomorphicArguments(sargs)) {
+      return iter.data();      // found it
+    }
+  }
+  return NULL;                 // not found
+}
+
+
+// make a Variable with type 'type' that will be an instantiation
+// of 'templ'
+Variable *Env::makeInstantiationVariable(Variable *templ, Type *instType)
+{
+  Variable *inst = makeVariable(templ->loc, templ->name, instType, templ->flags);
+  inst->setAccess(templ->getAccess());
+  inst->scope = templ->scope;
+  inst->setScopeKind(templ->getScopeKind());
+  return inst;
+}
+
+
+void Env::bindParametersInMap(MType &map, TemplateInfo *tinfo,
+                              SObjList<STemplateArgument> const &sargs)
+{
+  SObjListIter<STemplateArgument> argIter(sargs);
+
+  // inherited parameters
+  FOREACH_OBJLIST(InheritedTemplateParams, tinfo->inheritedParams, iter) {
+    bindParametersInMap(map, iter.data()->params, argIter);
+  }
+
+  // main parameters
+  bindParametersInMap(map, tinfo->params, argIter);
+
+  if (!argIter.isDone()) {
+    error(stringc << "too many template arguments supplied for "
+                  << tinfo->var->name);
+  }
+}
+
+void Env::bindParametersInMap(MType &map,
+                              SObjList<Variable> const &params,
+                              SObjListIter<STemplateArgument> &argIter)
+{
+  SFOREACH_OBJLIST(Variable, params, iter) {
+    Variable const *param = iter.data();
+
+    if (map.getBoundValue(param->name, tfac).hasValue()) {
+      error(stringc << "template parameter `" << param->name <<
+                       "' occurs more than once");
+    }
+    else if (argIter.isDone()) {
+      error(stringc << "no template argument supplied for parameter `" <<
+                       param->name << "'");
+    }
+    else {
+      map.setBoundValue(param->name, *argIter.data());
+    }
+
+    if (!argIter.isDone()) {
+      argIter.adv();
+    }
+  }
+}
+
+
+// given a CompoundType that is a template (primary or partial spec),
+// yield a PseudoInstantiation of that template with its own params
+Type *Env::pseudoSelfInstantiation(CompoundType *ct, CVFlags cv)
+{
+  TemplateInfo *tinfo = ct->typedefVar->templateInfo();
+  xassert(tinfo);     // otherwise why are we here?
+
+  PseudoInstantiation *pi = new PseudoInstantiation(
+    tinfo->getPrimary()->var->type->asCompoundType());   // awkward...
+
+  if (tinfo->isPrimary()) {
+    // 14.6.1 para 1
+
+    // I'm guessing we just use the main params, and not any
+    // inherited params?
+    SFOREACH_OBJLIST_NC(Variable, tinfo->params, iter) {
+      Variable *param = iter.data();
+
+      // build a template argument that just refers to the template
+      // parameter
+      STemplateArgument *sta = new STemplateArgument;
+      if (param->type->isTypeVariable()) {
+        sta->setType(param->type);
+      }
+      else {
+        // perhaps there should be an STemplateArgument variant that
+        // is like STA_DEPEXPR but can only hold a single Variable?
+        PQ_name *name = new PQ_name(param->loc, param->name);
+        E_variable *evar = new E_variable(name);
+        evar->var = param;
+        sta->setDepExpr(evar);
+      }
+
+      pi->args.append(sta);
+    }
+  }
+
+  else /*partial spec*/ {
+    // 14.6.1 para 2
+    xassert(tinfo->isPartialSpec());
+
+    // use the specialization arguments
+    copyTemplateArgs(pi->args, objToSObjListC(tinfo->arguments));
+  }
+
+  return makeCVAtomicType(pi, cv);
+}
+
+
+Variable *Env::makeExplicitFunctionSpecialization
+  (SourceLoc loc, DeclFlags dflags, PQName *name, FunctionType *ft)
+{
+  // find the overload set
+  LookupSet set;
+  lookupPQ(set, name, LF_TEMPL_PRIMARY);
+  if (set.isEmpty()) {
+    error(stringc << "cannot find primary `" << name->toString()
+                  << "' to specialize");
+    return NULL;
+  }
+
+  // find last component of 'name' so we can see if template arguments
+  // are explicitly supplied
+  PQ_template *pqtemplate = NULL;
+  ObjList<STemplateArgument> *nameArgs = NULL;
+  if (name->getUnqualifiedName()->isPQ_template()) {
+    pqtemplate = name->getUnqualifiedName()->asPQ_template();
+    nameArgs = &(pqtemplate->sargs);
+  }
+
+  // look for a template member of the overload set that can
+  // specialize to the type 'ft' and whose resulting parameter
+  // bindings are 'sargs' (if supplied)
+  Variable *best = NULL;
+  Variable *ret = NULL;
+  SFOREACH_OBJLIST_NC(Variable, set, iter) {
+    Variable *primary = iter.data();
+    if (!primary->isTemplate()) {
+      continue_outer_loop:     // poor man's labeled continue ...
+      continue;
+    }
+
+    // 2005-05-26 (in/t0485.cc): if we're trying to associate a
+    // specialization with a member template, the specialization
+    // does not yet know whether it is a nonstatic member or not,
+    // so we must ignore the receiver argument when matching
+    MatchFlags mflags = MF_IGNORE_IMPLICIT | MF_MATCH | MF_STAT_EQ_NONSTAT;
+
+    // can this element specialize to 'ft'?
+    MType match(env);
+    if (match.matchTypeNC(ft, primary->type, mflags)) {
+      // yes; construct the argument list that specializes 'primary'
+      TemplateInfo *primaryTI = primary->templateInfo();
+      ObjList<STemplateArgument> specArgs;
+
+      if (primaryTI->inheritedParams.isNotEmpty()) {
+        // two difficulties:
+        //   - both the primary and specialization types might refer
+        //     to inherited type varibles, but MM_BIND doesn't want
+        //     type variables occurring on both sides
+        //   - I want to compute right now the argument list that
+        //     specializes primary, but then later I will want the
+        //     full argument list for making the TemplateInfo
+        xunimp("specializing a member template of a class template");
+      }
+
+      // simultanously iterate over the user's provided arguments,
+      // if any, checking for correspondence with inferred arguments
+      ObjList<STemplateArgument> empty;
+      ObjListIter<STemplateArgument> nameArgsIter(nameArgs? *nameArgs : empty);
+
+      // just use the main (not inherited) parameters...
+      SFOREACH_OBJLIST_NC(Variable, primaryTI->params, paramIter) {
+        Variable *param = paramIter.data();
+
+        // get the binding
+        STemplateArgument binding = match.getBoundValue(param->name, tfac);
+        if (!binding.hasValue()) {
+          // inference didn't pin this down; did the user give me
+          // arguments to use instead?
+          if (!nameArgsIter.isDone()) {
+            // yes, use the user's argument instead
+            binding = *nameArgsIter.data();
+          }
+          else {
+            // no, so this candidate can't match
+            goto continue_outer_loop;
+          }
+        }
+        else {
+          // does the inferred argument match what the user has?
+          if (pqtemplate &&                               // user gave me arguments
+              (nameArgsIter.isDone() ||                           // but not enough
+               !binding.isomorphic(nameArgsIter.data()))) {       // or no match
+            // no match, this candidate can't match
+            goto continue_outer_loop;
+          }
+        }
+
+        // remember the argument
+        specArgs.append(new STemplateArgument(binding));
+
+        if (!nameArgsIter.isDone()) {
+          nameArgsIter.adv();
+        }
+      }
+
+      // does the inferred argument list match 'nameArgs'?  we already
+      // checked individual elements above, now just confirm the count
+      // is correct (in fact, only need to check there aren't too many)
+      if (pqtemplate &&                  // user gave me arguments
+          !nameArgsIter.isDone()) {        // but too many
+        // no match, go on to the next primary
+        continue;
+      }
+
+      // ok, found a suitable candidate
+      if (best) {
+        error(stringc << "ambiguous specialization, could specialize `"
+                      << best->type->toString() << "' or `"
+                      << primary->type->toString()
+                      << "'; use explicit template arguments to disambiguate",
+                      EF_STRONG);
+        // error recovery: use 'best' anyway
+        break;
+      }
+      best = primary;
+
+      // make SObjList version of specArgs
+      SObjList<STemplateArgument> const &serfSpecArgs = objToSObjListC(specArgs);
+
+      // do we already have a specialization like this?
+      ret = primary->templateInfo()->getSpecialization(specArgs);
+      if (ret) {
+        TRACE("template", "re-declaration of function specialization of " <<
+                          primary->type->toCString(primary->fullyQualifiedName0()) <<
+                          ": " << ret->name << sargsToString(serfSpecArgs));
+      }
+      else {
+        // build a Variable to represent the specialization
+        ret = makeSpecializationVariable(loc, dflags, primary, ft, serfSpecArgs);
+        TRACE("template", "complete function specialization of " <<
+                          primary->type->toCString(primary->fullyQualifiedName0()) <<
+                          ": " << ret->toQualifiedString());
+      }
+    } // initial candidate match check
+  } // candidate loop
+
+  if (!ret) {
+    error("specialization does not match any function template", EF_STRONG);
+    return NULL;
+  }
+
+  return ret;
+}
+
+
+Variable *Env::makeSpecializationVariable
+  (SourceLoc loc, DeclFlags dflags, Variable *templ, FunctionType *type,
+   SObjList<STemplateArgument> const &args)
+{
+  // make 'type' into a method if 'templ' is
+  FunctionType *templType = templ->type->asFunctionType();
+  if (templType->isMethod()) {
+    // The reason I am making a copy instead of modifying 'type' is
+    // that, at the call site in Declarator::mid_tcheck, if it gets
+    // back a Variable with a method it will method-ize 'type' again.
+    // But by making a copy, I method-ize my copy here, and then let
+    // Declarator::mid_tcheck method-ize 'type' later, harmlessly.
+    // (Wow, what a borked design... yikes.)
+
+    FunctionType *oldFt = type;
+    xassert(!oldFt->isMethod());
+
+    // everything the same but empty parameter list
+    FunctionType *newFt =
+      tfac.makeSimilarFunctionType(SL_UNKNOWN, oldFt->retType, oldFt);
+
+    // add the receiver parameter
+    NamedAtomicType *nat = templType->getNATOfMember();
+    newFt->addReceiver(receiverParameter(SL_UNKNOWN, nat, templType->getReceiverCV()));
+
+    // copy the other parameters
+    SObjListIterNC<Variable> iter(oldFt->params);
+    for (; !iter.isDone(); iter.adv()) {
+      newFt->addParam(iter.data());    // re-use parameter objects
+    }
+    doneParams(newFt);
+
+    // treat this new type as the one to declare from here out
+    type = newFt;
+  }
+
+  // make the Variable
+  Variable *spec = makeVariable(loc, templ->name, type, dflags);
+  spec->setAccess(templ->getAccess());
+  spec->scope = templ->scope;
+  spec->setScopeKind(templ->getScopeKind());
+
+  // make & attach the TemplateInfo
+  TemplateInfo *ti = new TemplateInfo(loc, spec);
+  ti->copyArguments(args);
+
+  // attach to the template
+  templ->templateInfo()->addSpecialization(spec);
+
+  // this is a specialization
+  xassert(ti->isSpecialization());
+
+  return spec;
+}
+
+
+void Env::explicitlyInstantiate(Variable *var, DeclFlags instFlags)
+{
+  TemplateInfo *tinfo = var->templateInfo();
+  xassert(tinfo);
+
+  // 8/12/04: This code has not been tested very much ...
+
+  // function instantiation?
+  if (var->type->isFunctionType()) {
+    if (instFlags & DF_EXTERN) {
+      // this is a request to *never* instantiate this thing
+      if (tinfo->instantiatedFunctionBody()) {
+        // already did it... oh well
+      }
+      else {
+        // prevent it
+        tinfo->instantiationDisallowed = true;
+      }
+    }
+
+    else {
+      // quarl 2006-07-20
+      //    If there is an explicit "extern template" instantiation followed
+      //    by a non-extern template instantiation, then ignore the extern
+      //    instantiation.  See oink/Test/extern_template1.cc (can't test
+      //    linking in pure Elsa).
+      tinfo->instantiationDisallowed = false;
+      
+      // It's ok if we haven't seen the definition yet, however, the
+      // presence of this explicit instantiation request means that the
+      // definition must be somewhere in the translation unit (14.7.2
+      // para 4).  However, I do not enforce this.
+      ensureFuncBodyTChecked(var);
+    }
+
+    return;
+  }
+
+  // class instantiation
+  xassert(var->type->isCompoundType());
+  CompoundType *ct = var->type->asCompoundType();
+  if (!ensureCompleteType("instantiate", var->type)) {
+    return;    // recovery
+  }
+
+  // 14.7.2 para 7: instantiate all members, too
+
+  // base classes
+  FOREACH_OBJLIST(BaseClass, ct->bases, baseIter) {
+    Variable *b = baseIter.data()->ct->typedefVar;
+    if (b->isInstantiation()) {     // t0273.cc
+      explicitlyInstantiate(b, instFlags);
+    }
+  }
+
+  // member variables, functions
+  for (PtrMap<const char, Variable>::Iter membIter(ct->getVariableIter());
+       !membIter.isDone(); membIter.adv()) {
+    Variable *memb = membIter.value();
+
+    if (memb->templateInfo()) {
+      explicitlyInstantiate(memb, instFlags);
+    }
+  }
+
+  // inner classes
+  for (PtrMap<const char, Variable>::Iter innerIter(ct->getTypeTagIter());
+       !innerIter.isDone(); innerIter.adv()) {
+    Variable *inner = innerIter.value();
+
+    if (inner->type->isCompoundType()) {
+      explicitlyInstantiate(inner, instFlags);
+    }
+  }
+}
+
+
+// This is called in response to syntax like (t0256.cc)
+//
+//   template
+//   int foo(int t);
+//
+// for which 'name' would be "foo" and 'type' would be "int ()(int)".
+// This function then finds a function template called "foo" that
+// matches the given type, and instantiates its body.  Finally, that
+// instantiation is returned.
+//
+// On error, an error message is emitted and NULL is returned.
+Variable *Env::explicitFunctionInstantiation(PQName *name, Type *type,
+                                             DeclFlags instFlags)
+{
+  if (!type->isFunctionType()) {
+    error("explicit instantiation of non-function type");
+    return NULL;
+  }
+
+  LookupSet set;
+  lookupPQ(set, name, LF_TEMPL_PRIMARY);
+  if (set.isEmpty() || !set.first()->type->isFunctionType()) {
+    error(stringc << "no such function `" << *name << "'");
+    return NULL;
+  }
+
+  // did the user attach arguments to the name?
+  ObjList<STemplateArgument> *nameArgs = NULL;
+  if (name->getUnqualifiedName()->isPQ_template()) {
+    nameArgs = &( name->getUnqualifiedName()->asPQ_template()->sargs );
+  }
+
+  // collect candidates
+  InstCandidateResolver resolver(env);
+
+  // examine all overloaded versions of the function
+  SFOREACH_OBJLIST_NC(Variable, set, iter) {
+    Variable *primary = iter.data();
+
+    if (!nameArgs &&                      // no arguments attached to final name
+        primary->isInstantiation() &&     // member of an instantiated template
+        type->equals(primary->type, MF_IGNORE_IMPLICIT |     // right type
+                                    MF_STAT_EQ_NONSTAT)) {
+      // an instantiation request like (in/k0016.cc)
+      //   template
+      //   void S<int>::foo();
+      // where 'foo' is *not* a member template, but is a member of
+      // a class template
+      explicitlyInstantiate(primary, instFlags);
+      return primary;
+    }
+
+    if (!primary->isTemplate()) continue;
+    TemplateInfo *primaryTI = primary->templateInfo();
+
+    // does the type we have match the type of this template?
+    MType match(env);
+    if (!match.matchTypeNC(type, primary->type, MF_MATCH)) {
+      continue;   // no match
+    }
+
+    // use user's arguments (if any) to fill in missing bindings
+    if (nameArgs) {
+      if (!loadBindingsWithExplTemplArgs(primary, *nameArgs, match,
+                                         IA_NO_ERRORS)) {
+        continue;      // no match
+      }
+    }
+
+    // build the candidate structure now, since it contains the
+    // 'sargs' to store the arguments
+    InstCandidate *cand = new InstCandidate(primary);
+
+    // convert the bindings into a sequential argument list
+    // (I am ignoring the inherited params b/c I'm not sure if it
+    // is correct to use them here...)
+    bool haveAllArgs = true;
+    getFuncTemplArgs_oneParamList(match, cand->sargs, IA_NO_ERRORS,
+                                  haveAllArgs, primaryTI->params);
+    if (!haveAllArgs) {
+      delete cand;
+      continue;   // no match
+    }
+
+    // at this point, the match is a success; store this candidate
+    resolver.candidates.push(cand);
+  }
+
+  // did we find any candidates?
+  if (resolver.candidates.isEmpty()) {
+    error(stringc << "type `" << type->toString()
+                  << "' does not match any template function `" << *name << "'");
+    return NULL;
+  }
+
+  // choose from among those we found
+  InstCandidate *best = resolver.selectBestCandidate();
+  if (!best) {
+    // TODO: make this error message more informative
+    error("ambiguous function template instantiation");
+    best = resolver.candidates[0];       // error recovery; pick arbitrarily
+  }
+
+  // apply the arguments to the primary
+  Variable *ret = instantiateFunctionTemplate(name->loc, best->primary, best->sargs);
+
+  // instantiate the body
+  explicitlyInstantiate(ret, instFlags);
+
+  // done; 'resolver' and its candidates automatically deallocated
+  return ret;
+}
+
+
+// This returns true if 'otherPrimary/otherArgs' names the same
+// template that I am.  For example, if 'this' template is
+//
+//   template <class T, int n>
+//   struct A { ... };
+//
+// and we see a definition like
+//
+//   template <class S, int m>
+//   A<S,m>::some_type *A<S,m>::foo(...) {}
+//   ^^^^^^
+//
+// then we need to recognize that "A<S,m>" means this template.  Note
+// that for this to work the parameters S and m must already have been
+// associated with a specific (i.e., this) template.
+bool TemplateInfo::matchesPI(CompoundType *otherPrimary,
+                             ObjList<STemplateArgument> const &otherArgs)
+{
+  // same template?
+  if (getPrimary()->var != otherPrimary->typedefVar) {
+    return false;
+  }
+
+  // if I am a primary, then 'pi->args' should be a list of
+  // type variables that correspond to my parameters
+  if (isPrimary()) {
+    int ct = -1;
+    FOREACH_OBJLIST(STemplateArgument, otherArgs, iter) {
+      ct++;
+      Variable *argVar = NULL;
+
+      // type parameter?
+      if (iter.data()->isType() &&
+          iter.data()->getType()->isTypeVariable()) {
+        argVar = iter.data()->getType()->asTypeVariable()->typedefVar;
+      }
+
+      // non-type paramter?
+      else if (iter.data()->isDepExpr() &&
+               iter.data()->getDepExpr()->isE_variable()) {
+        argVar = iter.data()->getDepExpr()->asE_variable()->var;
+      }
+
+      // TODO: template template parameter
+
+      if (argVar &&
+          argVar->isTemplateParam() &&
+          argVar->getParameterizedEntity() == this->var &&
+          argVar->getParameterOrdinal() == ct) {
+        // good to go
+      }
+      else {
+        return false;     // no match
+      }
+    }
+
+    // should be right # of args
+    if (ct+1 != params.count()) {
+      return false;
+    }
+
+    // TODO: Take default arguments into account. (in/t0440.cc)
+
+    // match!
+    return true;
+  }
+
+  // not a primary; we are a specialization; check against arguments
+  // to primary
+  return isomorphicArgumentLists(argumentsToPrimary, otherArgs);
+}
+
+
+bool TemplateInfo::instantiatedFunctionBody() const
+{
+  return var->funcDefn && !var->funcDefn->instButNotTchecked();
+}
+
+
+// ------------------- InstantiationContextIsolator -----------------------
+InstantiationContextIsolator::InstantiationContextIsolator(Env &e, SourceLoc loc)
+  : env(e),
+    origNestingLevel(e.disambiguationNestingLevel),
+    origSecondPass(e.secondPassTcheck),
+    origErrors()
+{
+  env.instantiationLocStack.push(loc);
+  env.disambiguationNestingLevel = 0;
+  env.secondPassTcheck = false;
+  origErrors.takeMessages(env.errors);
+}
+
+InstantiationContextIsolator::~InstantiationContextIsolator()
+{
+  env.setLoc(env.instantiationLocStack.pop());
+  env.disambiguationNestingLevel = origNestingLevel;
+  env.secondPassTcheck = origSecondPass;
+
+  // where do the newly-added errors, i.e. those from instantiation,
+  // which are sitting in 'env.errors', go?
+  if (env.hiddenErrors) {
+    // shuttle them around to the hidden message list
+    env.hiddenErrors->takeMessages(env.errors);
+  }
+  else {
+    // put them at the end of the original errors, as if we'd never
+    // squirreled away any messages
+    origErrors.takeMessages(env.errors);
+  }
+  xassert(env.errors.isEmpty());
+
+  // now put originals back into env.errors
+  env.errors.takeMessages(origErrors);
+}
+
+
+// ---------------------- XTypeDeduction ------------------------
+XTypeDeduction::XTypeDeduction(XTypeDeduction const &obj)
+  : xBase(obj)
+{}
+
+XTypeDeduction::~XTypeDeduction()
+{}
+
+
+void xTypeDeduction(rostring why)
+{
+  XTypeDeduction x(why);
+  THROW(x);
+}
+
+
+// ---------------------- DelayedFuncInst -----------------------
+DelayedFuncInst::DelayedFuncInst(Variable *v, ArrayStack<SourceLoc> const &s,
+                                 SourceLoc L)
+  : instV(v),
+    instLocStack(s),
+    loc(L)
+{}
+
+DelayedFuncInst::~DelayedFuncInst()
+{}
+
+
+// EOF

Added: vendor/elsa/current/elsa/template.h
===================================================================
--- vendor/elsa/current/elsa/template.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/template.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,587 @@
+// template.h
+// data structures for representing templates, etc.
+//
+// see Diagram 2 of doc/cpp_er.html
+//
+// Conceptually, everything here is an extension of cc_type.
+//
+// Note that there are many more template-related functions, declared
+// in cc_env.h in a block at the end of the declaration of the Env
+// class.  There isn't a nice way to separate those declarations out,
+// since I want them to be members of Env.
+
+#ifndef TEMPLATE_H
+#define TEMPLATE_H
+
+#include "cc_type.h"         // non-template parts of type system
+
+
+// used for (abstract) template parameter types
+class TypeVariable : public NamedAtomicType {
+public:
+  TypeVariable(StringRef name) : NamedAtomicType(name) {}
+  ~TypeVariable();
+
+  // AtomicType interface
+  virtual Tag getTag() const { return T_TYPEVAR; }
+  virtual string toCString() const;
+  virtual string toMLString() const;
+  virtual int reprSize() const;
+  virtual void traverse(TypeVisitor &vis);
+
+  // true if this template parameter has been associated with
+  // a specific template
+  bool isAssociated() const;
+};
+
+
+// denote a class template with arguments supplied, so it's like an
+// instantiation, but some of those arguments contain type variables,
+// so this does not denote a single concrete type; this appears in
+// template definitions only
+//
+// actually it might not contain type variables but instead only
+// contain non-type argument variables; the point is we don't have
+// enough information to do a concrete instantiation
+class PseudoInstantiation : public NamedAtomicType {
+public:      // data
+  // class template primary to which we are adding arguments
+  CompoundType *primary;
+
+  // the arguments, some of which contain type variables
+  ObjList<STemplateArgument> args;
+
+public:      // funcs
+  PseudoInstantiation(CompoundType *p);
+  ~PseudoInstantiation();
+
+  // AtomicType interface
+  virtual Tag getTag() const { return T_PSEUDOINSTANTIATION; }
+  virtual string toCString() const;
+  virtual string toMLString() const;
+  virtual int reprSize() const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// This object represents a type *name* that includes a
+// dependent-typed qualifier and therefore cannot be represented
+// as an ordinary TypeVariable or PseudoInstantiation.  For
+// example, T::foo where T is a template parameter.
+class DependentQType : public NamedAtomicType {
+public:      // data
+  // The first component is either a template parameter (e.g., T::foo)
+  // or is a PseudoInstantiation (e.g., C<T>::foo).  The latter could
+  // have been qualified in the original syntax, but those qualifiers
+  // have already been resolved (e.g., ::C<T>::foo)
+  AtomicType *first;            // (serf) TypeVariable or PseudoInstantiation
+
+  // After the first component comes whatever name components followed
+  // in the original syntax.  All template arguments have been
+  // tcheck'd.
+  PQName *rest;
+
+public:      // data
+  DependentQType(AtomicType *f);
+  ~DependentQType();
+
+  // AtomicType interface
+  virtual Tag getTag() const { return T_DEPENDENTQTYPE; }
+  virtual string toCString() const;
+  virtual string toMLString() const;
+  virtual int reprSize() const;
+  virtual void traverse(TypeVisitor &vis);
+};
+
+
+// just some template parameters (this class exists, in part, so
+// that Scope doesn't have to instantiate a full TemplateInfo)
+class TemplateParams {
+public:    // data
+  // template parameters: the dimensions along which the associated
+  // entity may be specialized at compile time
+  SObjList<Variable> params;
+
+public:    // funcs
+  TemplateParams() {}
+  TemplateParams(TemplateParams const &obj);
+  ~TemplateParams();
+  
+  // queries on parameters
+  string paramsToCString() const;
+  string paramsToMLString() const;
+  bool anyParamCtorSatisfies(TypePred &pred) const;
+  
+  // print the parameters like arguments, e.g. "<S, T>"
+  // instead of "template <class S, class T>"
+  string paramsLikeArgsToString() const;
+};
+
+// make this available outside the class too
+string paramsToCString(SObjList<Variable> const &params);
+
+
+// template parameters on an enclosing object; for example, if "this"
+// object is a member function enclosed in a template class, then
+// this object will store (a copy of) the parameters for the class
+// (this is needed, among other reasons, because when the member
+// function is defined, the user is free to rename the parameters
+// that applied to the class)
+class InheritedTemplateParams : public TemplateParams {
+public:      // data
+  // We can only inherit params from a class; this is it.  If these
+  // inherited parameters are attached to an instantiation, then
+  // 'enclosing' is the instantiated enclosing class.
+  CompoundType *enclosing;          // (serf)
+
+public:      // funcs
+  InheritedTemplateParams(CompoundType *e) : enclosing(e) {}
+  InheritedTemplateParams(InheritedTemplateParams const &obj);
+  ~InheritedTemplateParams();
+};
+
+
+// kind of template things (Variables with TemplateInfo)
+enum TemplateThingKind {
+  // template primary, the main template from which instantiations
+  // are generated
+  TTK_PRIMARY,
+  
+  // explicit specialization, a user-provided definition for a
+  // specific set of arguments (or argument patterns)
+  TTK_SPECIALIZATION,
+  
+  // instantiation, an object created by the compiler by taking
+  // a primary or a partial specialization and filling in the
+  // template parameters with concrete arguments
+  TTK_INSTANTIATION,
+  
+  NUM_TTKINDS
+};
+
+
+// for a template function or class, including instantiations thereof,
+// this is the information regarding its template-ness
+class TemplateInfo : public TemplateParams {
+public:    // data
+  // This class maintains a number of bidirectional relationships.
+  // To help ensure that both ends of the relation are maintained,
+  // I mark some pointer fields 'const', to force updates to go
+  // through dedicated routines.
+
+  // every TemplateInfo is associated 1-to-1 with some Variable,
+  // and this is the associated Variable; this value is initially
+  // NULL, and set by Variable::setTemplateInfo
+  //
+  // TODO: make TemplateInfo inherit from Variable instead of
+  // using two connected objects
+  Variable * const var;                    // (serf)
+
+  // inherited parameters, in order from outermost to innermost; this
+  // TemplateThing is parameterized by the inherited parameters *and*
+  // the main 'params' list
+  ObjList<InheritedTemplateParams> inheritedParams;
+
+  // the specialization / primary that we were instantiated from, if
+  // we are an instantiation; NULL if we are not
+  Variable * const instantiationOf;        // (serf)
+
+  // inverse of 'instantiatedFrom'
+  SObjList<Variable> instantiations;
+
+  // the primary that this is a specialization of
+  Variable * const specializationOf;       // (serf)
+
+  // inverse of 'specializationOf'
+  SObjList<Variable> specializations;
+
+  // arguments to apply to my parent's parameters (inherited, then
+  // main) to arrive at this object
+  ObjList<STemplateArgument> arguments;
+
+  // one of three conditions holds:
+  //
+  // TTKind              instantiatedFrom  specializationOf  arguments
+  // -----------------------------------------------------------------
+  // TTK_PRIMARY         NULL              NULL              empty
+  // TTK_SPECIALIZATION  NULL              non-NULL          non-empty
+  // TTK_INSTANTIATION   non-NULL          NULL              non-empty
+  //
+  // exception: partial instantiations are TTK_PRIMARY with non-empty arguments
+
+  // if this is an instantiation, this records the (most proximal)
+  // source location that gave rise to the need to instantiate it;
+  // if not, it's just the location of the declaration of the
+  // template itself
+  SourceLoc instLoc;
+
+  // Bidirectional "partial instantiation" relation: a partial
+  // instantiation is a template function that is in most respects a
+  // template primary.  However, it does not have its own independent
+  // definition, rather the definition is provided by
+  // 'partialInstantiationOf'.  Moreover, a partial instantiation
+  // carries 'arguments' that are to be applied to the template it
+  // is a partial instance of, with remaining arguments supplied by
+  // the partial instance's own parameters.
+  Variable * const partialInstantiationOf;      // (serf)
+  SObjList<Variable> partialInstantiations;
+
+
+  // bit of a hack: during type matching, I need the arguments that
+  // apply to the primary (not to a partial spec); I can compute them,
+  // but that requires an Env b/c it means constructing new types;
+  // better would be to extend matchtypes so it would allow a binding
+  // map for the LHS type, but until that is implemented I'll just
+  // keep a copy of the args to the primary too (this is empty unless
+  // this isInstOfPartialSpec())
+  ObjList<STemplateArgument> argumentsToPrimary;
+
+  // scope in which the definition appears, if this is a primary
+  // or a specialization (NULL otherwise)
+  Scope *defnScope;
+
+  // template parameters for use when instantiating a definition,
+  // if different from the declaration
+  TemplateInfo *definitionTemplateInfo;         // (nullable owner)
+
+
+  // true if we have seen syntax that demands an instantiation
+  // of the body, not just the declaration
+  bool instantiateBody;
+  
+  // if this is true, the user has requested that this template
+  // function not be instantiated, even if there is code that would
+  // otherwise require it; this is to support the GNU "extern
+  // template" extension
+  bool instantiationDisallowed;
+
+  // for a template function, number of default arguments that have
+  // not yet been instantiated
+  int uninstantiatedDefaultArgs;
+  
+  // for a template class, this is a list of the base classes that
+  // were dependent, and as a consequence not added to its normal
+  // base class list; this info is maintained to provide more
+  // informative diagnostic messages
+  SObjList<Type> dependentBases;
+
+private:     // funcs
+  // can modify the 'const' fields, for updates
+  void addToList(Variable *elt, SObjList<Variable> &children, 
+                 Variable * const &parentPtr);
+
+public:      // funcs
+  // Q: can I make the 'var' argument mandatory?
+  TemplateInfo(SourceLoc instLoc, Variable *var = NULL);
+  TemplateInfo(TemplateInfo const &obj);
+  ~TemplateInfo();
+
+  // name of the template class or function
+  //StringRef getBaseName() const;    // who calls this?
+
+  // what kind of template thing is this?
+  TemplateThingKind getKind() const;
+  bool isPrimary() const { return getKind() == TTK_PRIMARY; }
+  bool isSpecialization() const { return getKind() == TTK_SPECIALIZATION; }
+  bool isInstantiation() const { return getKind() == TTK_INSTANTIATION; }
+
+  // some more queries along these lines
+  bool isNotPrimary() const { return !isPrimary(); }
+  bool isPartialSpec() const;
+  bool isCompleteSpec() const;
+  bool isCompleteSpecOrInstantiation() const;
+  bool isPartialInstantiation() const { return !!partialInstantiationOf; }
+  bool isInstOfPartialSpec() const;
+
+  // return the primary for this template thing
+  TemplateInfo const *getPrimaryC() const;
+  TemplateInfo *getPrimary() { return const_cast<TemplateInfo*>(getPrimaryC()); }
+
+  // modify one of the bidirectional relations; this is always
+  // done by asking the parent to add a child
+  void addInstantiation(Variable *inst);
+  void addSpecialization(Variable *spec);
+  void addPartialInstantiation(Variable *pinst);
+  
+  // change this TemplateInfo, which currently represents an implicit
+  // instantiation, into an explicit specialization
+  void changeToExplicitSpec();
+
+  // return the arguments that get to this instantiation from the
+  // primary; this is different from 'args' if this is an
+  // instantiation of a partial specialization
+  ObjList<STemplateArgument> &getArgumentsToPrimary();
+
+
+  // true if 'list' contains equivalent semantic arguments
+  //
+  // 2005-08-03: I renamed this from 'equal' to 'isomorphic', because
+  // I am now introducing a variant called 'equal' that does not
+  // require the TypeFactory parameter.
+  bool isomorphicArguments(ObjList<STemplateArgument> const &list) const;
+
+  // and here it is
+  bool equalArguments(ObjList<STemplateArgument> const &list,
+                      MatchFlags mflags = MF_NONE) const;
+
+  // true if the arguments contain type variables
+  //
+  // TODO: remove this, and only have 'argumentsContainVariables'
+  bool argumentsContainTypeVariables() const;
+
+  // dsw: check the arguments contain type or object (say, int)
+  // variables; FIX: I'm not sure this is implemented right; see
+  // comments in implementation
+  bool argumentsContainVariables() const;
+
+  // true if there are parameters (at this level; not inherited)
+  bool hasParameters() const;
+
+  // true if there are parameters on my containers
+  bool hasInheritedParameters() const
+    { return countInheritedParameters() > 0; }
+  int countInheritedParameters() const;
+
+  // inherited or main
+  bool hasMainOrInheritedParameters() const;
+
+  // either
+  bool hasParametersEx(bool considerInherited) const;
+
+  // if one of my explicit specializations has arguments that
+  // exactly match 'sargs' (which is a list of concrete arguments),
+  // return it; otherwise return NULL
+  Variable *getSpecialization(ObjList<STemplateArgument> const &sargs);
+
+  // true if the given Variable is among the parameters (at any level)
+  //
+  // TODO: what is this used for?
+  bool hasSpecificParameter(Variable const *v) const;
+
+  // copy 'sargs' into 'arguments'; the latter must be empty
+  // to begin with
+  void copyArguments(ObjList<STemplateArgument> const &sargs);
+  void copyArguments(SObjList<STemplateArgument> const &sargs);
+
+  // prepend 'sargs' onto 'arguments'
+  void prependArguments(ObjList<STemplateArgument> const &sargs);
+
+  // debugging/error messages: print the fully qualified name,
+  // plus arguments/parameters, to identify this template thing
+  string templateName() const;
+                                           
+  // visit the template arguments with 'vis'
+  void traverseArguments(TypeVisitor &vis);
+                                                             
+  // see comments at implementation
+  bool matchesPI(CompoundType *primary,
+                 ObjList<STemplateArgument> const &args);
+
+  // assuming this is a function template, did we already instantiate
+  // the body?
+  bool instantiatedFunctionBody() const;
+
+  // debugging
+  void gdb();
+  void debugPrint(int depth = 0, bool printPartialInsts = true);
+};
+
+
+// semantic template argument (semantic as opposed to syntactic); this
+// breaks the argument down into the cases described in cppstd 14.3.2
+// para 1, plus types, minus template parameters, then grouped into
+// equivalence classes as implied by cppstd 14.4 para 1
+class STemplateArgument {
+public:
+  enum Kind {
+    STA_NONE,        // not yet resolved into a valid template argument
+    STA_TYPE,        // type argument
+    STA_INT,         // int argument
+    STA_ENUMERATOR,  // enum argument
+    STA_REFERENCE,   // reference to global object
+    STA_POINTER,     // pointer to global object
+    STA_MEMBER,      // pointer to class member
+    STA_DEPEXPR,     // value-dependent expression
+    STA_TEMPLATE,    // template argument (not implemented)
+    STA_ATOMIC,      // private to mtype: bind var to AtomicType
+    NUM_STA_KINDS
+  } kind;
+
+  union {
+    Type *t;         // (serf) for STA_TYPE
+    int i;           // for STA_INT
+    Variable *v;     // (serf) for STA_ENUMERATOR, STA_REFERENCE, STA_POINTER, STA_MEMBER
+    Expression *e;   // (serf) for STA_DEPEXPR
+    AtomicType const *at;  // (serf) for STA_ATOMIC
+  } value;
+
+public:
+  STemplateArgument() : kind(STA_NONE) { value.i = 0; }
+  STemplateArgument(Type *t) : kind(STA_TYPE) { value.t = t; }
+  STemplateArgument(STemplateArgument const &obj);
+
+  // 'new' + copy ctor
+  STemplateArgument *shallowClone() const;
+
+  // get 'value', ensuring correspondence between it and 'kind'
+  Type *    getType()      const { xassert(kind==STA_TYPE);      return value.t; }
+  int       getInt()       const { xassert(kind==STA_INT);       return value.i; }
+  Variable *getEnumerator()const { xassert(kind==STA_ENUMERATOR);return value.v; }
+  Variable *getReference() const { xassert(kind==STA_REFERENCE); return value.v; }
+  Variable *getPointer()   const { xassert(kind==STA_POINTER);   return value.v; }
+  Variable *getMember()    const { xassert(kind==STA_MEMBER);    return value.v; }
+  Expression *getDepExpr() const { xassert(kind==STA_DEPEXPR);   return value.e; }
+
+  // set 'value', ensuring correspondence between it and 'kind'
+  void setType(Type *t)          { kind=STA_TYPE;      value.t=t; }
+  void setInt(int i)             { kind=STA_INT;       value.i=i; }
+  void setEnumerator(Variable *v){ kind=STA_ENUMERATOR;value.v=v; }
+  void setReference(Variable *v) { kind=STA_REFERENCE; value.v=v; }
+  void setDepExpr(Expression *e) { kind=STA_DEPEXPR;   value.e=e; }
+  void setPointer(Variable *v)   { kind=STA_POINTER;   value.v=v; }
+  void setMember(Variable *v)    { kind=STA_MEMBER;    value.v=v; }
+
+  bool isObject() const;         // "non-type non-template" in the spec
+  bool isType() const            { return kind==STA_TYPE;         }
+  bool isTemplate() const        { return kind==STA_TEMPLATE;     }
+  bool isDepExpr() const         { return kind==STA_DEPEXPR;      }
+
+  bool hasValue() const { return kind!=STA_NONE; }
+
+  // AtomicType stuff
+  AtomicType const *getAtomicType() const { xassert(kind==STA_ATOMIC); return value.at; }
+  void setAtomicType(AtomicType const *at) { kind=STA_ATOMIC; value.at=at; }
+  bool isAtomicType() const { return kind==STA_ATOMIC; }
+
+  // true if it's '<dependent>'
+  bool isDependent() const;
+
+  // the point of boiling down the syntactic arguments into this
+  // simpler semantic form is to make equality checking easy
+  bool equals(STemplateArgument const *obj, MatchFlags mflags = MF_NONE) const;
+  bool equals(STemplateArgument const &obj, MatchFlags mflags = MF_NONE) const
+    { return equals(&obj); }
+
+  // does it contain variables?
+  bool containsVariables(MType *map = NULL) const;
+
+  // let type variables bind to each other
+  bool isomorphic(STemplateArgument const *obj) const;
+
+  // traverse argument
+  void traverse(TypeVisitor &vis);
+
+  // debug print
+  string toString() const;
+
+  // debugging
+  void gdb();
+  void debugPrint(int depth = 0);
+};
+
+SObjList<STemplateArgument> *cloneSArgs(SObjList<STemplateArgument> &sargs);
+string sargsToString(SObjList<STemplateArgument> const &list);
+inline string sargsToString(ObjList<STemplateArgument> const &list)
+  { return sargsToString((SObjList<STemplateArgument> const &)list); }
+string sargsToString(SObjListIter<STemplateArgument> &iter);
+
+bool containsVariables(SObjList<STemplateArgument> const &args, MType *map = NULL);
+bool containsVariables(ObjList<STemplateArgument> const &args, MType *map = NULL);
+
+bool hasDependentArgs(SObjList<STemplateArgument> const &args);
+
+void copyTemplateArgs(ObjList<STemplateArgument> &dest,
+                      ObjList<STemplateArgument> const &src);
+void copyTemplateArgs(ObjList<STemplateArgument> &dest,
+                      SObjList<STemplateArgument> const &src);
+
+bool isomorphicArgumentLists(ObjList<STemplateArgument> const &list1,
+                             ObjList<STemplateArgument> const &list2);
+
+bool equalArgumentLists(ObjList<STemplateArgument> const &list1,
+                        ObjList<STemplateArgument> const &list2,
+                        MatchFlags mflags = MF_NONE);
+
+char const *toString(STemplateArgument::Kind k);
+
+
+// holder for the CompoundType template candidates
+class TemplCandidates {
+private:     // types
+  // for comparing two STemplateArgument-s; There are four possible
+  // answers: leftGreater, rightGreater, equal, and incomparable.
+  enum STemplateArgsCmp {
+    STAC_LEFT_MORE_SPEC,
+    STAC_RIGHT_MORE_SPEC,
+    STAC_EQUAL,
+    STAC_INCOMPARABLE,
+  };
+
+public:      // data
+  // the set of candidates
+  ArrayStack<Variable*> candidates;
+
+private:     // funcs
+  // disallowed
+  TemplCandidates(TemplCandidates const &);
+
+  // compare two arguments
+  static STemplateArgsCmp compareSTemplateArgs
+    (STemplateArgument const *larg, STemplateArgument const *rarg);
+
+public:      // funcs
+  TemplCandidates() {}
+
+  // add a candidate
+  void add(Variable *v) { candidates.push(v); }
+
+  // compare two different templates (primary / specialization /
+  // instantiation) to see which is more specific; used by
+  // instantiateTemplate() to decide which to use for a given
+  // instantiation request
+  // return:
+  //   -1 if left is better (more specific)
+  //    0 if they are incomparable
+  //   +1 if right is better
+  int compareCandidates(Variable const *left, Variable const *right);
+
+  // static version
+  static int compareCandidatesStatic
+    (TemplateInfo const *lti, TemplateInfo const *rti);
+};
+
+
+// thrown when type deduction fails in some cases
+class XTypeDeduction : public xBase {
+public:
+  XTypeDeduction(rostring why) : xBase(why) {}
+  XTypeDeduction(XTypeDeduction const &obj);
+  ~XTypeDeduction();
+};
+
+// function that throws XTypeDeduction
+void xTypeDeduction(rostring why) NORETURN;
+
+
+// an object of this class is used to record context when a function
+// template instantiation is delayed
+class DelayedFuncInst {
+public:      // data
+  // the instantiation declaration entry
+  Variable *instV;
+
+  // instantiation location stack
+  ArrayStack<SourceLoc> instLocStack;
+  
+  // most proximal location from which the instantiation was
+  // requested; additional context is in the loc stack
+  SourceLoc loc;
+
+public:
+  DelayedFuncInst(Variable *v, ArrayStack<SourceLoc> const &s,
+                  SourceLoc loc);
+  ~DelayedFuncInst();
+};
+
+
+#endif // TEMPLATE_H

Added: vendor/elsa/current/elsa/test-cipart
===================================================================
--- vendor/elsa/current/elsa/test-cipart	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-cipart	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+#!/bin/sh
+# run cipart then make sure the tree is ok
+
+if [ "$1" = "" ]; then
+  echo "usage: $0 foo.c"
+  exit 2
+fi
+
+while [ "$1" != "" ]; do
+  echo "---- $1 ----"
+
+  ./cipart "$1" || exit
+
+  ./smin -tr checktree "$1" "$1".str || exit
+
+  rm "$1".str
+  
+  shift
+done
+
+exit 0


Property changes on: vendor/elsa/current/elsa/test-cipart
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-for-error
===================================================================
--- vendor/elsa/current/elsa/test-for-error	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-for-error	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,103 @@
+#!/bin/sh
+# test an input to see if it exhibits a given error message
+
+
+# ---------------------- setup --------------------
+usage() {
+  echo "usage: msg=message_fragment $0 [-v]"
+  echo "  This script tests tmp.i to see if it:"
+  echo "    - goes through gcc, and"
+  echo "    - provokes an error from ccparse, where"
+  echo "    - the error message matches the fragment regexp"
+  echo "  Use the special msg \"segfault\" to test for a segfault (SIGSEGV),"
+  echo "  and \"abort\" to test for a SIGABRT."
+}
+
+# verbose operation?
+verbose=false
+if [ "$1" = "-v" ]; then
+  verbose=true
+  shift
+fi
+
+# gcc to use
+if [ "$GCC" = "" ]; then
+  GCC=$HOME/opt/gcc-3.4.3/bin/g++
+fi
+
+# input file
+input=tmp.i
+if [ ! -f "$input" ]; then
+  echo "error: $input does not exist"
+  exit 2
+fi
+
+# error message fragment
+if [ "$msg" = "" ]; then
+  echo "error: must set \$msg to a message fragment regexp"
+  usage
+  exit 2
+fi
+
+
+# ---------------------- execution --------------------
+if $verbose; then
+  # leave outputs as they are
+  true
+else
+  # trash all output
+  exec >/dev/null 2>&1
+fi
+
+# limit resources; this is important because sometimes delta creates
+# inputs that cause gcc to go into infinite loops
+#   virtual memory: 500MB
+#   time: 30s
+ulimit -v 500000
+ulimit -t 30
+
+if [ "$DELTA_REQUIRED_STRING" != "" ]; then
+  if grep "$DELTA_REQUIRED_STRING" tmp.i >/dev/null 2>&1; then
+    echo "required string ($DELTA_REQUIRED_STRING) is present"
+  else
+    echo "required string ($DELTA_REQUIRED_STRING) is missing"
+    exit 2
+  fi
+fi
+
+# integrity check
+if $GCC $ARGS -o /dev/null -c tmp.i; then
+  echo "gcc ok"
+else
+  echo "did not pass gcc test"
+  exit 2
+fi
+
+# ccparse
+if [ "$msg" = "segfault" ]; then
+  ./ccparse -tr permissive $ARGS tmp.i >/dev/null 2>&1
+  if [ "$?" = "139" ]; then
+    echo "got the segfault I am looking for"
+    exit 0
+  else
+    echo "did not get a segfault"
+    exit 4
+  fi
+elif [ "$msg" = "abort" ]; then
+  ./ccparse -tr permissive $ARGS tmp.i >/dev/null 2>&1
+  if [ "$?" = "134" ]; then
+    echo "got the SIGABRT I am looking for"
+    exit 0
+  else
+    echo "did not get a SIGABRT"
+    exit 4
+  fi
+else
+  if ./ccparse -tr permissive $ARGS tmp.i 2>&1 | grep "$msg"; then
+    echo "found the error message I am looking for"
+    exit 0
+  else
+    echo "didn't get the error I want"
+    exit 4
+  fi
+fi


Property changes on: vendor/elsa/current/elsa/test-for-error
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse
===================================================================
--- vendor/elsa/current/elsa/test-parse	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,67 @@
+#!/bin/sh
+# parse a preprocessed file, and verify it
+# can parse it and leave no ambiguities
+               
+if [ "$1" = "" ]; then
+  echo "usage: $0 [-tr flag] file.i [file2.i [...]]"
+  exit 0
+fi
+
+extra=""
+if [ "$1" = "-tr" ]; then
+  extra="-tr $2"
+  shift
+  shift
+fi
+
+if [ "$KEEP_GOING" = "2" ]; then
+  # arrange to send status reports (only) to stderr
+  exec 3>&2
+  exec 2>&1
+fi
+
+while [ "$1" != "" ]; do
+  fname="$1"
+  shift
+
+  echo "--------- $fname --------"
+
+  case $fname in
+    *.gz)
+      inputFname=tmp.i
+      echo "gunzip -c $fname >$inputFname"
+      gunzip -c "$fname" >"$inputFname" || exit
+      ;;
+
+    *)
+      inputFname="$fname"
+      ;;
+  esac
+
+  # try to parse it
+  echo "./ccparse $extra $inputFname"
+  if ./ccparse -tr nohashline,permissive $extra "$inputFname"; then
+    # ok
+    if [ "$KEEP_GOING" = "2" ]; then
+      echo -n . >&3
+    fi
+  else
+    code=$?
+    echo "$fname: had errors"
+    if [ "$KEEP_GOING" = "" ]; then
+      exit $code
+    elif [ "$KEEP_GOING" = "2" ]; then
+      echo -n e >&3
+    fi
+  fi
+done
+
+if [ "$KEEP_GOING" = "2" ]; then
+  # final newline
+  echo "" >&3
+fi
+
+exit 0
+
+
+


Property changes on: vendor/elsa/current/elsa/test-parse
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse-big
===================================================================
--- vendor/elsa/current/elsa/test-parse-big	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse-big	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,123 @@
+#!/bin/sh
+# use test-parse-buildlog to test Elsa's ability to parse several
+# large packages
+
+# This script really only will work on my machine ....
+
+if [ "$1" = "" ]; then
+  exec $0 smbase ast elkhound elsa doxygen pine e2fsprogs \
+          binutils ddd qt mozilla debian/c debian/c++ headers
+fi
+
+# the lines
+#      if [ $? = 130 ]; then exit 130; fi
+# are to propagate ctrl-C
+
+while [ "$1" != "" ]; do
+  case $1 in
+    smbase)
+      # 39 modules
+      echo "smbase"
+      ./test-parse-buildlog ../smbase/make.out >smbase.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    ast)
+      # 14 modules
+      echo "ast"
+      ./test-parse-buildlog ../ast/make.out >ast.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    elkhound)
+      # 41 modules
+      echo "elkhound"
+      ./test-parse-buildlog ../elkhound/make.out >elkhound.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    elsa)
+      # 36 modules
+      echo "elsa"
+      ./test-parse-buildlog make.out >elsa.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    doxygen)
+      # 80 modules
+      echo "Doxygen 1.2.14"
+      ./test-parse-buildlog $HOME/bld/doxygen-1.2.14/make.out >doxygen.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+        
+    pine)
+      # 80 modules
+      echo "Pine 4.44"
+      ./test-parse-buildlog ~/bld/pine4.44/build.out >pine.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    e2fsprogs)
+      # 184 modules
+      echo "e2fsprogs-1.36"
+      ./test-parse-manyfiles < ~/preproc/scott/bld/e2fsprogs-1.36/build1 >e2fsprogs.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    binutils)
+      # 190 modules
+      echo "Binutils 2.14"
+      ./test-parse-buildlog ~/bld/binutils-2.14/make.out >binutils.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    ddd)
+      # 259 modules
+      echo "DDD 3.3.1"
+      ./test-parse-buildlog $HOME/bld/ddd-3.3.1/make.out >ddd.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    qt)
+      # 710 modules
+      echo "Qt 2.3.2"
+      ./test-parse-buildlog /opt/qt-2.3.2/make.out >qt.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    mozilla)
+      # 2404 modules
+      echo "Mozilla 1.0"
+      ./test-parse-buildlog $HOME/bld/mozilla-1.0/make.out >moz.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    debian/c)
+      echo "debian/c"
+      KEEP_GOING=2 ./test-parse -tr gnu_c89 bigin/debian/c89/*.gz >debian.c.parse.out
+      KEEP_GOING=2 ./test-parse -tr c_lang bigin/debian/c/*.gz >>debian.c.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    debian/c++)
+      echo "debian/c++"
+      KEEP_GOING=2 ./test-parse bigin/debian/c++/*.gz >>debian.c++.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    headers)
+      echo "headers (2nd-to-last is valarray)"
+      KEEP_GOING=2 ./test-parse bigin/headers/*.gz >>headers.parse.out
+      if [ $? = 130 ]; then exit 130; fi
+      ;;
+
+    *)
+      echo "undefined big test: $1"
+      exit 2
+      ;;
+  esac
+  shift
+done
+
+
+# EOF


Property changes on: vendor/elsa/current/elsa/test-parse-big
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse-buildlog
===================================================================
--- vendor/elsa/current/elsa/test-parse-buildlog	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse-buildlog	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,322 @@
+#!/usr/bin/perl -w
+# read in the output of a 'make' command, and use that to
+# drive the Elsa C/C++ parser
+
+# The intended usage is to run this script with stdout redirected to a
+# file (to save error messages, etc.) but stderr going to a console,
+# where there will be one character printed for each file that we
+# attempt to parse:
+#
+#   p    preprocessing (with gcc -E) failed
+#   e    parsing (with Elsa) failed
+#   .    success
+#
+# Finally, on stderr the sum of all failures will be printed.
+#                                              
+# Then, the saved log can be examined for lines that begin with
+# "failing" to find the details on what failed.
+
+use strict 'subs';
+
+$SIG{INT} = \&sigIntHandler;
+
+$dry = 0;
+$minCt = 0;
+$maxCt = 99999999;
+$diag = 0;
+
+$cwd = `pwd`;   # gets changed below
+chomp($cwd);
+$ccparse = "$cwd/ccparse";
+if (! -x $ccparse) {
+  die("cannot execute $cwd/ccparse");
+}
+
+while ($ARGV[0] && $ARGV[0] =~ m/^-/) {
+  my $op = $ARGV[0];
+  shift @ARGV;
+
+  if ($op eq "-dry") {
+    $dry = 1;
+  }
+
+  elsif ($op eq "-range") {
+    my ($n, $m) = ($ARGV[0] =~ m/^(\d*)-(\d*)/);
+    shift @ARGV;
+
+    if (!defined($m)) {
+      print("-range option must be followed by argument of form [n]-[m]\n");
+      exit(2);
+    }
+    if ($n) {
+      $minCt = $n;
+    }
+    if ($m) {
+      $maxCt = $m;
+    }
+    diagnostic("minCt=$minCt maxCt=$maxCt");
+  }
+
+  elsif ($op eq "-debug") {
+    $diag = 1;
+  }
+
+  else {
+    print("unknown option: $op\n");
+    exit(2);
+  }
+}
+
+if (@ARGV != 1) {
+  print(<<"EOF");
+usage: $0 [options] make.out
+  options
+    -dry          dry run; do not run any commands
+    -range n-m    do only runs 'n' through 'm'
+    -range n-     do only runs 'n' or higher
+    -range -m     do only up to 'm'
+    -debug        print debug mode diagnostics
+EOF
+  exit(0);
+}
+
+$buildlog = $ARGV[0];
+
+
+# counter for run commands
+$runCount = 0;
+
+# stack of directories; return to the topmost when we see
+# make say "Leaving directory ..."
+ at dirstack = ();
+
+# initial directory: wherever $buildlog is
+($cwd) = ($buildlog =~ m|^(.*)/[^/]*$|);
+if (defined($cwd)) {
+  mychdir($cwd);
+}
+$cwd = `pwd`;
+chomp($cwd);
+
+# directory for last-printed 'run' command
+#$lastRunDir = "";
+
+# statistics
+%ppfail    = ('gcc' => 0, 'g++' => 0);     # preprocessing failures, per mode
+%parsefail = %ppfail;                      # parse failures
+%parseok   = %ppfail;                      # parse success
+
+
+sub timeStamp {
+  $curDate = `date`;
+  chomp($curDate);
+  print("time: $curDate\n");
+}           
+
+timeStamp();
+
+open(IN,"<$buildlog") or die("can't open $buildlog: $!\n");
+while (defined($line = <IN>)) {
+  chomp($line);
+  my $s;
+
+  # "Entering directory ..."
+  ($s) = ($line =~ m|^g?make.*: Entering directory \`(.*)\'$|);
+  if (defined($s)) {
+    pushdir($s);
+    next;
+  }
+
+  # "Leaving directory ..."
+  ($s) = ($line =~ m|^g?make.*: Leaving directory \`(.*)\'$|);
+  if (defined($s)) {
+    if ($s ne $cwd) {
+      warning("I think cwd is $cwd, but make thinks it is $s");
+    }
+    popdir();
+    next;
+  }
+
+  # gcc or g++
+  ($s) = ($line =~ m/^(cc|gcc|g\+\+) /);
+  if (defined($s)) {
+    # normalize cc vs gcc
+    if ($s eq "cc") {
+      $s = "gcc";
+    }
+
+    # splice lines if it ends in backslash
+    while (substr($line, -1, 1) eq "\\") {
+      diagnostic("continued line");
+      chop($line);             # throw away the backslash
+      my $next = <IN>;
+      if (!defined($next)) {
+        die("log ended with a backslash!\n");
+      }
+      chomp($next);
+      $line = $line . $next;
+    }
+
+    # modify command string to send output to tmp.i
+    if ($line !~ s/-o \S+/-o tmp.i/) {
+      # no -o option, add one
+      $line .= " -o tmp.i";
+    }
+
+    # modify command to preprocess instead of compile
+    if ($line !~ s/ -c/ -E/) {
+      # link command.. ignore it
+      next;
+    }
+
+    $runCount++;
+
+    if ($runCount > $maxCt) {
+      bail();
+      exit(0);
+    }
+    if ($runCount < $minCt) {
+      next;
+    }
+
+    # run the gcc/g++ command to preprocess the input
+    if (!run($line)) {
+      $ppfail{$s}++;
+      print STDERR ("g");      # gcc failed
+    }
+    else {
+      if (! -f "tmp.i") {
+        # the preprocessor did not report an error, and yet no tmp.i
+        # file was created; this happens under gcc-2 (at least) when
+        # the original command was simply intending to run the
+        # assembler; let's just assume that it's all good and skip it
+        print ("No tmp.i was generated; skipping.\n");
+        next;
+      }
+
+      # run Elsa to parse it
+      my $op = (($s eq "gcc")? "-tr gnu_kandr_c_lang " : "");
+      if (run("$ccparse ${op}tmp.i")) {
+        $parseok{$s}++;
+        print STDERR (".");
+      }
+      else {
+        $parsefail{$s}++;
+        print STDERR ("e");    # elsa failed
+      }
+    }
+
+    # remove tmp.i so as not to leave a bunch of them hanging
+    # around; in firefox, the accumulation of tmp.i files consumes
+    # more than 100MB of space
+    unlink("tmp.i");
+
+    next;
+  }
+
+  # skip other lines
+}
+close(IN);
+
+bail();
+exit(0);
+
+
+sub bail {
+  print("final statistics (stopped after $runCount):\n");
+  print("                 C   C++\n");
+  print("  ----------------------\n");
+  printf("  ppfail      %4d  %4d\n", $ppfail{'gcc'}, $ppfail{'g++'});
+  printf("  parsefail   %4d  %4d\n", $parsefail{'gcc'}, $parsefail{'g++'});
+  printf("  parseok     %4d  %4d\n", $parseok{'gcc'}, $parseok{'g++'});
+  print("  ----------------------\n");
+  printf("  total       %4d  %4d\n",
+         $ppfail{'gcc'}+$parsefail{'gcc'}+$parseok{'gcc'},
+         $ppfail{'g++'}+$parsefail{'g++'}+$parseok{'g++'});
+  timeStamp();
+
+  my $failures = $ppfail{'gcc'} + $ppfail{'g++'} +
+                 $parsefail{'gcc'} + $parsefail{'g++'};
+  print ("($failures failures)\n");
+  print STDERR ("($failures failures)\n");
+}
+
+sub sigIntHandler {
+  bail();
+  exit(130);
+}
+
+
+sub run {
+  my ($cmd) = @_;
+
+  #if ($cwd ne $lastRunDir) {
+  #  print("cd $cwd\n");
+  #  $lastRunDir = $cwd;
+  #}
+
+  print("cwd: $cwd\n");
+
+  print("$runCount: $cmd\n");
+  my $code = 0;
+  if ($dry) {
+    # don't run
+  }
+  else {
+    $code = system($cmd . " 2>&1");    # all output to stdout
+  }
+
+  if ($code != 0) {
+    my $expl;
+    if ($code >= 256) {    
+      # ordinary exit with nonzero status
+      $code = $code >> 8;
+      $expl = "code $code";              
+    }
+    else {
+      # terminated by signal
+      $expl = "signal $code";
+      if ($code == 2) {
+        # ctrl-c
+        sigIntHandler();
+      }
+    }
+    printf("failing command ($expl): $cmd\n");
+    return 0;
+  }
+  else {
+    return 1;
+  }
+}
+
+sub warning {
+  my ($msg) = @_;
+  print("warning: $msg\n");
+}
+
+sub diagnostic {
+  my ($msg) = @_;
+  if ($diag) {
+    print("diagnostic: $msg\n");
+  }
+}
+
+sub pushdir {
+  my ($d) = @_;
+  push @dirstack, ($cwd);
+  $cwd = $d;
+  mychdir($cwd);
+}
+
+sub popdir {
+  $cwd = pop @dirstack;
+  mychdir($cwd);
+}
+
+sub mychdir {
+  my ($d) = @_;
+  diagnostic("cd $d");
+  chdir($d) or die("can't chdir to $d: $!\n");
+}
+
+# EOF


Property changes on: vendor/elsa/current/elsa/test-parse-buildlog
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse-manyfiles
===================================================================
--- vendor/elsa/current/elsa/test-parse-manyfiles	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse-manyfiles	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+#!/usr/bin/perl -w
+# read a list of filenames from stdin, one per line, and try
+# to parse them with Elsa
+
+use strict 'subs';
+  
+$SIG{INT} = \&sigIntHandler;
+
+$lineNum = 0;
+$files = 0;
+$success = 0;
+$failures = 0;
+
+
+while (defined($line = <STDIN>)) {
+  chomp($line);
+  $lineNum++;
+
+  print("----------------------\n");
+  print("fname: $line\n");
+
+  if ($line !~ m/\.gz$/) {
+    die("line $lineNum: expected name ending in .gz\n");
+  }
+
+  if (0 != runecho("gunzip -c $line >tmp.i")) {
+    die("gunzip failed\n");
+  }
+
+  $files++;
+  if (0 != runecho("./ccparse -tr c_lang tmp.i")) {
+    print("failed to parse $line\n");
+    print STDERR ("e");
+    $failures++;
+  }
+  else {
+    print STDERR (".");
+    $success++;
+  }
+}
+
+bail();
+exit(0);
+
+sub bail {
+  print("----------------------\n");
+  print("total files: $files\n");
+  print("  succeeded: $success\n");
+  print("     failed: $failures\n");
+
+  print STDERR ("($failures failures)\n");
+}
+
+sub sigIntHandler {
+  bail();
+  exit(130);
+}
+
+sub runecho {
+  print(@_, "\n");
+  
+  my $code = system(@_);
+  if ($code == 2) {
+    # ctrl-c
+    sigIntHandler();
+  }
+  
+  return $code;
+}
+
+# EOF


Property changes on: vendor/elsa/current/elsa/test-parse-manyfiles
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse-mozilla
===================================================================
--- vendor/elsa/current/elsa/test-parse-mozilla	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse-mozilla	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+#!/bin/sh
+# test-parse mozilla's .i files, without stopping at failures
+
+for fn in `cat /home/scott/bld/mozilla-1.0/allifiles`; do
+  ./test-parse $fn
+done


Property changes on: vendor/elsa/current/elsa/test-parse-mozilla
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse-mozilla-gcc
===================================================================
--- vendor/elsa/current/elsa/test-parse-mozilla-gcc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse-mozilla-gcc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,13 @@
+#!/bin/sh
+# test-parse mozilla's .i files, without stopping at failures
+# use gcc instead of elsa
+
+for fn in `cat /home/scott/bld/mozilla-1.0/allifiles`; do
+  echo "--------- $fn"
+  echo ./run-g++ -xc++ $fn
+  if ./run-g++ -xc++ $fn; then
+    echo "$fn: ok"
+  else
+    echo "$fn: error (code $?)"
+  fi
+done


Property changes on: vendor/elsa/current/elsa/test-parse-mozilla-gcc
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse-openssh
===================================================================
--- vendor/elsa/current/elsa/test-parse-openssh	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse-openssh	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+#!/bin/sh
+# test-parse openssl's .i files, without stopping at failures
+
+exec >parse.log 2>&1
+
+for fn in `cat /home/scott/bld/openssh-3.5p1/allifiles`; do
+  ./test-parse -tr c_lang $fn
+done


Property changes on: vendor/elsa/current/elsa/test-parse-openssh
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse-openssl
===================================================================
--- vendor/elsa/current/elsa/test-parse-openssl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse-openssl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,8 @@
+#!/bin/sh
+# test-parse openssl's .i files, without stopping at failures
+
+exec >parse.log 2>&1
+
+for fn in `cat /home/scott/bld/openssl-0.9.7/allifiles`; do
+  ./test-parse -tr c_lang $fn
+done


Property changes on: vendor/elsa/current/elsa/test-parse-openssl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-parse-std
===================================================================
--- vendor/elsa/current/elsa/test-parse-std	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-parse-std	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,43 @@
+#!/bin/sh
+# run ccparse on preprocessed stdlib headers
+
+
+#  valarray       fails because of template template params
+
+for n in           \
+  algorithm        \
+  bitset           \
+  complex          \
+  deque            \
+  exception        \
+  fstream          \
+  functional       \
+  iomanip          \
+  ios              \
+  iosfwd           \
+  iostream         \
+  istream          \
+  iterator         \
+  limits           \
+  list             \
+  locale           \
+  map              \
+  memory           \
+  new              \
+  numeric          \
+  ostream          \
+  queue            \
+  set              \
+  sstream          \
+  stack            \
+  stdexcept        \
+  strstream        \
+  streambuf        \
+  string           \
+  typeinfo         \
+  utility          \
+  vector; do       \
+  echo "----------------- $n --------------"
+  ./ccparse ../elsa/other-examples/triv/$n.ii || exit
+done
+


Property changes on: vendor/elsa/current/elsa/test-parse-std
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/test-perl-crlf.pl
===================================================================
--- vendor/elsa/current/elsa/test-perl-crlf.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/test-perl-crlf.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,89 @@
+#!/usr/bin/perl -w
+# test prevailing CRLF<->LF translation
+
+use strict 'subs';
+
+if (@ARGV == 0) {
+  # start the test
+  exec("$0 -test <crlf.txt >stdout.txt");
+}
+
+if ($ARGV[0] ne "-test") {
+  die("wrong usage");
+}
+
+report("OS: $^O\n");
+
+report("CRLF->LF on inputs NOT opened by perl: ");
+$line = <STDIN>;
+if (length($line) == 1) {
+  report("yes\n");
+}
+elsif (length($line) == 2) {
+  report("no\n");
+}
+else {
+  die;
+}
+
+report("CRLF->LF on inputs opened by perl: ");
+open(IN, "<crlf.txt") or die;
+$line = <IN>;
+close(IN);
+if (length($line) == 1) {
+  report("yes\n");
+}
+elsif (length($line) == 2) {
+  report("no\n");
+}
+else {
+  die;
+}
+
+report("LF->CRLF on outputs NOT opened by perl: ");
+print("\n");
+close(STDOUT);   # flushes too
+$len = getFileSize("stdout.txt");
+if ($len == 1) {
+  report("no\n");
+}
+elsif ($len == 2) {
+  report("yes\n");
+}
+else {
+  die;
+}
+
+report("LF->CRLF on outputs opened by perl: ");
+open(OUT, ">output.txt") or die;
+print OUT ("\n");
+close(OUT) or die;
+$len = getFileSize("output.txt");
+if ($len == 1) {
+  report("no\n");
+}
+elsif ($len == 2) {
+  report("yes\n");
+}
+else {
+  die;
+}
+
+exit(0);
+
+
+sub report {
+  print STDERR (@_);
+}
+
+sub getFileSize {
+  my ($fname) = @_;
+
+  my @details = stat($fname);
+
+  # how do I tell if 'stat' failed?
+
+  return $details[7];
+}
+
+# EOF


Property changes on: vendor/elsa/current/elsa/test-perl-crlf.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/tlexer.cc
===================================================================
--- vendor/elsa/current/elsa/tlexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/tlexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,51 @@
+// tlexer.cc            see license.txt for copyright and terms of use
+// test the lexer alone
+
+#include "lexer.h"         // Lexer
+#include "strtable.h"      // StringTable
+#include "cc_lang.h"       // CCLang
+#include "test.h"          // ARGS_MAIN
+#include "nonport.h"       // getMilliseconds
+#include "trace.h"         // tracingSys
+
+#include <iostream.h>      // cout
+
+
+void entry(int argc, char **argv)
+{
+  char const *progName = argv[0];
+  TRACE_ARGS()
+
+  if (argc != 2) {
+    cout << "usage: " << progName << " [-tr tokens] input.i\n";
+    return;
+  }
+  traceAddSys("progress");
+
+  StringTable table;
+  CCLang lang;
+  lang.ANSI_Cplusplus();     // want 'true' and 'false' keywords
+  SourceLocManager mgr;
+
+  traceProgress() << "making Lexer\n";
+  Lexer lexer(table, lang, argv[1]);
+  Lexer::NextTokenFunc nextToken = lexer.getTokenFunc();
+
+  bool print = tracingSys("tokens");
+
+  traceProgress() << "lexing " << argv[1] << "...\n";
+  long start = getMilliseconds();
+
+  while (lexer.type != 0 /*eof*/) {
+    if (print) {
+      cout << toString(lexer.loc) << ": " << lexer.tokenDesc() << endl;
+    }
+
+    nextToken(&lexer);
+  }
+
+  traceProgress() << "done lexing (" << (getMilliseconds() - start)
+                  << " ms)\n";
+}
+
+ARGS_MAIN

Added: vendor/elsa/current/elsa/todo.txt
===================================================================
--- vendor/elsa/current/elsa/todo.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/todo.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,214 @@
+todo.txt    -*- outline -*-
+
+* Introduction
+
+This is a list of incomplete aspects of the Elsa C++ front end.
+
+See also the various places in the sources marked "TODO" and "BUG".
+This list is meant to be a summary of the major things not done, but
+there are plenty of little things not mentioned here.
+
+** Emacs outline-mode keybindings
+
+There are here as a reminder:
+  M-x show-all         Show all text
+  (keypad) +           Expand by one level
+  (keypad) -           Collapse
+  (keypad) *           Expand completely
+  (keypad) /           Make all non-heading text invisible
+  C-h m                Help for current mode (outline-mode)
+
+* Language recognition
+
+Generally, language recognition (distinguishing valid from invalid
+C++) is incomplete.  This front end is currently envisioned working in
+an environment where the programs in question are already known to be
+valid, for example by checking with gcc.  As Elsa intended to be a
+research tool, isn't seen as a problem for now.
+
+** Type checking
+
+We don't check type correspondences.
+
+*** arguments vs. parameters
+*** initializers vs. initialized variable
+
+** Access control
+
+Nothing is done with "public", "private", etc., besides writing that
+information down.
+
+** Undefined behavior
+
+Many sources of undefined behavior, like multiple interacting
+side effects between sequence points, are not diagnosed.  As the
+standard does not require a diagnostic, this isn't a standards
+conformance problem, but it would be nice to detect as many of
+these as possible.
+
+** Default arguments
+
+Some of the rules for when default arguments can be supplied are
+not implemented.
+
+** Casts
+
+All casts are currently taken at face value, ignoring the possibility
+that the requested conversion can't be performed (e.g. dynamic_cast
+of a non-polymorphic type).
+
+** Error messages
+
+I think there's an opportunity to greatly improve the way compilers
+report error messages, by having it generate error *objects* that have
+e.g. pointers to the relevant items.  The user could then ask for
+varying levels of detail, or even explore the errors interactively for
+complicated situations like overload resolution failures.  But all
+this is just an idea for now; I build strings like everyone else.
+
+** Deprecated features
+
+A number of language features, like the automatic conversion from
+string literal to char* (as opposed to char const*) are marked
+"deprecated" by the standard (Annex D).  It would be nice to have
+a flag to diagnose use of deprecated features.
+
+** Exception specs
+
+No checking is done w.r.t. exception specs.
+
+** Globals without initializers
+
+At least according to the sixth example in section 7.3.3, C++ allows
+"int i; int i;" at toplevel.  We currently reject this.
+
+* Types of literals
+
+A few literals get the wrong type.  For example, 1U should be
+unsigned, but it isn't.
+
+* String concatenation
+
+Nothing is properly interpreting concatenated strings, though the
+AST does record them.
+
+* Overload resolution
+
+** Conversions for control flow contexts
+
+For example, when a class that can convert to bool is used as the
+guard of an "if", we need to recognize that the conversion is
+happening.
+
+** Operator overloading
+
+Several overloadable operators do not have overload resolution
+being performed.
+
+*** operator->
+*** operator[]
+*** operator new/delete
+
+*** operator?
+
+The ?: operator needs to have resolution performed as if it
+could be overloaded, to determine what conversions to perform on
+the arguments.
+
+** Greatest lower bound for pointer-to-member conversions
+
+See the notes in convertibility.txt.  Elsa does not implement the
+GLB analysis, and quite possibly never will.
+
+* Qualified name lookup
+
+There's a bug in D_name_tcheck that doesn't allow class members inside
+the class body to use qualified names.  It's an indicator that there
+are more serious problems in handling of qualified names.
+
+* Compiler-supplied functions
+
+Each class automatically gets default (no-arg) and copy constructors,
+an operator=, and a destructor, depending on various conditions.
+
+** We need operator=
+
+** Rules for argument type
+
+The argument type for operator= and the copy ctor are not correct
+in all cases.
+
+* Implicit function call
+
+A general goal is to make all function calls explicit in the AST, even
+if they were implicit in the original syntax.  That's not done in
+some cases.
+
+** Conversions for function call arguments
+
+** Implicit constructors and destructors
+
+This is now done by the 'elaborate' module.
+
+* Namespaces
+
+** Synthesized calls
+
+In a few places, I synthesize e.g. "::operator~(a)", intending to get
+a non-member operator~, but it might not be in the global scope if
+namespaces are present.
+
+** Grammar
+
+In at least one place, cc.gr doesn't allow leading "::"s where it should.
+
+** std namespace
+
+None of the language-defined entities, e.g. the "typeid" class, are
+in the "std" namespace as they should be.
+
+** friend declarations
+
+I haven't done anything with friends, esp. 7.3.1.2 para 3.
+
+** using-directive overload sets
+
+To implement 3.4.3.2 para 2 and 7.3.4 para 5, name lookup and overload
+resolution in the presence of "using directives", I need my lookup
+functions to be capable of returning sets of declarations that are not
+all in the same scope.  Currently that is impossible, requiring
+significant design changes to accomodate.  :(
+
+* Templates
+
+The template implementation is still evolving.
+
+** Grammar
+
+The standard grammar has a number of places where the keyword
+"template" is allowed, and has some meaning, but currently our grammar
+(cc.gr) does not allow it.
+
+* Single-pass design
+
+In principle, it should be possible to parse, typecheck, and analyze
+each function one at a time, and then deallocate the storage used
+while processing that function.  But there are a few things standing
+in the way of actually doing that.
+
+** Region-based AST allocation
+
+Put the AST for each function into a region, so it can be deallocated
+as a group despite the internal sharing
+
+** Hash-consing for types
+
+Reduce storage requirements for types by implementing hash-consing.
+
+** Do something about variables
+
+The Variable class is has a mixture of AST and type aspects.
+Variables that correspond to locals could go away with the AST, but
+variables in function parameters are needed for longer.  Perhaps a
+systematic way of deciding when to deallocate variables can be found.
+

Added: vendor/elsa/current/elsa/token.pl
===================================================================
--- vendor/elsa/current/elsa/token.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/token.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,85 @@
+#!/usr/bin/perl -w
+# token.pl            see license.txt for copyright and terms of use
+
+use strict;
+
+# Think of this perl script as compressed data: the set of tokens for
+# the xml for the type system.  This file generates three different
+# files that have to agree with one another.
+
+# defines the token names for purposes of printing out
+my $tokenNamesFile = "xml_name_1.gen.cc";
+# the lexer file
+my $tokenLexerFile = "xml_lex_1.gen.lex";
+# the file that goes into the definition of enum XmlToken
+my $tokenEnumFile = "xml_enum_1.gen.h";
+
+open(NAMES, ">$tokenNamesFile") or die $!;
+open(LEXER, ">$tokenLexerFile") or die $!;
+open(ENUM,  ">$tokenEnumFile") or die $!;
+
+my %data_lines;                 # data lines should be idempotent
+
+sub renderFiles {
+  while (<>) {
+    chomp;                      # trim trailing newline
+    s/^\s*//;                   # trim leading whitespace
+    s/\s*$//;                   # trim trailnig whitespace
+
+    if (/^$/) {
+      # blank line
+      print NAMES "\n";
+      print LEXER "\n";
+      print ENUM  "\n";
+      next;
+    }
+
+    my $comment;
+
+    if (/^\w+$/) {
+      # data line
+      if (defined $data_lines{$_}) {
+        # if we have already seen it, comment it out
+        $comment = "redundant token: $_";
+      } else {
+        $data_lines{$_}++;
+        undef $comment;         # redundant
+        print NAMES "  \"XTOK_$_\",\n";
+        print LEXER "\"$_\" return tok(XTOK_$_);\n";
+        print ENUM  "  XTOK_$_, // \"$_\"\n";
+        next;
+      }
+    }
+
+    if (m/^\#(.*)$/) {
+      die "this line is both data and comment?!: $_" if $comment;
+      $comment = $1;
+    }
+
+    if ($comment) {
+      # comment line
+      print NAMES "  // $comment\n";
+      print LEXER "  /*${comment}*/\n";
+      print ENUM  "  // $comment\n";
+      next;
+    }
+
+    # illegal line
+    die "illegal line: $_\n";
+  }
+}
+
+eval {
+  renderFiles();
+};
+if ($@) {
+  print "$@";
+  unlink $tokenNamesFile;
+  unlink $tokenLexerFile;
+  unlink $tokenEnumFile;
+  exit 1;
+}
+
+close(NAMES) or die $!;
+close(LEXER) or die $!;
+close(ENUM)  or die $!;


Property changes on: vendor/elsa/current/elsa/token.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/toplevel/license.txt
===================================================================
--- vendor/elsa/current/elsa/toplevel/license.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/toplevel/license.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+The software in this directory is
+Copyright (c) 2002, Regents of the University of California
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above 
+      copyright notice, this list of conditions and the following 
+      disclaimer in the documentation and/or other materials provided 
+      with the distribution.
+
+    * Neither the name of the University of California, Berkeley nor 
+      the names of its contributors may be used to endorse or promote 
+      products derived from this software without specific prior 
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: vendor/elsa/current/elsa/toplevel/readme.txt
===================================================================
--- vendor/elsa/current/elsa/toplevel/readme.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/toplevel/readme.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+readme.txt for Elkhound/Elsa distribution
+-----------------------------------------
+
+This release is provided under the BSD license.  See license.txt.
+
+Elkhound is a parser generator.  
+Elsa is a C/C++ parser that uses Elkhound.
+
+See additional documentation in index.html in the various 
+subdirectories.
+
+Alternatively, see the Documentation section of
+http://www.cs.berkeley.edu/~smcpeak/elkhound/ .
+
+
+Build instructions:
+
+  $ ./configure 
+  $ make
+  $ make check     (optional but a good idea)
+
+This simply does each of these activities in each of the directories:
+smbase, ast, elkhound and elsa.  If a command fails you can restart it
+in a particular directory just by going into the failing directory and
+issuing it there.
+
+After building, the interesting binary is elsa/ccparse.  See
+elsa/index.html for more info on what to do with it.
+
+
+If you run into problems you can email me: smcpeak at cs.berkeley.edu
+But be aware I'm usually pretty busy so responses may take a couple
+of days.

Added: vendor/elsa/current/elsa/typelistiter.cc
===================================================================
--- vendor/elsa/current/elsa/typelistiter.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/typelistiter.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,48 @@
+// typelistiter.cc
+// code for typelistiter.h
+
+#include "typelistiter.h"      // this module
+#include "cc_ast.h"            // C++ ast components
+
+
+// -------- TypeListIter_FakeList --------
+
+bool TypeListIter_FakeList::isDone() const
+{
+  return curFuncArgs == 0;
+}
+
+void TypeListIter_FakeList::adv()
+{
+  xassert(!isDone());
+  curFuncArgs = curFuncArgs->butFirst();
+}
+
+Type *TypeListIter_FakeList::data() const
+{
+  xassert(!isDone());
+  return curFuncArgs->first()->getType();
+}
+
+
+// -------- TypeListIter_GrowArray --------
+
+bool TypeListIter_GrowArray::isDone() const
+{
+  return i == args.size();
+}
+
+void TypeListIter_GrowArray::adv()
+{
+  xassert(!isDone());
+  ++i;
+}
+
+Type *TypeListIter_GrowArray::data() const
+{
+  xassert(!isDone());
+  return args[i].type;
+}
+
+
+// EOF

Added: vendor/elsa/current/elsa/typelistiter.h
===================================================================
--- vendor/elsa/current/elsa/typelistiter.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/typelistiter.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,61 @@
+// typelistiter.h                       see license.txt for copyright and terms of use
+// iterate over a sequence of objects, looking at their types
+// author: dsw
+
+#ifndef TYPELISTITER_H
+#define TYPELISTITER_H
+
+#include "overload.h"        // Type, GrowArray, ArgumentInfo, etc.
+#include "fakelist.h"        // FakeList
+
+// unifies the process of iterating over a list of types
+class TypeListIter {
+  public:
+  // can't share the common dtor in the superclass because it calls a
+  // virtual abstract method
+  virtual ~TypeListIter() {}
+
+  // iterator actions
+  virtual bool isDone() const = 0;
+  virtual void adv() = 0;
+  virtual Type *data() const = 0;
+};
+
+class TypeListIter_FakeList : public TypeListIter {
+  FakeList<ArgExpression> *curFuncArgs;
+
+  public:
+  TypeListIter_FakeList(FakeList<ArgExpression> *funcArgs0)
+    : curFuncArgs(funcArgs0)
+  {}
+  virtual ~TypeListIter_FakeList() {
+    // this is not always the case if argument list processing aborts
+    // part way through due to an error
+//      xassert(isDone());
+  }
+
+  virtual bool isDone() const;
+  virtual void adv();
+  virtual Type *data() const;
+};
+
+class TypeListIter_GrowArray : public TypeListIter {
+  GrowArray<ArgumentInfo> &args;
+  int i;
+
+  public:
+  TypeListIter_GrowArray(GrowArray<ArgumentInfo> &args0)
+    : args(args0), i(0)
+  {}
+  virtual ~TypeListIter_GrowArray() {
+    // this is not always the case if argument list processing aborts
+    // part way through due to an error
+//      xassert(isDone());
+  }
+
+  virtual bool isDone() const;
+  virtual void adv();
+  virtual Type *data() const;
+};
+
+#endif // TYPELISTITER_H

Added: vendor/elsa/current/elsa/variable.cc
===================================================================
--- vendor/elsa/current/elsa/variable.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/variable.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,884 @@
+// variable.cc            see license.txt for copyright and terms of use
+// code for variable.h
+
+#include "variable.h"      // this module
+#include "template.h"      // Type, TemplateInfo, etc.
+#include "trace.h"         // tracingSys
+#include "mangle.h"        // mangle()
+
+// dsw: need this for Oink; we'll figure out how to make this non-global later
+bool variablesLinkerVisibleEvenIfNonStaticDataMember = false;
+
+// ---------------------- SomeTypeVarNotInTemplParams_Pred --------------------
+
+// existential search for a type variable that is not in the template
+// parameters
+class SomeTypeVarNotInTemplParams_Pred : public TypePred {
+  TemplateInfo *ti;
+  public:
+  SomeTypeVarNotInTemplParams_Pred(TemplateInfo *ti0) : ti(ti0) {}
+  virtual bool operator() (Type const *t);
+  virtual ~SomeTypeVarNotInTemplParams_Pred() {}
+};
+
+bool SomeTypeVarNotInTemplParams_Pred::operator() (Type const *t)
+{
+  if (!t->isCVAtomicType()) return false;
+  CVAtomicType const *cv = t->asCVAtomicTypeC();
+
+  if (cv->isCompoundType()) {
+    CompoundType const *cpd = cv->asCompoundTypeC();
+    // recurse on all of the arugments of the template instantiation
+    // if any
+    if (cpd->templateInfo()) {
+      FOREACH_OBJLIST_NC(STemplateArgument, cpd->templateInfo()->arguments, iter) {
+        STemplateArgument *sta = iter.data();
+        if (sta->isType()) {
+          if (sta->getType()->anyCtorSatisfies(*this)) return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  if (cv->isTypeVariable()) {
+    // check that this tvar occurs in the parameters list of the
+    // template info
+    Variable *tvar = cv->asTypeVariableC()->typedefVar;
+    if (ti->hasSpecificParameter(tvar)) {
+      return false;
+    }
+    return true;
+  }
+
+  return false;                 // some other type of compound type
+};
+
+size_t Variable::numVariables = 0;
+
+// ---------------------- Variable --------------------
+Variable::Variable(SourceLoc L, StringRef n, Type *t, DeclFlags f)
+  : loc(L),
+    name(n),
+    type(t),
+    flags(f),
+    value(NULL),
+    defaultParamType(NULL),
+    funcDefn(NULL),
+    overload(NULL),
+    virtuallyOverride(NULL),
+    scope(NULL),
+    usingAlias_or_parameterizedEntity(NULL),
+    templInfo(NULL)
+{
+  // the first time through, do some quick tests of the
+  // encodings of 'intData'
+  static int didSelfTest = false;
+  if (!didSelfTest) {
+    didSelfTest = true;
+
+    setAccess(AK_PRIVATE);
+    setScopeKind(SK_NAMESPACE);
+    setParameterOrdinal(1000);
+
+    xassert(getAccess() == AK_PRIVATE);
+    xassert(getScopeKind() == SK_NAMESPACE);
+    xassert(getParameterOrdinal() == 1000);
+
+    // opposite order
+    setParameterOrdinal(88);
+    setScopeKind(SK_CLASS);
+    setAccess(AK_PROTECTED);
+
+    xassert(getAccess() == AK_PROTECTED);
+    xassert(getScopeKind() == SK_CLASS);
+    xassert(getParameterOrdinal() == 88);
+  }
+
+  setAccess(AK_PUBLIC);
+  setScopeKind(SK_UNKNOWN);
+  setParameterOrdinal(0);
+
+  if (!isNamespace()) {
+    xassert(type);
+  }
+
+  ++numVariables;
+}
+
+// ctor for de-serialization
+Variable::Variable(XmlReader&)
+  : loc(SL_UNKNOWN),
+    name(NULL),
+    type(NULL),
+    flags(DF_NONE),
+    value(NULL),
+    defaultParamType(NULL),
+    funcDefn(NULL),
+    overload(NULL),
+    virtuallyOverride(NULL),
+    scope(NULL),
+    usingAlias_or_parameterizedEntity(NULL),
+    templInfo(NULL)
+{
+  ++numVariables;
+}
+
+Variable::~Variable()
+{}
+
+
+void Variable::setFlagsTo(DeclFlags f)
+{
+  // this method is the one that gets to modify 'flags'
+  const_cast<DeclFlags&>(flags) = f;
+}
+
+bool Variable::isSemanticallyGlobal() const {
+  switch(getScopeKind()) {
+  case NUM_SCOPEKINDS:
+    xfailure("can't happen");
+    break;                      // silly gcc warning
+  case SK_UNKNOWN:              // not yet registered in a scope
+    // FIX: the global scope has ScopeKind SK_UNKNOWN
+//     xfailure("got SK_UNKNOWN on a real variable");
+    break;
+  case SK_GLOBAL:               // toplevel names
+    return true;
+    break;
+  case SK_FUNCTION:             // includes local variables
+    if (hasFlag(DF_STATIC)) {
+      return true;
+    }
+    break;
+  case SK_CLASS:                // class member scope
+    if (hasFlag(DF_STATIC)) {
+      return true;
+    }
+    break;
+  default:
+    break;
+  }
+  return false;
+}
+
+bool Variable::inGlobalOrNamespaceScope() const {
+  return scope && (scope->isGlobalScope() || scope->isNamespace());
+}
+
+bool Variable::linkerVisibleName() const {
+  return linkerVisibleName(false);
+}
+
+bool Variable::linkerVisibleName(bool evenIfStaticLinkage) const {
+//    bool oldAnswer;
+//    if (scope) oldAnswer = scope->linkerVisible();
+//    else oldAnswer = hasFlag(DF_GLOBAL);
+
+  // do not consider templates
+  if (isTemplate()) return false;
+
+  // do not consider members of uninstantiated template primaries or
+  // partial specializations
+  if (isUninstTemplateMember()) return false;
+
+  // it seems that we should not consider typedefs to be linker-visible
+  if (hasFlag(DF_TYPEDEF)) return false;
+  // nor namespaces, such as '<globalScope>'
+  if (hasFlag(DF_NAMESPACE)) return false;
+
+  // dsw: nothing starting with __builtin_va is linker-visible
+  static char *builtin_va_prefix = "__builtin_va";
+  static int builtin_va_prefix_len = strlen(builtin_va_prefix);
+  if (name && 0==strncmp(name, builtin_va_prefix, builtin_va_prefix_len)) return false;
+
+  // quarl 2006-06-03, 2006-07-11
+  //     *In C++ mode only*, inline implies static.  In C mode, 'inline'
+  //     functions can be non-static (see e.g. package gnutls11).
+  //     isStaticLinkage() now handles this implication with help from
+  //     typechecking.  A function can both be a static member and have static
+  //     linkage (via inline).
+  if (!evenIfStaticLinkage) {
+    if (isStaticLinkage()) {
+      return false;
+    }
+  }
+
+  // FIX: what the heck was this?  Some attempt to treat struct
+  // members as linkerVisibleName-s?  This doesn't work because there
+  // is no well-defined name for an anonymous struct anyway.
+  if (!scope) {
+    // FIX: I hope this is right.
+    // FIX: hmm, when else can this occur?
+//      xassert(hasFlag(DF_PARAMETER));
+    // this one fails for template parameters!?
+//      xassert(!hasFlag(DF_GLOBAL));
+    return false;
+  }
+
+  // quarl 2006-07-11
+  //    Check for this even if not in class scope, e.g. a struct defined
+  //    within a function (Test/struct_sizeof.c)
+  if (!scope->linkerVisible()) {
+    return false;
+  }
+
+  // dsw: I hate this overloading of the 'static' keyword.  Static members of
+  // CompoundTypes are linker visible if the CompoundType is linkerVisible.
+  // Non-static members are visible only if they are FunctionTypes.
+  if (scope->isClassScope()) {
+    if (!hasFlag(DF_MEMBER)) {
+      return false;
+    }
+
+    // non-static members of a class
+    if (!variablesLinkerVisibleEvenIfNonStaticDataMember) {
+      if (!(type->asRval()->isFunctionType() || hasFlag(DF_STATIC))) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+
+// 2005-08-15: Previously, this would return false for unions because
+// I misunderstood the standard.  However, 9p4 is clear that unions
+// are classes, and can have destructors, etc. (in/t0571.cc)
+bool Variable::isClass() const
+{
+  return hasFlag(DF_TYPEDEF) && type->isCompoundType();
+}
+
+
+bool Variable::isUninstTemplateMember() const
+{
+  if (isTemplate() &&
+      !templateInfo()->isCompleteSpecOrInstantiation()) {
+    return true;
+  }
+  return scope && scope->isWithinUninstTemplate();
+}
+
+
+bool Variable::isUninstClassTemplMethod() const
+{
+  return hasFlag(DF_VIRTUAL) && type->isMethod() && isInstantiation() && !funcDefn;
+}
+
+
+bool Variable::isTemplate(bool considerInherited) const
+{
+  return templateInfo() &&
+         templateInfo()->hasParametersEx(considerInherited);
+}
+
+
+bool Variable::isTemplateFunction(bool considerInherited) const
+{
+  return type &&
+         type->isFunctionType() &&
+         isTemplate(considerInherited) &&
+         !hasFlag(DF_TYPEDEF);
+}
+
+
+bool Variable::isTemplateClass(bool considerInherited) const
+{
+  return hasFlag(DF_TYPEDEF) &&
+         type->isCompoundType() &&
+         isTemplate(considerInherited);
+}
+
+
+bool Variable::isInstantiation() const
+{
+  return templInfo && templInfo->isInstantiation();
+}
+
+
+TemplateInfo *Variable::templateInfo() const
+{
+  // 2005-02-23: experiment: alias shares referent's template info
+  return skipAliasC()->templInfo;
+}
+
+void Variable::setTemplateInfo(TemplateInfo *templInfo0)
+{
+  templInfo = templInfo0;
+
+  // 2005-03-07: this assertion fails in some error cases (e.g., error
+  // 1 of in/t0434.cc); I tried a few hacks but am now giving up on it
+  // entirely
+  //xassert(!(templInfo && notQuantifiedOut()));
+
+  // complete the association
+  if (templInfo) {
+    // I am the method allowed to change TemplateInfo::var
+    const_cast<Variable*&>(templInfo->var) = this;
+  }
+  else {
+    // this happens when we're not in a template at all, but the
+    // parser just takes the pending template info (which is NULL)
+    // and passes it in here anyway
+  }
+}
+
+
+bool Variable::notQuantifiedOut()
+{
+  TemplateInfo *ti = templateInfo();
+  if (!ti) return false;
+  SomeTypeVarNotInTemplParams_Pred pred(ti);
+  return type->anyCtorSatisfies(pred);
+}
+
+
+void Variable::gdb() const
+{
+  cout << toString() << endl;
+}
+
+string Variable::toString() const
+{
+  if (Type::printAsML) {
+    return toMLString();
+  }
+  else {
+    return toCString();
+  }
+}
+
+
+string Variable::toCString() const
+{
+  // as an experiment, I'm saying public(field) in the .ast file
+  // in a place where the Variable* might be NULL, so I will
+  // tolerate a NULL 'this'
+  if (this == NULL) {
+    return "NULL";
+  }
+
+  // The purpose of this method is to print the name and type
+  // of this Variable object, in a debugging context.  It is
+  // not necessarily intended to print them in a way consistent
+  // with the C syntax that might give rise to the Variable.
+  // If more specialized printing is desired, do that specialized
+  // printing from outside (by directly accessing 'name', 'type',
+  // 'flags', etc.).
+  //
+  // dsw: namespace variables have no type
+  if (type) {
+    return type->toCString(stringc << (name? name : "/*anon*/") << namePrintSuffix());
+  } else {
+    return name? name : "/*anon*/";
+  }
+}
+
+
+string Variable::toQualifiedString() const
+{
+  if (isType()) {
+    // I'm seeing printouts like "S1<T>::S2 S1<T>::S2", where the type
+    // is printed twice.  I think for types we should just print the
+    // type itself.
+    return type->toCString();
+  }
+
+  string qname;
+  if (name) {
+    qname = fullyQualifiedName0();
+  }
+  else {
+    qname = "/*anon*/";
+  }
+  return type->toCString(stringc << qname << namePrintSuffix());
+}
+
+
+string Variable::toCStringAsParameter() const
+{
+  if (!global_mayUseTypeAndVarToCString) xfailure("suspended during CTypePrinter::print");
+  stringBuilder sb;
+  if (type->isTypeVariable()) {
+    // type variable's name, then the parameter's name (if any)
+    sb << type->asTypeVariable()->name;
+    if (name) {
+      sb << " " << name;
+    }
+  }
+  else {
+    sb << type->toCString(name);
+  }
+
+  if (value) {
+    sb << renderExpressionAsString(" = ", value);
+  }
+  return sb;
+}
+
+
+string Variable::toMLString() const
+{
+  stringBuilder sb;
+  #if USE_SERIAL_NUMBERS
+    printSerialNo(sb, "v", serialNumber, "-");
+  #endif
+  char const *name0 = "<no_name>";
+  if (name) {
+    name0 = name;
+  }
+  sb << "'" << name0 << "'->" << type->toMLString();
+  return sb;
+}
+
+
+string Variable::fullyQualifiedName0() const
+{
+  // dsw: I don't think it makes sense to ask for the fully qualified
+  // name of a Variable that does not reside in a permanent scope,
+  // except for built-ins which are basically global.  Unfortunately,
+  // Scott doesn't use it that way.
+//   if (loc != SL_INIT) {
+//     xassert(scope);
+//     xassert(scope->hasName() || scope->isGlobalScope());
+//   }
+
+  if (isNamespace()) {
+    if (scope->isGlobalScope()) {
+      return "::";
+    }
+    else {
+      return scope->fullyQualifiedCName();
+    }
+  }
+
+  stringBuilder tmp;
+  if (scope && !scope->isGlobalScope()) {
+    tmp << scope->fullyQualifiedCName();
+  }
+  if (hasFlag(DF_SELFNAME)) {
+    // don't need another "::name", since my 'scope' is the same
+  }
+  else {
+    if (!tmp.empty()) {
+      tmp << "::";
+    }
+
+    if (name) {
+      tmp << name;        // NOTE: not mangled
+
+      TemplateInfo *ti = templateInfo();
+      if (ti) {
+        // only print arguments that do not correspond to inherited params
+        // of the thing of which this is an instance
+        int numInh = 0;
+        if (ti->instantiationOf) {
+          numInh = ti->instantiationOf->templateInfo()->countInheritedParameters();
+        }
+        SObjList<STemplateArgument> const &allArgs = objToSObjListC(ti->arguments);
+        SObjListIter<STemplateArgument> iter(allArgs);
+        while (numInh && !iter.isDone()) {
+          numInh--;
+          iter.adv();
+        }
+
+        // any args left to print?
+        if (!iter.isDone()) {
+          tmp << sargsToString(iter);
+        }
+      }
+    }
+    else {
+      tmp << "/*anon*/";
+    }
+  }
+  return tmp;
+}
+
+void Variable::appendMangledness(stringBuilder &mgldName) {
+  // for function types, be sure to use the mangled name of their
+  // signature so that overloading works right
+  if (type && type->isFunctionType() && !hasFlag(DF_EXTERN_C)) {
+    mgldName << " SIG " << mangle(type); // this is passed through the globalStrTable below
+  }
+}
+
+string Variable::mangledName0() {
+  // dsw: what was I thinking here?  See assertion at the top of
+  // fullyQualifiedName0()
+  //
+  // NOTE: This is a very important assertion
+//   xassert(linkerVisibleName());
+
+  stringBuilder mgldName;
+  // FIX: should this be an assertion?  It can fail.
+  if (name) mgldName << name;
+  appendMangledness(mgldName);
+  return mgldName;
+}
+
+string Variable::fullyQualifiedMangledName0() {
+//    cout << "name '" << name;
+//    if (scope) cout << "; has a scope" << endl;
+//    else cout << "; NO scope" << endl;
+
+  // dsw: what was I thinking here?  See assertion at the top of
+  // fullyQualifiedName0()
+  //
+  // NOTE: dsw: This is a very important assertion
+//   xassert(linkerVisibleName());
+
+  stringBuilder fqName;
+
+  // dsw: prepend with the filename if is global and static; this
+  // ensures proper linking
+  if (isStaticLinkage()) {
+    fqName << "file:" << sourceLocManager->getFile(loc) << ";";
+  }
+
+  // quarl 2006-07-10
+  //    Prepend with either "D:" or "F:" for data/function.  This way we
+  //    imitate the real linker's "type system" for data and functions
+  //    (e.g. "clog" the iostream data member and "clog" the math function can
+  //    coexist).
+  //
+  //    Should we add more -- templates?
+
+  if (type->isFunctionType()) {
+    fqName << "F:";
+  } else {
+    fqName << "D:";
+  }
+
+  fqName << fullyQualifiedName0();
+//    if (scope) fqName << scope->fullyQualifiedName();
+//    fqName << "::" << mangledName0();
+  appendMangledness(fqName);
+
+  return fqName;
+}
+
+
+string Variable::namePrintSuffix() const
+{
+  return "";
+}
+
+
+OverloadSet *Variable::getOrCreateOverloadSet()
+{
+  xassert(type);
+  xassert(type->isFunctionType());
+  if (!overload) {
+    overload = new OverloadSet;
+    overload->addMember(this);
+  }
+  return overload;
+}
+
+
+void Variable::getOverloadList(SObjList<Variable> &set)
+{
+  if (overload) {
+    set = overload->set;     // copy the elements
+  }
+  else {
+    set.prepend(this);       // just put me into it
+  }
+}
+
+
+int Variable::overloadSetSize() const
+{
+  return overload? overload->count() : 1;
+}
+
+bool Variable::isPureVirtualMethod() const
+{
+  // NOTE: use getHasValue() here instead of testing for the existance
+  // of the value field.  The value field is AST and there are some
+  // modes of usage where we serialize the typesystem but not the AST;
+  // the behavior of this method before and after serialization would
+  // alter in such a case.
+  bool ret = type && type->isMethod() && getHasValue();
+  // FIX: figure out how to add these assertions without having to
+  // include cc_ast.h
+//   if (ret) {
+//     xassert(value->isE_intLit());
+//     xassert(value->asE_intLit()->i == 0);
+//   }
+  return ret;
+}
+
+bool Variable::isMemberOfTemplate() const
+{
+  if (!scope) { return false; }
+  if (!scope->curCompound) { return false; }
+
+  if (scope->curCompound->isTemplate()) {
+    return true;
+  }
+
+  // member of non-template class; ask if that class is itself
+  // a member of a template
+  return scope->curCompound->typedefVar->isMemberOfTemplate();
+}
+
+
+bool Variable::isTemplateTypeParam() const
+{
+  // The second part of this test is how we can distinguish type
+  // parameters from non-type parameters whose type happens to be a
+  // previous type parameter.  For example, in
+  //   template <class T, T i>      // in/t0505.cc
+  // 'T' is a type parameter, while 'i' is a non-type parameter but
+  // its type is a type parameter.
+  return hasFlag(DF_TYPEDEF) &&              // true only of 'T'
+         type->isTypeVariable();             // true of both 'T' and 'i'
+}
+
+
+Variable *Variable::getUsingAlias() const
+{
+  if (!isTemplateParam()) {
+    if (usingAlias_or_parameterizedEntity) {
+      xassert(usingAlias_or_parameterizedEntity->getMaybeUsedAsAlias());
+    }
+    return usingAlias_or_parameterizedEntity;
+  }
+  else {
+    return NULL;
+  }
+}
+
+void Variable::setUsingAlias(Variable *target)
+{
+  xassert(!isTemplateParam());
+  usingAlias_or_parameterizedEntity = target;
+  if (usingAlias_or_parameterizedEntity) {
+    usingAlias_or_parameterizedEntity->setMaybeUsedAsAlias(true);
+  }
+}
+
+
+Variable *Variable::getParameterizedEntity() const
+{
+  if (isTemplateParam()) {
+    return usingAlias_or_parameterizedEntity;
+  }
+  else {
+    return NULL;
+  }
+}
+
+void Variable::setParameterizedEntity(Variable *templ)
+{
+  xassert(isTemplateParam());
+  usingAlias_or_parameterizedEntity = templ;
+}
+
+
+bool Variable::sameTemplateParameter(Variable const *other) const
+{
+  if (getParameterizedEntity() == NULL) {
+    // I haven't been associated with a template yet, so don't
+    // claim to be the same as anything else
+    return false;
+  }
+
+  if (getParameterOrdinal() == other->getParameterOrdinal() &&
+      getParameterizedEntity() == other->getParameterizedEntity()) {
+    // same!
+    return true;
+  }
+
+  return false;
+}
+
+
+// I'm not sure what analyses' disposition towards usingAlias ought to
+// be.  One possibility is to just say they should sprinkle calls to
+// skipAlias all over the place, but that's obviously not very nice.
+// However, I can't just make the lookup functions call skipAlias,
+// since the access control for the *alias* is what's relevant for
+// implementing access control restrictions.  Perhaps there should be
+// a pass that replaces all Variables in the AST with their skipAlias
+// versions?  I don't know yet.  Aliasing is often convenient for the
+// programmer but a pain for the analysis.
+
+Variable const *Variable::skipAliasC() const
+{
+  // tolerate NULL 'this' so I don't have to conditionalize usage
+  if (this && getUsingAlias()) {
+    return getUsingAlias()->skipAliasC();
+  }
+  else {
+    return this;
+  }
+}
+
+
+// this isn't right if either is a set of overloaded functions...
+bool sameEntity(Variable const *v1, Variable const *v2)
+{
+  v1 = v1->skipAliasC();
+  v2 = v2->skipAliasC();
+
+  if (v1 == v2) {
+    return true;
+  }
+
+  if (v1 && v2 &&                   // both non-NULL
+      v1->name == v2->name &&       // same simple name
+      v1->hasFlag(DF_EXTERN_C) &&   // both are extern "C"
+      v2->hasFlag(DF_EXTERN_C)) {
+    // They are the same entity.. unfortunately, outside this
+    // rather oblique test, there's no good way for the analysis
+    // to know this in advance.  Ideally the tchecker should be
+    // maintaining some symbol table of extern "C" names so that
+    // it could use the *same* Variable object for multiple
+    // occurrences in different namespaces, but I'm too lazy to
+    // implement that now.
+    return true;
+  }
+
+  return false;
+}
+
+
+static bool namesTemplateFunction_one(Variable const *v)
+{
+  // we are using this to compare template arguments to the
+  // preceding name, so we are only interested in the
+  // template-ness of the name itself, not any parent scopes
+  bool const considerInherited = false;
+
+  return v->isTemplate(considerInherited) ||
+         v->isInstantiation();     // 2005-08-11: in/t0545.cc
+}
+
+bool Variable::namesTemplateFunction() const
+{
+  if (isOverloaded()) {
+    // check amongst all overloaded names; 14.2 is not terribly
+    // clear about that, but 14.8.1 para 2 example 2 seems to
+    // imply this behavior
+    SFOREACH_OBJLIST(Variable, overload->set, iter) {
+      if (namesTemplateFunction_one(iter.data())) {
+        return true;
+      }
+    }
+  }
+
+  else if (namesTemplateFunction_one(this)) {
+    return true;
+  }
+
+  return false;
+}
+
+
+int Variable::getEnumeratorValue() const
+{
+  EnumType *et = type->asCVAtomicType()->atomic->asEnumType();
+  EnumType::Value const *val = et->getValue(name);
+  xassert(val);    // otherwise the type information is wrong..
+  return val->value;
+}
+
+
+void Variable::setBitfieldSize(int bits)
+{
+  xassert(isBitfield());
+
+  setParameterOrdinal(bits);
+}
+
+int Variable::getBitfieldSize() const
+{
+  xassert(isBitfield());
+
+  return getParameterOrdinal();
+}
+
+
+Scope *Variable::getDenotedScope() const
+{
+  if (isNamespace()) {
+    return scope;
+  }
+
+  if (type->isCompoundType()) {
+    CompoundType *ct = type->asCompoundType();
+    return ct;
+  }
+
+  xfailure(stringc << "expected `" << name << "' to name a scope");
+  return NULL;    // silence warning
+}
+
+
+void Variable::traverse(TypeVisitor &vis) {
+  if (!vis.visitVariable(this)) {
+    return;
+  }
+  if (type) {
+    type->traverse(vis);
+  }
+  vis.postvisitVariable(this);
+}
+
+
+// --------------------- OverloadSet -------------------
+OverloadSet::OverloadSet()
+  : set()
+{}
+
+OverloadSet::~OverloadSet()
+{}
+
+
+void OverloadSet::addMember(Variable *v)
+{
+  // dsw: wow, this can happen when you import two names into a
+  // namespace.  So the idea is we allow ambiguity and then only
+  // report an error at lookup, which is The C++ Way.
+//    xassert(!findByType(v->type->asFunctionType()));
+  xassert(v->type->isFunctionType());
+  set.prepend(v);
+}
+
+
+// The problem with these is they don't work for templatized types
+// because they call 'equals', not MatchType.
+//
+// But I've re-enabled them for Oink ....
+#if 1     // obsolete; see Env::findInOverloadSet
+
+Variable *OverloadSet::findByType(FunctionType const *ft, CVFlags receiverCV)
+{
+  SFOREACH_OBJLIST_NC(Variable, set, iter) {
+    FunctionType *iterft = iter.data()->type->asFunctionType();
+
+    // check the parameters other than '__receiver'
+    if (!iterft->equalOmittingReceiver(ft)) continue;
+
+    // if 'this' exists, it must match 'receiverCV'
+    if (iterft->getReceiverCV() != receiverCV) continue;
+
+    // ok, this is the right one
+    return iter.data();
+  }
+  return NULL;    // not found
+}
+
+
+Variable *OverloadSet::findByType(FunctionType const *ft) {
+  return findByType(ft, ft->getReceiverCV());
+}
+#endif // obsolete; see Env::findInOverloadSet
+
+
+// EOF

Added: vendor/elsa/current/elsa/variable.h
===================================================================
--- vendor/elsa/current/elsa/variable.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/variable.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,434 @@
+// variable.h                       see license.txt for copyright and terms of use
+// information about a name
+// see Diagram 1 of doc/cpp_er.html
+//
+// Every binding introduction (e.g. declaration) of a name will own
+// one of these to describe the introduced name; every reference to
+// that name will be annotated with a pointer to the Variable hanging
+// off the introduction.
+//
+// The name 'variable' is a slight misnomer; it's used for naming:
+//   - local and global variables
+//   - logic variables (in the verifier)
+//   - functions
+//   - function parameters
+//   - structure fields
+//   - enumeration values
+//   - typedefs
+//   - namespaces
+// All of these things can appear in syntactically similar contexts,
+// and the lookup rules generally treat them as all being in the
+// same lookup space (as opposed to enum and class tag names).
+//
+// I've decided that, rather than AST nodes trying to own Variables,
+// Variables will live in a separate pool (like types) so the AST
+// nodes can share them at will.
+//
+// In fact, my current idea is that the cc_type and variable modules
+// are so intertwined they might as well be one.  They share
+// dependencies extensively, including the TypeFactory.  So while
+// they are (and will remain) physically separate files, they
+// should be treated as their own subsystem.
+
+#ifndef VARIABLE_H
+#define VARIABLE_H
+
+#include "srcloc.h"            // SourceLoc
+#include "strtable.h"          // StringRef
+#include "cc_flags.h"          // DeclFlags, ScopeKind
+#include "sobjlist.h"          // SObjList
+#include "sobjset.h"           // SObjSet
+#include "serialno.h"          // INHERIT_SERIAL_BASE
+#include "packedword.h"        // PackedWord
+
+class Type;                    // cc_type.h
+class TypeVisitor;             // cc_type.h
+class FunctionType;            // cc_type.h
+class OverloadSet;             // below
+class Scope;                   // cc_scope.h
+class Expression;              // cc.ast
+class Function;                // cc.ast
+class BasicTypeFactory;        // cc_type.h
+class TemplateInfo;            // cc_type.h
+class XmlReader;
+
+class Variable INHERIT_SERIAL_BASE {
+public:    // data
+  // for now, there's only one location, and it's the definition
+  // location if that exists, else the declaration location; there
+  // are significant advantages to storing *two* locations (first
+  // declaration, and definition), but I haven't done that yet
+  SourceLoc loc;          // location of the name in the source text
+
+  // name introduced (possibly NULL for abstract declarators)
+  StringRef name;
+
+  // type of the variable (NULL iff flags has DF_NAMESPACE)
+  Type *type;
+
+  // various flags; 'const' to force modifications to go through
+  // the 'setFlagsTo' method
+  const DeclFlags flags;
+
+  // associated value for constant literals, e.g. "const int five = 5;",
+  // or default value for function parameters
+  //
+  // if this Variable is a parameter of a template function, then this
+  // 'value' might not have been tchecked; you have to look at the
+  // associated TemplateInfo::uninstantiatedDefaultArgs to find out
+  //
+  // this is const to encourage use of use setValue()
+  Expression * const value;     // (nullable serf)
+
+  // default value for template parameters; see TODO at end
+  // of this file
+  Type *defaultParamType; // (nullable serf)
+
+  // associated function definition; if NULL, either this thing isn't
+  // a function or we never saw a definition
+  Function *funcDefn;     // (nullable serf)
+
+  // if this name has been overloaded, then this will be a pointer
+  // to the set of overloaded names; otherwise it's NULL
+  OverloadSet *overload;  // (nullable serf)
+
+  // if we are a virtual method, the set of variables of other
+  // viritual methods that we immediately override; a NULL pointer
+  // here just means the empty list;
+  //
+  // NOTE: Scott: I wanted to do it in full correctness and not omit
+  // anything in the case of multiple-inheritance; however it is
+  // really hard to know what functions to omit, so I therefore do the
+  // quadratic thing and include them all; given that you do something
+  // similar with the BaseClassSubobj heriarchy for classes, I don't
+  // think this is so bad; feel free to change it; please change the
+  // name to directlyVirtuallyOverride if you do.
+  SObjSet<Variable*> *virtuallyOverride;
+
+  // named scope in which the variable appears; this is only non-NULL
+  // if the scope has a name, i.e. it continues to be available for
+  // use even after it's lexically closed
+  //
+  // if this Variable isNamespace(), then 'scope' points at the
+  // namespace it names, rather than the containing scope; see
+  // getDenotedScope()
+  Scope *scope;           // (nullable serf)
+
+  // total number of Variables created
+  static size_t numVariables;
+
+private:      // data
+
+  // so serialization/deserialization is possible
+  friend class XmlTypeWriter;
+  friend class XmlTypeReader;
+
+  // The next two fields are used to store conceptually different
+  // things in a single word in order to save space.  I am concerned
+  // about the space used by Variable because they are ubiquitous.  I
+  // would like to move to a model where Variable is a superclass and
+  // there are subclasses for various roles, as that would minimize
+  // wasted storage, but that is a fairly big change, and for the
+  // moment these localized hacks will suffice.
+  //
+  // dsw: see the use of the PACKEDWORD_DEF_GS macro below for the
+  // partition into bits
+  PackedWord intData;
+
+  // for most kinds of Variables, this is 'getUsingAlias()'; for
+  // template parameters (isTemplateParam()), this is
+  // 'getParameterizedEntity()'
+  Variable *usingAlias_or_parameterizedEntity;   // (nullable serf)
+
+  // for templates, this is the list of template parameters and other
+  // template stuff; for a primary it includes a list of
+  // already-instantiated versions
+  //
+  // this is private to force clients to go through templateInfo(),
+  // which skips aliases, as aliases now share templateInfos with
+  // the things they are aliases of
+  TemplateInfo *templInfo;      // (owner)
+
+protected:    // funcs
+  friend class BasicTypeFactory;
+  Variable(SourceLoc L, StringRef n, Type *t, DeclFlags f);
+  Variable(XmlReader&);         // ctor for de-serialization
+
+public:
+  virtual ~Variable();
+
+  bool hasFlag(DeclFlags f) const { return (flags & f) != 0; }
+  bool hasAnyFlags(DeclFlags /*union*/ f) const { return (flags & f) != 0; }
+  bool hasAllFlags(DeclFlags /*union*/ f) const { return (flags & f) == f; }
+
+  void setFlag(DeclFlags f) { setFlagsTo(flags | f); }
+  void addFlags(DeclFlags f) { setFlag(f); }
+  void clearFlag(DeclFlags f) { setFlagsTo(flags & ~f); }
+
+  // change the value of 'flags'; this is virtual so that annotation
+  // systems can monitor flag modifications
+  virtual void setFlagsTo(DeclFlags f);
+
+  // some convenient interpretations of 'flags'
+  bool hasAddrTaken() const { return hasFlag(DF_ADDRTAKEN); }
+  bool isGlobal() const { return hasFlag(DF_GLOBAL); }
+
+  // persists as a global; not on stack or heap
+  bool isSemanticallyGlobal() const;
+
+  bool inGlobalOrNamespaceScope() const;
+  bool isStaticLinkage() const {
+    // quarl 2006-07-11
+    //    See Declarator::mid_tcheck() for why this checks for DF_INLINE|DF_MEMBER.
+    //    Note that these are not exclusive; a variable can have both static
+    //    linkage (by being inline) and be a static member.
+    return ((hasFlag(DF_STATIC) &&
+             (hasFlag(DF_GLOBAL) || inGlobalOrNamespaceScope()) ||
+             hasAllFlags(DF_INLINE | DF_MEMBER)) /*&&
+                                                   !hasFlag(DF_GNU_EXTERN_INLINE)*/);
+  }
+  bool isStaticLocal() const {
+    return (hasFlag(DF_STATIC) &&
+            !(hasFlag(DF_GLOBAL) || inGlobalOrNamespaceScope()) &&
+            !hasFlag(DF_MEMBER));
+  }
+  bool isStaticMember() const { return hasAllFlags(DF_STATIC | DF_MEMBER); }
+  bool isNonStaticMember() const { return hasFlag(DF_MEMBER) && !hasFlag(DF_STATIC); }
+  // bool isStatic() const { return hasFlag(DF_STATIC); }
+  bool isMember() const { return hasFlag(DF_MEMBER); }
+  bool isNamespace() const { return hasFlag(DF_NAMESPACE); }
+  bool isImplicitTypedef() const { return hasAllFlags(DF_IMPLICIT | DF_TYPEDEF); }
+  bool isImplicitMemberFunc() const { return hasFlag(DF_IMPLICIT) && !hasFlag(DF_TYPEDEF); }
+  bool isEnumerator() const { return hasFlag(DF_ENUMERATOR); }
+  bool isType() const { return hasFlag(DF_TYPEDEF); }
+
+  bool linkerVisibleName() const;
+  bool linkerVisibleName(bool evenIfStaticLinkage) const;
+
+  // true if this name refers to a class or struct or union
+  bool isClass() const;
+
+  // refers to a user-provided typedef
+  bool isExplicitTypedef() const
+    { return hasFlag(DF_TYPEDEF) && !hasFlag(DF_IMPLICIT); }
+
+  // break intData apart into various typed sub-fields
+  PACKEDWORD_DEF_GS(intData, Access,           AccessKeyword,  0,  4)
+  PACKEDWORD_DEF_GS(intData, Real,             bool,           4,  5)
+  PACKEDWORD_DEF_GS(intData, MaybeUsedAsAlias, bool,           5,  6)
+  PACKEDWORD_DEF_GS(intData, User1,            bool,           6,  7)
+  PACKEDWORD_DEF_GS(intData, User2,            bool,           7,  8)
+  PACKEDWORD_DEF_GS(intData, ScopeKind,        ScopeKind,      8, 11)
+  PACKEDWORD_DEF_GS(intData, HasValue,         bool,          11, 12)
+  PACKEDWORD_DEF_GS(intData, ParameterOrdinal, int,           16, 32)
+  // ParameterOrdinal and BitfieldSize overlap, but
+  // set/getBitfieldSize check an assertion before delegating to
+  // ParameterOrdinal
+  // PACKEDWORD_DEF_GS(intData, BitfieldSize, int, 16, 32)
+
+  void setValue(Expression *e) { const_cast<Expression *&>(value)=e; setHasValue(e!=NULL); }
+
+  // true if this name refers to a template function, or is
+  // the typedef-name of a template class (or partial specialization)
+  //
+  // if 'considerInherited' is false, then the template-ness
+  // is only as w.r.t. its containing class
+  bool isTemplate(bool considerInherited = true) const;
+  bool isTemplateFunction(bool considerInherited = true) const;
+  bool isTemplateClass(bool considerInherited = true) const;
+
+  // true if this is an instantiation of a template
+  bool isInstantiation() const;
+
+  // templates (and specializations) and instantiatons have
+  // TemplateInfo
+  TemplateInfo *templateInfo() const;
+  void setTemplateInfo(TemplateInfo *templInfo0);
+
+  // Are there templatized variables (such as type variables) that are
+  // not in the template info template parameters?
+  bool notQuantifiedOut();
+
+  // are we an uninstantiated template or a member of one?
+  bool isUninstTemplateMember() const;
+
+  // dsw: need a way to tell if a Variable is a method on a
+  // templatized class that was never instantiated because it was
+  // never used
+  bool isUninstClassTemplMethod() const;
+
+  // variable's type.. same as the public 'type' field..
+  Type *getType() { return type; }
+  Type const *getTypeC() const { return type; }
+
+  // create an overload set if it doesn't exist, and return it (do not
+  // do this unless you actually need a set; if you just want to treat
+  // overloaded and non-overloaded variables uniformly, use
+  // 'getOverloadList' instead)
+  OverloadSet *getOrCreateOverloadSet();
+
+  // return the set of overloaded entities; this might just
+  // be the singleton 'this', if it isn't overloaded
+  void getOverloadList(SObjList<Variable> &set);
+
+  // true if this name is overloaded
+  bool isOverloaded() const { return !!overload; }
+
+  // number of elements in the overload set, or 1 if there is no
+  // overload set
+  int overloadSetSize() const;
+
+  // true if this a pure virtual non-static member function (method)
+  bool isPureVirtualMethod() const;
+
+  // true if this is a member of a template (uninstantiated template)
+  bool isMemberOfTemplate() const;
+
+  // true if this is a template parameter or bound arg or both
+  bool isAbstractTemplateParam() const
+    { return hasFlag(DF_TEMPL_PARAM) && !hasFlag(DF_BOUND_TPARAM); }
+  bool isBoundTemplateParam() const
+    { return hasAllFlags(DF_TEMPL_PARAM | DF_BOUND_TPARAM); }
+  bool isTemplateParam() const
+    { return hasFlag(DF_TEMPL_PARAM); }
+
+  // true if this is a template type parameter (unbound/abstract)
+  bool isTemplateTypeParam() const;
+
+  // generic print (C or ML depending on Type::printAsML)
+  string toString() const;
+
+  // C declaration syntax
+  string toCString() const;
+
+  // syntax when used in a parameter list
+  string toCStringAsParameter() const;
+
+  // ML-style
+  string toMLString() const;
+
+  // toString+newline to cout
+  void gdb() const;
+
+  // fully qualified but not mangled name
+  string fullyQualifiedName0() const;
+  void appendMangledness(stringBuilder &mgldName);
+  string mangledName0(); 	// no scope
+  string fullyQualifiedMangledName0(); // scope+mangling
+
+  // like toString but with the fully qualified name
+  string toQualifiedString() const;
+
+  // hook for verifier: text to be printed after the variable's name
+  // in declarator syntax
+  virtual string namePrintSuffix() const;    // default: ""
+
+  // if this is variable is actually an alias for another one, via a
+  // "using declaration" (cppstd 7.3.3), then this points to the one
+  // it is an alias of; otherwise NULL; see comments near
+  // implementation of skipAliasC
+  Variable *getUsingAlias() const;
+  void setUsingAlias(Variable *target);
+
+  // if this variable is a template parameter, then this says which
+  // template entity is paramterized by it; otherwise NULL
+  Variable *getParameterizedEntity() const;
+  void setParameterizedEntity(Variable *templ);
+
+  // true if 'this' and 'other' are the same ordinal parameter of
+  // the same template entity
+  bool sameTemplateParameter(Variable const *other) const;
+
+  // follow the 'usingAlias' field if non-NULL; otherwise return this
+  Variable const *skipAliasC() const;
+  Variable *skipAlias() { return const_cast<Variable*>(skipAliasC()); }
+
+  // true if this name refers to a template (function) or an overload
+  // set that includes one
+  bool namesTemplateFunction() const;
+
+  // this must be an enumerator; get the integer value it denotes
+  int getEnumeratorValue() const;
+
+  // bitfield access
+  bool isBitfield() const { return hasFlag(DF_BITFIELD); }
+  void setBitfieldSize(int bits);      // must be bitfield
+  int getBitfieldSize() const;         // must be bitfield
+
+  // this variable refers to a scope; get it
+  Scope *getDenotedScope() const;
+
+  // dsw: Variables are part of the type system at least for purposes
+  // of traversal
+  void traverse(TypeVisitor &vis);
+};
+
+inline string toString(Variable const *v) { return v->toString(); }
+
+// true if 'v1' and 'v2' refer to the same run-time entity
+bool sameEntity(Variable const *v1, Variable const *v2);
+
+
+class OverloadSet {
+public:
+  // list-as-set
+  SObjList<Variable> set;
+
+public:
+  OverloadSet();
+  ~OverloadSet();
+
+  void addMember(Variable *v);
+  int count() const { return set.count(); }
+
+  // These are obsolete; see Env::findInOverloadSet.
+  //
+  // Update: But Oink wants to use them for linker imitation.. and
+  // I don't see much harm in that, since non-concrete types should
+  // not be linker visible anyway.
+  Variable *findByType(FunctionType const *ft, CVFlags receiverCV);
+  Variable *findByType(FunctionType const *ft);
+};
+
+
+// This function renders an Expression as a string, if it knows how
+// to.  This function is here to cut the dependency between Types and
+// the AST.  If the AST-aware modules are compiled into this program,
+// then this function just calls into them, prepending the prefix; but
+// if not, then this always returns "".
+string renderExpressionAsString(char const *prefix, Expression const *e);
+
+
+/*
+TODO: More efficient storage for Variable.
+
+First, I want to make a class hierarchy like this:
+
+  - Variable
+    - TypeVariable: things that currently have DF_TYPEDEF
+      - TypeParamVariable: template type paramters; make up
+        a new DeclFlag to distinguish them (DF_TEMPL_PARAM?)
+        [has defaultTypeArg]
+      - ClassVariable: DF_TYPEDEF where 'type->isClassType()'
+        [has templInfo]
+    - ObjectVariable: no DF_TYPEDEF
+      [has value]
+      - FunctionVariable: objects where 'type->isFunctionType()'
+        [has templInfo]
+        [has funcDefn]
+        [has overload]
+      - Enumerator (obviates EnumType::Value)
+    - AliasVariable (DF_USING_ALIAS?)
+      [has usingAlias]
+    - NamespaceVariable (?? how to namespaces name their space?)
+
+Second, I want to collapse 'access' and 'scopeKind', since
+these fields waste most of their bits.  Perhaps when DeclFlags
+gets split I can arrange a storage sharing strategy among the
+(then four) fields that are bit-sets.
+
+*/
+
+extern bool variablesLinkerVisibleEvenIfNonStaticDataMember;
+
+#endif // VARIABLE_H

Added: vendor/elsa/current/elsa/xml_ast_reader.cc
===================================================================
--- vendor/elsa/current/elsa/xml_ast_reader.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_ast_reader.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// xml_ast_reader.cc          see license.txt for copyright and terms of use
+
+// NOTE: the implementation of this class is generated
+
+#include "xml_ast_reader.h"     // this module
+#include "xmlhelp.h"            // toXml_int etc.
+#include "xml_enum.h"           // XTOK_*
+
+void *XmlAstReader::ctorNodeFromTag(int tag) {
+  switch(tag) {
+  default: return NULL;
+  case 0: xmlUserFatalError("unexpected file termination while looking for an open tag name");
+#include "xml_ast_reader_2ctrc.gen.cc"
+  }
+}
+
+bool XmlAstReader::registerStringToken(void *target, int kind, char const *yytext0) {
+  return false;
+}
+
+bool XmlAstReader::registerAttribute(void *target, int kind, int attr, char const *yytext0) {
+  switch(kind) {
+  default: return false; break;
+#include "xml_ast_reader_3regc.gen.cc"
+  }
+
+  return true;
+}
+
+#include "xml_ast_reader_1defn.gen.cc"

Added: vendor/elsa/current/elsa/xml_ast_reader.h
===================================================================
--- vendor/elsa/current/elsa/xml_ast_reader.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_ast_reader.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,42 @@
+// xml_ast_reader.h         see license.txt for copyright and terms of use
+
+// parse AST serialized as XML
+// NOTE: the declarations of this class are generated
+
+#ifndef XML_AST_READER_H
+#define XML_AST_READER_H
+
+#include "xml_reader.h"         // XmlReader
+#include "cc_ast.h"             // TranslationUnit
+
+class XmlAstReader : public XmlReader {
+  public:
+  XmlAstReader() {}
+  virtual ~XmlAstReader() {}
+
+  private:
+  // Parse a tag: construct a node for a tag
+  virtual void *ctorNodeFromTag(int tag);
+
+  // Parse an attribute: register an attribute into the current node
+  virtual bool registerAttribute(void *target, int kind, int attr, char const *yytext0);
+  virtual bool registerStringToken(void *target, int kind, char const *yytext0);
+
+  // implement an eq-relation on tag kinds by mapping a tag kind to a
+  // category
+  virtual bool kind2kindCat(int kind, KindCategory *kindCat);
+
+  // **** Generic Convert
+
+  virtual bool recordKind(int kind, bool& answer);
+
+  // convert nodes
+  virtual bool callOpAssignToEmbeddedObj(void *obj, int kind, void *target);
+  virtual bool upcastToWantedType(void *obj, int kind, void **target, int targetKind);
+  virtual bool prependToFakeList(void *&list, void *obj, int listKind);
+  virtual bool reverseFakeList(void *&list, int listKind);
+
+#include "xml_ast_reader_0decl.gen.h"
+};
+
+#endif // XML_AST_READER_H

Added: vendor/elsa/current/elsa/xml_basic.tokens
===================================================================
--- vendor/elsa/current/elsa/xml_basic.tokens	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_basic.tokens	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,21 @@
+# Xml tokens for basic serialization
+
+# a list element
+_List_Item
+item
+
+# a name-map element
+_NameMap_Item
+name
+item
+
+# a map element
+_Map_Item
+key
+item
+
+# NOTE: off for now
+# an bidirectional unsatisfied link
+# __Link
+# from
+# to

Added: vendor/elsa/current/elsa/xml_do_read.cc
===================================================================
--- vendor/elsa/current/elsa/xml_do_read.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_do_read.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,74 @@
+// xml_do_read.cc          see license.txt for copyright and terms of use
+
+#include "xml_do_read.h"        // this module
+#include "fstream.h"            // ifstream
+#include "xml_lexer.h"          // XmlLexer
+#include "xml_file_reader.h"    // XmlFileReader
+#include "xml_type_reader.h"    // XmlTypeReader
+#include "xml_ast_reader.h"     // XmlAstReader
+
+class TranslationUnit;
+
+
+TranslationUnit *xmlDoRead(StringTable &strTable, char const *inputFname) {
+  // make reader manager
+  ifstream in(inputFname);
+  XmlLexer lexer;
+  lexer.inputFname = inputFname;
+  lexer.restart(&in);
+  XmlReaderManager manager(lexer, strTable);
+  manager.inputFname = inputFname;
+
+  // prevent the SourceLocManager from looking at files in the file
+  // system
+  sourceLocManager->mayOpenFiles = false;
+
+  // make and register file reader
+  manager.registerReader(new XmlFileReader);
+
+  // make and register ast reader
+  manager.registerReader(new XmlAstReader);
+
+  // make and register type reader
+  manager.registerReader(new XmlTypeReader);
+
+  // read until we get a translation unit tag; FIX: not sure what
+  // happens if the last tag is not a TranslationUnit
+  while(true) {
+    manager.parseOneTopLevelTag();
+    if (lexer.haveSeenEof()) {
+      manager.xmlUserFatalError("unexpected EOF");
+    }
+    int lastKind = manager.getLastKind();
+    if (lastKind == XTOK_List_files) {
+      // complete the link graph so that the FileData object is
+      // complete
+      manager.satisfyLinks();
+      ObjList<SourceLocManager::FileData> *files =
+        (ObjList<SourceLocManager::FileData>*) manager.getLastNode();
+      FOREACH_OBJLIST_NC(SourceLocManager::FileData, *files, iter) {
+        SourceLocManager::FileData *fileData = iter.data();
+        if (!fileData->complete()) {
+          manager.xmlUserFatalError("missing attributes to File tag");
+        }
+        sourceLocManager->loadFile(fileData);
+      }
+      // Note: 'files' owns the FileDatas so it will delete them for us.
+      delete files;
+    } else if (lastKind == XTOK_TranslationUnit) {
+      break;                    // we are done
+    } else {
+      manager.xmlUserFatalError("illegal top-level tag");
+    }
+  }
+
+  // complete the link graph
+  manager.satisfyLinks();
+
+//    if (manager.getLastKind() != XTOK_TranslationUnit) {
+//      manager.xmlUserFatalError("top tag is not a TranslationUnit");
+//    }
+  TranslationUnit *tunit = (TranslationUnit*) manager.getLastNode();
+
+  return tunit;
+}

Added: vendor/elsa/current/elsa/xml_do_read.h
===================================================================
--- vendor/elsa/current/elsa/xml_do_read.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_do_read.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// xml_do_read.h         see license.txt for copyright and terms of use
+
+#ifndef XML_DO_READ_H
+#define XML_DO_READ_H
+
+class TranslationUnit;
+class StringTable;
+
+TranslationUnit *xmlDoRead(StringTable &strTable, char const *inputFname);
+
+#endif // XML_DO_READ_H

Added: vendor/elsa/current/elsa/xml_enum.h
===================================================================
--- vendor/elsa/current/elsa/xml_enum.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_enum.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// xml_enum.h            see license.txt for copyright and terms of use
+
+#ifndef XML_ENUM_H
+#define XML_ENUM_H
+
+enum XmlToken {
+  XTOK_EOF,
+
+  // non-keyword name
+  XTOK_NAME,
+
+  // literals
+  XTOK_INT_LITERAL,
+  XTOK_FLOAT_LITERAL,
+  XTOK_HEX_LITERAL,
+  XTOK_STRING_LITERAL,
+
+  // punctuation
+  XTOK_LESSTHAN,                // "<"
+  XTOK_GREATERTHAN,             // ">"
+  XTOK_EQUAL,                   // "="
+  XTOK_SLASH,                   // "/"
+
+  // special attributes
+  XTOK_DOT_ID,                  // "_id"
+
+#include "xml_enum_1.gen.h"
+
+  // dummy terminals
+  NUM_XML_TOKEN_TYPES,
+
+};  // enum TokenType
+
+#endif // XML_ENUM_H

Added: vendor/elsa/current/elsa/xml_file.tokens
===================================================================
--- vendor/elsa/current/elsa/xml_file.tokens	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_file.tokens	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+# Xml tokens for serializing file metadata nodes
+
+# File nodes
+File
+name
+numChars
+numLines
+lineLengths
+LineLengths
+hashLines
+HashLineMap
+ppFname
+List_HashLineMap_directives
+directives
+HashLine
+ppLine
+origLine
+origFname
+size
+
+# Some containers; I no longer care about order
+#   ObjList
+List_files
+
+# FIX: are these in File or somewhere else?
+loc
+curLoc

Added: vendor/elsa/current/elsa/xml_file_reader.cc
===================================================================
--- vendor/elsa/current/elsa/xml_file_reader.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_file_reader.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,207 @@
+// xml_file_reader.cc            see license.txt for copyright and terms of use
+
+#include "xml_file_reader.h"    // this module
+#include "xml_reader.h"         // XmlReader
+#include "hashline.h"           // HashLineMap
+#include "xmlhelp.h"            // xml helpers
+#include "xml_enum.h"           // XTOK_*
+
+void *XmlFileReader::ctorNodeFromTag(int tag) {
+  switch(tag) {
+  default: return NULL;
+  case 0: xmlUserFatalError("unexpected file termination while looking for an open tag name");
+  case XTOK_File:
+    return new SourceLocManager::FileData();
+    break;
+  case XTOK_LineLengths:
+    // NOTE: This is not technically a list object as it does not
+    // have list item children, only data; it is a regular node that
+    // happens to be a list of data.
+    return new ArrayStack<unsigned char>;
+    break;
+  case XTOK_HashLineMap:
+    return new HashLineMap("");
+    break;
+  case XTOK_HashLine: {
+    // quarl 2006-06-01
+    //    Optimization: insert directly into the HashLineMap.  This is useful
+    //    because an ArrayStack embeds its contents.
+    ArrayStack<HashLineMap::HashLine> *directives =
+      (ArrayStack<HashLineMap::HashLine>*) manager->getNthNode(
+        1, XTOK_List_HashLineMap_directives);
+
+    // return new HashLineMap::HashLine();
+    return & directives->pushAlt();
+    break; }
+  case XTOK_List_HashLineMap_directives:
+    return new ArrayStack<HashLineMap::HashLine>;
+    break;
+
+  // **** Containers
+  case XTOK_List_files:
+    return new ObjList<SourceLocManager::FileData>();
+    break;
+  }
+}
+
+
+bool XmlFileReader::registerStringToken(void *target, int kind, char const *yytext0) {
+  switch(kind) {
+  default: return false; break;
+
+  case XTOK_File: {
+    xmlUserFatalError("cannot register data with a File tag");
+    break;
+  }
+
+  case XTOK_LineLengths: {
+    ArrayStack<unsigned char> *lineLengths = (ArrayStack<unsigned char>*)target;
+    // FIX: this does not detect any errors if it is not a non-neg int
+    lineLengths->push(atoi(yytext0));
+    break;
+  }
+
+  }
+  return true;
+}
+
+
+bool XmlFileReader::registerAttribute(void *target0, int kind, int attr, char const *strValue) {
+  switch(kind) {
+  default: return false; break;
+
+  case XTOK_File: {
+    SourceLocManager::FileData *obj = (SourceLocManager::FileData*)target0;
+    switch(attr) {
+    default: xmlUserFatalError("illegal attribute for a File tag"); break;
+    case XTOK_name: obj->name = strValue; break;
+    case XTOK_numChars: fromXml_int(obj->numChars, strValue); break;
+    case XTOK_numLines: fromXml_int(obj->numLines, strValue); break;
+    case XTOK_lineLengths: ul(lineLengths, XTOK_LineLengths); break;
+    case XTOK_hashLines: ul(hashLines, XTOK_HashLineMap); break;
+    }
+    break;
+  }
+
+  case XTOK_LineLengths: {
+    ArrayStack<unsigned char> *lineLengths = (ArrayStack<unsigned char>*)target0;
+    switch(attr) {
+    default: xmlUserFatalError("illegal attribute for a LineLengths tag"); break;
+    case XTOK_size: {
+      // quarl 2006-06-01: 'size' is an optional hint to reserve N elements in
+      // the ArrayStack.
+      int size; fromXml_int(size, strValue);
+      lineLengths->ensureAtLeast(size);
+      break; }
+    }
+    break;
+  }
+
+  case XTOK_HashLineMap: {
+    HashLineMap *obj = (HashLineMap*) target0;
+    switch(attr) {
+    default: xmlUserFatalError("illegal attribute for a HashLineMap tag"); break;
+    case XTOK_ppFname: obj->serializationOnly_set_ppFname(strValue); break;
+    case XTOK_directives:
+      // ulList(_List, directives, XTOK_List_HashLineMap_directives);
+      ulEmbed(directives, XTOK_List_HashLineMap_directives);
+      break;
+    // NOTE: there is no XTOK_filenames; the file names dictionary is
+    // redundant and reconstructed from the File names fields
+    }
+    break;
+  }
+
+  case XTOK_HashLine: {
+    HashLineMap::HashLine *obj = (HashLineMap::HashLine*) target0;
+    switch(attr) {
+    default: xmlUserFatalError("illegal attribute for a HashLine tag"); break;
+    case XTOK_ppLine: fromXml_int(obj->ppLine, strValue); break;
+    case XTOK_origLine: fromXml_int(obj->origLine, strValue); break;
+    case XTOK_origFname:
+      HashLineMap *hmap = (HashLineMap*) manager->getNthNode(3, XTOK_HashLineMap);
+      obj->origFname = hmap->canonizeFilename(strValue); break;
+    }
+    break;
+  }
+
+  }
+  return true;
+}
+
+bool XmlFileReader::kind2kindCat(int kind, KindCategory *kindCat) {
+  switch(kind) {
+  default: return false;        // we don't know this kind
+  case XTOK_File:
+  case XTOK_LineLengths:
+  case XTOK_HashLineMap:
+  case XTOK_HashLine:
+    *kindCat = KC_Node;
+    break;
+
+  case XTOK_List_HashLineMap_directives:
+    *kindCat = KC_ArrayStack;
+    break;
+
+  // **** Containers
+  //   ObjList
+  case XTOK_List_files:
+    *kindCat = KC_ObjList;
+    break;
+  }
+
+  return true;
+}
+
+bool XmlFileReader::recordKind(int kind, bool& answer) {
+  switch(kind) {
+  default: return false;        // we don't know this kind
+  // **** do not record these
+  case XTOK_File:
+  case XTOK_LineLengths:
+  case XTOK_HashLineMap:
+  case XTOK_HashLine:
+  case XTOK_List_HashLineMap_directives:
+  // **** Containers
+  //   ObjList
+  case XTOK_List_files:
+    answer = false;
+    return true;
+    break;
+  }
+}
+
+bool XmlFileReader::callOpAssignToEmbeddedObj(void *obj, int kind, void *target) {
+  xassert(obj);
+  xassert(target);
+  switch(kind) {
+  default:
+    // This handler conflates two situations; see the node in
+    // XmlTypeReader::callOpAssignToEmbeddedObj().
+    return false;
+    break;
+  }
+}
+
+bool XmlFileReader::upcastToWantedType(void *obj, int kind, void **target, int targetKind) {
+  xassert(obj);
+  xassert(target);
+  // This handler conflates two situations; see the node in
+  // XmlTypeReader::upcastToWantedType
+  return false;
+}
+
+bool XmlFileReader::appendToArrayStack(void *arrayStack, void *obj, int listKind) {
+  switch(listKind) {
+  default: return false;        // we did not find a matching tag
+
+  case XTOK_List_HashLineMap_directives:
+    // We already used 'pushAlt' when we created it, so no need to do anything
+    // now; just return true.
+
+    // appendToArrayStack0<HashLineMap::HashLine>(arrayStack, obj);
+    break;
+  }
+
+  return true;
+}

Added: vendor/elsa/current/elsa/xml_file_reader.h
===================================================================
--- vendor/elsa/current/elsa/xml_file_reader.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_file_reader.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,29 @@
+// xml_file_reader.h            see license.txt for copyright and terms of use
+
+// De-serialization of file information for purposes of capturing the
+// state of the SourceLocManager.
+
+#ifndef XML_FILE_READER_H
+#define XML_FILE_READER_H
+
+#include "xml_reader.h"
+#include "astlist.h"
+
+
+class XmlFileReader : public XmlReader {
+  public:
+  XmlFileReader() {}
+  virtual ~XmlFileReader() {}
+
+  virtual void *ctorNodeFromTag(int tag);
+  virtual bool registerAttribute(void *target, int kind, int attr, char const *yytext0);
+  virtual bool registerStringToken(void *target, int kind, char const *yytext0);
+  virtual bool kind2kindCat(int kind, KindCategory *kindCat);
+  // **** Generic Convert
+  virtual bool recordKind(int kind, bool& answer);
+  virtual bool callOpAssignToEmbeddedObj(void *obj, int kind, void *target);
+  virtual bool upcastToWantedType(void *obj, int kind, void **target, int targetKind);
+  virtual bool appendToArrayStack(void *arrayStack, void *obj, int listKind);
+};
+
+#endif // XML_FILE_READER_H

Added: vendor/elsa/current/elsa/xml_file_writer.cc
===================================================================
--- vendor/elsa/current/elsa/xml_file_writer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_file_writer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,153 @@
+// xml_file_writer.cc            see license.txt for copyright and terms of use
+
+#include "xml_file_writer.h"    // this module
+#include "xml_writer.h"         // serialization support
+#include "asthelp.h"            // xmlAttrQuote()
+#include "sobjset.h"            // SObjSet
+
+#define serializeOracle serializeOracle_m
+
+XmlFileWriter::XmlFileWriter(IdentityManager &idmgr0,
+                             ostream *out0, int &depth0, bool indent0,
+                             XmlFileWriter::XFW_SerializeOracle *serializeOracle0)
+  : XmlWriter(idmgr0, out0, depth0, indent0),
+    serializeOracle(serializeOracle0)
+{}
+
+void XmlFileWriter::toXml(SourceLocManager::FileList &files)
+{
+  travObjList0(files, files, SourceLocManager::File, FOREACH_OBJARRAYSTACK_NC, ObjArrayStack);
+
+  // FOREACH_OBJLIST_NC(SourceLocManager::File, files, iter) {
+  //   SourceLocManager::File *file = iter.data();
+  //   toXml(file);
+  // }
+}
+
+void XmlFileWriter::toXml(SourceLocManager::File *file)
+{
+  // idempotency
+  if (idmgr.printed(file)) return;
+
+  unsigned char *lineLengths = file->serializationOnly_get_lineLengths();
+
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("File", file);
+
+    // **** attributes
+    printStrRef(name, file->name.c_str());
+    printXml_int(numChars, file->numChars);
+    printXml_int(numLines, file->numLines);
+
+  // this doesn't work because lineLengths is private
+//    printPtr(file, lineLengths);
+
+    // FIX: this special situation just breaks all the macros so we do
+    // it manually
+    newline();
+    *out << "lineLengths=";
+    outputXmlPointerQuoted(*out, "FI", idmgr.uniqueId(lineLengths));
+
+    printPtr(file, hashLines);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  // NOTE: we do not use the trav() macro as we call a non-standard
+  // method name; see note at the method declaration
+  if (lineLengths) {
+    // NOTE: we pass the file instead of the lineLengths
+    toXml_lineLengths(file);
+  }
+  trav(file->hashLines);
+}
+
+void XmlFileWriter::toXml_lineLengths(SourceLocManager::File *file)
+{
+  // NOTE: no idempotency check is needed as the line lengths are
+  // one-to-one with the Files.
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    unsigned char *lineLengths = file->serializationOnly_get_lineLengths();
+    int lineLengthsSize = file->serializationOnly_get_lineLengthsSize();
+    // NOTE: can't do this since we would have to implement dispatch on
+    // a pointer to unsigned chars, which is too general; we need
+    // LineLengths to be their own class.
+//    openTagWhole(LineLengths, lineLengths);
+    tagPrinter.readyTag("LineLengths");
+    *out << "<LineLengths _id=";
+    outputXmlPointerQuoted(*out, "FI", idmgr.uniqueId(lineLengths));
+    *out << " size='" << lineLengthsSize;
+    *out << "'>";
+
+    // **** sub-data
+    // Note: This simple whitespace-separated list is the suggested
+    // output format for lists of numbers in XML:
+    // http://www.w3.org/TR/xmlschema-0/primer.html#ListDt
+    //
+    // Note also that I do not bother to indent blocks of data between
+    // tags, just the tags themselves.
+    for (int i=0; i<lineLengthsSize; ++i) {
+      if (i%20 == 0) *out << '\n';
+      else *out << ' ';
+      *out << static_cast<int>(lineLengths[i]);
+    }
+  }
+}
+
+void XmlFileWriter::toXml(HashLineMap *hashLines)
+{
+  // idempotency
+  if (idmgr.printed(hashLines)) return;
+
+  ArrayStack<HashLineMap::HashLine> &directives = hashLines->serializationOnly_get_directives();
+
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("HashLineMap", hashLines);
+
+    // **** attributes
+    string &ppFname = hashLines->serializationOnly_get_ppFname();
+    printStrRef(ppFname, ppFname.c_str());
+
+    // NOTE: can't do this because it is private; FIX: I have inlined
+    // "FI" here.
+//    printEmbed(hashLines, directives);
+    newline();
+    *out << "directives=";
+    outputXmlPointerQuoted(*out, "FI", idmgr.uniqueId(&directives));
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  // FIX: again, it is private so I inline the macro
+//    travArrayStack(hashLines, HashLineMap, directives, HashLine);
+  if (!idmgr.printed(&directives)) {
+    XmlTagPrinter tagPrinter2(*this);
+    if (writingP()) {
+      tagPrinter2.printOpenTag("List_HashLineMap_directives", &directives);
+      tagPrinter2.tagEnd();
+    }
+    FOREACH_ARRAYSTACK_NC(HashLineMap::HashLine, directives, iter) {
+      travListItem(iter.data());
+    }
+  }
+}
+
+void XmlFileWriter::toXml(HashLineMap::HashLine *hashLine)
+{
+  // idempotency
+  if (idmgr.printed(hashLine)) return;
+
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("HashLine", hashLine);
+
+    // **** attributes
+    printXml_int(ppLine, hashLine->ppLine);
+    printXml_int(origLine, hashLine->origLine);
+    printStrRef(origFname, hashLine->origFname);
+    tagPrinter.tagEnd();
+  }
+}

Added: vendor/elsa/current/elsa/xml_file_writer.h
===================================================================
--- vendor/elsa/current/elsa/xml_file_writer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_file_writer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+// xml_file_writer.h            see license.txt for copyright and terms of use
+
+// Serialization of file information for purposes of capturing the
+// state of the SourceLocManager.
+
+#ifndef XML_FILE_WRITER_H
+#define XML_FILE_WRITER_H
+
+#include "sobjset.h"            // SObjSet
+#include "objlist.h"            // ObjList
+#include "srcloc.h"             // SourceLocManager
+#include "xml_writer.h"         // XmlWriter
+#include "hashline.h"           // HashLineMap
+
+class XmlFileWriter : public XmlWriter {
+public:
+
+  class XFW_SerializeOracle {
+  public:
+    virtual ~XFW_SerializeOracle() {}
+    virtual bool shouldSerialize(SourceLocManager::File const *) {return true;}
+    virtual bool shouldSerialize(HashLineMap const *) {return true;}
+    virtual bool shouldSerialize(HashLineMap::HashLine const *) {return true;}
+  };
+
+  XFW_SerializeOracle *serializeOracle_m;
+
+  XmlFileWriter(IdentityManager &idmgr0, ostream *out0, int &depth0, bool indent0,
+                XFW_SerializeOracle *serializeOracle0);
+  virtual ~XmlFileWriter() {}
+
+  void toXml(SourceLocManager::FileList &files);
+  void toXml(SourceLocManager::File *file);
+  // this is an exception to the generic toXml() mechanism since
+  // lineLengths are not self-contained
+  void toXml_lineLengths(SourceLocManager::File *file);
+  void toXml(HashLineMap *hashLines);
+  void toXml(HashLineMap::HashLine *hashLine);
+};
+
+#endif // XML_FILE_WRITER_H

Added: vendor/elsa/current/elsa/xml_lex_0top.lex
===================================================================
--- vendor/elsa/current/elsa/xml_lex_0top.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_lex_0top.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,132 @@
+/* xml_lex_0top.lex            see license.txt for copyright and terms of use
+ * flex description of scanner for C and C++ souce
+ */
+
+/* This file is the top part of the generated .lex file. */
+
+/* ----------------------- C definitions ---------------------- */
+%{
+
+#include "xml_lexer.h"       // Lexer class
+
+// this works around a problem with cygwin & fileno
+#define YY_NEVER_INTERACTIVE 1
+
+#include "xml_lex_extra.h"
+
+%}
+
+
+/* -------------------- flex options ------------------ */
+/* no wrapping is needed; setting this means we don't have to link with libfl.a */
+%option noyywrap
+
+/* don't use the default-echo rules */
+%option nodefault
+
+/* I don't call unput */
+%option nounput
+
+/* generate a c++ lexer */
+%option c++
+
+/* use the "fast" algorithm with no table compression */
+%option full
+
+/* utilize character equivalence classes */
+%option ecs
+
+/* the scanner is never interactive */
+%option never-interactive
+
+/* I want to give good error messages and flex is way faster than a
+   parser so I think this is a good tradeoff; UPDATE: arg, Scott's
+   scheme seems to require %option full just to work at all and which
+   seems to contradict this option. */
+  /* %option yylineno */
+
+/* and I will define the class (lexer.h) */
+%option yyclass="XmlLexer"
+
+/* ------------------- definitions -------------------- */
+/* newline */
+NL            "\n"
+
+/* anything but newline */
+NOTNL         .
+
+/* any of 256 source characters */
+ANY           ({NOTNL}|{NL})
+
+/* backslash */
+BACKSL        "\\"
+
+/* beginnging of line (must be start of a pattern) */
+BOL           ^
+
+/* end of line (would like EOF to qualify also, but flex doesn't allow it */
+EOL           {NL}
+
+/* letter or underscore */
+LETTER        [A-Za-z_]
+LETTERDOT     [A-Za-z_\.]
+
+/* letter or underscore or digit */
+ALNUM         [A-Za-z_0-9]
+ALNUMDOT      [A-Za-z_0-9\.]
+
+/* decimal digit */
+DIGIT         [0-9]
+HEXDIGIT      [0-9A-Fa-f]
+
+/* sequence of decimal digits */
+DIGITS        ({DIGIT}+)
+/* sequence of hex digits */
+HEXDIGITS     ({HEXDIGIT}+)
+
+/* sign of a number */
+SIGN          ("+"|"-")
+
+/* integer suffix */
+/* added 'LL' option for gcc/c99 long long compatibility */
+ELL_SUFFIX    [lL]([lL]?)
+INT_SUFFIX    ([uU]{ELL_SUFFIX}?|{ELL_SUFFIX}[uU]?)
+
+/* floating-point suffix letter */
+FLOAT_SUFFIX  [flFL]
+
+/* normal string character: any but quote, newline, or backslash */
+STRCHAR       [^\"\n\\]
+STRCHAR_S     [^\'\n\\]
+
+/* (start of) an escape sequence */
+ESCAPE        ({BACKSL}{ANY})
+
+/* double quote */
+QUOTE         [\"]
+
+/* single quote (apos) */
+SQUOTE          [\']
+
+/* normal character literal character: any but single-quote, newline, or backslash */
+CCCHAR        [^\'\n\\]
+
+/* single quote */
+TICK          [\']
+
+/* space or tab */
+SPTAB         [ \t]
+
+/* preprocessor "character" -- any but escaped newline */
+PPCHAR        ([^\\\n]|{BACKSL}{NOTNL})
+
+
+/* ------------- token definition rules --------------- */
+%%
+
+  /* operators, punctuators and keywords: tokens with one spelling */
+"<"                return tok(XTOK_LESSTHAN);
+">"                return tok(XTOK_GREATERTHAN);
+"/"                return tok(XTOK_SLASH);
+"="                return tok(XTOK_EQUAL);
+"_id"              return tok(XTOK_DOT_ID);

Added: vendor/elsa/current/elsa/xml_lex_2bot.lex
===================================================================
--- vendor/elsa/current/elsa/xml_lex_2bot.lex	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_lex_2bot.lex	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,47 @@
+  /* xml_lex_2bot.lex            see license.txt for copyright and terms of use
+   * flex description of scanner for C and C++ souce
+   */
+
+  /* This file is the bottom part of the generated .lex file. */
+
+  /* identifier: e.g. foo */
+{ALNUMDOT}* {
+  return svalTok(XTOK_NAME);
+}
+
+  /** dequote the string directly while lexing */
+
+({QUOTE}|{SQUOTE}) {
+  // read_xml_string() will Do The Right Thing: read a quoted and escaped
+  // string; dequote and unescape into yytext and update all pointers
+  // appropriately.
+  read_xml_string();
+  return svalTok(XTOK_STRING_LITERAL);
+}
+
+[\n]   {
+  ++linenumber;                 /* have to do this manually; see above */
+}
+
+  /* whitespace */
+  /* 10/20/02: added '\r' to accomodate files coming from Windows; this
+   * could be seen as part of the mapping from physical source file
+   * characters to the basic character set (cppstd 2.1 para 1 phase 1),
+   * except that it doesn't happen for chars in string/char literals... */
+[ \t\f\v\r]+  {
+  /*    whitespace(); */
+}
+
+  /* illegal */
+.  {
+  /* updLoc(); */
+  err(stringc << "illegal character: `" << yytext[0] << "'");
+}
+
+<<EOF>> {
+  /*    srcFile->doneAdding(); */
+  yyterminate();
+}
+
+
+%%

Added: vendor/elsa/current/elsa/xml_lex_extra.h
===================================================================
--- vendor/elsa/current/elsa/xml_lex_extra.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_lex_extra.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,265 @@
+#ifndef FLEX_SCANNER
+# error "This file should only be included in the flex-generated scanner"
+#endif
+
+#include <assert.h>
+
+// SGM 2006-05-26: My flex does not seem to have
+// YY_CURRENT_BUFFER_LVALUE.. maybe this will work?  seems to.
+#ifndef YY_CURRENT_BUFFER_LVALUE
+  #define YY_CURRENT_BUFFER_LVALUE YY_CURRENT_BUFFER
+#endif
+
+// This file is to be included in xml_lex.gen.yy.cc (see xml_lex_0top.lex).
+// It depends on flex macros so we can't make it a separate translation unit.
+// It's named a ".h" file to work with existing oink build infrastructure.
+
+// Read a string, save it in dequote, and advance pointer past closing quote.
+//
+// The dequoted and unescaped string is null-terminated and stored in yytext.
+//
+// Returns 1 on success (or recoverable error); returns 0 on error.
+bool XmlLexer::read_xml_string()
+{
+  // action should have read 1 char
+  assert(yy_c_buf_p == yytext + 1);
+
+  // unput the saved char (which was clobbered with '\0')
+  assert(*yy_c_buf_p == '\0');
+  *yy_c_buf_p = (yy_hold_char);
+
+  // the quote char is the previous character
+  char delim = yy_c_buf_p[-1];
+  assert(delim == '\'' || delim == '"');
+
+  // p now points to the after the open quote.
+  // This pointer which is what we'll return.
+  yytext = yy_c_buf_p;
+
+  // Optimization: try to do a lot before we have to start copying chars due
+  // to unescaping.  If the entire string has nothing to unescape we can
+  // just return a pointer from the lexer buffer without modification!
+
+  // loop#1: no copying, since no characters so far were modified.
+  while (1) {
+    if (yyunderflow() < 0) return false;
+    if (*yy_c_buf_p == delim) {
+      // Yay, reached end of string with nothing to decode!
+      // Overwrite quote, which we no longer need, with a '\0'
+      *yy_c_buf_p = '\0';
+
+      // yy_c_buf_p currently points at the quote; the next character to lex
+      // is the one after that
+      ++yy_c_buf_p;
+
+      // This is needed since the real lexer will try to unclobber with this
+      // character
+      yy_hold_char = *yy_c_buf_p;
+      return true;
+    }
+
+    if (*yy_c_buf_p == '&' /*|| *yy_c_buf_p == '\\'*/) {
+      // Special characters: we're going to have to copy characters now so
+      // go into loop#2.
+      break;
+    }
+
+    if (*yy_c_buf_p == '<') {
+      // illegal - http://www.w3.org/TR/2004/REC-xml-20040204/#NT-AttValue
+      err("non-escaped left-angle-bracket (<) inside string literal");
+      return false;
+    }
+
+    if (*yy_c_buf_p == '\n') {
+      err("string literal missing final `\"'");
+
+      // error recovery
+      *yy_c_buf_p = '\0';
+      ++yy_c_buf_p;
+      yy_hold_char = *yy_c_buf_p;
+      return true;
+    }
+
+    // normal character; continue.
+    ++yy_c_buf_p;
+  }
+
+  // Destination to write characters.
+  char *d = yy_c_buf_p;
+
+  // loop#2: for all characters, whether unescaped or not, we have to copy
+  // to the destination.  The destination is actually in the same buffer,
+  // but guaranteed to be <= the current position since unescaping can only
+  // shorten.
+
+  while (1) {
+    if (int movement = yyunderflow()) {
+      if (movement < 0) return false;
+      d -= movement;
+    }
+
+    if (*yy_c_buf_p == delim) {
+      // Reached end of string.
+      //
+      // Null-terminate destination string by overwriting some character
+      // which we no longer need.
+      *d = '\0';
+      // Advance read pointer to past quote char.
+      ++yy_c_buf_p;
+      yy_hold_char = *yy_c_buf_p;
+      return true;
+    }
+
+    // It looks like backslash is not an escaping character in XML?
+    // if (*yy_c_buf_p == '\\') {
+    // }
+
+    else if (*yy_c_buf_p == '&') {
+      static const int MAX_ENTITY_CHARS = 10;
+      // Special characters
+
+      char *entity_start = ++yy_c_buf_p;
+      int entity_length;
+      // find the ';'
+      while (1) {
+        if (int movement = yyunderflow()) {
+          if (movement < 0) return false;
+          d -= movement;
+          entity_start -= movement;
+        }
+        if (*yy_c_buf_p == ';') break;
+        ++yy_c_buf_p;
+        if (yy_c_buf_p - entity_start > MAX_ENTITY_CHARS)
+          goto bad_entity;
+      }
+
+      // entity_start points at after '&', and yy_c_buf_p points at ';'
+      assert (*yy_c_buf_p == ';');
+
+      entity_length = yy_c_buf_p - entity_start;
+      if (entity_length < 2) goto bad_entity;
+
+      if (*entity_start == '#') {
+        char *digit = entity_start + 1;
+        int base = 10;
+        if (*digit == 'x') {
+          base = 16;
+          digit++;
+        }
+
+        char *endptr;
+        unsigned long val = strtoul(digit, &endptr, base);
+        // endptr should now point to the ';' if strtoul was happy
+        if (endptr != yy_c_buf_p) {
+          goto bad_entity;
+        }
+        // possible truncation since we're using skinny chars
+        *d++ = ((char) (unsigned char) val);
+        yy_c_buf_p++;
+        continue;
+      }
+
+#define DO_ENTITY(S, C) DO_ENTITY1(S, (sizeof(S)-1), C)
+#define DO_ENTITY1(S, N, C)                                       \
+      if (entity_length==N && 0==memcmp(entity_start, S, N)) {    \
+        *d++ = C;                                                 \
+        yy_c_buf_p++;                                             \
+        continue;                                                 \
+      }
+
+      DO_ENTITY("lt",   '<');
+      DO_ENTITY("gt",   '>');
+      DO_ENTITY("amp",  '&');
+      DO_ENTITY("quot", '"');
+      DO_ENTITY("apos", '\'');
+#undef DO_ENTITY
+
+    bad_entity:
+      err("use of an unimplemented or illegal amperstand escape");
+
+      // error recovery: write character as usual
+      yy_c_buf_p = entity_start;
+    }
+
+    else if (*yy_c_buf_p == '<') {
+      // illegal - http://www.w3.org/TR/2004/REC-xml-20040204/#NT-AttValue
+      err("non-escaped left-angle-bracket (<) inside string literal");
+      return false;
+    }
+
+    else if (*yy_c_buf_p == '\n') {
+      err("string literal missing final `\"'");
+
+      // error recovery
+      *yy_c_buf_p = '\0';
+      ++yy_c_buf_p;
+      yy_hold_char = *yy_c_buf_p;
+      return false;
+    }
+
+    else {
+      // regular character
+      *d++ = *yy_c_buf_p++;
+    }
+  }
+  // not reached
+}
+
+// Underflow function to read_xml_string() based on yyinput() but optimized
+// for read_xml_string().  It returns the backwards movement (as a positive
+// number) of current pointers within the buffer.  yy_c_buf_p is updated if
+// necessary.  Other pointers between yytext and yy_c_buf_p are still valid
+// if you update them.  After calling this function, *yy_c_buf_p should
+// point to the next character to read.
+//
+// If end-of-buffer is reached, return -1.
+//
+// It assumes yytext is not NULL-terminated i.e. do not unclobber the buffer
+// (which is unnecessary and annoying), and do not reclobber the buffer
+// after input.  Also do not support yywrap().  If we reach end of buffer,
+// die.
+
+inline int XmlLexer::yyunderflow() {
+  assert(*yy_c_buf_p != '\0');
+  if (*yy_c_buf_p == YY_END_OF_BUFFER_CHAR) {
+    if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) {
+      // reached null
+
+      // TODO: improve error messages. prefix with "XML parser: " and add
+      // line number.
+      err("unterminated string literal");
+      return -1;
+    } else {
+      // need more input
+      char *old_yytext = yytext;
+      int movement;
+#ifndef NDEBUG
+      int offset = yy_c_buf_p - yytext; // debug
+#endif
+      ++yy_c_buf_p;
+
+      switch (yy_get_next_buffer())
+      {
+      case EOB_ACT_LAST_MATCH: // fall-through
+      case EOB_ACT_END_OF_FILE:
+        // end of file.
+        err("unterminated string literal");
+        return -1;
+
+      case EOB_ACT_CONTINUE_SCAN:
+        // yytext should have been moved to beginning of buffer
+        movement = old_yytext - yytext;
+        assert (movement > 0);
+
+        yy_c_buf_p--;
+        yy_c_buf_p -= movement;
+        assert (yy_c_buf_p == yytext+offset);
+        return movement;
+
+      default:
+        assert(0);
+      }
+    }
+  }
+  return 0;
+}

Added: vendor/elsa/current/elsa/xml_lexer.cc
===================================================================
--- vendor/elsa/current/elsa/xml_lexer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_lexer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,80 @@
+// xml_lexer.cc         see License.txt for copyright and terms of use
+
+#include "xml_lexer.h"
+#include "xassert.h"
+#include "exc.h"
+
+
+// ------------------------ XmlLexer -------------------
+static char const * const tokenNames[] = {
+  "XTOK_EOF",
+
+  "XTOK_NAME",
+
+  "XTOK_INT_LITERAL",
+  "XTOK_FLOAT_LITERAL",
+  "XTOK_HEX_LITERAL",
+  "XTOK_STRING_LITERAL",
+
+  "XTOK_LESSTHAN",
+  "XTOK_GREATERTHAN",
+  "XTOK_EQUAL",
+  "XTOK_SLASH",
+
+  "XTOK_DOT_ID",
+
+  // tokens for lexing the Xml
+#include "xml_name_1.gen.cc"
+
+  "NUM_XML_TOKEN_TYPES",
+};
+
+int XmlLexer::getToken() {
+  int token = this->yylex();
+  if (token==0) {
+    sawEof = true;
+  }
+  return token;
+}
+
+int XmlLexer::tok(XmlToken kind)
+{
+//    printf("%s\n", tokenKindDesc(kind).c_str());
+//    fflush(stdout);
+  return kind;
+}
+
+int XmlLexer::svalTok(XmlToken kind)
+{
+//    printf("%s '%s'\n", tokenKindDesc(kind).c_str(), yytext);
+//    fflush(stdout);
+  return kind;
+}
+
+void XmlLexer::err(char const *msg)
+{
+  stringBuilder msg0;
+  if (inputFname) {
+    msg0 << inputFname << ":";
+  }
+  msg0 << linenumber << ":" << msg;
+  THROW(xBase(msg0));
+}
+
+string XmlLexer::tokenKindDesc(int kind) const
+{
+  xassert(0 <= kind && kind < NUM_XML_TOKEN_TYPES);
+  xassert(tokenNames[kind]);     // make sure the tokenNames array grows with the enum
+  return tokenNames[kind];
+}
+
+string XmlLexer::tokenKindDescV(int kind) const
+{
+  xassert(0 <= kind && kind < NUM_XML_TOKEN_TYPES);
+  xassert(tokenNames[kind]);     // make sure the tokenNames array grows with the enum
+
+  stringBuilder s;
+  s << tokenNames[kind]
+    << " (" << kind << ")";
+  return s;
+}

Added: vendor/elsa/current/elsa/xml_lexer.h
===================================================================
--- vendor/elsa/current/elsa/xml_lexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_lexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,51 @@
+// xml_lexer.h           see license.txt for copyright and terms of use
+
+#ifndef XML_LEXER_H
+#define XML_LEXER_H
+
+#include <stdio.h>
+#include "fstream.h"            // ifstream
+
+#include "str.h"                // string
+#include "sm_flexlexer.h"       // yyFlexLexer
+#include "baselexer.h"          // FLEX_OUTPUT_METHOD_DECLS
+#include "xml_enum.h"           // XTOK_*
+
+class XmlLexer : private yyFlexLexer {
+private:
+  inline int yyunderflow(); // helper for read_xml_string
+  bool read_xml_string();   // used by lexer when reading strings
+
+public:
+  char const *inputFname;       // just for error messages
+  int linenumber;
+  bool sawEof;
+
+  XmlLexer()
+    : inputFname(NULL)
+    , linenumber(1)             // file line counting traditionally starts at 1
+    , sawEof(false)
+  {}
+
+  // this is yylex() but does what I want it to with EOF
+  int getToken();
+  // have we seen the EOF?
+  bool haveSeenEof() { return sawEof; }
+
+  // This is yytext.  Strings are already dequoted+unescaped.
+  char const *currentText() { return this->YYText(); }
+
+  // this is yyrestart.  For starting and restarting.
+  void restart(istream *in) { this->yyrestart(in); sawEof = false; }
+
+  int tok(XmlToken kind);
+  int svalTok(XmlToken t);
+  void err(char const *msg);
+
+  string tokenKindDesc(int kind) const;
+  string tokenKindDescV(int kind) const;
+
+  FLEX_OUTPUT_METHOD_DECLS
+};
+
+#endif // XML_LEXER_H

Added: vendor/elsa/current/elsa/xml_reader.cc
===================================================================
--- vendor/elsa/current/elsa/xml_reader.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_reader.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,916 @@
+// xml_reader.cc            see license.txt for copyright and terms of use
+
+#include "xml_reader.h"         // this module
+#include "exc.h"                // xBase
+#include "taillist.h"
+#include "sobjlist.h"
+#include "objlist.h"
+
+bool xmlDanglingPointersAllowed = true;
+
+UnsatLink::UnsatLink(void *ptr0, char const *id0, int kind0, bool embedded0)
+  : ptr(ptr0), id(id0), kind(kind0), embedded(embedded0)
+{};
+
+
+void XmlReader::setManager(XmlReaderManager *manager0) {
+  xassert(!manager);
+  manager = manager0;
+}
+
+void XmlReader::xmlUserFatalError(char const *msg) {
+  manager->xmlUserFatalError(msg);
+}
+
+void XmlReaderManager::registerReader(XmlReader *reader) {
+  xassert(reader);
+  readers.append(reader);
+  reader->setManager(this);
+}
+
+void XmlReaderManager::unregisterReader(XmlReader *reader) {
+  xassert(reader);
+  readers.deleteItem(reader);
+}
+
+void XmlReaderManager::reset() {
+  // TODO: should this clear readers?
+  lastNode = NULL;
+  lastKind = 0;
+  xassert(parseStack.isEmpty());
+}
+
+void XmlReaderManager::parseOneTopLevelTag() {
+  // FIX: a do-while is always a bug
+  do parseOneTagOrDatum();
+  while(!atTopLevel());
+}
+
+// TODO: shorten this function
+void XmlReaderManager::parseOneTagOrDatum() {
+  static int count=0;
+  ++count;
+
+  // state: looking for a tag start
+  if (lexer.haveSeenEof()) {
+    xmlUserFatalError("unexpected EOF while looking for '<' of an open tag");
+  }
+  int start = lexer.getToken();
+  //      printf("start:%s\n", lexer.tokenKindDesc(start).c_str());
+  switch(start) {
+  default:
+    xmlUserFatalError("unexpected token while looking for '<' of an open tag");
+    break;
+  case XTOK_NAME:
+    // this is raw data in between tags
+    registerStringToken(parseStack.top().object, parseStack.top().kind, lexer.currentText());
+    return;
+    break;
+  case 0:                     // eof
+    return;
+    break;
+  case XTOK_LESSTHAN:
+    break;                    // continue parsing
+  }
+
+  // state: read a tag name
+  int tag = lexer.getToken();
+  // construct the tag object on the stack
+  void *topTemp = NULL;
+  bool sawOpenTag = true;
+  switch(tag) {
+  default:
+    topTemp = ctorNodeFromTag(tag);
+    break;
+  // Slash: start of a close tag
+  case XTOK_SLASH:
+    sawOpenTag = false;
+    break;
+  // ListItem: a list element
+  case XTOK__List_Item:
+    // TODO: avoid creating ListItems by just appending to the list above us
+    // in the stack.
+    topTemp = new ListItem();
+    break;
+  // NameMapItem: a name-map element
+  case XTOK__NameMap_Item:
+    topTemp = new NameMapItem();
+    break;
+  // MapItem: a map element
+  case XTOK__Map_Item:
+    topTemp = new MapItem();
+    break;
+//    // Special case the <__Link/> tag
+//    case XTOK___Link:
+//      topTemp = new UnsatBiLink();
+//      break;
+  }
+  if (sawOpenTag) {
+    // NOTE: even if it is a stand-alone tag that will not stay on the
+    // stack, we still have to put it here as readAttributes()
+    // attaches attributes to the node on the top of the stack (my
+    // parser is some sort of stack machine).
+    xassert(topTemp);
+    // fprintf(stderr, "## parseOneTagOrDatum: sawOpenTag count=%d, node=%p\n", count, topTemp);
+    ParseStackItem &psi = parseStack.pushAlt();
+    psi.object = topTemp;
+    psi.kind = tag;
+    // ulinks must be new or had its contents moved to allUnsatLinks.
+    xassert(psi.ulinks.isEmpty());
+
+    // read the attributes
+    bool sawContainerTag = readAttributes();
+
+    // if it is a container tag, we just leave it on the stack
+    if (sawContainerTag) {
+      // state: we saw a container tag
+      return;
+    }
+
+    // state: we saw a stand-alone tag.  FIX: I suppose I should
+    // generalize this, but for now there is only one stand-alone tag
+//      if (!tag == XTOK___Link) {
+    xmlUserFatalError("illegal stand-alone tag");
+//      }
+//      UnsatBiLink *ulink = (UnsatBiLink*) topTemp;
+//      if (!ulink->from) {
+//        xmlUserFatalError("missing 'from' field on __Link tag");
+//      }
+//      if (!ulink->to) {
+//        xmlUserFatalError("missing 'to' field on __Link tag");
+//      }
+//      unsatBiLinks.append(ulink);
+//      // we don't need it on the stack anymore
+//      nodeStack.pop();
+//      kindStack.pop();            // FIX: delete the return?
+    return;
+  }
+
+  // state: read a close tag name
+  int closeTag = lexer.getToken();
+  if (!closeTag) {
+    xmlUserFatalError("unexpected file termination while looking for a close tag name");
+  }
+  if (parseStack.isEmpty()) {
+    xmlUserFatalError("too many close tags");
+  }
+  lastNode = parseStack.top().object;
+  lastKind = parseStack.top().kind;
+  ASTList<UnsatLink> &ulinks = parseStack.top().ulinks;
+  if (lastKind != closeTag) {
+    xmlUserFatalError(stringc << "close tag " << lexer.tokenKindDescV(closeTag)
+                      << " does not match open tag " << lexer.tokenKindDescV(lastKind));
+  }
+
+  // quarl 2006-06-01
+  //    Hopefully, we've already satisfied most by now so this is usually
+  //    empty.  Steal the rest of them onto the list of all unsat links.
+  allUnsatLinks.concat(ulinks);
+  xassert(ulinks.isEmpty());
+
+  // use popMany() instead of pop() to avoid the operator= call
+  parseStack.popMany(1);
+
+  // state: read the '>' after a close tag
+  int closeGreaterThan = lexer.getToken();
+  switch(closeGreaterThan) {
+  default: xmlUserFatalError("unexpected token while looking for '>' of a close tag");
+  case 0: xmlUserFatalError("unexpected file termination while looking for '>' of a close tag");
+  case XTOK_GREATERTHAN:
+    break;
+  }
+
+  // quarl 2006-06-01
+  //    Append to any list/map items.
+  switch(lastKind) {
+  default:
+    // normal non-list tag; no further processing required.
+    break;
+  case XTOK__List_Item: appendListItem(); break;
+  case XTOK__NameMap_Item: appendNameMapItem(); break;
+  case XTOK__Map_Item: appendMapItem(); break;
+  }
+
+  // quarl 2006-06-01
+  //    We had to prepend in appendListItem() due to lack of constant-time
+  //    append, so now reverse.
+  switch (kind2kindCat(lastKind)) {
+  default:
+    // nothing to do
+    break;
+
+  case KC_FakeList:
+    reverseFakeList(*reinterpret_cast<void**>(lastNode), lastKind);
+    break;
+
+  case KC_SObjList:
+    reinterpret_cast<SObjList<void>*>(lastNode)->reverse();
+    break;
+
+  case KC_ObjList:
+    reinterpret_cast<ObjList<void>*>(lastNode)->reverse();
+    break;
+
+  case KC_ArrayStack:
+    // TODO: consolidate
+    break;
+  }
+}
+
+// quarl 2006-06-01
+//    FakeList strategy: since a prepend to a fakelist modifies the
+//    pointer to the fakelist, we must have a place to store the
+//    pointer.  Thus the item stored in the nodeStack is actually a
+//    pointer to a FakeList*.
+//
+//    We expect the parent to point to us, so as soon as we
+//    have an ID in readAttributes(), we'll deallocate this void*.
+
+void XmlReaderManager::appendListItem() {
+  // save the item tag
+  ListItem *itemNode = (ListItem*)lastNode;
+
+  // find the Node pointed to by the item; it should have been seen
+  // by now
+  if (itemNode->to.empty()) {
+    xmlUserFatalError("no 'to' field for this _List_Item tag");
+  }
+
+  // TODO: optimization: 99% of the time, the pointedToItem was our xml-child
+  // TODO: can just re-use UnsatLink to implement optimization
+  void *pointedToItem = id2obj.queryif(itemNode->to);
+  if (!pointedToItem) {
+    if (!xmlDanglingPointersAllowed) xmlUserFatalError("no Node pointed to by _List_Item");
+    return;
+  }
+
+  // what kind of thing is next on the stack?
+  void *listNode = getTopNode0();
+  if (!listNode) {
+    xmlUserFatalError("a _List_Item tag not immediately under a List");
+  }
+  int listKind = parseStack.top().kind;
+  KindCategory listKindCat = kind2kindCat(listKind);
+
+  // quarl 2006-06-01
+  //    For void*-based lists such as ASTList and ObjList, we can just
+  //    reinterpret the list type and append, since it's just a type-safety
+  //    wrapper with identical representation.
+  //
+  //    For others, namely FakeList and ArrayStack, we have no choice but to
+  //    do a manual virtual dispatch on listKind.
+  switch (listKindCat) {
+  default:
+    xmlUserFatalError("a _List_Item tag not immediately under a List");
+    break;
+
+  case KC_ASTList:
+    reinterpret_cast<ASTList<void>*>(listNode)->append(pointedToItem);
+    break;
+  case KC_TailList:
+    reinterpret_cast<TailList<void>*>(listNode)->append(pointedToItem);
+    break;
+  case KC_FakeList:
+    // no constant append; reversed later
+    prependToFakeList(*reinterpret_cast<void**>(listNode), pointedToItem, listKind);
+    break;
+  case KC_ObjList:
+    // no constant append; reversed later
+    reinterpret_cast<ObjList<void>*>(listNode)->prepend(pointedToItem);
+    break;
+  case KC_SObjList:
+    // no constant append; reversed later
+    reinterpret_cast<SObjList<void>*>(listNode)->prepend(pointedToItem);
+    break;
+  case KC_ArrayStack:
+    appendToArrayStack(listNode, pointedToItem, listKind);
+    break;
+  }
+
+  delete itemNode;
+}
+
+void XmlReaderManager::appendNameMapItem() {
+  // save the name tag
+  NameMapItem *nameNode = (NameMapItem*)lastNode;
+
+  // find the Node pointed to by the item; it should have been seen
+  // by now
+  // TODO: factor and optimize as above
+  void *pointedToItem = id2obj.queryif(nameNode->to);
+  if (!pointedToItem) {
+    if (!xmlDanglingPointersAllowed) xmlUserFatalError("no Node pointed to by _NameMap_Item");
+  }
+
+  void *mapNode = getTopNode0();
+  if (!mapNode) {
+    xmlUserFatalError("a _NameMap_Item tag not immediately under a Map");
+  }
+  int mapKind = parseStack.top().kind;
+  KindCategory mapKindCat = kind2kindCat(mapKind);
+  switch (mapKindCat) {
+  default:
+    xmlUserFatalError("a _NameMap_Item tag not immediately under a Map");
+    break;
+
+  case KC_StringRefMap: {
+    char const *key = strTable(nameNode->from.c_str());
+    StringRefMap<void>* map = reinterpret_cast <StringRefMap<void>*>(mapNode);
+    if (map->get(key)) {
+      xmlUserFatalError(stringc << "duplicate name " << key << " in map");
+    }
+    map->add(key, pointedToItem);
+    break; }
+
+  case KC_StringSObjDict: {
+    string const &key = nameNode->from;
+    StringSObjDict<void>* map = reinterpret_cast <StringSObjDict<void>*>(mapNode);
+    if (map->isMapped(key)) {
+      xmlUserFatalError(stringc << "duplicate name " << key << " in map");
+    }
+    map->add(key, pointedToItem);
+    break; }
+  }
+
+  delete nameNode;
+}
+
+void XmlReaderManager::appendMapItem() {
+  // save the name tag
+  MapItem *nameNode = (MapItem*)lastNode;
+
+  // find the Node-s pointed to by both the key and item; they
+  // should have been seen by now
+  void *pointedToKey = id2obj.queryif(nameNode->from);
+  void *pointedToItem = id2obj.queryif(nameNode->to);
+  if (!pointedToItem) {
+    if (!xmlDanglingPointersAllowed) xmlUserFatalError("no Node pointed to by _Map_Item");
+  }
+  // TODO: check that pointedToKey not null?
+
+  // what kind of thing is next on the stack?
+  void *mapNode = getTopNode0();
+  if (!mapNode) {
+    xmlUserFatalError("a _NameMap_Item tag not immediately under a Map");
+  }
+  int mapKind = parseStack.top().kind;
+  KindCategory mapKindCat = kind2kindCat(mapKind);
+
+  switch (mapKindCat) {
+  default:
+    xmlUserFatalError("a _Map_Item tag not immediately under a Map");
+    break;
+
+  case KC_PtrMap: {
+    PtrMap<void, void> *map = reinterpret_cast<PtrMap<void, void>*>(mapNode);
+    if (map->get(pointedToKey)) {
+      // there is no good way to print out the key
+      xmlUserFatalError(stringc << "duplicate key in map");
+    }
+    map->add(pointedToKey, pointedToItem);
+    break; }
+  }
+}
+
+// state: read the attributes
+bool XmlReaderManager::readAttributes() {
+  size_t count = 0;
+  while(1) {
+    ++count;
+    int attr = lexer.getToken();
+    switch(attr) {
+    default: break;             // go on; assume it is a legal attribute tag
+    case 0: xmlUserFatalError("unexpected file termination while looking for an attribute name");
+    case XTOK_GREATERTHAN:
+      return true;              // container tag
+    case XTOK_SLASH:
+      attr = lexer.getToken();  // eat the '>' token
+      if (attr!=XTOK_GREATERTHAN) {
+        xmlUserFatalError("expected '>' after '/' that terminates a stand-alone tag");
+      }
+      return false;             // non-container tag
+    }
+
+    int eq = lexer.getToken();
+    switch(eq) {
+    default: xmlUserFatalError("unexpected token while looking for an '='");
+    case 0: xmlUserFatalError("unexpected file termination while looking for an '='");
+    case XTOK_EQUAL:
+      break;                    // go on
+    }
+
+    int value = lexer.getToken();
+    switch(value) {
+    default: xmlUserFatalError("unexpected token while looking for an attribute value");
+    case 0: xmlUserFatalError("unexpected file termination while looking for an attribute value");
+    case XTOK_INT_LITERAL:
+      // get it out of yytext below
+      break;
+    case XTOK_STRING_LITERAL:
+      // Get it out of yytext below.  Note that this string has already been
+      // dequoted/unescaped in the lexer!
+      break;                    // go on
+    }
+
+    // register the attribute
+    xassert(parseStack.isNotEmpty());
+    // special case the '_id' attribute
+    if (attr == XTOK_DOT_ID) {
+      // the map makes a copy of this string (if it needs it)
+      const char *id0 = lexer.currentText();
+      // DEBUG1
+      // cout << "## readAttributes: _id=" << id0 << endl;
+
+      // quarl 2006-06-01
+      //    Important: record the kind before we call satisfyUnsatLink,
+      //    because it needs to know what kind to upcast to.
+      if (recordKind(parseStack.top().kind)) {
+        id2kind.add(id0, parseStack.top().kind);
+      }
+
+#if 1
+      // quarl 2006-06-01: preemptive link satisfaction
+      //    See if the parent XML node has an unsatisfied link pointing to
+      //    this one -- the common case -- so that we can get rid of the
+      //    unsatLink, saving us from having to do a more work later.  If it's
+      //    an embedded object, even better: just point to the target.
+
+      // TODO: when parsing the tag, peek to see if it's an upcoming _id for
+      // an embedded object, and if so, don't even construct one!
+
+      UnsatLink *ulink = getUnsatLink(id0);
+      if (ulink) {
+        if (count == 1 && ulink->embedded)
+        {
+          // quarl 2006-06-01 if this is the first attribute then we don't
+          // need to copy anything; just delete the temporary.
+          void *obj = parseStack.top().object;
+          xassert(obj);
+          deleteObj(obj, ulink->kind);
+        } else {
+          satisfyUnsatLink(ulink, parseStack.top().object);
+        }
+
+        if (ulink->embedded) {
+          // now we point directly to the place we want to write to.
+          parseStack.top().object = ulink->ptr;
+        }
+
+        // yay, got rid of a ulink!
+        delete ulink;
+      }
+#endif
+
+      if (id2obj.isMapped(id0)) {
+        xmlUserFatalError(stringc << "this _id is taken: " << id0);
+      }
+      id2obj.add(id0, parseStack.top().object);
+    }
+    // special case the _List_Item node and its one attribute
+    else if (parseStack.top().kind == XTOK__List_Item) {
+      switch(attr) {
+      default:
+        xmlUserFatalError("illegal attribute for _List_Item");
+        break;
+      case XTOK_item:
+        static_cast<ListItem*>(parseStack.top().object)->to =
+          lexer.currentText();
+        break;
+      }
+    }
+    // special case the _NameMap_Item node and its one attribute
+    else if (parseStack.top().kind == XTOK__NameMap_Item) {
+      switch(attr) {
+      default:
+        xmlUserFatalError("illegal attribute for _NameMap_Item");
+        break;
+      case XTOK_name:
+        static_cast<NameMapItem*>(parseStack.top().object)->from =
+          lexer.currentText();
+        break;
+      case XTOK_item:
+        static_cast<NameMapItem*>(parseStack.top().object)->to =
+          lexer.currentText();
+        break;
+      }
+    }
+    // special case the _Map_Item node and its one attribute
+    else if (parseStack.top().kind == XTOK__Map_Item) {
+      switch(attr) {
+      default:
+        xmlUserFatalError("illegal attribute for _Map_Item");
+        break;
+      case XTOK_key:
+        static_cast<MapItem*>(parseStack.top().object)->from =
+          lexer.currentText();
+        break;
+      case XTOK_item:
+        static_cast<MapItem*>(parseStack.top().object)->to =
+          lexer.currentText();
+        break;
+      }
+    }
+//      // special case the __Link node and its attributes
+//      else if (kindStack.top() == XTOK___Link) {
+//        switch(attr) {
+//        default:
+//          xmlUserFatalError("illegal attribute for __Link");
+//          break;
+//        case XTOK_from:
+//          static_cast<UnsatBiLink*>(nodeStack.top())->from =
+//            lexer.currentText();
+//          break;
+//        case XTOK_to:
+//          static_cast<UnsatBiLink*>(nodeStack.top())->to =
+//            lexer.currentText();
+//          break;
+//        }
+//      }
+    // not a built-in attribute or tag
+    else {
+      registerAttribute(parseStack.top().object, parseStack.top().kind, attr, lexer.currentText());
+    }
+  }
+  if (!parseStack.isEmpty()) {
+    xmlUserFatalError("missing closing tags at eof");
+  }
+  // stacks should not be out of sync
+  xassert(parseStack.isEmpty());
+}
+
+void XmlReaderManager::kind2kindCat(int kind, KindCategory *kindCat) {
+  xassert(kind != -1);          // this means you shouldn't be asking
+
+  switch(kind) {
+  default:
+    // fallthrough the switch
+    break;
+
+  // special list element _List_Item
+  case XTOK__List_Item:
+    *kindCat = KC_Item;
+    return;
+    break;
+
+  // special map element _NameMap_Item
+  case XTOK__NameMap_Item:
+    *kindCat = KC_Name;
+    return;
+    break;
+  }
+
+  // try each registered reader
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    if (iter.data()->kind2kindCat(kind, kindCat)) {
+      return;
+    }
+  }
+
+  xfailure(stringc << "no kind category registered for kind "
+           << lexer.tokenKindDescV(kind));
+}
+
+void *XmlReaderManager::ctorNodeFromTag(int tag) {
+  xassert(tag != -1);          // this means you shouldn't be asking
+
+  // try each registered reader
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    XmlReader *r = iter.data();
+    void *node = r->ctorNodeFromTag(tag);
+    if (node) {
+      xassert(node != (void*) 0xBADCAFE);
+      return node;
+    }
+  }
+
+  xmlUserFatalError(stringc
+                    << "no ctor registered for tag " << lexer.tokenKindDescV(tag));
+}
+
+void XmlReaderManager::registerAttribute
+  (void *target, int kind, int attr, char const *yytext0) {
+  xassert(kind != -1);          // this means you shouldn't be asking
+
+  // try each registered reader
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    if (iter.data()->registerAttribute(target, kind, attr, yytext0)) {
+      return;
+    }
+  }
+
+  xfailure("no handler registered for this tag and attribute");
+}
+
+void XmlReaderManager::registerStringToken(void *target, int kind, char const *yytext0) {
+  xassert(kind != -1);          // this means you shouldn't be asking
+
+  // try each registered reader
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    if (iter.data()->registerStringToken(target, kind, yytext0)) {
+      return;
+    }
+  }
+
+  xfailure("no raw data handler registered for this tag");
+}
+
+void XmlReaderManager::xmlUserFatalError(char const *msg) {
+  stringBuilder msg0;
+  if (inputFname) {
+    msg0 << inputFname << ':';
+  }
+  msg0 << lexer.linenumber << ':' << msg;
+  THROW(xBase(msg0));
+  xfailure("should not get here");
+}
+
+// quarl 2006-06-01:
+//    We now maintain a list of UnsatLinks for each level of the parse stack;
+//    when we pop them we concat them to the global list.  The per-level unsat
+//    links allow us to quickly scan the parent level's unsat links and
+//    satisfy them now, yielding a big performance gain.  This is also
+//    necessary for deserializing FakeLists directly into the target location.
+//
+//    If a link is found, return the UnsatLink, which the caller must delete.
+//    Otherwise, return NULL.
+
+UnsatLink *XmlReaderManager::getUnsatLink(char const *id0)
+{
+  if (parseStack.length() <= 1) {
+    return NULL;
+  }
+
+  ASTList<UnsatLink> &parentUnsatLinks = parseStack.nth(1).ulinks;
+  for (ASTListMutator<UnsatLink> mut(parentUnsatLinks); !mut.isDone(); mut.adv()) {
+    UnsatLink *ulink = mut.data();
+    if (streq(ulink->id, id0)) {
+      // remove this ulink; caller deletes
+      mut.remove();
+      return ulink;
+    }
+  }
+  return NULL;
+}
+
+void XmlReaderManager::addUnsatLink(UnsatLink *u)
+{
+  // I OWNZ U
+  // fprintf(stderr, "## addUnsatLink: u=%p, u->id=%s, u->embedded=%d\n",
+  //         u, u->id.c_str(), u->embedded);
+  parseStack.top().ulinks.append(u);
+}
+
+
+// quarl 2006-05-31:
+//    UNFORTUNATELY, the order in which we satisfy links matters when embedded
+//    objects are involved.  Embedded objects must be satisfied last, and if
+//    there are nested embedding, then the outermost object must be satisfied
+//    last.  The order we use now (lists, nodes without embedding, nodes with
+//    embedding) works for now, but the whole thing is brittle.
+
+// TODO: make separate lists for embedded and non-embedded ulinks
+
+void XmlReaderManager::satisfyLinks() {
+  // satisfyLinks_Lists();
+  satisfyLinks_Nodes();
+  // satisfyLinks_Maps();
+//    satisfyLinks_Bidirectional();
+}
+
+#include "xmlhelp.h"
+static inline
+bool inputXmlPointerIsNull(char const * s_id) {
+  return streq(s_id, "(null)");
+}
+
+void XmlReaderManager::satisfyLinks_Nodes() {
+  // printf("## id2obj.size() = %d, id2kind.size() = %d\n",
+  //        id2obj.size(), id2kind.size());
+
+  // satisfy non-embedded objects first, then embedded objects (see 2006-05-31
+  // comment above)
+  satisfyLinks_Nodes_1(false);
+  satisfyLinks_Nodes_1(true);
+
+  // remove the links
+  allUnsatLinks.deleteAll();
+}
+
+void XmlReaderManager::satisfyLinks_Nodes_1(bool processEmbedded) {
+  FOREACH_ASTLIST(UnsatLink, allUnsatLinks, iter) {
+    UnsatLink const *ulink = iter.data();
+
+    if (ulink->embedded != processEmbedded)
+      continue;
+
+    // fprintf(stderr, "## satisfyLinks_Nodes: processing link id=%s\n", ulink->id.c_str());
+    void *obj;
+    if (inputXmlPointerIsNull(ulink->id.c_str())) {
+      // Note: as of 2006-05-30, we no longer serialize "(null)" pointers, so
+      // when deserializing data that we serialized, we just get a dangling
+      // pointer which defaults to NULL.
+      obj = NULL;
+    } else {
+      obj = id2obj.queryif(ulink->id);
+      if (obj == NULL) {
+        if (!xmlDanglingPointersAllowed) {
+          xmlUserFatalError(stringc << "unsatisfied node link: " << ulink->id);
+        }
+      }
+    }
+
+    satisfyUnsatLink(ulink, obj);
+  }
+}
+
+void XmlReaderManager::satisfyUnsatLink(UnsatLink const *ulink, void *obj)
+{
+  if (ulink->embedded) {
+    // I can assume that the kind of the object that was
+    // de-serialized is the same as the target because it was
+    // embedded and there is no chance for a reference/referent
+    // type mismatch.
+    callOpAssignToEmbeddedObj(obj, ulink->kind, ulink->ptr);
+    // FIX: we should now delete obj; in fact, this should be done
+    // by callOpAssignToEmbeddedObj() since it knows the type of
+    // the object which is necessary to delete it of course.  I'll
+    // leave this for an optimization pass which we will do later
+    // to handle many of these things.
+    deleteObj(obj, ulink->kind);
+
+    // we should not use this obj anymore
+    id2obj.add(ulink->id, (void*) 0xBADCAFE);
+  } else {
+    if (int kind = id2kind.queryif(ulink->id)) {
+      *( (void**)(ulink->ptr) ) = upcastToWantedType(obj, kind, ulink->kind);
+    } else {
+      // no kind was registered for the object and therefore no
+      // upcasting is required and there is no decision to make; so
+      // just do the straight pointer assignment
+      *( (void**) (ulink->ptr) ) = obj;
+    }
+  }
+}
+
+//  void XmlReaderManager::satisfyLinks_Bidirectional() {
+//    FOREACH_ASTLIST(UnsatBiLink, unsatBiLinks, iter) {
+//      UnsatBiLink const *ulink = iter.data();
+//      void **from = (void**)id2obj.queryif(ulink->from);
+//      // NOTE: these are different from unidirectional links: you really
+//      // shouldn't make one unless both parties can be found.
+//      if (!from) {
+//        xmlUserFatalError("Unsatisfied bidirectional link: 'from' not found");
+//      }
+//      void *to = id2obj.queryif(ulink->to);
+//      if (!to) {
+//        xmlUserFatalError("Unsatisfied bidirectional link: 'to' not found");
+//      }
+//      *(from) = to;
+//    }
+//  }
+
+bool XmlReaderManager::recordKind(int kind) {
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    bool answer;
+    XmlReader *r = iter.data();
+    if (r->recordKind(kind, answer)) {
+      return answer;
+    }
+  }
+  THROW(xBase(stringc << "no way to decide if kind should be recorded"));
+}
+
+// Do "*target = *obj" for the right type.
+// It's okay to destroy the contents of target since it's an embedded object,
+// so it can only be used once.
+// target is deleted later in deleteObj().
+void XmlReaderManager::callOpAssignToEmbeddedObj(void *obj, int kind, void *target) {
+  xassert(obj != target);
+  KindCategory kindcat = kind2kindCat(kind);
+
+  // quarl 2006-06-01
+  //    For list items, steal obj's list into the target.  This avoids doing a
+  //    needless O(N) copy (which we aren't allowed to do anyway for owning
+  //    lists).
+  // quarl 2006-06-02
+  //    If any of these target->isEmpty() assertions are failing, something is
+  //    wrong: since these lists are embedded (since we're in
+  //    callOpAssignToEmbeddedObj()), it should not be possible to have two
+  //    objects referring to the same one.  The most likely error is that the
+  //    data member is actually a pointer to a list rather than an embedded
+  //    list.
+  switch (kindcat) {
+  default: break;
+
+  case KC_ASTList:
+    if (!obj) return;
+    xassert(reinterpret_cast<ASTList<void>*>(target)->isEmpty());
+    reinterpret_cast<ASTList<void>*>(target)->concat(
+      *reinterpret_cast<ASTList<void>*>(obj));
+    return;
+  case KC_TailList:
+    if (!obj) return;
+    xassert(reinterpret_cast<TailList<void>*>(target)->isEmpty());
+    reinterpret_cast<TailList<void>*>(target)->concat(
+      *reinterpret_cast<TailList<void>*>(obj));
+    return;
+
+  case KC_FakeList: {
+    if (!obj) return;
+    // for fake lists, it's just a pointer location, so copy the pointer.
+    *((void**) target) = *((void**) obj);
+    return; }
+
+  case KC_ObjList:
+    if (!obj) return;
+    xassert(reinterpret_cast<ObjList<void>*>(target)->isEmpty());
+    reinterpret_cast<ObjList<void>*>(target)->concat(
+      *reinterpret_cast<ObjList<void>*>(obj));
+    return;
+  case KC_SObjList:
+    if (!obj) return;
+    xassert(reinterpret_cast<SObjList<void>*>(target)->isEmpty() && "61010461-dc93-4312-bca7-219392176c22");
+    reinterpret_cast<SObjList<void>*>(target)->concat(
+      *reinterpret_cast<SObjList<void>*>(obj));
+    return;
+  case KC_ArrayStack:
+    // can't do it without the type, so have to use dispatch
+    break;
+
+  case KC_StringRefMap:
+    xfailure("should have been preemptively satisfied");
+    break;
+
+  case KC_StringSObjDict:
+    xfailure("should have been preemptively satisfied");
+    break;
+
+  }
+
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    XmlReader *r = iter.data();
+    if (r->callOpAssignToEmbeddedObj(obj, kind, target)) {
+      return;
+    }
+  }
+  THROW(xBase(stringc << "no way to call op assign"));
+}
+
+void XmlReaderManager::deleteObj(void *obj, int kind)
+{
+  KindCategory kindcat = kind2kindCat(kind);
+  switch (kindcat) {
+  default: break;
+
+  case KC_FakeList: {
+    // the allocated object is actually a void*
+    void **ptr = (void**) obj;
+    delete ptr;
+    return; }
+  }
+
+  // TODO
+}
+
+
+void *XmlReaderManager::upcastToWantedType(void *obj, int kind, int targetKind) {
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    void *target = (void*) 0xBADCAFE;
+    XmlReader *r = iter.data();
+    if (r->upcastToWantedType(obj, kind, &target, targetKind)) {
+      xassert(target != (void*) 0xBADCAFE);
+      return target;
+    }
+  }
+  THROW(xBase(stringc << "no way to upcast"));
+}
+
+void XmlReaderManager::prependToFakeList(void *&list, void *obj, int listKind) {
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    XmlReader *r = iter.data();
+    if (r->prependToFakeList(list, obj, listKind)) {
+      return;
+    }
+  }
+  THROW(xBase(stringc << "no prepender for FakeList type"));
+}
+
+void XmlReaderManager::reverseFakeList(void *&list, int listKind) {
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    XmlReader *r = iter.data();
+    if (r->reverseFakeList(list, listKind)) {
+      return;
+    }
+  }
+  THROW(xBase(stringc << "no reverser for FakeList type"));
+}
+
+void XmlReaderManager::appendToArrayStack(void *list, void *obj, int listKind) {
+  FOREACH_ASTLIST_NC(XmlReader, readers, iter) {
+    XmlReader *r = iter.data();
+    if (r->appendToArrayStack(list, obj, listKind)) {
+      return;
+    }
+  }
+  THROW(xBase(stringc << "no appender for ArrayStack type"));
+}

Added: vendor/elsa/current/elsa/xml_reader.h
===================================================================
--- vendor/elsa/current/elsa/xml_reader.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_reader.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,356 @@
+// xml_reader.h            see license.txt for copyright and terms of use
+
+// Support for XML de-serialization
+
+// FIX: this module should eventually go into the ast repository
+
+#ifndef XML_READER_H
+#define XML_READER_H
+
+#include "id_obj_dict.h"        // IdSObjDict
+#include "strintdict.h"         // StringIntDict
+#include "bitwise_array.h"      // BitwiseArrayStack
+#include "astlist.h"            // ASTList
+#include "strtable.h"           // StringRef
+#include "strmap.h"             // StringRefMap
+#include "xml_lexer.h"          // XmlLexer
+#include "fakelist.h"
+
+class StringTable;
+
+// forwards in this file
+class XmlReaderManager;
+
+
+// if on the deserialization code will tolerate dangling pointers: ids
+// to objects that themselves were not serialized
+extern bool xmlDanglingPointersAllowed;
+
+
+// from Xml for enums
+#define READENUM(X) else if (streq(str, #X)) out = (X)
+#define READFLAG(X) else if (streq(token, #X)) out |= (X)
+
+#define ul(FIELD, KIND) \
+  manager->addUnsatLink \
+    (new UnsatLink((void*) &(obj->FIELD), \
+                   strValue, \
+                   (KIND), \
+                   false))
+
+#define ulEmbed(FIELD, KIND) \
+  manager->addUnsatLink \
+    (new UnsatLink((void*) &(obj->FIELD), \
+                   strValue, \
+                   (KIND), \
+                   true))
+
+// there are 3 categories of kinds of Tags
+enum KindCategory {
+  // normal node
+  KC_Node,
+
+  // list
+  KC_ASTList,
+  KC_TailList,
+  KC_FakeList,
+  KC_ObjList,
+  KC_SObjList,
+  KC_ArrayStack,
+  KC_Item,                      // an item entry in a list
+
+  // name map
+  KC_StringRefMap,
+  KC_StringSObjDict,
+  KC_Name,                      // a name entry in a name map
+
+  // map
+  KC_PtrMap,
+  KC_Key,                       // a key entry in a name map
+};
+
+// the <_List_Item> </_List_Item> tag is parsed into this class to
+// hold the name while the value contained by it is being parsed.
+// Then it is deleted.
+struct ListItem {
+  string to;
+};
+
+// the <_NameMap_Item> </_NameMap_Item> tag is parsed into this class
+// to hold the name while the value contained by it is being parsed.
+// Then it is deleted.
+struct NameMapItem {
+  string from;
+  string to;
+};
+
+// the <_Map_Item> </_Map_Item> tag is parsed into this class
+// to hold the name while the value contained by it is being parsed.
+// Then it is deleted.
+struct MapItem {
+  string from;
+  string to;
+};
+
+// datastructures for dealing with unsatisified links; FIX: we can
+// do the in-place recording of a lot of these unsatisified links
+// (not the ast links)
+
+// TODO: make ptr a 'void **'
+
+// An unsatisfied link from an object A to another B
+struct UnsatLink {
+  void *ptr;                    // a ptr to a member of A that should point to B (unless embedded)
+  string id;                    // id of B
+  int kind;                     // type of B (roll-our-own-RTTI)
+  bool embedded;                // B embedded into A or pointed at?
+  UnsatLink(void *ptr0, char const *id0, int kind0, bool embedded0);
+};
+
+//  // datastructures for dealing with unsatisified links where neither
+//  // party wants to know about the other
+//  struct UnsatBiLink {
+//    char const *from;
+//    char const *to;
+//    UnsatBiLink() : from(NULL), to(NULL) {}
+//  };
+
+// TODO: use an array of vtables for each tag, then we don't need this manual
+// dispatch stuff.
+
+// struct XmlKind {
+//   virtual void *construct() = 0;
+//   virtual bool upcastTo(void *obj, void *&target, XmlKind const &targetKind)
+//   { xfailure("cannot upcast from this type"); }
+//   virtual bool prependToFakeList(void *&list, void *obj, int objKind) { return false; }
+//   virtual bool appendToArrayStack(void *list, void *obj, int objKind) { return false; }
+//   class
+
+// };
+
+// template <class T>
+// struct XmlKindT : XmlKind {
+//   virtual void *construct() { return new T(); }
+
+// };
+
+// A subclass fills-in the methods that need to know about individual
+// tags.
+class XmlReader {
+  protected:
+  XmlReaderManager *manager;
+
+  public:
+  XmlReader() : manager(NULL) {}
+  virtual ~XmlReader() {}
+
+  public:
+  void setManager(XmlReaderManager *manager0);
+
+  protected:
+  void xmlUserFatalError(char const *msg) NORETURN;
+
+  // **** virtual API
+  public:
+
+  // Parse a tag: construct a node for a tag
+  virtual void *ctorNodeFromTag(int tag) = 0;
+
+  // Parse an attribute: register an attribute into the current node
+  virtual bool registerAttribute(void *target, int kind, int attr, char const *yytext0) = 0;
+
+  // Parse raw data: register some raw data into the current node
+  virtual bool registerStringToken(void *target, int kind, char const *yytext0) = 0;
+
+  // implement an eq-relation on tag kinds by mapping a tag kind to a
+  // category
+  virtual bool kind2kindCat(int kind, KindCategory *kindCat) = 0;
+
+  // **** Generic Convert
+
+  // note: return whether we know the answer, not the answer which
+  // happens to also be a bool
+  virtual bool recordKind(int kind, bool& answer) = 0;
+
+  // cast a pointer to the pointer type we need it to be; this is only
+  // needed because of multiple inheritance
+  virtual bool callOpAssignToEmbeddedObj(void *obj, int kind, void *target) = 0;
+  virtual bool upcastToWantedType(void *obj, int kind, void **target, int targetKind) = 0;
+  virtual bool prependToFakeList(void *&list, void *obj, int listKind) { return false; }
+  virtual bool reverseFakeList(void *&list, int listKind) { return false; }
+  virtual bool appendToArrayStack(void *list, void *obj, int listKind) { return false; }
+
+protected:
+
+  // TODO: use pushAlt() so we avoid extra object creation
+  template <class T>
+  static
+  void appendToArrayStack0(void *arrayStack, void *obj)
+  { static_cast<ArrayStack<T>*>(arrayStack)->push(* static_cast<T*>(obj));
+    delete static_cast<T*>(obj); }
+
+  template <class T>
+  static
+  void prependToFakeList0(void *&list, void *obj)
+  { list = static_cast<FakeList<T>*>(list)->prepend(static_cast<T*>(obj)); }
+
+  template <class T>
+  static
+  void reverseFakeList0(void *&list)
+  { list = static_cast<FakeList<T>*>(list)->reverse(); }
+
+};
+
+// XmlReader-s register themselves with the Manager which tries them
+// one at a time while handling incoming xml tags.
+class XmlReaderManager {
+  // the readers we are managing
+  ASTList<XmlReader> readers;
+
+  // **** Parsing
+  public:
+  char const *inputFname;       // just for error messages
+  XmlLexer &lexer;              // a lexer on a stream already opened from the file
+  // TODO: partition StringTables as much as possible
+  StringTable &strTable;        // for canonicalizing the StringRef's in the input file
+
+  private:
+  // the node (and its kind) for the last closing tag we saw; useful
+  // for extracting the top of the tree
+  void *lastNode;
+  int lastKind;
+
+  // parsing stack
+  struct ParseStackItem {
+    void *object;
+    int kind;
+    ASTList<UnsatLink> ulinks;
+  };
+
+  BitwiseArrayStack<ParseStackItem> parseStack;
+
+  // **** Satisfying links
+
+protected:
+  // Since AST nodes are embedded, we have to put this on to a
+  // different list than the ususal pointer unsatisfied links.
+  ASTList<UnsatLink> allUnsatLinks;
+//    ASTList<UnsatBiLink> unsatBiLinks;
+
+  // map object ids to the actual object
+  IdSObjDict id2obj;
+  // StringSObjDict<void> id2obj;
+
+  // map object ids to their kind ONLY IF there is a non-trivial
+  // upcast to make at the link satisfaction point
+  StringIntDict id2kind;
+  // StringSObjDict<int> id2kind;
+
+  public:
+  XmlReaderManager(XmlLexer &lexer0, StringTable &strTable0)
+    : inputFname(NULL)
+    , lexer(lexer0)
+    , strTable(strTable0)
+    , lastNode(NULL)            // also done in reset()
+    , lastKind(0)               // also done in reset()
+  {
+    reset();
+  }
+  virtual ~XmlReaderManager() {
+    // We no longer need to do the following since we *own* the readers:
+    //readers.removeAll_dontDelete();
+  }
+
+  // **** initialization
+  public:
+  // NOTE: XmlReaderManager owns the readers that have been registered with
+  // it. It deallocates them on destruction and also upon unregisterReader.
+  void registerReader(XmlReader *reader);
+
+  // unregister a reader (deallocating it in the process); this is only needed
+  // if you no longer want to use a reader, otherwise the reader is
+  // deallocated automatically on destruction.
+  void unregisterReader(XmlReader *reader);
+
+  void reset();
+
+  // **** parsing
+  public:
+  void parseOneTopLevelTag();
+
+  private:
+  void parseOneTagOrDatum();
+  bool readAttributes();
+
+  void appendListItem();
+  void appendNameMapItem();
+  void appendMapItem();
+
+public:
+  void *getNodeById(char const *id) { return id2obj.queryif(id); }
+
+  // add an UnsatLink to the current stack node's unsatLinks.  Owns ulinks.
+  void addUnsatLink(UnsatLink *ulink);
+
+private:
+  void *getTopNode0() { return parseStack.isEmpty() ? NULL : parseStack.top().object; }
+
+  // try to find a link from topmost list of unsatLinks.
+  UnsatLink *getUnsatLink(char const *id0);
+
+  // satisfy a single UnsatLink
+  void satisfyUnsatLink(UnsatLink const *ulink, void *obj);
+
+  // disjunctive dispatch to the list of readers
+  void kind2kindCat(int kind, KindCategory *kindCat);
+  KindCategory kind2kindCat(int kind) { KindCategory kindCat; kind2kindCat(kind, &kindCat); return kindCat; }
+  void *ctorNodeFromTag(int tag);
+  void registerAttribute(void *target, int kind, int attr, char const *yytext0);
+  void registerStringToken(void *target, int kind, char const *yytext0);
+
+  void append2List(void *list, int listKind, void *datum);
+  void insertIntoNameMap(void *map, int mapKind, StringRef name, void *datum);
+  void insertIntoMap(void *map0, int mapKind, void *key, void *item);
+
+  // **** parsing result
+  public:
+  // report an error to the user with source location information
+  void xmlUserFatalError(char const *msg) NORETURN;
+  // are we at the top level during parsing?
+  bool atTopLevel() {return parseStack.isEmpty();}
+  // return the top of the stack: the one tag that was parsed
+  void *getLastNode() {return lastNode;}
+  int getLastKind() {return lastKind;}
+  // peek at nth item (linear time)
+  void *getNthNode(int which) { return parseStack.nth(which).object; }
+  int getNthKind(int which) { return parseStack.nth(which).kind; }
+
+  // peek, with assertion for kind
+  void *getNthNode(int which, int kind)
+  { xassert(getNthKind(which) == kind); return getNthNode(which); }
+
+  // **** satisfying links
+  public:
+  void satisfyLinks();
+
+  private:
+  void satisfyLinks_Nodes();
+  void satisfyLinks_Nodes_1(bool processEmbedded);
+  void satisfyLinks_Lists();
+  void satisfyLinks_Maps();
+//    void satisfyLinks_Bidirectional();
+
+  public:
+  bool recordKind(int kind);
+
+  private:
+  // convert nodes
+  void callOpAssignToEmbeddedObj(void *obj, int kind, void *target);
+  void deleteObj(void *obj, int kind);
+  void *upcastToWantedType(void *obj, int kind, int targetKind);
+  void prependToFakeList(void *&list, void *obj, int listKind);
+  void reverseFakeList(void *&list, int listKind);
+  void appendToArrayStack(void *list, void *obj, int listKind);
+};
+
+#endif // XML_READER_H

Added: vendor/elsa/current/elsa/xml_test.mk
===================================================================
--- vendor/elsa/current/elsa/xml_test.mk	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_test.mk	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1710 @@
+# xml_test.mk            see license.txt for copyright and terms of use
+
+.SUFFIX:
+
+# DIFF := diff -u
+DIFF := diff -c -b
+
+PR := ./ccparse
+
+.PHONY: all
+all: clean
+all: check_ast
+all: check_type
+# all: check_lower
+
+TEST1 :=
+TEST1 += t0001.cc
+TEST1 += t0002.cc
+TEST1 += t0003.cc
+TEST1 += t0004.cc
+TEST1 += t0005.cc
+TEST1 += t0006.cc
+TEST1 += t0007.cc
+TEST1 += t0008.cc
+TEST1 += t0009.cc
+TEST1 += t0010.cc
+TEST1 += t0011.cc
+TEST1 += t0012.cc
+TEST1 += t0013.cc
+TEST1 += t0014.cc
+TEST1 += t0014a.cc
+TEST1 += t0015.cc
+TEST1 += t0016.cc
+TEST1 += t0017.cc
+TEST1 += t0018.cc
+TEST1 += t0019.cc
+TEST1 += t0020.cc
+TEST1 += t0021.cc
+TEST1 += t0022.cc
+TEST1 += t0023.cc
+TEST1 += t0024.cc
+TEST1 += t0025.cc
+TEST1 += t0026.cc
+TEST1 += t0027.cc
+TEST1 += t0028.cc
+TEST1 += t0029.cc
+TEST1 += t0030.cc
+TEST1 += t0030a.cc
+TEST1 += t0030b.cc
+TEST1 += t0031.cc
+TEST1 += t0032.cc
+TEST1 += t0033.cc
+TEST1 += t0034.cc
+TEST1 += t0035.cc
+TEST1 += t0036.cc
+TEST1 += t0037.cc
+TEST1 += t0038.cc
+TEST1 += t0039.cc
+TEST1 += t0040.cc
+TEST1 += t0041.cc
+TEST1 += t0042.cc
+TEST1 += t0043.cc
+TEST1 += t0044.cc
+TEST1 += t0045.cc
+TEST1 += t0046.cc
+TEST1 += t0047.cc
+TEST1 += t0048.cc
+TEST1 += t0049.cc
+TEST1 += t0050.cc
+TEST1 += t0051.cc
+TEST1 += t0052.cc
+TEST1 += t0053.cc
+TEST1 += t0054.cc
+TEST1 += t0055.cc
+TEST1 += t0056.cc
+TEST1 += t0057.cc
+TEST1 += t0058.cc
+TEST1 += t0059.cc
+TEST1 += t0060.cc
+TEST1 += t0061.cc
+TEST1 += t0062.cc
+TEST1 += t0063.cc
+TEST1 += t0064.cc
+TEST1 += t0065.cc
+TEST1 += t0066.cc
+TEST1 += t0067.cc
+TEST1 += t0068.cc
+TEST1 += t0069.cc
+TEST1 += t0070.cc
+TEST1 += t0071.cc
+TEST1 += t0072.cc
+TEST1 += t0073.cc
+TEST1 += t0074.cc
+TEST1 += t0075.cc
+TEST1 += t0076.cc
+TEST1 += t0077.cc
+TEST1 += t0078.cc
+TEST1 += t0079.cc
+TEST1 += t0080.cc
+TEST1 += t0081.cc
+TEST1 += t0082.cc
+TEST1 += t0083.cc
+TEST1 += t0084.cc
+TEST1 += t0085.cc
+TEST1 += t0086.cc
+TEST1 += t0087.cc
+TEST1 += t0088.cc
+TEST1 += t0089.cc
+TEST1 += t0090.cc
+TEST1 += t0091.cc
+TEST1 += t0092.cc
+TEST1 += t0093.cc
+TEST1 += t0094.cc
+TEST1 += t0095.cc
+TEST1 += t0096.cc
+TEST1 += t0097.cc
+TEST1 += t0098.cc
+TEST1 += t0099.cc
+TEST1 += t0100.cc
+
+TEST2 :=
+
+TEST2 += t0001.cc
+TEST2 += t0002.cc
+TEST2 += t0003.cc
+TEST2 += t0004.cc
+TEST2 += t0005.cc
+TEST2 += t0006.cc
+TEST2 += t0007.cc
+TEST2 += t0008.cc
+TEST2 += t0009.cc
+TEST2 += t0010.cc
+TEST2 += t0011.cc
+TEST2 += t0012.cc
+TEST2 += t0013.cc
+TEST2 += t0014.cc
+TEST2 += t0014a.cc
+TEST2 += t0015.cc
+TEST2 += t0016.cc
+TEST2 += t0017.cc
+TEST2 += t0018.cc
+TEST2 += t0019.cc
+TEST2 += t0020.cc
+TEST2 += t0021.cc
+TEST2 += t0022.cc
+TEST2 += t0023.cc
+TEST2 += t0024.cc
+TEST2 += t0025.cc
+TEST2 += t0026.cc
+TEST2 += t0027.cc
+TEST2 += t0028.cc
+TEST2 += t0029.cc
+TEST2 += t0030.cc
+TEST2 += t0030a.cc
+TEST2 += t0030b.cc
+TEST2 += t0031.cc
+TEST2 += t0032.cc
+TEST2 += t0033.cc
+TEST2 += t0034.cc
+TEST2 += t0035.cc
+TEST2 += t0036.cc
+TEST2 += t0037.cc
+TEST2 += t0038.cc
+TEST2 += t0039.cc
+TEST2 += t0040.cc
+TEST2 += t0041.cc
+TEST2 += t0042.cc
+TEST2 += t0043.cc
+TEST2 += t0044.cc
+TEST2 += t0045.cc
+TEST2 += t0046.cc
+TEST2 += t0047.cc
+TEST2 += t0048.cc
+TEST2 += t0049.cc
+TEST2 += t0050.cc
+TEST2 += t0051.cc
+TEST2 += t0052.cc
+TEST2 += t0053.cc
+TEST2 += t0054.cc
+TEST2 += t0055.cc
+TEST2 += t0056.cc
+TEST2 += t0057.cc
+TEST2 += t0058.cc
+TEST2 += t0059.cc
+TEST2 += t0060.cc
+TEST2 += t0061.cc
+TEST2 += t0062.cc
+TEST2 += t0063.cc
+TEST2 += t0064.cc
+TEST2 += t0065.cc
+TEST2 += t0066.cc
+TEST2 += t0067.cc
+TEST2 += t0068.cc
+TEST2 += t0069.cc
+TEST2 += t0070.cc
+TEST2 += t0071.cc
+TEST2 += t0072.cc
+TEST2 += t0073.cc
+TEST2 += t0074.cc
+TEST2 += t0075.cc
+TEST2 += t0076.cc
+TEST2 += t0077.cc
+TEST2 += t0078.cc
+TEST2 += t0079.cc
+TEST2 += t0080.cc
+TEST2 += t0081.cc
+TEST2 += t0082.cc
+TEST2 += t0083.cc
+TEST2 += t0084.cc
+TEST2 += t0085.cc
+TEST2 += t0086.cc
+TEST2 += t0087.cc
+TEST2 += t0088.cc
+TEST2 += t0089.cc
+TEST2 += t0090.cc
+TEST2 += t0091.cc
+TEST2 += t0092.cc
+TEST2 += t0093.cc
+TEST2 += t0094.cc
+TEST2 += t0095.cc
+TEST2 += t0096.cc
+TEST2 += t0097.cc
+TEST2 += t0098.cc
+TEST2 += t0099.cc
+TEST2 += t0100.cc
+TEST2 += t0101.cc
+TEST2 += t0102.cc
+TEST2 += t0103.cc
+TEST2 += t0104.cc
+TEST2 += t0105.cc
+TEST2 += t0106.cc
+TEST2 += t0107.cc
+TEST2 += t0108.cc
+TEST2 += t0108b.cc
+TEST2 += t0109.cc
+TEST2 += t0110.cc
+TEST2 += t0111.cc
+TEST2 += t0112.cc
+TEST2 += t0113.cc
+TEST2 += t0114.cc
+TEST2 += t0115.cc
+TEST2 += t0116.cc
+TEST2 += t0117.cc
+TEST2 += t0118.cc
+TEST2 += t0119.cc
+TEST2 += t0120.cc
+TEST2 += t0121.cc
+TEST2 += t0122.cc
+TEST2 += t0123.cc
+TEST2 += t0124.cc
+TEST2 += t0125.cc
+TEST2 += t0126.cc
+TEST2 += t0127.cc
+TEST2 += t0128.cc
+TEST2 += t0129.cc
+TEST2 += t0130.cc
+TEST2 += t0131.cc
+TEST2 += t0132.cc
+TEST2 += t0133.cc
+TEST2 += t0134.cc
+TEST2 += t0135.cc
+TEST2 += t0136.cc
+TEST2 += t0137.cc
+TEST2 += t0138.cc
+TEST2 += t0139.cc
+TEST2 += t0140.cc
+TEST2 += t0141.cc
+TEST2 += t0142.cc
+TEST2 += t0143.cc
+TEST2 += t0144.cc
+TEST2 += t0145.cc
+TEST2 += t0146.cc
+TEST2 += t0147.cc
+TEST2 += t0148.cc
+TEST2 += t0149.cc
+TEST2 += t0150.cc
+TEST2 += t0151.cc
+TEST2 += t0152.cc
+TEST2 += t0153.cc
+TEST2 += t0154.cc
+TEST2 += t0155.cc
+TEST2 += t0156.cc
+TEST2 += t0157.cc
+TEST2 += t0158.cc
+TEST2 += t0159.cc
+TEST2 += t0160.cc
+TEST2 += t0161.cc
+TEST2 += t0162.cc
+TEST2 += t0163.cc
+TEST2 += t0164.cc
+TEST2 += t0165.cc
+TEST2 += t0166.cc
+TEST2 += t0167.cc
+TEST2 += t0168.cc
+TEST2 += t0169.cc
+TEST2 += t0170.cc
+TEST2 += t0171.cc
+TEST2 += t0172.cc
+TEST2 += t0173.cc
+TEST2 += t0174.cc
+TEST2 += t0175.cc
+TEST2 += t0176.cc
+TEST2 += t0177.cc
+TEST2 += t0178.cc
+TEST2 += t0179.cc
+TEST2 += t0180.cc
+TEST2 += t0181.cc
+TEST2 += t0182.cc
+TEST2 += t0183.cc
+TEST2 += t0184.cc
+TEST2 += t0185.cc
+TEST2 += t0186.cc
+TEST2 += t0187.cc
+TEST2 += t0188.cc
+TEST2 += t0189.cc
+TEST2 += t0190.cc
+TEST2 += t0191.cc
+TEST2 += t0192.cc
+TEST2 += t0193.cc
+TEST2 += t0194.cc
+TEST2 += t0195.cc
+TEST2 += t0196.cc
+TEST2 += t0197.cc
+TEST2 += t0198.cc
+TEST2 += t0200.cc
+TEST2 += t0201.cc
+TEST2 += t0202.cc
+TEST2 += t0203.cc
+TEST2 += t0204.cc
+TEST2 += t0205.cc
+TEST2 += t0206.cc
+TEST2 += t0207.cc
+TEST2 += t0208.cc
+TEST2 += t0209.cc
+TEST2 += t0210.cc
+TEST2 += t0211.cc
+TEST2 += t0212.cc
+TEST2 += t0213.cc
+TEST2 += t0214.cc
+TEST2 += t0216.cc
+TEST2 += t0217.cc
+TEST2 += t0218.cc
+TEST2 += t0219.cc
+TEST2 += t0220.cc
+TEST2 += t0221.cc
+TEST2 += t0222.cc
+TEST2 += t0223.cc
+TEST2 += t0224.cc
+TEST2 += t0225.cc
+TEST2 += t0226.cc
+TEST2 += t0227.cc
+TEST2 += t0228.cc
+TEST2 += t0228b.cc
+TEST2 += t0229.cc
+TEST2 += t0230.cc
+TEST2 += t0231.cc
+TEST2 += t0232.cc
+TEST2 += t0233.cc
+TEST2 += t0234.cc
+TEST2 += t0235.cc
+TEST2 += t0236.cc
+TEST2 += t0237.cc
+TEST2 += t0238.cc
+TEST2 += t0239.cc
+TEST2 += t0240.cc
+TEST2 += t0241.cc
+TEST2 += t0242.cc
+TEST2 += t0243.cc
+TEST2 += t0244.cc
+TEST2 += t0245.cc
+TEST2 += t0246.cc
+TEST2 += t0247.cc
+TEST2 += t0248.cc
+TEST2 += t0249.cc
+TEST2 += t0250.cc
+TEST2 += t0251.cc
+TEST2 += t0252.cc
+TEST2 += t0253.cc
+TEST2 += t0254.cc
+TEST2 += t0255.cc
+TEST2 += t0256.cc
+TEST2 += t0257.cc
+TEST2 += t0258.cc
+TEST2 += t0259.cc
+TEST2 += t0260.cc
+TEST2 += t0261.cc
+TEST2 += t0262.cc
+TEST2 += t0263.cc
+TEST2 += t0264.cc
+TEST2 += t0265.cc
+TEST2 += t0266.cc
+TEST2 += t0268.cc
+TEST2 += t0268a.cc
+TEST2 += t0269.cc
+TEST2 += t0270.cc
+TEST2 += t0271.cc
+TEST2 += t0272.cc
+TEST2 += t0273.cc
+TEST2 += t0274.cc
+TEST2 += t0275.cc
+TEST2 += t0276.cc
+TEST2 += t0277.cc
+TEST2 += t0278.cc
+TEST2 += t0280.cc
+TEST2 += t0281.cc
+TEST2 += t0282.cc
+TEST2 += t0283.cc
+TEST2 += t0284.cc
+TEST2 += t0285.cc
+TEST2 += t0286.cc
+TEST2 += t0287.cc
+TEST2 += t0288.cc
+TEST2 += t0289.cc
+TEST2 += t0290.cc
+TEST2 += t0290a.cc
+TEST2 += t0291.cc
+TEST2 += t0292.cc
+TEST2 += t0293.cc
+TEST2 += t0294.cc
+TEST2 += t0295.cc
+TEST2 += t0296.cc
+TEST2 += t0297.cc
+TEST2 += t0298.cc
+TEST2 += t0299.cc
+TEST2 += t0300.cc
+TEST2 += t0301.cc
+TEST2 += t0302.cc
+TEST2 += t0303.cc
+TEST2 += t0304.cc
+TEST2 += t0305.cc
+TEST2 += t0306.cc
+TEST2 += t0307.cc
+TEST2 += t0308.cc
+TEST2 += t0309.cc
+TEST2 += t0310.cc
+TEST2 += t0311.cc
+TEST2 += t0312.cc
+TEST2 += t0313.cc
+TEST2 += t0314.cc
+TEST2 += t0315.cc
+TEST2 += t0316.cc
+TEST2 += t0317.cc
+TEST2 += t0318.cc
+TEST2 += t0319.cc
+TEST2 += t0320.cc
+TEST2 += t0321.cc
+TEST2 += t0322.cc
+TEST2 += t0323.cc
+TEST2 += t0324.cc
+TEST2 += t0325.cc
+TEST2 += t0326.cc
+TEST2 += t0327.cc
+TEST2 += t0328.cc
+TEST2 += t0329.cc
+TEST2 += t0330.cc
+TEST2 += t0331.cc
+TEST2 += t0332.cc
+TEST2 += t0333.cc
+TEST2 += t0334.cc
+TEST2 += t0335.cc
+TEST2 += t0336.cc
+TEST2 += t0337.cc
+TEST2 += t0338.cc
+TEST2 += t0339.cc
+TEST2 += t0340.cc
+TEST2 += t0341.cc
+TEST2 += t0342.cc
+TEST2 += t0343.cc
+TEST2 += t0344.cc
+TEST2 += t0345.cc
+TEST2 += t0346.cc
+TEST2 += t0347.cc
+TEST2 += t0348.cc
+TEST2 += t0349.cc
+TEST2 += t0350.cc
+TEST2 += t0351.cc
+TEST2 += t0352.cc
+TEST2 += t0353.cc
+TEST2 += t0354.cc
+TEST2 += t0355.cc
+TEST2 += t0356.cc
+TEST2 += t0357.cc
+TEST2 += t0358.cc
+TEST2 += t0359.cc
+TEST2 += t0360.cc
+TEST2 += t0361.cc
+TEST2 += t0362.cc
+TEST2 += t0363.cc
+TEST2 += t0364.cc
+TEST2 += t0365.cc
+TEST2 += t0366.cc
+TEST2 += t0367.cc
+TEST2 += t0368.cc
+TEST2 += t0369.cc
+TEST2 += t0370.cc
+TEST2 += t0371.cc
+TEST2 += t0372.cc
+TEST2 += t0373.cc
+TEST2 += t0374.cc
+TEST2 += t0375.cc
+TEST2 += t0376.cc
+TEST2 += t0377.cc
+TEST2 += t0378.cc
+TEST2 += t0379.cc
+TEST2 += t0380.cc
+TEST2 += t0381.cc
+TEST2 += t0382.cc
+TEST2 += t0383.cc
+TEST2 += t0384.cc
+TEST2 += t0385.cc
+TEST2 += t0386.cc
+TEST2 += t0387.cc
+TEST2 += t0388.cc
+TEST2 += t0389.cc
+TEST2 += t0390.cc
+TEST2 += t0391.cc
+TEST2 += t0392.cc
+TEST2 += t0393.cc
+TEST2 += t0394.cc
+TEST2 += t0395.cc
+TEST2 += t0396.cc
+TEST2 += t0397.cc
+TEST2 += t0398.cc
+TEST2 += t0399.cc
+TEST2 += t0400.cc
+TEST2 += t0401.cc
+TEST2 += t0402.cc
+TEST2 += t0403.cc
+TEST2 += t0404.cc
+TEST2 += t0405.cc
+TEST2 += t0406.cc
+TEST2 += t0407.cc
+TEST2 += t0408.cc
+TEST2 += t0409.cc
+TEST2 += t0410.cc
+TEST2 += t0411.cc
+TEST2 += t0412.cc
+TEST2 += t0413.cc
+TEST2 += t0414.cc
+TEST2 += t0415.cc
+TEST2 += t0416.cc
+TEST2 += t0417.error2.cc
+TEST2 += t0418.cc
+TEST2 += t0419.cc
+TEST2 += t0420.cc
+TEST2 += t0421.cc
+TEST2 += t0422.cc
+TEST2 += t0422a.cc
+TEST2 += t0423.cc
+TEST2 += t0424.cc
+TEST2 += t0425.cc
+TEST2 += t0426.cc
+TEST2 += t0427.cc
+TEST2 += t0428.cc
+TEST2 += t0429.cc
+TEST2 += t0430.cc
+TEST2 += t0431.cc
+TEST2 += t0432.cc
+TEST2 += t0433.cc
+TEST2 += t0434.cc
+TEST2 += t0437.cc
+TEST2 += t0438.cc
+TEST2 += t0438a.cc
+TEST2 += t0441.cc
+TEST2 += t0441a.cc
+TEST2 += t0442.cc
+TEST2 += t0443.cc
+TEST2 += t0444.cc
+TEST2 += t0445.cc
+TEST2 += t0446.cc
+TEST2 += t0447.cc
+TEST2 += t0448.cc
+TEST2 += t0449.cc
+TEST2 += t0450.cc
+TEST2 += t0451.cc
+TEST2 += t0452.cc
+TEST2 += t0453.cc
+TEST2 += t0454.cc
+TEST2 += t0455.cc
+TEST2 += t0456.cc
+TEST2 += t0457.cc
+TEST2 += t0458.cc
+TEST2 += t0459.cc
+TEST2 += t0460.cc
+TEST2 += t0461.cc
+TEST2 += t0462.cc
+TEST2 += t0463.cc
+TEST2 += t0467.cc
+TEST2 += t0468.cc
+TEST2 += t0469.cc
+TEST2 += t0470.cc
+TEST2 += t0471.cc
+TEST2 += t0472.error1.cc
+TEST2 += t0473.cc
+TEST2 += t0474.cc
+TEST2 += t0475.cc
+TEST2 += t0476.cc
+TEST2 += t0477.cc
+TEST2 += t0478.cc
+TEST2 += t0479.cc
+TEST2 += t0480.cc
+TEST2 += t0481.cc
+TEST2 += t0482.cc
+TEST2 += t0483.cc
+TEST2 += t0484.cc
+TEST2 += t0485.cc
+TEST2 += t0486.cc
+TEST2 += t0487.cc
+TEST2 += t0487b.cc
+TEST2 += t0488.cc
+TEST2 += t0489.cc
+TEST2 += t0490.cc
+TEST2 += t0491.cc
+TEST2 += t0492.cc
+TEST2 += t0493.cc
+TEST2 += t0494.cc
+TEST2 += t0495.cc
+TEST2 += t0496.cc
+TEST2 += t0497.cc
+TEST2 += t0498.cc
+TEST2 += t0499.cc
+TEST2 += t0501.cc
+TEST2 += t0502.cc
+TEST2 += t0503.cc
+TEST2 += t0504.cc
+TEST2 += t0505.cc
+TEST2 += t0506.cc
+TEST2 += t0507.cc
+TEST2 += t0508.cc
+TEST2 += t0510.cc
+TEST2 += t0511.cc
+TEST2 += t0512.cc
+TEST2 += t0513.cc
+TEST2 += t0514.cc
+TEST2 += t0515.cc
+TEST2 += t0516.cc
+TEST2 += t0517.cc
+TEST2 += t0522.cc
+TEST2 += t0523.cc
+TEST2 += t0524.cc
+TEST2 += t0525.cc
+TEST2 += t0526.cc
+TEST2 += t0527.cc
+TEST2 += t0528.cc
+TEST2 += t0529.cc
+TEST2 += t0530.cc
+TEST2 += t0531.cc
+TEST2 += t0532.cc
+TEST2 += t0533.cc
+TEST2 += t0534.cc
+TEST2 += t0535.cc
+TEST2 += t0536.cc
+TEST2 += t0537.cc
+TEST2 += t0538.cc
+TEST2 += t0540.cc
+TEST2 += t0541.cc
+TEST2 += t0542.cc
+TEST2 += t0543.cc
+TEST2 += t0544.cc
+TEST2 += t0545.cc
+TEST2 += t0546.cc
+TEST2 += t0547.cc
+TEST2 += t0548.cc
+TEST2 += t0549.cc
+TEST2 += t0550.cc
+TEST2 += t0551.cc
+TEST2 += t0552.cc
+TEST2 += t0553.cc
+TEST2 += t0555.cc
+TEST2 += t0557.cc
+TEST2 += t0558.cc
+TEST2 += t0559.cc
+TEST2 += t0560.cc
+TEST2 += t0561.cc
+TEST2 += t0562.cc
+TEST2 += t0563.cc
+TEST2 += t0564.cc
+TEST2 += t0566.cc
+TEST2 += t0567.cc
+TEST2 += t0568.cc
+TEST2 += t0569.cc
+TEST2 += d0001.cc
+TEST2 += d0002.cc
+TEST2 += d0003.cc
+TEST2 += d0004.cc
+TEST2 += d0005.cc
+TEST2 += d0006.cc
+TEST2 += d0007.cc
+TEST2 += d0008.cc
+TEST2 += d0009.cc
+TEST2 += d0010.cc
+TEST2 += d0011.cc
+TEST2 += d0012.cc
+TEST2 += d0013.cc
+TEST2 += d0014.cc
+TEST2 += d0015.cc
+TEST2 += d0016.cc
+TEST2 += d0017.cc
+TEST2 += d0018.cc
+TEST2 += d0019.cc
+TEST2 += d0020.cc
+TEST2 += d0021.cc
+TEST2 += d0022.cc
+TEST2 += d0023.cc
+TEST2 += d0024.cc
+TEST2 += d0025.cc
+TEST2 += d0026.cc
+TEST2 += d0027.cc
+TEST2 += d0028.cc
+TEST2 += d0029.cc
+TEST2 += d0032.cc
+TEST2 += d0034.cc
+TEST2 += d0035.cc
+TEST2 += d0036.cc
+TEST2 += d0037.cc
+TEST2 += d0038.cc
+TEST2 += d0039.cc
+TEST2 += d0046.cc
+TEST2 += d0046elab.cc
+TEST2 += d0047.cc
+TEST2 += d0048.cc
+TEST2 += d0048elab.cc
+TEST2 += d0049.cc
+TEST2 += d0050.cc
+TEST2 += d0050elab.cc
+TEST2 += d0051.cc
+TEST2 += d0051elab.cc
+TEST2 += d0052.cc
+TEST2 += d0053.cc
+TEST2 += d0054.cc
+TEST2 += d0055.cc
+TEST2 += d0056.cc
+TEST2 += d0057.cc
+TEST2 += d0058.cc
+TEST2 += d0059.cc
+TEST2 += d0060.cc
+TEST2 += d0061.cc
+TEST2 += d0064.cc
+TEST2 += d0065.cc
+TEST2 += d0066.cc
+TEST2 += d0067.cc
+TEST2 += d0068.cc
+TEST2 += d0069.cc
+TEST2 += d0070.cc
+TEST2 += d0071.cc
+TEST2 += d0072.cc
+TEST2 += d0073.cc
+TEST2 += d0074.cc
+TEST2 += d0075.cc
+TEST2 += d0079.cc
+TEST2 += d0080.cc
+TEST2 += d0084.cc
+TEST2 += d0088.cc
+TEST2 += d0089.cc
+TEST2 += d0090.cc
+TEST2 += d0091.cc
+TEST2 += d0097.cc
+TEST2 += d0098.cc
+TEST2 += d0099.cc
+TEST2 += d0100.cc
+TEST2 += d0101.cc
+TEST2 += d0102.cc
+TEST2 += d0103.cc
+TEST2 += d0104.cc
+TEST2 += d0105.cc
+TEST2 += d0106.cc
+TEST2 += d0107.cc
+TEST2 += d0108.cc
+TEST2 += d0109.cc
+TEST2 += d0110.cc
+TEST2 += d0111.cc
+TEST2 += d0112.cc
+TEST2 += d0113.cc
+TEST2 += d0114.cc
+TEST2 += d0116.cc
+TEST2 += d0117.cc
+TEST2 += d0118.cc
+TEST2 += d0119.cc
+TEST2 += d0120.cc
+TEST2 += d0124.cc
+TEST2 += k0001.cc
+TEST2 += k0002.cc
+TEST2 += k0003.cc
+TEST2 += k0004.cc
+TEST2 += k0005.cc
+TEST2 += k0005a.cc
+TEST2 += k0006.cc
+TEST2 += k0007.cc
+TEST2 += k0009.cc
+TEST2 += k0011.cc
+TEST2 += k0012.cc
+TEST2 += k0013.cc
+TEST2 += k0014.cc
+TEST2 += k0015.cc
+TEST2 += k0016.cc
+TEST2 += k0017.cc
+TEST2 += k0018.cc
+TEST2 += k0019.cc
+TEST2 += k0020.cc
+TEST2 += k0021.cc
+TEST2 += k0022.cc
+TEST2 += k0023.cc
+TEST2 += k0024.cc
+TEST2 += k0025.cc
+TEST2 += k0026.cc
+TEST2 += k0027.cc
+TEST2 += k0029.cc
+TEST2 += k0030.cc
+TEST2 += k0031.cc
+TEST2 += k0032.cc
+TEST2 += k0033.cc
+TEST2 += k0035.cc
+TEST2 += k0036.cc
+TEST2 += k0037.cc
+TEST2 += k0038.cc
+TEST2 += k0039.cc
+TEST2 += k0040.cc
+TEST2 += k0041.cc
+TEST2 += k0042.cc
+TEST2 += k0043.cc
+TEST2 += k0045.cc
+TEST2 += k0046.cc
+TEST2 += k0046a.cc
+TEST2 += k0047.cc
+TEST2 += k0048.cc
+TEST2 += k0049.cc
+TEST2 += k0050.cc
+TEST2 += k0051.cc
+TEST2 += k0052.cc
+TEST2 += k0053.cc
+TEST2 += k0054.cc
+TEST2 += k0055.cc
+TEST2 += k0056.cc
+TEST2 += k0057.cc
+TEST2 += k0058.cc
+TEST2 += sg0001.cc
+
+TEST3 :=
+
+# TEST3 += t0001.cc
+# TEST3 += t0002.cc
+# TEST3 += t0003.cc
+# TEST3 += t0004.cc
+# TEST3 += t0005.cc
+# TEST3 += t0006.cc
+# TEST3 += t0007.cc
+# TEST3 += t0008.cc
+# TEST3 += t0009.cc
+# TEST3 += t0010.cc
+# TEST3 += t0011.cc
+# TEST3 += t0012.cc
+# TEST3 += t0013.cc
+# TEST3 += t0014.cc
+# TEST3 += t0014a.cc
+# TEST3 += t0015.cc
+# TEST3 += t0016.cc
+# TEST3 += t0017.cc
+# TEST3 += t0018.cc
+# TEST3 += t0019.cc
+# TEST3 += t0020.cc
+# TEST3 += t0021.cc
+# TEST3 += t0022.cc
+# TEST3 += t0023.cc
+# TEST3 += t0024.cc
+# TEST3 += t0025.cc
+TEST3 += t0026.cc
+TEST3 += t0027.cc
+TEST3 += t0028.cc
+TEST3 += t0029.cc
+TEST3 += t0030.cc
+TEST3 += t0030a.cc
+TEST3 += t0030b.cc
+TEST3 += t0031.cc
+TEST3 += t0032.cc
+TEST3 += t0033.cc
+TEST3 += t0034.cc
+TEST3 += t0035.cc
+TEST3 += t0036.cc
+TEST3 += t0037.cc
+TEST3 += t0038.cc
+TEST3 += t0039.cc
+TEST3 += t0040.cc
+TEST3 += t0041.cc
+TEST3 += t0042.cc
+TEST3 += t0043.cc
+TEST3 += t0044.cc
+TEST3 += t0045.cc
+TEST3 += t0046.cc
+TEST3 += t0047.cc
+TEST3 += t0048.cc
+TEST3 += t0049.cc
+TEST3 += t0050.cc
+TEST3 += t0051.cc
+TEST3 += t0052.cc
+TEST3 += t0053.cc
+TEST3 += t0054.cc
+TEST3 += t0055.cc
+TEST3 += t0056.cc
+TEST3 += t0057.cc
+TEST3 += t0058.cc
+TEST3 += t0059.cc
+TEST3 += t0060.cc
+TEST3 += t0061.cc
+TEST3 += t0062.cc
+TEST3 += t0063.cc
+TEST3 += t0064.cc
+TEST3 += t0065.cc
+TEST3 += t0066.cc
+TEST3 += t0067.cc
+TEST3 += t0068.cc
+TEST3 += t0069.cc
+TEST3 += t0070.cc
+TEST3 += t0071.cc
+TEST3 += t0072.cc
+TEST3 += t0073.cc
+TEST3 += t0074.cc
+TEST3 += t0075.cc
+TEST3 += t0076.cc
+TEST3 += t0077.cc
+TEST3 += t0078.cc
+TEST3 += t0079.cc
+TEST3 += t0080.cc
+TEST3 += t0081.cc
+TEST3 += t0082.cc
+TEST3 += t0083.cc
+TEST3 += t0084.cc
+TEST3 += t0085.cc
+TEST3 += t0086.cc
+TEST3 += t0087.cc
+TEST3 += t0088.cc
+TEST3 += t0089.cc
+TEST3 += t0090.cc
+TEST3 += t0091.cc
+TEST3 += t0092.cc
+TEST3 += t0093.cc
+TEST3 += t0094.cc
+TEST3 += t0095.cc
+TEST3 += t0096.cc
+TEST3 += t0097.cc
+TEST3 += t0098.cc
+TEST3 += t0099.cc
+TEST3 += t0100.cc
+TEST3 += t0101.cc
+TEST3 += t0102.cc
+TEST3 += t0103.cc
+TEST3 += t0104.cc
+TEST3 += t0105.cc
+TEST3 += t0106.cc
+TEST3 += t0107.cc
+TEST3 += t0108.cc
+TEST3 += t0108b.cc
+TEST3 += t0109.cc
+TEST3 += t0110.cc
+TEST3 += t0111.cc
+TEST3 += t0112.cc
+TEST3 += t0113.cc
+TEST3 += t0114.cc
+TEST3 += t0115.cc
+TEST3 += t0116.cc
+TEST3 += t0117.cc
+TEST3 += t0118.cc
+TEST3 += t0119.cc
+TEST3 += t0120.cc
+TEST3 += t0121.cc
+TEST3 += t0122.cc
+TEST3 += t0123.cc
+TEST3 += t0124.cc
+TEST3 += t0125.cc
+TEST3 += t0126.cc
+TEST3 += t0127.cc
+TEST3 += t0128.cc
+TEST3 += t0129.cc
+TEST3 += t0130.cc
+TEST3 += t0131.cc
+TEST3 += t0132.cc
+TEST3 += t0133.cc
+TEST3 += t0134.cc
+TEST3 += t0135.cc
+TEST3 += t0136.cc
+TEST3 += t0137.cc
+TEST3 += t0138.cc
+TEST3 += t0139.cc
+TEST3 += t0140.cc
+TEST3 += t0141.cc
+TEST3 += t0142.cc
+TEST3 += t0143.cc
+TEST3 += t0144.cc
+TEST3 += t0145.cc
+TEST3 += t0146.cc
+TEST3 += t0147.cc
+TEST3 += t0148.cc
+TEST3 += t0149.cc
+TEST3 += t0150.cc
+TEST3 += t0151.cc
+TEST3 += t0152.cc
+TEST3 += t0153.cc
+TEST3 += t0154.cc
+TEST3 += t0155.cc
+TEST3 += t0156.cc
+TEST3 += t0157.cc
+TEST3 += t0158.cc
+TEST3 += t0159.cc
+TEST3 += t0160.cc
+TEST3 += t0161.cc
+TEST3 += t0162.cc
+TEST3 += t0163.cc
+TEST3 += t0164.cc
+TEST3 += t0165.cc
+TEST3 += t0166.cc
+TEST3 += t0167.cc
+TEST3 += t0168.cc
+TEST3 += t0169.cc
+TEST3 += t0170.cc
+TEST3 += t0171.cc
+TEST3 += t0172.cc
+TEST3 += t0173.cc
+TEST3 += t0174.cc
+TEST3 += t0175.cc
+TEST3 += t0176.cc
+TEST3 += t0177.cc
+TEST3 += t0178.cc
+TEST3 += t0179.cc
+TEST3 += t0180.cc
+TEST3 += t0181.cc
+TEST3 += t0182.cc
+TEST3 += t0183.cc
+TEST3 += t0184.cc
+TEST3 += t0185.cc
+TEST3 += t0186.cc
+TEST3 += t0187.cc
+TEST3 += t0188.cc
+TEST3 += t0189.cc
+TEST3 += t0190.cc
+TEST3 += t0191.cc
+TEST3 += t0192.cc
+TEST3 += t0193.cc
+TEST3 += t0194.cc
+TEST3 += t0195.cc
+TEST3 += t0196.cc
+TEST3 += t0197.cc
+TEST3 += t0198.cc
+TEST3 += t0200.cc
+TEST3 += t0201.cc
+TEST3 += t0202.cc
+TEST3 += t0203.cc
+TEST3 += t0204.cc
+TEST3 += t0205.cc
+TEST3 += t0206.cc
+TEST3 += t0207.cc
+TEST3 += t0208.cc
+TEST3 += t0209.cc
+TEST3 += t0210.cc
+TEST3 += t0211.cc
+TEST3 += t0212.cc
+TEST3 += t0213.cc
+TEST3 += t0214.cc
+TEST3 += t0216.cc
+TEST3 += t0217.cc
+TEST3 += t0218.cc
+TEST3 += t0219.cc
+TEST3 += t0220.cc
+TEST3 += t0221.cc
+TEST3 += t0222.cc
+TEST3 += t0223.cc
+TEST3 += t0224.cc
+TEST3 += t0225.cc
+TEST3 += t0226.cc
+TEST3 += t0227.cc
+TEST3 += t0228.cc
+TEST3 += t0228b.cc
+TEST3 += t0229.cc
+TEST3 += t0230.cc
+TEST3 += t0231.cc
+TEST3 += t0232.cc
+TEST3 += t0233.cc
+TEST3 += t0234.cc
+TEST3 += t0235.cc
+TEST3 += t0236.cc
+TEST3 += t0237.cc
+TEST3 += t0238.cc
+TEST3 += t0239.cc
+TEST3 += t0240.cc
+TEST3 += t0241.cc
+TEST3 += t0242.cc
+TEST3 += t0243.cc
+TEST3 += t0244.cc
+TEST3 += t0245.cc
+TEST3 += t0246.cc
+TEST3 += t0247.cc
+TEST3 += t0248.cc
+TEST3 += t0249.cc
+TEST3 += t0250.cc
+TEST3 += t0251.cc
+TEST3 += t0252.cc
+TEST3 += t0253.cc
+TEST3 += t0254.cc
+TEST3 += t0255.cc
+TEST3 += t0256.cc
+TEST3 += t0257.cc
+TEST3 += t0258.cc
+TEST3 += t0259.cc
+TEST3 += t0260.cc
+TEST3 += t0261.cc
+TEST3 += t0262.cc
+TEST3 += t0263.cc
+TEST3 += t0264.cc
+TEST3 += t0265.cc
+TEST3 += t0266.cc
+TEST3 += t0268.cc
+TEST3 += t0268a.cc
+TEST3 += t0269.cc
+TEST3 += t0270.cc
+TEST3 += t0271.cc
+TEST3 += t0272.cc
+TEST3 += t0273.cc
+TEST3 += t0274.cc
+TEST3 += t0275.cc
+TEST3 += t0276.cc
+TEST3 += t0277.cc
+TEST3 += t0278.cc
+TEST3 += t0280.cc
+TEST3 += t0281.cc
+TEST3 += t0282.cc
+TEST3 += t0283.cc
+TEST3 += t0284.cc
+TEST3 += t0285.cc
+TEST3 += t0286.cc
+TEST3 += t0287.cc
+TEST3 += t0288.cc
+TEST3 += t0289.cc
+TEST3 += t0290.cc
+TEST3 += t0290a.cc
+TEST3 += t0291.cc
+TEST3 += t0292.cc
+TEST3 += t0293.cc
+TEST3 += t0294.cc
+TEST3 += t0295.cc
+TEST3 += t0296.cc
+TEST3 += t0297.cc
+TEST3 += t0298.cc
+TEST3 += t0299.cc
+TEST3 += t0300.cc
+TEST3 += t0301.cc
+TEST3 += t0302.cc
+TEST3 += t0303.cc
+TEST3 += t0304.cc
+TEST3 += t0305.cc
+TEST3 += t0306.cc
+TEST3 += t0307.cc
+TEST3 += t0308.cc
+TEST3 += t0309.cc
+TEST3 += t0310.cc
+TEST3 += t0311.cc
+TEST3 += t0312.cc
+TEST3 += t0313.cc
+TEST3 += t0314.cc
+TEST3 += t0315.cc
+TEST3 += t0316.cc
+TEST3 += t0317.cc
+TEST3 += t0318.cc
+TEST3 += t0319.cc
+TEST3 += t0320.cc
+TEST3 += t0321.cc
+TEST3 += t0322.cc
+TEST3 += t0323.cc
+TEST3 += t0324.cc
+TEST3 += t0325.cc
+TEST3 += t0326.cc
+TEST3 += t0327.cc
+TEST3 += t0328.cc
+TEST3 += t0329.cc
+TEST3 += t0330.cc
+TEST3 += t0331.cc
+TEST3 += t0332.cc
+TEST3 += t0333.cc
+TEST3 += t0334.cc
+TEST3 += t0335.cc
+TEST3 += t0336.cc
+TEST3 += t0337.cc
+TEST3 += t0338.cc
+TEST3 += t0339.cc
+TEST3 += t0340.cc
+TEST3 += t0341.cc
+TEST3 += t0342.cc
+TEST3 += t0343.cc
+TEST3 += t0344.cc
+TEST3 += t0345.cc
+TEST3 += t0346.cc
+TEST3 += t0347.cc
+TEST3 += t0348.cc
+TEST3 += t0349.cc
+TEST3 += t0350.cc
+TEST3 += t0351.cc
+TEST3 += t0352.cc
+TEST3 += t0353.cc
+TEST3 += t0354.cc
+TEST3 += t0355.cc
+TEST3 += t0356.cc
+TEST3 += t0357.cc
+TEST3 += t0358.cc
+TEST3 += t0359.cc
+TEST3 += t0360.cc
+TEST3 += t0361.cc
+TEST3 += t0362.cc
+TEST3 += t0363.cc
+TEST3 += t0364.cc
+TEST3 += t0365.cc
+TEST3 += t0366.cc
+TEST3 += t0367.cc
+TEST3 += t0368.cc
+TEST3 += t0369.cc
+TEST3 += t0370.cc
+TEST3 += t0371.cc
+TEST3 += t0372.cc
+TEST3 += t0373.cc
+TEST3 += t0374.cc
+TEST3 += t0375.cc
+TEST3 += t0376.cc
+TEST3 += t0377.cc
+TEST3 += t0378.cc
+TEST3 += t0379.cc
+TEST3 += t0380.cc
+TEST3 += t0381.cc
+TEST3 += t0382.cc
+TEST3 += t0383.cc
+TEST3 += t0384.cc
+TEST3 += t0385.cc
+TEST3 += t0386.cc
+TEST3 += t0387.cc
+TEST3 += t0388.cc
+TEST3 += t0389.cc
+TEST3 += t0390.cc
+TEST3 += t0391.cc
+TEST3 += t0392.cc
+TEST3 += t0393.cc
+TEST3 += t0394.cc
+TEST3 += t0395.cc
+TEST3 += t0396.cc
+TEST3 += t0397.cc
+TEST3 += t0398.cc
+TEST3 += t0399.cc
+TEST3 += t0400.cc
+TEST3 += t0401.cc
+TEST3 += t0402.cc
+TEST3 += t0403.cc
+TEST3 += t0404.cc
+TEST3 += t0405.cc
+TEST3 += t0406.cc
+TEST3 += t0407.cc
+TEST3 += t0408.cc
+TEST3 += t0409.cc
+TEST3 += t0410.cc
+TEST3 += t0411.cc
+TEST3 += t0412.cc
+TEST3 += t0413.cc
+TEST3 += t0414.cc
+TEST3 += t0415.cc
+TEST3 += t0416.cc
+TEST3 += t0417.error2.cc
+TEST3 += t0418.cc
+TEST3 += t0419.cc
+TEST3 += t0420.cc
+TEST3 += t0421.cc
+TEST3 += t0422.cc
+TEST3 += t0422a.cc
+TEST3 += t0423.cc
+TEST3 += t0424.cc
+TEST3 += t0425.cc
+TEST3 += t0426.cc
+TEST3 += t0427.cc
+TEST3 += t0428.cc
+TEST3 += t0429.cc
+TEST3 += t0430.cc
+TEST3 += t0431.cc
+TEST3 += t0432.cc
+TEST3 += t0433.cc
+TEST3 += t0434.cc
+TEST3 += t0437.cc
+TEST3 += t0438.cc
+TEST3 += t0438a.cc
+TEST3 += t0441.cc
+TEST3 += t0441a.cc
+TEST3 += t0442.cc
+TEST3 += t0443.cc
+TEST3 += t0444.cc
+TEST3 += t0445.cc
+TEST3 += t0446.cc
+TEST3 += t0447.cc
+TEST3 += t0448.cc
+TEST3 += t0449.cc
+TEST3 += t0450.cc
+TEST3 += t0451.cc
+TEST3 += t0452.cc
+TEST3 += t0453.cc
+TEST3 += t0454.cc
+TEST3 += t0455.cc
+TEST3 += t0456.cc
+TEST3 += t0457.cc
+TEST3 += t0458.cc
+TEST3 += t0459.cc
+TEST3 += t0460.cc
+TEST3 += t0461.cc
+TEST3 += t0462.cc
+TEST3 += t0463.cc
+TEST3 += t0467.cc
+TEST3 += t0468.cc
+TEST3 += t0469.cc
+TEST3 += t0470.cc
+TEST3 += t0471.cc
+TEST3 += t0472.error1.cc
+TEST3 += t0473.cc
+TEST3 += t0474.cc
+TEST3 += t0475.cc
+TEST3 += t0476.cc
+TEST3 += t0477.cc
+TEST3 += t0478.cc
+TEST3 += t0479.cc
+TEST3 += t0480.cc
+TEST3 += t0481.cc
+TEST3 += t0482.cc
+TEST3 += t0483.cc
+TEST3 += t0484.cc
+TEST3 += t0485.cc
+TEST3 += t0486.cc
+TEST3 += t0487.cc
+TEST3 += t0487b.cc
+TEST3 += t0488.cc
+TEST3 += t0489.cc
+TEST3 += t0490.cc
+TEST3 += t0491.cc
+TEST3 += t0492.cc
+TEST3 += t0493.cc
+TEST3 += t0494.cc
+TEST3 += t0495.cc
+TEST3 += t0496.cc
+TEST3 += t0497.cc
+TEST3 += t0498.cc
+TEST3 += t0499.cc
+TEST3 += t0501.cc
+TEST3 += t0502.cc
+TEST3 += t0503.cc
+TEST3 += t0504.cc
+TEST3 += t0505.cc
+TEST3 += t0506.cc
+TEST3 += t0507.cc
+TEST3 += t0508.cc
+TEST3 += t0510.cc
+TEST3 += t0511.cc
+TEST3 += t0512.cc
+TEST3 += t0513.cc
+TEST3 += t0514.cc
+TEST3 += t0515.cc
+TEST3 += t0516.cc
+TEST3 += t0517.cc
+TEST3 += t0522.cc
+TEST3 += t0523.cc
+TEST3 += t0524.cc
+TEST3 += t0525.cc
+TEST3 += t0526.cc
+TEST3 += t0527.cc
+TEST3 += t0528.cc
+TEST3 += t0529.cc
+TEST3 += t0530.cc
+TEST3 += t0531.cc
+TEST3 += t0532.cc
+TEST3 += t0533.cc
+TEST3 += t0534.cc
+TEST3 += t0535.cc
+TEST3 += t0536.cc
+TEST3 += t0537.cc
+TEST3 += t0538.cc
+TEST3 += t0540.cc
+TEST3 += t0541.cc
+TEST3 += t0542.cc
+TEST3 += t0543.cc
+TEST3 += t0544.cc
+TEST3 += t0545.cc
+TEST3 += t0546.cc
+TEST3 += t0547.cc
+TEST3 += t0548.cc
+TEST3 += t0549.cc
+TEST3 += t0550.cc
+TEST3 += t0551.cc
+TEST3 += t0552.cc
+TEST3 += t0553.cc
+TEST3 += t0555.cc
+TEST3 += t0557.cc
+TEST3 += t0558.cc
+TEST3 += t0559.cc
+TEST3 += t0560.cc
+TEST3 += t0561.cc
+TEST3 += t0562.cc
+TEST3 += t0563.cc
+TEST3 += t0564.cc
+TEST3 += t0566.cc
+TEST3 += t0567.cc
+TEST3 += t0568.cc
+TEST3 += t0569.cc
+TEST3 += d0001.cc
+TEST3 += d0002.cc
+TEST3 += d0003.cc
+TEST3 += d0004.cc
+TEST3 += d0005.cc
+TEST3 += d0006.cc
+TEST3 += d0007.cc
+TEST3 += d0008.cc
+TEST3 += d0009.cc
+TEST3 += d0010.cc
+TEST3 += d0011.cc
+TEST3 += d0012.cc
+TEST3 += d0013.cc
+TEST3 += d0014.cc
+TEST3 += d0015.cc
+TEST3 += d0016.cc
+TEST3 += d0017.cc
+TEST3 += d0018.cc
+TEST3 += d0019.cc
+TEST3 += d0020.cc
+TEST3 += d0021.cc
+TEST3 += d0022.cc
+TEST3 += d0023.cc
+TEST3 += d0024.cc
+TEST3 += d0025.cc
+TEST3 += d0026.cc
+TEST3 += d0027.cc
+TEST3 += d0028.cc
+TEST3 += d0029.cc
+TEST3 += d0032.cc
+TEST3 += d0034.cc
+TEST3 += d0035.cc
+TEST3 += d0036.cc
+TEST3 += d0037.cc
+TEST3 += d0038.cc
+TEST3 += d0039.cc
+TEST3 += d0046.cc
+TEST3 += d0046elab.cc
+TEST3 += d0047.cc
+TEST3 += d0048.cc
+TEST3 += d0048elab.cc
+TEST3 += d0049.cc
+TEST3 += d0050.cc
+TEST3 += d0050elab.cc
+TEST3 += d0051.cc
+TEST3 += d0051elab.cc
+TEST3 += d0052.cc
+TEST3 += d0053.cc
+TEST3 += d0054.cc
+TEST3 += d0055.cc
+TEST3 += d0056.cc
+TEST3 += d0057.cc
+TEST3 += d0058.cc
+TEST3 += d0059.cc
+TEST3 += d0060.cc
+TEST3 += d0061.cc
+TEST3 += d0064.cc
+TEST3 += d0065.cc
+TEST3 += d0066.cc
+TEST3 += d0067.cc
+TEST3 += d0068.cc
+TEST3 += d0069.cc
+TEST3 += d0070.cc
+TEST3 += d0071.cc
+TEST3 += d0072.cc
+TEST3 += d0073.cc
+TEST3 += d0074.cc
+TEST3 += d0075.cc
+TEST3 += d0079.cc
+TEST3 += d0080.cc
+TEST3 += d0084.cc
+TEST3 += d0088.cc
+TEST3 += d0089.cc
+TEST3 += d0090.cc
+TEST3 += d0091.cc
+TEST3 += d0097.cc
+TEST3 += d0098.cc
+TEST3 += d0099.cc
+TEST3 += d0100.cc
+TEST3 += d0101.cc
+TEST3 += d0102.cc
+TEST3 += d0103.cc
+TEST3 += d0104.cc
+TEST3 += d0105.cc
+TEST3 += d0106.cc
+TEST3 += d0107.cc
+TEST3 += d0108.cc
+TEST3 += d0109.cc
+TEST3 += d0110.cc
+TEST3 += d0111.cc
+TEST3 += d0112.cc
+TEST3 += d0113.cc
+TEST3 += d0114.cc
+TEST3 += d0116.cc
+TEST3 += d0117.cc
+TEST3 += d0118.cc
+TEST3 += d0119.cc
+TEST3 += d0120.cc
+TEST3 += d0124.cc
+TEST3 += k0001.cc
+TEST3 += k0002.cc
+TEST3 += k0003.cc
+TEST3 += k0004.cc
+TEST3 += k0005.cc
+TEST3 += k0005a.cc
+TEST3 += k0006.cc
+TEST3 += k0007.cc
+TEST3 += k0009.cc
+TEST3 += k0011.cc
+TEST3 += k0012.cc
+TEST3 += k0013.cc
+TEST3 += k0014.cc
+TEST3 += k0015.cc
+TEST3 += k0016.cc
+TEST3 += k0017.cc
+TEST3 += k0018.cc
+TEST3 += k0019.cc
+TEST3 += k0020.cc
+TEST3 += k0021.cc
+TEST3 += k0022.cc
+TEST3 += k0023.cc
+TEST3 += k0024.cc
+TEST3 += k0025.cc
+TEST3 += k0026.cc
+TEST3 += k0027.cc
+TEST3 += k0029.cc
+TEST3 += k0030.cc
+TEST3 += k0031.cc
+TEST3 += k0032.cc
+TEST3 += k0033.cc
+TEST3 += k0035.cc
+TEST3 += k0036.cc
+TEST3 += k0037.cc
+TEST3 += k0038.cc
+TEST3 += k0039.cc
+TEST3 += k0040.cc
+TEST3 += k0041.cc
+TEST3 += k0042.cc
+TEST3 += k0043.cc
+TEST3 += k0045.cc
+TEST3 += k0046.cc
+TEST3 += k0046a.cc
+TEST3 += k0047.cc
+TEST3 += k0048.cc
+TEST3 += k0049.cc
+TEST3 += k0050.cc
+TEST3 += k0051.cc
+TEST3 += k0052.cc
+TEST3 += k0053.cc
+TEST3 += k0054.cc
+TEST3 += k0055.cc
+TEST3 += k0056.cc
+TEST3 += k0057.cc
+TEST3 += k0058.cc
+TEST3 += sg0001.cc
+
+TOCLEAN :=
+
+XML_FLAGS :=
+# see if the user wants us to indent the XML; default to off because
+# it is faster and smaller
+ifdef XML_INDENT
+XML_FLAGS += -tr xmlPrintAST-indent
+endif
+
+# something is not working about serializing source locations that go
+# through hashlines
+# ifdef XML_HASHLINE
+# else
+# XML_FLAGS += -tr nohashline
+# endif
+
+# **************** section A: there is no section A
+
+# **************** section B: check parsing commutes with xml serialization
+
+T1D := $(addprefix outdir/,$(TEST1))
+TOCLEAN += outdir/*.B0.dp outdir/*.B0.dp_filtered outdir/*.B1.xml outdir/*.B1.xml_filtered outdir/*.B2.xml.dp outdir/*.B2.xml.dp_filtered outdir/*.B3.diff
+
+# generate initial debug-print
+$(addsuffix .B0.dp,$(T1D)): outdir/%.B0.dp: in/%
+	$(PR) -tr no-elaborate,prettyPrint $(XML_FLAGS) $< > $@
+$(addsuffix .B0.dp_filtered,$(T1D)): outdir/%.B0.dp_filtered: outdir/%.B0.dp
+	./chop_out < $< > $@
+
+# generate xml print
+$(addsuffix .B1.xml,$(T1D)): outdir/%.B1.xml: in/%
+	$(PR) -tr no-elaborate,xmlPrintAST $(XML_FLAGS) $< > $@
+$(addsuffix .B1.xml_filtered,$(T1D)): outdir/%.B1.xml_filtered: outdir/%.B1.xml
+	./chop_out < $< > $@
+
+# parse xml and generate second debug-print
+$(addsuffix .B2.xml.dp,$(T1D)): outdir/%.B2.xml.dp: outdir/%.B1.xml_filtered
+# NOTE: we omit the tracing flag parseXml-no-danglingPointers because
+# it will fail on a pure AST de-serialization
+	$(PR) -tr parseXml,no-elaborate,prettyPrint $(XML_FLAGS) $< > $@
+$(addsuffix .B2.xml.dp_filtered,$(T1D)): outdir/%.B2.xml.dp_filtered: outdir/%.B2.xml.dp
+	./chop_out < $< > $@
+
+# diff the two debug-prints
+$(addsuffix .B3.diff,$(T1D)): outdir/%.B3.diff: outdir/%.B0.dp_filtered outdir/%.B2.xml.dp_filtered
+# NOTE: do not, say, replace this with a pipe into 'tee' because that
+# masks the return code and prevents make from stopping if there is a
+# difference
+	$(DIFF) $^ > $@
+# if it passes, delete the temporary files
+	rm -f outdir/$*.B?.*
+
+check_ast: $(addsuffix .B3.diff,$(T1D))
+
+# **************** section C: check typechecking commutes with xml serialization
+
+T2D := $(addprefix outdir/,$(TEST2))
+TOCLEAN += outdir/*.C0.dp outdir/*.C0.dp_filtered outdir/*.C1.xml outdir/*.C1.xml_filtered outdir/*.C2.xml.dp outdir/*.C2.xml.dp_filtered outdir/*.C3.diff outdir/*.C4.xml
+
+# generate initial debug-print
+$(addsuffix .C0.dp,$(T2D)): outdir/%.C0.dp: in/%
+	$(PR) -tr no-elaborate,printTypedAST $(XML_FLAGS) $< > $@
+$(addsuffix .C0.dp_filtered,$(T2D)): outdir/%.C0.dp_filtered: outdir/%.C0.dp
+	./filter_elsa_noise < $< > $@
+
+# generate xml print
+$(addsuffix .C1.xml,$(T2D)): outdir/%.C1.xml: in/%
+	$(PR) -tr no-elaborate,xmlPrintAST,xmlPrintAST-types $(XML_FLAGS) $< > $@
+$(addsuffix .C1.xml_filtered,$(T2D)): outdir/%.C1.xml_filtered: outdir/%.C1.xml
+	./chop_out < $< > $@
+
+# parse xml and generate second debug-print
+$(addsuffix .C2.xml.dp,$(T2D)): outdir/%.C2.xml.dp: outdir/%.C1.xml_filtered
+	$(PR) -tr parseXml,parseXml-no-danglingPointers,no-typecheck,no-elaborate,printAST $(XML_FLAGS) $< > $@
+$(addsuffix .C2.xml.dp_filtered,$(T2D)): outdir/%.C2.xml.dp_filtered: outdir/%.C2.xml.dp
+	./filter_elsa_noise < $< > $@
+
+# diff the two debug-prints
+$(addsuffix .C3.diff,$(T2D)): outdir/%.C3.diff: outdir/%.C0.dp_filtered outdir/%.C2.xml.dp_filtered
+# NOTE: do not, say, replace this with a pipe into 'tee' because that
+# masks the return code and prevents make from stopping if there is a
+# difference
+	$(DIFF) $^ > $@
+# if it passes, delete the temporary files
+	rm -f outdir/$*.C?.*
+
+# # parse xml and generate second xml print
+# $(addsuffix .C4.xml,$(T2D)): outdir/%.C4.xml: outdir/%.C1.xml_filtered
+# 	$(PR) -tr parseXml,parseXml-no-danglingPointers,no-typecheck,no-elaborate,xmlPrintAST,xmlPrintAST-types $(XML_FLAGS) $< > $@
+# $(addsuffix .C4.xml_filtered,$(T2D)): outdir/%.C4.xml_filtered: outdir/%.C4.xml
+# 	./chop_out < $< > $@
+
+# # diff the two xml-prints
+# $(addsuffix .C5.diff,$(T2D)): outdir/%.C5.diff: outdir/%.C1.xml_filtered outdir/%.C4.xml_filtered
+# # NOTE: do not, say, replace this with a pipe into 'tee' because that
+# # masks the return code and prevents make from stopping if there is a
+# # difference
+# 	./filter_ids < $(filter %.C1.xml_filtered,$^) > outdir/a1.xml
+# 	./filter_ids < $(filter %.C4.xml_filtered,$^) > outdir/a4.xml
+# 	$(DIFF) outdir/a1.xml outdir/a4.xml > $@
+# # if it passes, delete the temporary files
+# $(error finish this)
+# 	rm -f $^ $@
+
+.PHONY: check_type
+check_type: $(addsuffix .C3.diff,$(T2D))
+
+# when it works, this test will find things that are being written but
+# not read.  Right now, the order of printing is not canonical so it
+# is not yet useful.
+# check_type: $(addsuffix .C5.diff,$(T2D))
+
+# **************** section D: check lowering commutes with xml serialization
+
+# # NOTE: this is not implemented.
+# $(error this is not implemented)
+
+# T3D := $(addprefix outdir/,$(TEST3))
+# TOCLEAN += outdir/*.D0.dp outdir/*.D0.dp_filtered outdir/*.D1.xml outdir/*.D1.xml_filtered outdir/*.D2.xml.dp outdir/*.D2.xml.dp_filtered outdir/*.D3.diff outdir/*.D4.xml
+
+# # generate initial debug-print
+# $(addsuffix .D0.dp,$(T3D)): outdir/%.D0.dp: in/%
+# 	$(PR) -tr prettyPrint $(XML_FLAGS) $< > $@
+# $(addsuffix .D0.dp_filtered,$(T3D)): outdir/%.D0.dp_filtered: outdir/%.D0.dp
+# 	./chop_out < $< > $@
+
+# # generate xml print
+# $(addsuffix .D1.xml,$(T3D)): outdir/%.D1.xml: in/%
+# 	$(PR) -tr xmlPrintAST,xmlPrintAST-types,xmlPrintAST-lowered $(XML_FLAGS) $< > $@
+# $(addsuffix .D1.xml_filtered,$(T3D)): outdir/%.D1.xml_filtered: outdir/%.D1.xml
+# 	./chop_out < $< > $@
+
+# # parse xml and generate second debug-print
+# $(addsuffix .D2.xml.dp,$(T3D)): outdir/%.D2.xml.dp: outdir/%.D1.xml_filtered
+# 	$(PR) -tr parseXml,parseXml-no-danglingPointers,no-typecheck,no-elaborate,prettyPrint $(XML_FLAGS) $< > $@
+# $(addsuffix .D2.xml.dp_filtered,$(T3D)): outdir/%.D2.xml.dp_filtered: outdir/%.D2.xml.dp
+# 	./chop_out < $< > $@
+
+# # diff the two debug-prints
+# $(addsuffix .D3.diff,$(T3D)): outdir/%.D3.diff: outdir/%.D0.dp_filtered outdir/%.D2.xml.dp_filtered
+# # NOTE: do not, say, replace this with a pipe into 'tee' because that
+# # masks the return code and prevents make from stopping if there is a
+# # difference
+# 	$(DIFF) $^ > $@
+
+# .PHONY: check_lower
+# check_lower: $(addsuffix .D3.diff,$(T3D))
+
+# ****************
+
+.PHONY: clean
+clean:
+	find outdir -type f -maxdepth 1 | grep -v .cvsignore | xargs rm -f
+
+# this probably results in an arg too long error
+#	rm -f $(TOCLEAN)


Property changes on: vendor/elsa/current/elsa/xml_test.mk
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/elsa/xml_type.tokens
===================================================================
--- vendor/elsa/current/elsa/xml_type.tokens	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_type.tokens	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,138 @@
+# Xml tokens for serializing typesystem nodes
+
+# Type nodes
+Type
+CVAtomicType
+PointerType
+ReferenceType
+FunctionType
+  FunctionType_ExnSpec
+ArrayType
+PointerToMemberType
+# fields
+atomic
+atType
+retType
+eltType
+inClassNAT
+cv
+size
+
+# AtomicType nodes
+AtomicType
+NamedAtomicType
+SimpleType
+CompoundType
+EnumType
+  EnumType_Value
+TypeVariable
+PseudoInstantiation
+DependentQType
+# more fields
+typedefVar
+forward
+dataMembers
+virtualBases
+subobj
+conversionOperators
+instName
+syntax
+parameterizingScope
+selfType
+valueIndex
+nextValue
+hasNegativeValues
+primary
+first
+name
+access
+type
+bases
+args
+rest
+fullyQualifiedMangledName
+
+# Other
+Variable
+Scope
+BaseClass
+BaseClassSubobj
+OverloadSet
+STemplateArgument
+TemplateInfo
+InheritedTemplateParams
+# yet more fields
+flags
+value
+defaultParamType
+funcDefn
+scope
+# should no longer be using this: intData
+real
+maybeUsedAsAlias
+user1
+user2
+usingAlias_or_parameterizedEntity
+templInfo
+canAcceptNames
+parentScope
+scopeKind
+hasValue
+namespaceVar
+curCompound
+ct
+variables
+typeTags
+parents
+templateParams
+overload
+set
+inheritedParams
+instantiationOf
+instantiations
+specializationOf
+specializations
+arguments
+partialInstantiationOf
+partialInstantiations
+argumentsToPrimary
+defnScope
+definitionTemplateInfo
+enclosing
+instLoc
+# params
+kind
+t
+i
+v
+e
+at
+parameterOrdinal
+
+# Some containers; I no longer care about order
+#   ObjList
+List_CompoundType_bases
+List_CompoundType_virtualBases
+List_PseudoInstantiation_args
+List_TemplateInfo_inheritedParams
+List_TemplateInfo_arguments
+List_TemplateInfo_argumentsToPrimary
+List_PQ_qualifier_sargs
+List_PQ_template_sargs
+#   SObjList
+List_FunctionType_params
+List_CompoundType_dataMembers
+List_CompoundType_conversionOperators
+List_BaseClassSubobj_parents
+List_ExnSpec_types
+List_Scope_templateParams
+List_OverloadSet_set
+List_TemplateInfo_instantiations
+List_TemplateInfo_specializations
+List_TemplateInfo_partialInstantiations
+List_TemplateParams_params
+
+#   StringRefMap
+NameMap_Scope_variables
+NameMap_Scope_typeTags
+NameMap_EnumType_valueIndex

Added: vendor/elsa/current/elsa/xml_type_id.h
===================================================================
--- vendor/elsa/current/elsa/xml_type_id.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_type_id.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,111 @@
+// xml_type_id.h            see license.txt for copyright and terms of use
+
+// identity management for serialization for the type system, template
+// system, and variables.
+
+#ifndef XML_TYPE_ID_H
+#define XML_TYPE_ID_H
+
+#include "cc_type.h"            // types
+#include "variable.h"           // variables
+#include "xmlhelp.h"            // xmlUniqueId_t
+#include "hashline.h"           // HashLineMap
+#include "template.h"           // InheritedTemplateParams
+
+// manage identity; definitions; FIX: I don't like how printed() is
+// still using the object address instead of its unique id, but those
+// are one-to-one so I suppose its ok for now
+
+class IdentityManager_Elsa {
+public:
+#define identity_defn0(PREFIX, NAME, TEMPL) \
+  TEMPL char const *idPrefix(NAME const * const) {return #PREFIX;} \
+  TEMPL xmlUniqueId_t uniqueId(NAME const * const obj) {return mapAddrToUniqueId(obj);} \
+  TEMPL bool printed0(NAME const * const obj) {                                \
+    if (printedSet ##PREFIX.contains(obj)) return true;                        \
+    return false;                                                              \
+  }                                                                            \
+  TEMPL bool printed(NAME const * const obj) {                                 \
+    if (printedSet ##PREFIX.contains(obj)) return true;                        \
+    printedSet ##PREFIX.add(obj);                                              \
+    return false;                                                              \
+  }
+
+#define identity_defn(PREFIX, NAME) identity_defn0(PREFIX, NAME, )
+#define identityTempl_defn(PREFIX, NAME) identity_defn0(PREFIX, NAME, template<class T>)
+
+  identity_defn(FI, SourceLocManager::File)
+  identity_defn(FI, HashLineMap)
+  identity_defn(FI, HashLineMap::HashLine)
+  identity_defn(FI, unsigned char) // for lineLengths
+
+  identity_defn(BC, BaseClass)
+  identity_defn(TY, Type)
+  identity_defn(TY, CompoundType)
+  identity_defn(TY, FunctionType::ExnSpec)
+  // identity_defn(TY, EnumType)
+  identity_defn(TY, EnumType::Value)
+  identity_defn(TY, Variable)
+  identity_defn(TY, OverloadSet)
+  identity_defn(TY, STemplateArgument)
+  identity_defn(TY, TemplateInfo)
+  identity_defn(TY, InheritedTemplateParams)
+  identity_defn(TY, StringRefMap<Variable>)
+
+  identityTempl_defn(OL, ObjList<T>)
+  identityTempl_defn(OL, ObjArrayStack<T>)
+  identityTempl_defn(OL, SObjList<T>)
+  identityTempl_defn(NM, StringRefMap<T>)
+  identityTempl_defn(NM, StringObjDict<T>)
+  identityTempl_defn(FI, ArrayStack<T>)
+
+#define identityCpdSuper(PREFIX, NAME)                                         \
+  char const *idPrefix(NAME const * const obj) {                               \
+    if (CompoundType const * const cpd = dynamic_cast<CompoundType const * const>(obj)) { \
+      return idPrefix(cpd);                                                    \
+    }                                                                          \
+    return #PREFIX;                                                            \
+  }                                                                            \
+    xmlUniqueId_t uniqueId(NAME const * const obj) {                           \
+      if (CompoundType const * const cpd = dynamic_cast<CompoundType const * const>(obj)) { \
+        return uniqueId(cpd);                                                  \
+      }                                                                        \
+      return mapAddrToUniqueId(obj);                                           \
+    }                                                                          \
+    bool printed(NAME const * const obj) {                                     \
+      if (CompoundType const * const cpd = dynamic_cast<CompoundType const * const>(obj)) { \
+        return printed(cpd);                                                   \
+      }                                                                        \
+      if (printedSet ##PREFIX.contains(obj)) return true;                      \
+      printedSet ##PREFIX.add(obj);                                            \
+      return false;                                                            \
+    }
+
+  // AtomicType and Scope are special because they both can be a
+  // CompoundType sometimes and so have to change their notion of
+  // identity when they do
+  identityCpdSuper(TY, AtomicType)
+  identityCpdSuper(TY, Scope)
+
+protected:
+  // printing of types is idempotent
+  SObjSet<void const *> printedSetTY;
+  SObjSet<void const *> printedSetBC;
+  SObjSet<void const *> printedSetOL;
+  SObjSet<void const *> printedSetNM;
+  SObjSet<void const *> printedSetFI;
+
+};
+
+// the next line is good for replacing with codepatch.pl:
+typedef IdentityManager_Elsa IdentityManager_T;
+
+// class IdentityManager is used in cc.ast.gen.cc
+class IdentityManager : public IdentityManager_T {};
+
+#undef identity_defn0
+#undef identity_defn
+#undef identityTempl_defn
+#undef identityCpdSuper
+
+#endif

Added: vendor/elsa/current/elsa/xml_type_reader.cc
===================================================================
--- vendor/elsa/current/elsa/xml_type_reader.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_type_reader.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,780 @@
+// xml_type_reader.cc            see license.txt for copyright and terms of use
+
+#include "xml_type_reader.h"    // this module
+#include "variable.h"           // Variable
+#include "strtokpc.h"           // StrtokParseC
+#include "cc_flags.h"           // fromXml(DeclFlags &out, rostring str)
+#include "xmlhelp.h"            // fromXml_int() etc.
+#include "xml_enum.h"           // XTOK_*
+
+
+// fromXml for enums
+
+void fromXml(CompoundType::Keyword &out, char const *str) {
+  if(0) xfailure("?");
+  READENUM(CompoundType::K_STRUCT);
+  READENUM(CompoundType::K_CLASS);
+  READENUM(CompoundType::K_UNION);
+  else xfailure("bad enum string");
+}
+
+void fromXml(FunctionFlags &out, char const *str) {
+  StrtokParseC tok(str);
+  char const *token;
+  while ( (token = tok.nextToken('|')) != NULL ) {
+    if(0) xfailure("?");
+    READFLAG(FF_NONE);
+    READFLAG(FF_METHOD);
+    READFLAG(FF_VARARGS);
+    READFLAG(FF_CONVERSION);
+    READFLAG(FF_CTOR);
+    READFLAG(FF_DTOR);
+    READFLAG(FF_BUILTINOP);
+    READFLAG(FF_NO_PARAM_INFO);
+    READFLAG(FF_DEFAULT_ALLOC);
+    READFLAG(FF_KANDR_DEFN);
+    else xfailure("illegal flag");
+  }
+}
+
+void fromXml(ScopeKind &out, char const *str) {
+  if(0) xfailure("?");
+  READENUM(SK_UNKNOWN);
+  READENUM(SK_GLOBAL);
+  READENUM(SK_PARAMETER);
+  READENUM(SK_FUNCTION);
+  READENUM(SK_CLASS);
+  READENUM(SK_TEMPLATE_PARAMS);
+  READENUM(SK_TEMPLATE_ARGS);
+  READENUM(SK_NAMESPACE);
+  else xfailure("bad enum string");
+}
+
+void fromXml(STemplateArgument::Kind &out, char const *str) {
+  if(0) xfailure("?");
+  READENUM(STemplateArgument::STA_NONE);
+  READENUM(STemplateArgument::STA_TYPE);
+  READENUM(STemplateArgument::STA_INT);
+  READENUM(STemplateArgument::STA_ENUMERATOR);
+  READENUM(STemplateArgument::STA_REFERENCE);
+  READENUM(STemplateArgument::STA_POINTER);
+  READENUM(STemplateArgument::STA_MEMBER);
+  READENUM(STemplateArgument::STA_DEPEXPR);
+  READENUM(STemplateArgument::STA_TEMPLATE);
+  READENUM(STemplateArgument::STA_ATOMIC);
+  else xfailure("bad enum string");
+}
+
+
+bool XmlTypeReader::kind2kindCat(int kind, KindCategory *kindCat) {
+  switch(kind) {
+  default: return false;        // we don't know this kind
+
+  // Types
+  case XTOK_CVAtomicType:
+  case XTOK_PointerType:
+  case XTOK_ReferenceType:
+  case XTOK_FunctionType:
+  case XTOK_FunctionType_ExnSpec:
+  case XTOK_ArrayType:
+  case XTOK_PointerToMemberType:
+  // AtomicTypes
+  case XTOK_SimpleType:
+  case XTOK_CompoundType:
+  case XTOK_EnumType:
+  case XTOK_EnumType_Value:
+  case XTOK_TypeVariable:
+  case XTOK_PseudoInstantiation:
+  case XTOK_DependentQType:
+  // Other
+  case XTOK_Variable:
+  case XTOK_Scope:
+  case XTOK_BaseClass:
+  case XTOK_BaseClassSubobj:
+  case XTOK_OverloadSet:
+  case XTOK_STemplateArgument:
+  case XTOK_TemplateInfo:
+  case XTOK_InheritedTemplateParams:
+    *kindCat = KC_Node;
+    break;
+
+  // **** Containers
+
+  //   ObjList
+  case XTOK_List_CompoundType_bases:
+  case XTOK_List_CompoundType_virtualBases:
+  case XTOK_List_PseudoInstantiation_args:
+  case XTOK_List_TemplateInfo_inheritedParams:
+  case XTOK_List_TemplateInfo_arguments:
+  case XTOK_List_TemplateInfo_argumentsToPrimary:
+  case XTOK_List_PQ_qualifier_sargs:
+  case XTOK_List_PQ_template_sargs:
+    *kindCat = KC_ObjList;
+    break;
+
+  //   SObjList
+  case XTOK_List_FunctionType_params:
+  case XTOK_List_CompoundType_dataMembers:
+  case XTOK_List_CompoundType_conversionOperators:
+  case XTOK_List_BaseClassSubobj_parents:
+  case XTOK_List_ExnSpec_types:
+  case XTOK_List_Scope_templateParams:
+  case XTOK_List_OverloadSet_set:
+  case XTOK_List_TemplateInfo_instantiations:
+  case XTOK_List_TemplateInfo_specializations:
+  case XTOK_List_TemplateInfo_partialInstantiations:
+  case XTOK_List_TemplateParams_params:
+    *kindCat = KC_SObjList;
+    break;
+
+  //   StringRefMap
+  case XTOK_NameMap_Scope_variables:
+  case XTOK_NameMap_Scope_typeTags:
+    *kindCat = KC_StringRefMap;
+    break;
+
+  //   StringSObjDict
+  case XTOK_NameMap_EnumType_valueIndex:
+    *kindCat = KC_StringSObjDict;
+    break;
+  }
+  return true;
+}
+
+bool XmlTypeReader::recordKind(int kind, bool& answer) {
+  switch(kind) {
+  default: return false;        // we don't know this kind
+
+  // **** record these kinds
+  case XTOK_CompoundType:
+    answer = true;
+    return true;
+    break;
+
+  // **** do not record these
+
+  // Types
+  case XTOK_CVAtomicType:
+  case XTOK_PointerType:
+  case XTOK_ReferenceType:
+  case XTOK_FunctionType:
+  case XTOK_FunctionType_ExnSpec:
+  case XTOK_ArrayType:
+  case XTOK_PointerToMemberType:
+  // AtomicTypes
+  case XTOK_SimpleType:
+//    case XTOK_CompoundType: handled above
+  case XTOK_EnumType:
+  case XTOK_EnumType_Value:
+  case XTOK_TypeVariable:
+  case XTOK_PseudoInstantiation:
+  case XTOK_DependentQType:
+  // Other
+  case XTOK_Variable:
+  case XTOK_Scope:
+  case XTOK_BaseClass:
+  case XTOK_BaseClassSubobj:
+  case XTOK_OverloadSet:
+  case XTOK_STemplateArgument:
+  case XTOK_TemplateInfo:
+  case XTOK_InheritedTemplateParams:
+  // **** Containers
+  //   ObjList
+  case XTOK_List_CompoundType_bases:
+  case XTOK_List_CompoundType_virtualBases:
+  case XTOK_List_PseudoInstantiation_args:
+  case XTOK_List_TemplateInfo_inheritedParams:
+  case XTOK_List_TemplateInfo_arguments:
+  case XTOK_List_TemplateInfo_argumentsToPrimary:
+  case XTOK_List_PQ_qualifier_sargs:
+  case XTOK_List_PQ_template_sargs:
+  //   SObjList
+  case XTOK_List_FunctionType_params:
+  case XTOK_List_CompoundType_dataMembers:
+  case XTOK_List_CompoundType_conversionOperators:
+  case XTOK_List_BaseClassSubobj_parents:
+  case XTOK_List_ExnSpec_types:
+  case XTOK_List_Scope_templateParams:
+  case XTOK_List_OverloadSet_set:
+  case XTOK_List_TemplateInfo_instantiations:
+  case XTOK_List_TemplateInfo_specializations:
+  case XTOK_List_TemplateInfo_partialInstantiations:
+  case XTOK_List_TemplateParams_params:
+  //   StringRefMap
+  case XTOK_NameMap_Scope_variables:
+  case XTOK_NameMap_Scope_typeTags:
+  //   StringSObjDict
+  case XTOK_NameMap_EnumType_valueIndex:
+    answer = false;
+    return true;
+    break;
+  }
+}
+
+bool XmlTypeReader::callOpAssignToEmbeddedObj(void *obj, int kind, void *target) {
+  xassert(obj);
+  xassert(target);
+  switch(kind) {
+
+  default:
+    // This handler conflates two situations; one is where kind is a
+    // kind from the typesystem, but not an XTOK_BaseClassSubobj,
+    // which is an error; the other is where kind is just not from the
+    // typesystem, which should just be a return false so that another
+    // XmlReader will be attempted.  However the first situation
+    // should not be handled by any of the other XmlReaders either and
+    // so should also result in an error, albeit perhaps not as exact
+    // of one as it could have been.  I just don't want to put a huge
+    // switch statement here for all the other kinds in the type
+    // system.
+    return false;
+    break;
+
+  case XTOK_BaseClassSubobj:
+    BaseClassSubobj *obj1 = reinterpret_cast<BaseClassSubobj*>(obj);
+    BaseClassSubobj *target1 = reinterpret_cast<BaseClassSubobj*>(target);
+    // fprintf(stderr,
+    //         "## embed XTOK_BaseClassSubobj: obj1=%p, &obj1->parents=%p, target1=%p, &target1->parents=%p\n",
+    //         obj1, &obj1->parents, target1, &target1->parents);
+    target1->operator=(*obj1);
+    return true;
+    break;
+
+  }
+}
+
+bool XmlTypeReader::upcastToWantedType(void *obj, int objKind, void **target, int targetKind) {
+  xassert(obj);
+  xassert(target);
+
+  // classes where something interesting happens
+  if (objKind == XTOK_CompoundType) {
+    CompoundType *tmp = reinterpret_cast<CompoundType*>(obj);
+    if (targetKind == XTOK_CompoundType) {
+      *target = tmp;
+    } else if (targetKind == XTOK_Scope) {
+      // upcast to a Scope
+      *target = static_cast<Scope*>(tmp);
+    } else if (targetKind == XTOK_AtomicType) {
+      // upcast to an AtomicType
+      *target = static_cast<AtomicType*>(tmp);
+    } else if (targetKind == XTOK_NamedAtomicType) {
+      // upcast to an NamedAtomicType
+      *target = static_cast<NamedAtomicType*>(tmp);
+    }
+    return true;
+  } else {
+    // This handler conflates two situations; one is where objKind is
+    // a kind from the typesystem, but not an XTOK_CompoundType, which
+    // is an error; the other is where objKind is just not from the
+    // typesystem, which should just be a return false so that another
+    // XmlReader will be attempted.  However the first situation
+    // should not be handled by any of the other XmlReaders either and
+    // so should also result in an error, albeit perhaps not as exact
+    // of one as it could have been.  I just don't want to put a huge
+    // switch statement here for all the other kinds in the type
+    // system.
+    return false;
+  }
+}
+
+void *XmlTypeReader::ctorNodeFromTag(int tag) {
+  switch(tag) {
+  default: return NULL; break;
+  case 0: xmlUserFatalError("unexpected file termination while looking for an open tag name");
+
+  // **** Types
+  case XTOK_CVAtomicType: return new CVAtomicType((AtomicType*)0, (CVFlags)0);
+  case XTOK_PointerType: return new PointerType((CVFlags)0, (Type*)0);
+  case XTOK_ReferenceType: return new ReferenceType((Type*)0);
+  case XTOK_FunctionType: return new FunctionType((Type*)0);
+  case XTOK_FunctionType_ExnSpec: return new FunctionType::ExnSpec();
+  case XTOK_ArrayType: return new ArrayType((XmlReader&)*this); // call the special ctor
+  case XTOK_PointerToMemberType:
+    return new PointerToMemberType((XmlReader&)*this); // call the special ctor
+
+  // **** Atomic Types
+  // NOTE: this really should go through the SimpleTyp::fixed array
+  case XTOK_SimpleType: return new SimpleType((SimpleTypeId)0);
+  case XTOK_CompoundType: return new CompoundType((CompoundType::Keyword)0, (StringRef)0);
+  case XTOK_EnumType: return new EnumType((StringRef)0);
+  case XTOK_EnumType_Value:
+    return new EnumType::Value((StringRef)0, (EnumType*)0, (int)0, (Variable*)0);
+  case XTOK_TypeVariable: return new TypeVariable((StringRef)0);
+  case XTOK_PseudoInstantiation: return new PseudoInstantiation((CompoundType*)0);
+  case XTOK_DependentQType: return new DependentQType((AtomicType*)0);
+
+  // **** Other
+  case XTOK_Variable: return new Variable((XmlReader&)*this);// call the special ctor
+  case XTOK_Scope: return new Scope((XmlReader&)*this); // call the special ctor
+  case XTOK_BaseClass: return new BaseClass((CompoundType*)0, (AccessKeyword)0, (bool)0);
+  case XTOK_BaseClassSubobj:
+    // NOTE: special; FIX: should I make the BaseClass on the heap and
+    // then delete it?  I'm not sure if the compiler is going to be
+    // able to tell that even though it is passed by reference to the
+    // BaseClassSubobj that it is not kept there and therefore can be
+    // deleted at the end of the full expression.
+    return new BaseClassSubobj(BaseClass((CompoundType*)0, (AccessKeyword)0, (bool)0));
+  case XTOK_OverloadSet: return new OverloadSet();
+  case XTOK_STemplateArgument: return new STemplateArgument();
+  case XTOK_TemplateInfo: return new TemplateInfo((SourceLoc)0);
+  case XTOK_InheritedTemplateParams: return new InheritedTemplateParams((CompoundType*)0);
+
+  // **** Containers
+  // ObjList
+  case XTOK_List_CompoundType_bases:
+    return new ObjList<BaseClass>();
+  case XTOK_List_CompoundType_virtualBases:
+    return new ObjList<BaseClassSubobj>();
+  case XTOK_List_TemplateInfo_inheritedParams:
+    return new ObjList<InheritedTemplateParams>();
+  case XTOK_List_TemplateInfo_arguments:
+  case XTOK_List_TemplateInfo_argumentsToPrimary:
+  case XTOK_List_PseudoInstantiation_args:
+  case XTOK_List_PQ_qualifier_sargs:
+  case XTOK_List_PQ_template_sargs:
+    return new ObjList<STemplateArgument>();
+
+  // SObjList
+  case XTOK_List_BaseClassSubobj_parents:
+    return new SObjList<BaseClassSubobj>();
+  case XTOK_List_ExnSpec_types:
+    return new SObjList<Type>();
+  case XTOK_List_FunctionType_params:
+  case XTOK_List_CompoundType_dataMembers:
+  case XTOK_List_CompoundType_conversionOperators:
+  case XTOK_List_Scope_templateParams:
+  case XTOK_List_OverloadSet_set:
+  case XTOK_List_TemplateInfo_instantiations:
+  case XTOK_List_TemplateInfo_specializations:
+  case XTOK_List_TemplateInfo_partialInstantiations:
+  case XTOK_List_TemplateParams_params:
+    return new SObjList<Variable>();
+
+  // StringRefMap
+  case XTOK_NameMap_Scope_variables:
+  case XTOK_NameMap_Scope_typeTags:
+    return new StringRefMap<Variable>();
+  case XTOK_NameMap_EnumType_valueIndex:
+    return new StringObjDict<EnumType::Value>();
+  }
+}
+
+// **************** registerStringToken
+
+bool XmlTypeReader::registerStringToken(void *target, int kind, char const *yytext0) {
+  return false;
+}
+
+// **************** registerAttribute
+
+#define regAttr(TYPE) \
+  registerAttr_##TYPE((TYPE*)target, attr, yytext0)
+
+bool XmlTypeReader::registerAttribute(void *target, int kind, int attr, char const *yytext0) {
+  switch(kind) {
+  default: return false; break;
+
+  // **** Types
+  case XTOK_CVAtomicType: regAttr(CVAtomicType);               break;
+  case XTOK_PointerType: regAttr(PointerType);                 break;
+  case XTOK_ReferenceType: regAttr(ReferenceType);             break;
+  case XTOK_FunctionType: regAttr(FunctionType);               break;
+  case XTOK_ArrayType: regAttr(ArrayType);                     break;
+  case XTOK_PointerToMemberType: regAttr(PointerToMemberType); break;
+  case XTOK_FunctionType_ExnSpec:
+    registerAttr_FunctionType_ExnSpec
+      ((FunctionType::ExnSpec*)target, attr, yytext0);         break;
+
+  // **** Atomic Types
+  case XTOK_SimpleType: regAttr(SimpleType);                   break;
+  case XTOK_CompoundType: regAttr(CompoundType);               break;
+  case XTOK_EnumType: regAttr(EnumType);                       break;
+  case XTOK_TypeVariable: regAttr(TypeVariable);               break;
+  case XTOK_PseudoInstantiation: regAttr(PseudoInstantiation); break;
+  case XTOK_DependentQType: regAttr(DependentQType);           break;
+  case XTOK_EnumType_Value:
+    registerAttr_EnumType_Value
+      ((EnumType::Value*)target, attr, yytext0);               break;
+
+  // **** Other
+  case XTOK_Variable: regAttr(Variable);                       break;
+  case XTOK_Scope: regAttr(Scope);                             break;
+  case XTOK_BaseClass: regAttr(BaseClass);                     break;
+  case XTOK_BaseClassSubobj: regAttr(BaseClassSubobj);         break;
+  case XTOK_OverloadSet: regAttr(OverloadSet);                 break;
+  case XTOK_STemplateArgument: regAttr(STemplateArgument);     break;
+  case XTOK_TemplateInfo: regAttr(TemplateInfo);               break;
+  case XTOK_InheritedTemplateParams:
+    regAttr(InheritedTemplateParams);                          break;
+  }
+
+  return true;
+}
+
+void XmlTypeReader::registerAttr_CVAtomicType(CVAtomicType *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a CVAtomicType"); break;
+  case XTOK_atomic: ul(atomic, XTOK_AtomicType); break;
+  case XTOK_cv: fromXml(obj->cv, strValue); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_PointerType(PointerType *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a PointerType"); break;
+  case XTOK_cv: fromXml(obj->cv, strValue); break;
+  case XTOK_atType: ul(atType, XTOK_Type); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_ReferenceType(ReferenceType *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a ReferenceType"); break;
+  case XTOK_atType: ul(atType, XTOK_Type); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_FunctionType(FunctionType *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a FunctionType"); break;
+  case XTOK_flags: fromXml(obj->flags, strValue); break;
+  case XTOK_retType: ul(retType, XTOK_Type); break;
+  case XTOK_params: ulEmbed(params, XTOK_List_FunctionType_params); break;
+  case XTOK_exnSpec: ul(exnSpec, XTOK_FunctionType_ExnSpec); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_FunctionType_ExnSpec
+  (FunctionType::ExnSpec *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a FunctionType_ExnSpec"); break;
+  case XTOK_types: ulEmbed(types, XTOK_List_ExnSpec_types); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_ArrayType(ArrayType *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a ArrayType"); break;
+  case XTOK_eltType: ul(eltType, XTOK_Type); break;
+  case XTOK_size: fromXml_int(obj->size, strValue); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_PointerToMemberType
+  (PointerToMemberType *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a PointerToMemberType"); break;
+  case XTOK_inClassNAT:
+    ul(inClassNAT, XTOK_NamedAtomicType); break;
+  case XTOK_cv: fromXml(obj->cv, strValue); break;
+  case XTOK_atType: ul(atType, XTOK_Type); break;
+  }
+}
+
+bool XmlTypeReader::registerAttr_Variable_super(Variable *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: return false; break; // we didn't find it
+  case XTOK_loc: fromXml_SourceLoc(obj->loc, strValue); break;
+  case XTOK_name: obj->name = manager->strTable(strValue); break;
+  case XTOK_type: ul(type, XTOK_Type); break;
+  case XTOK_flags:
+    fromXml(const_cast<DeclFlags&>(obj->flags), strValue); break;
+  case XTOK_value: ul(value, XTOK_Expression); break;
+  case XTOK_defaultParamType: ul(defaultParamType, XTOK_Type); break;
+  case XTOK_funcDefn: ul(funcDefn, XTOK_Function); break;
+  case XTOK_overload: ul(overload, XTOK_OverloadSet); break;
+  case XTOK_scope: ul(scope, XTOK_Scope); break;
+
+  // these fields are abstractions; however here we pretend they are
+  // real
+  case XTOK_access:
+    AccessKeyword access;
+    fromXml(access, strValue);
+    obj->setAccess(access);
+    break;
+  case XTOK_real:
+    bool real;
+    fromXml_bool(real, strValue);
+    obj->setReal(real);
+    break;
+  case XTOK_maybeUsedAsAlias:
+    bool maybeUsedAsAlias;
+    fromXml_bool(maybeUsedAsAlias, strValue);
+    obj->setMaybeUsedAsAlias(maybeUsedAsAlias);
+    break;
+  case XTOK_user1:
+    bool user1;
+    fromXml_bool(user1, strValue);
+    obj->setUser1(user1);
+    break;
+  case XTOK_user2:
+    bool user2;
+    fromXml_bool(user2, strValue);
+    obj->setUser2(user2);
+    break;
+  case XTOK_scopeKind:
+    ScopeKind scopeKind;
+    fromXml(scopeKind, strValue);
+    obj->setScopeKind(scopeKind);
+    break;
+  case XTOK_hasValue:
+    bool hasValue;
+    fromXml_bool(hasValue, strValue);
+    obj->setHasValue(hasValue);
+    break;
+  case XTOK_parameterOrdinal:
+    int parameterOrdinal;
+    fromXml_int(parameterOrdinal, strValue);
+    obj->setParameterOrdinal(parameterOrdinal);
+    break;
+
+  case XTOK_fullyQualifiedMangledName:
+    // FIX: For now throw it away; I suppose perhaps we should check
+    // that it is indeed the fully qualified name, but we would have
+    // to be done de-serializing the whole object heirarcy first and
+    // we aren't even done de-serializing the Variable object.
+    break;
+
+  case XTOK_usingAlias_or_parameterizedEntity:
+    ul(usingAlias_or_parameterizedEntity, XTOK_Variable); break;
+  case XTOK_templInfo: ul(templInfo, XTOK_TemplateInfo); break;
+  }
+
+  return true;                  // found it
+}
+
+void XmlTypeReader::registerAttr_Variable(Variable *obj, int attr, char const *strValue) {
+  // "superclass": just re-use our own superclass code for ourself
+  if (registerAttr_Variable_super(obj, attr, strValue)) return;
+  // shouldn't get here
+  xmlUserFatalError("illegal attribute for a Variable");
+}
+
+bool XmlTypeReader::registerAttr_NamedAtomicType_super
+  (NamedAtomicType *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: return false; break; // we didn't find it
+  case XTOK_name: obj->name = manager->strTable(strValue); break;
+  case XTOK_typedefVar: ul(typedefVar, XTOK_Variable); break;
+  case XTOK_access: fromXml(obj->access, strValue); break;
+  }
+  return true;                  // found it
+}
+
+void XmlTypeReader::registerAttr_SimpleType(SimpleType *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a SimpleType"); break;
+  case XTOK_type:
+    // NOTE: this 'type' is not a type node, but basically an enum,
+    // and thus is handled more like a flag would be.
+    fromXml(const_cast<SimpleTypeId&>(obj->type), strValue);
+    break;
+  }
+}
+
+void XmlTypeReader::registerAttr_CompoundType(CompoundType *obj, int attr, char const *strValue) {
+  // superclasses
+  if (registerAttr_NamedAtomicType_super(obj, attr, strValue)) return;
+  if (registerAttr_Scope_super(obj, attr, strValue)) return;
+
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a CompoundType"); break;
+  case XTOK_forward: obj->forward = fromXml_bool(strValue); break;
+  case XTOK_keyword: fromXml(obj->keyword, strValue); break;
+  case XTOK_dataMembers: ulEmbed(dataMembers, XTOK_List_CompoundType_dataMembers); break;
+  case XTOK_bases: ulEmbed(bases, XTOK_List_CompoundType_bases); break;
+  case XTOK_virtualBases: ulEmbed(virtualBases, XTOK_List_CompoundType_virtualBases); break;
+  case XTOK_subobj: ulEmbed(subobj, XTOK_BaseClassSubobj); break;
+  case XTOK_conversionOperators:
+    ulEmbed(conversionOperators, XTOK_List_CompoundType_conversionOperators); break;
+  case XTOK_instName: obj->instName = manager->strTable(strValue); break;
+  case XTOK_syntax: ul(syntax, XTOK_TS_classSpec); break;
+  case XTOK_parameterizingScope: ul(parameterizingScope, XTOK_Scope); break;
+  case XTOK_selfType: ul(selfType, XTOK_Type); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_EnumType(EnumType *obj, int attr, char const *strValue) {
+  // superclass
+  if (registerAttr_NamedAtomicType_super(obj, attr, strValue)) return;
+
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a EnumType"); break;
+  case XTOK_valueIndex: ulEmbed(valueIndex, XTOK_NameMap_EnumType_valueIndex); break;
+  case XTOK_nextValue: fromXml_int(obj->nextValue, strValue); break;
+  case XTOK_hasNegativeValues: fromXml_bool(obj->hasNegativeValues, strValue); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_EnumType_Value
+  (EnumType::Value *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a EnumType"); break;
+  case XTOK_name: obj->name = manager->strTable(strValue); break;
+  case XTOK_type: ul(type, XTOK_EnumType); break; // NOTE: 'type' here is actually an atomic type
+  case XTOK_value: fromXml_int(obj->value, strValue); break;
+  case XTOK_decl: ul(decl, XTOK_Variable); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_TypeVariable(TypeVariable *obj, int attr, char const *strValue) {
+  // superclass
+  if (registerAttr_NamedAtomicType_super(obj, attr, strValue)) return;
+  // shouldn't get here
+  xmlUserFatalError("illegal attribute for a TypeVariable");
+}
+
+void XmlTypeReader::registerAttr_PseudoInstantiation
+  (PseudoInstantiation *obj, int attr, char const *strValue) {
+  // superclass
+  if (registerAttr_NamedAtomicType_super(obj, attr, strValue)) return;
+
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a PsuedoInstantiation"); break;
+  case XTOK_primary: ul(primary, XTOK_CompoundType); break;
+  case XTOK_args: ulEmbed(args, XTOK_List_PseudoInstantiation_args); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_DependentQType
+  (DependentQType *obj, int attr, char const *strValue) {
+  // superclass
+  if (registerAttr_NamedAtomicType_super(obj, attr, strValue)) return;
+
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a DependentQType"); break;
+  case XTOK_first: ul(first, XTOK_AtomicType); break;
+  case XTOK_rest: ul(rest, XTOK_PQName); break;
+  }
+}
+
+bool XmlTypeReader::registerAttr_Scope_super(Scope *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: return false; break; // we didn't find it
+  case XTOK_variables: ulEmbed(variables, XTOK_NameMap_Scope_variables); break;
+  case XTOK_typeTags: ulEmbed(typeTags, XTOK_NameMap_Scope_typeTags); break;
+  case XTOK_canAcceptNames: fromXml_bool(obj->canAcceptNames, strValue); break;
+  case XTOK_parentScope: ul(parentScope, XTOK_Scope); break;
+  case XTOK_scopeKind: fromXml(obj->scopeKind, strValue); break;
+  case XTOK_namespaceVar: ul(namespaceVar, XTOK_Variable); break;
+  case XTOK_templateParams: ulEmbed(templateParams, XTOK_List_Scope_templateParams); break;
+  case XTOK_curCompound: ul(curCompound, XTOK_CompoundType); break;
+  case XTOK_curLoc: fromXml_SourceLoc(obj->curLoc, strValue); break;
+  }
+  return true;                  // found it
+}
+
+void XmlTypeReader::registerAttr_Scope(Scope *obj, int attr, char const *strValue) {
+  // "superclass": just re-use our own superclass code for ourself
+  if (registerAttr_Scope_super(obj, attr, strValue)) return;
+  // shouldn't get here
+  xmlUserFatalError("illegal attribute for a Scope");
+}
+
+bool XmlTypeReader::registerAttr_BaseClass_super(BaseClass *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: return false; break;
+  case XTOK_ct: ul(ct, XTOK_CompoundType); break;
+  case XTOK_access: fromXml(obj->access, strValue); break;
+  case XTOK_isVirtual: fromXml_bool(obj->isVirtual, strValue); break;
+  }
+  return true;
+}
+
+void XmlTypeReader::registerAttr_BaseClass(BaseClass *obj, int attr, char const *strValue) {
+  // "superclass": just re-use our own superclass code for ourself
+  if (registerAttr_BaseClass_super(obj, attr, strValue)) return;
+  // shouldn't get here
+  xmlUserFatalError("illegal attribute for a BaseClass");
+}
+
+void XmlTypeReader::registerAttr_BaseClassSubobj
+  (BaseClassSubobj *obj, int attr, char const *strValue) {
+  // "superclass": just re-use our own superclass code for ourself
+  if (registerAttr_BaseClass_super(obj, attr, strValue)) return;
+
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a BaseClassSubobj"); break;
+  case XTOK_parents:
+    // fprintf(stderr, "## registerAttr_BaseClassSubobj: id=%s, obj=%p, &obj->parents=%p\n",
+    //         strValue, obj, &obj->parents);
+    ulEmbed(parents, XTOK_List_BaseClassSubobj_parents); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_OverloadSet(OverloadSet *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a OverloadSet"); break;
+  case XTOK_set: ulEmbed(set, XTOK_List_OverloadSet_set); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_STemplateArgument
+  (STemplateArgument *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a STemplateArgument"); break;
+  case XTOK_kind: fromXml(obj->kind, strValue); break;
+  // exactly one of these must show up as it is a union; I don't check that though
+  case XTOK_t: ul(value.t, XTOK_Type); break;
+  case XTOK_i: fromXml_int(obj->value.i, strValue); break;
+  case XTOK_v: ul(value.v, XTOK_Variable); break;
+  case XTOK_e: ul(value.e, XTOK_Expression); break;
+  case XTOK_at: ul(value.at, XTOK_AtomicType); break;
+  }
+}
+
+bool XmlTypeReader::registerAttr_TemplateParams_super
+  (TemplateParams *obj, int attr, char const *strValue) {
+  switch(attr) {
+  default: return false; break; // we didn't find it
+  case XTOK_params: ulEmbed(params, XTOK_List_TemplateParams_params); break;
+  }
+  return true;
+}
+
+void XmlTypeReader::registerAttr_TemplateInfo(TemplateInfo *obj, int attr, char const *strValue) {
+  // superclass
+  if (registerAttr_TemplateParams_super(obj, attr, strValue)) return;
+
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a TemplateInfo"); break;
+  case XTOK_var: ul(var, XTOK_Variable); break;
+  case XTOK_inheritedParams:
+    ulEmbed(inheritedParams, XTOK_List_TemplateInfo_inheritedParams); break;
+  case XTOK_instantiationOf:
+    ul(instantiationOf, XTOK_Variable); break;
+  case XTOK_instantiations:
+    ulEmbed(instantiations, XTOK_List_TemplateInfo_instantiations); break;
+  case XTOK_specializationOf:
+    ul(specializationOf, XTOK_Variable); break;
+  case XTOK_specializations:
+    ulEmbed(specializations, XTOK_List_TemplateInfo_specializations); break;
+  case XTOK_arguments:
+    ulEmbed(arguments, XTOK_List_TemplateInfo_arguments); break;
+  case XTOK_instLoc:
+    fromXml_SourceLoc(obj->instLoc, strValue); break;
+  case XTOK_partialInstantiationOf:
+    ul(partialInstantiationOf, XTOK_Variable); break;
+  case XTOK_partialInstantiations:
+    ulEmbed(partialInstantiations, XTOK_List_TemplateInfo_partialInstantiations); break;
+  case XTOK_argumentsToPrimary:
+    ulEmbed(argumentsToPrimary, XTOK_List_TemplateInfo_argumentsToPrimary); break;
+  case XTOK_defnScope:
+    ul(defnScope, XTOK_Scope); break;
+  case XTOK_definitionTemplateInfo:
+    ul(definitionTemplateInfo, XTOK_TemplateInfo); break;
+  }
+}
+
+void XmlTypeReader::registerAttr_InheritedTemplateParams
+  (InheritedTemplateParams *obj, int attr, char const *strValue) {
+  // superclass
+  if (registerAttr_TemplateParams_super(obj, attr, strValue)) return;
+
+  switch(attr) {
+  default: xmlUserFatalError("illegal attribute for a InheritedTemplateParams"); break;
+  case XTOK_enclosing:
+    ul(enclosing, XTOK_CompoundType); break;
+  }
+}

Added: vendor/elsa/current/elsa/xml_type_reader.h
===================================================================
--- vendor/elsa/current/elsa/xml_type_reader.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_type_reader.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,83 @@
+// xml_type_reader.h            see license.txt for copyright and terms of use
+
+// De-serialization for the type system, template system, and
+// variables.
+
+#ifndef XML_TYPE_READER_H
+#define XML_TYPE_READER_H
+
+#include "cc_type.h"            // Type
+#include "variable.h"
+#include "template.h"           // Template stuff is only forward-declared in cc_type.h
+#include "xml_reader.h"         // XmlReader
+
+//  void fromXml(CompoundType::Keyword &out, rostring str);
+//  void fromXml(FunctionFlags &out, rostring str);
+//  void fromXml(ScopeKind &out, rostring str);
+//  void fromXml(STemplateArgument::Kind &out, rostring str);
+
+
+class XmlTypeReader : public XmlReader {
+//    BasicTypeFactory &tFac;
+
+  public:
+  // Parse a tag: construct a node for a tag
+  virtual void *ctorNodeFromTag(int tag);
+
+  // Parse an attribute: register an attribute into the current node
+  virtual bool registerAttribute(void *target, int kind, int attr, char const *yytext0);
+
+  virtual bool registerStringToken(void *target, int kind, char const *yytext0);
+
+  // implement an eq-relation on tag kinds by mapping a tag kind to a
+  // category
+  virtual bool kind2kindCat(int kind, KindCategory *kindCat);
+
+  // **** Generic Convert
+  virtual bool recordKind(int kind, bool& answer);
+
+  // cast a pointer to the pointer type we need it to be
+  virtual bool callOpAssignToEmbeddedObj(void *obj, int kind, void *target);
+  virtual bool upcastToWantedType(void *obj, int kind, void **target, int targetKind);
+
+  private:
+  // Types
+  void registerAttr_CVAtomicType       (CVAtomicType *,        int attr, char const *strValue);
+  void registerAttr_PointerType        (PointerType *,         int attr, char const *strValue);
+  void registerAttr_ReferenceType      (ReferenceType *,       int attr, char const *strValue);
+  void registerAttr_FunctionType       (FunctionType *,        int attr, char const *strValue);
+  void registerAttr_FunctionType_ExnSpec
+    (FunctionType::ExnSpec *, int attr, char const *strValue);
+  void registerAttr_ArrayType          (ArrayType *,           int attr, char const *strValue);
+  void registerAttr_PointerToMemberType(PointerToMemberType *, int attr, char const *strValue);
+
+  // AtomicTypes
+  bool registerAttr_NamedAtomicType_super(NamedAtomicType *,   int attr, char const *strValue);
+  void registerAttr_SimpleType         (SimpleType *,          int attr, char const *strValue);
+  void registerAttr_CompoundType       (CompoundType *,        int attr, char const *strValue);
+  void registerAttr_EnumType           (EnumType *,            int attr, char const *strValue);
+  void registerAttr_EnumType_Value     (EnumType::Value *,     int attr, char const *strValue);
+  void registerAttr_TypeVariable       (TypeVariable *,        int attr, char const *strValue);
+  void registerAttr_PseudoInstantiation(PseudoInstantiation *, int attr, char const *strValue);
+  void registerAttr_DependentQType     (DependentQType *,      int attr, char const *strValue);
+
+  // other
+  public:
+  bool registerAttr_Variable_super     (Variable *,            int attr, char const *strValue);
+
+  private:
+  void registerAttr_Variable           (Variable *,            int attr, char const *strValue);
+  bool registerAttr_Scope_super        (Scope *,               int attr, char const *strValue);
+  void registerAttr_Scope              (Scope *,               int attr, char const *strValue);
+  bool registerAttr_BaseClass_super    (BaseClass *,           int attr, char const *strValue);
+  void registerAttr_BaseClass          (BaseClass *,           int attr, char const *strValue);
+  void registerAttr_BaseClassSubobj    (BaseClassSubobj *,     int attr, char const *strValue);
+  void registerAttr_OverloadSet        (OverloadSet *,         int attr, char const *strValue);
+  void registerAttr_STemplateArgument  (STemplateArgument *,   int attr, char const *strValue);
+  bool registerAttr_TemplateParams_super(TemplateParams *obj,  int attr, char const *strValue);
+  void registerAttr_TemplateInfo       (TemplateInfo *,        int attr, char const *strValue);
+  void registerAttr_InheritedTemplateParams(InheritedTemplateParams*,
+                                                               int attr, char const *strValue);
+};
+
+#endif // XML_TYPE_READER_H

Added: vendor/elsa/current/elsa/xml_type_writer.cc
===================================================================
--- vendor/elsa/current/elsa/xml_type_writer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_type_writer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,980 @@
+// xml_type_writer.cc            see license.txt for copyright and terms of use
+
+#include "xml_type_writer.h"    // this module
+#include "variable.h"           // Variable
+#include "cc_flags.h"           // toXml(DeclFlags &out, rostring str)
+#include "asthelp.h"            // xmlPrintPointer
+#include "xmlhelp.h"            // toXml_int() etc.
+#include "strutil.h"            // DelimStr
+#include "cc_ast.h"             // AST nodes only for AST sub-traversals
+
+#define serializeOracle serializeOracle_m
+
+// toXml for enums
+
+char const *toXml(CompoundType::Keyword id) {
+  switch(id) {
+  default: xfailure("bad enum"); break;
+    PRINTENUM(CompoundType::K_STRUCT);
+    PRINTENUM(CompoundType::K_CLASS);
+    PRINTENUM(CompoundType::K_UNION);
+  }
+}
+
+string toXml(FunctionFlags id) {
+  if (id == FF_NONE) return "FF_NONE";
+  DelimStr b('|');
+  PRINTFLAG(FF_METHOD);
+  PRINTFLAG(FF_VARARGS);
+  PRINTFLAG(FF_CONVERSION);
+  PRINTFLAG(FF_CTOR);
+  PRINTFLAG(FF_DTOR);
+  PRINTFLAG(FF_BUILTINOP);
+  PRINTFLAG(FF_NO_PARAM_INFO);
+  PRINTFLAG(FF_DEFAULT_ALLOC);
+  PRINTFLAG(FF_KANDR_DEFN);
+  return b.sb;
+}
+
+char const *toXml(ScopeKind id) {
+  switch(id) {
+  default: xfailure("bad enum"); break;
+  PRINTENUM(SK_UNKNOWN);
+  PRINTENUM(SK_GLOBAL);
+  PRINTENUM(SK_PARAMETER);
+  PRINTENUM(SK_FUNCTION);
+  PRINTENUM(SK_CLASS);
+  PRINTENUM(SK_TEMPLATE_PARAMS);
+  PRINTENUM(SK_TEMPLATE_ARGS);
+  PRINTENUM(SK_NAMESPACE);
+  }
+}
+
+char const *toXml(STemplateArgument::Kind id) {
+  switch(id) {
+  default: xfailure("bad enum"); break;
+  PRINTENUM(STemplateArgument::STA_NONE);
+  PRINTENUM(STemplateArgument::STA_TYPE);
+  PRINTENUM(STemplateArgument::STA_INT);
+  PRINTENUM(STemplateArgument::STA_ENUMERATOR);
+  PRINTENUM(STemplateArgument::STA_REFERENCE);
+  PRINTENUM(STemplateArgument::STA_POINTER);
+  PRINTENUM(STemplateArgument::STA_MEMBER);
+  PRINTENUM(STemplateArgument::STA_DEPEXPR);
+  PRINTENUM(STemplateArgument::STA_TEMPLATE);
+  PRINTENUM(STemplateArgument::STA_ATOMIC);
+  }
+}
+
+XmlTypeWriter::XmlTypeWriter (IdentityManager &idmgr0,
+                              ASTVisitor *astVisitor0, ostream *out0, int &depth0, bool indent0,
+                              XTW_SerializeOracle *serializeOracle0)
+  : XmlWriter(idmgr0, out0, depth0, indent0)
+  , astVisitor(astVisitor0)
+  , serializeOracle(serializeOracle0)
+{}
+
+// **** toXml
+
+// This one occurs in the AST, so it has to have its own first-class
+// method.  FIX: This should not have such a general API and yet refer
+// to such a specific list: PseudoInstantiation::args.
+void XmlTypeWriter::toXml(ObjList<STemplateArgument> *list) {
+  travObjList_standalone(*list, PseudoInstantiation, args, STemplateArgument);
+}
+
+void XmlTypeWriter::toXml(Type *t) {
+  // idempotency
+  if (idmgr.printed(t)) return;
+
+  switch(t->getTag()) {
+  default: xfailure("illegal tag");
+
+  case Type::T_ATOMIC: {
+    CVAtomicType *atom = t->asCVAtomicType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("CVAtomicType", atom);
+      // **** attributes
+      printPtr(atom, atomic);
+      printXml(cv, atom->cv);
+      tagPrinter.tagEnd();
+    }
+    // **** subtags
+    trav(atom->atomic);
+    break;
+  }
+
+  case Type::T_POINTER: {
+    PointerType *ptr = t->asPointerType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("PointerType", ptr);
+      // **** attributes
+      printXml(cv, ptr->cv);
+      printPtr(ptr, atType);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    trav(ptr->atType);
+    break;
+  }
+
+  case Type::T_REFERENCE: {
+    ReferenceType *ref = t->asReferenceType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("ReferenceType", ref);
+      // **** attributes
+      printPtr(ref, atType);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    trav(ref->atType);
+    break;
+  }
+
+  case Type::T_FUNCTION: {
+    FunctionType *func = t->asFunctionType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("FunctionType", func);
+      // **** attributes
+      printXml(flags, func->flags);
+      printPtr(func, retType);
+      printEmbed(func, params);
+      printPtr(func, exnSpec);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    trav(func->retType);
+    travObjList_S(func, FunctionType, params, Variable); // Variable
+    // exnSpec
+    if (func->exnSpec) {
+      toXml_FunctionType_ExnSpec(func->exnSpec);
+    }
+    break;
+  }
+
+  case Type::T_ARRAY: {
+    ArrayType *arr = t->asArrayType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("ArrayType", arr);
+      // **** attributes
+      printPtr(arr, eltType);
+      printXml_int(size, arr->size);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    trav(arr->eltType);
+    break;
+  }
+
+  case Type::T_POINTERTOMEMBER: {
+    PointerToMemberType *ptm = t->asPointerToMemberType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("PointerToMemberType", ptm);
+      // **** attributes
+      printPtr(ptm, inClassNAT);
+      printXml(cv, ptm->cv);
+      printPtr(ptm, atType);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    trav(ptm->inClassNAT);
+    trav(ptm->atType);
+    break;
+  }
+
+  }
+}
+
+void XmlTypeWriter::toXml(AtomicType *atom) {
+  // idempotency done in each sub-type as it is not done for
+  // CompoundType here.
+  switch(atom->getTag()) {
+  default: xfailure("illegal tag");
+
+  case AtomicType::T_SIMPLE: {
+    // idempotency
+    if (idmgr.printed(atom)) return;
+    SimpleType *simple = atom->asSimpleType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("SimpleType", simple);
+      // **** attributes
+      printXml(type, simple->type);
+      tagPrinter.tagEnd();
+    }
+    break;
+  }
+
+  case AtomicType::T_COMPOUND: {
+    // NO!  Do NOT do this here:
+//      // idempotency
+//      if (idmgr.printed(atom)) return;
+    CompoundType *cpd = atom->asCompoundType();
+    toXml(cpd);
+    break;
+  }
+
+  case AtomicType::T_ENUM: {
+    // idempotency
+    if (idmgr.printed(atom)) return;
+    EnumType *e = atom->asEnumType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("EnumType", e);
+      // **** attributes
+      // * superclasses
+      toXml_NamedAtomicType_properties(e);
+      // * members
+      printEmbed(e, valueIndex);
+      printXml_int(nextValue, e->nextValue);
+      printXml_bool(hasNegativeValues, e->hasNegativeValues);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    // * superclasses
+    toXml_NamedAtomicType_subtags(e);
+    // * members
+    // valueIndex
+    if (!idmgr.printed(&e->valueIndex)) {
+      XmlTagPrinter tagPrinter2(*this);
+      if (writingP()) {
+        tagPrinter2.printOpenTag("NameMap_EnumType_valueIndex", &e->valueIndex);
+        tagPrinter2.tagEnd();
+      }
+
+      if (sortNameMapDomainWhenSerializing) {
+        for(StringObjDict<EnumType::Value>::SortedKeyIter iter(e->valueIndex);
+            !iter.isDone(); iter.next()) {
+          char const *name = iter.key();
+          // dsw: do you know how bad it gets if I don't put a
+          // const-cast here?
+          EnumType::Value *eValue = const_cast<EnumType::Value*>(iter.value());
+
+          XmlTagPrinter tagPrinter3(*this);
+          if (writingP()) {
+            tagPrinter3.printNameMapItemOpenTag(name, eValue);
+          }
+
+          toXml_EnumType_Value(eValue);
+        }
+      } else {
+        for(StringObjDict<EnumType::Value>::Iter iter(e->valueIndex);
+            !iter.isDone(); iter.next()) {
+          rostring name = iter.key();
+          // dsw: do you know how bad it gets if I don't put a
+          // const-cast here?
+          EnumType::Value *eValue = const_cast<EnumType::Value*>(iter.value());
+
+          XmlTagPrinter tagPrinter3(*this);
+          if (writingP()) {
+            tagPrinter3.printNameMapItemOpenTag(name.c_str(), eValue);
+          }
+
+          toXml_EnumType_Value(eValue);
+        }
+      }
+    }
+    break;
+  }
+
+  case AtomicType::T_TYPEVAR: {
+    // idempotency
+    if (idmgr.printed(atom)) return;
+    TypeVariable *tvar = atom->asTypeVariable();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("TypeVariable", tvar);
+      // **** attributes
+      // * superclasses
+      toXml_NamedAtomicType_properties(tvar);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    // * superclasses
+    toXml_NamedAtomicType_subtags(tvar);
+    break;
+  }
+
+  case AtomicType::T_PSEUDOINSTANTIATION: {
+    // idempotency
+    if (idmgr.printed(atom)) return;
+    PseudoInstantiation *pseudo = atom->asPseudoInstantiation();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("PseudoInstantiation", pseudo);
+      // **** attributes
+      // * superclasses
+      toXml_NamedAtomicType_properties(pseudo);
+      // * members
+      printPtr(pseudo, primary);
+      printEmbed(pseudo, args);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    // * superclasses
+    toXml_NamedAtomicType_subtags(pseudo);
+    // * members
+    trav(pseudo->primary);
+    travObjList(pseudo, PseudoInstantiation, args, STemplateArgument);
+    break;
+  }
+
+  case AtomicType::T_DEPENDENTQTYPE: {
+    // idempotency
+    if (idmgr.printed(atom)) return;
+    DependentQType *dep = atom->asDependentQType();
+    XmlTagPrinter tagPrinter(*this);
+    if (writingP()) {
+      tagPrinter.printOpenTag("DependentQType", dep);
+      // **** attributes
+      // * superclasses
+      toXml_NamedAtomicType_properties(dep);
+      // * members
+      printPtr(dep, first);
+      printPtrAST(dep, rest);
+      tagPrinter.tagEnd();
+    }
+
+    // **** subtags
+    // * superclasses
+    toXml_NamedAtomicType_subtags(dep);
+    // * members
+    trav(dep->first);
+    travAST(dep->rest);
+    break;
+  }
+
+  }
+}
+
+void XmlTypeWriter::toXml(CompoundType *cpd) {
+  // idempotency
+  if (idmgr.printed(cpd)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("CompoundType", cpd);
+    // **** attributes
+    // * superclasses
+    toXml_NamedAtomicType_properties(cpd);
+    toXml_Scope_properties(cpd);
+    // * members
+    printXml_bool(forward, cpd->forward);
+    // FIX: isTransparentUnion; turn this on
+//     printXml_bool(isTransparentUnion, cpd->isTransparentUnion);
+    printXml(keyword, cpd->keyword);
+    printEmbed(cpd, dataMembers);
+    printEmbed(cpd, bases);
+    printEmbed(cpd, virtualBases);
+    printEmbed(cpd, subobj);
+    printEmbed(cpd, conversionOperators);
+    // FIX: friends; turn this on
+//     printEmbed(cpd, friends);
+    printStrRef(instName, cpd->instName);
+    printPtrAST(cpd, syntax);
+    printPtr(cpd, parameterizingScope);
+    printPtr(cpd, selfType);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  // * superclasses
+  toXml_NamedAtomicType_subtags(cpd);
+  toXml_Scope_subtags(cpd);
+  // * members
+  travObjList_S(cpd, CompoundType, dataMembers, Variable); // Variable
+  travObjList(cpd, CompoundType, bases, BaseClass);
+  travObjList(cpd, CompoundType, virtualBases, BaseClassSubobj);
+  toXml(&cpd->subobj);          // embedded
+  travObjList_S(cpd, CompoundType, conversionOperators, Variable); // Variable
+  // FIX: friends; turn this on
+//   travObjList_S(cpd, CompoundType, friends, Variable); // Variable
+  travAST(cpd->syntax);
+  trav(cpd->parameterizingScope);
+  trav(cpd->selfType);
+}
+
+void XmlTypeWriter::toXml_Variable_properties(Variable *var) {
+  xassert(writingP());
+  printXml_SourceLoc(loc, var->loc);
+  printStrRef(name, var->name);
+  printPtr(var, type);
+  printXml(flags, var->flags);
+  printPtrAST(var, value);
+  printPtr(var, defaultParamType);
+  printPtrAST(var, funcDefn);
+  printPtr(var, overload);
+  printPtr(var, scope);
+
+  // **** these fields are abstractions; however here we pretend they
+  // are real
+  AccessKeyword access = var->getAccess();
+  printXml(access, access);
+  bool real = var->getReal();
+  printXml_bool(real, real);
+  bool maybeUsedAsAlias = var->getMaybeUsedAsAlias();
+  printXml_bool(maybeUsedAsAlias, maybeUsedAsAlias);
+
+  // dsw: perhaps these should instead be serialized by the client
+  // code as they would have more meaningful names
+  bool user1 = var->getUser1();
+  printXml_bool(user1, user1);
+  bool user2 = var->getUser2();
+  printXml_bool(user2, user2);
+
+  ScopeKind scopeKind = var->getScopeKind();
+  printXml(scopeKind, scopeKind);
+  bool hasValue = var->getHasValue();
+  printXml_bool(hasValue, hasValue);
+  int parameterOrdinal = var->getParameterOrdinal();
+  printXml_int(parameterOrdinal, parameterOrdinal);
+  // **** end abstract fields
+
+  // dsw: FIX: usingAlias_or_parameterizedEntity is actually an
+  // implicit union of two fields and should be serialized that way
+  printPtr(var, usingAlias_or_parameterizedEntity);
+  printPtr(var, templInfo);
+
+  if (var->linkerVisibleName()) {
+    newline();
+    *out << "fullyQualifiedMangledName=";
+    outputXmlAttrQuoted(*out, var->fullyQualifiedMangledName0());
+  }
+}
+
+void XmlTypeWriter::toXml_Variable_subtags(Variable *var) {
+  trav(var->type);
+  travAST(var->value);
+  trav(var->defaultParamType);
+  travAST(var->funcDefn);
+  trav(var->overload);
+  trav(var->scope);
+  trav(var->usingAlias_or_parameterizedEntity); // Variable
+  trav(var->templInfo);
+}
+
+void XmlTypeWriter::toXml(Variable *var) {
+#ifdef OINK
+  xfailure("this should never be called in Oink");
+#endif
+
+  // idempotency
+  if (idmgr.printed(var)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("Variable", var);
+    // **** attributes
+    toXml_Variable_properties(var);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  toXml_Variable_subtags(var);
+}
+
+void XmlTypeWriter::toXml_FunctionType_ExnSpec(void /*FunctionType::ExnSpec*/ *exnSpec0) {
+  FunctionType::ExnSpec *exnSpec = static_cast<FunctionType::ExnSpec *>(exnSpec0);
+  // idempotency
+  if (idmgr.printed(exnSpec)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("FunctionType_ExnSpec", exnSpec);
+    // **** attributes
+    printEmbed(exnSpec, types);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  travObjList_S(exnSpec, ExnSpec, types, Type);
+}
+
+void XmlTypeWriter::toXml_EnumType_Value(void /*EnumType::Value*/ *eValue0) {
+  EnumType::Value *eValue = static_cast<EnumType::Value *>(eValue0);
+  // idempotency
+  if (idmgr.printed(eValue)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("EnumType_Value", eValue);
+    // **** attributes
+    printStrRef(name, eValue->name);
+    printPtr(eValue, type);
+    printXml_int(value, eValue->value);
+
+    // quarl 2006-05-31
+    //    'decl' might be pointing at a Variable A which we have linked with
+    //    another variable B, but we are serializing variable B and not A.
+    //    See 'make oink-check-srz-multi-file-enum', which fails if we just
+    //    serialize 'decl' directly.
+    //
+    //    One solution would be to add a union-find to variables so that we
+    //    can follow and find the linked target. TODO.
+    //
+    //    For now we simply lose the 'decl' in such situations.
+    if (!serializeOracle || serializeOracle->shouldSerialize(eValue->decl)) {
+      printPtr(eValue, decl);
+    }
+
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  trav(eValue->type);
+  trav(eValue->decl);           // Variable
+}
+
+void XmlTypeWriter::toXml_NamedAtomicType_properties(NamedAtomicType *nat) {
+  printStrRef(name, nat->name);
+  printPtr(nat, typedefVar);
+  printXml(access, nat->access);
+}
+
+void XmlTypeWriter::toXml_NamedAtomicType_subtags(NamedAtomicType *nat) {
+  trav(nat->typedefVar);        // Variable
+}
+
+void XmlTypeWriter::toXml(OverloadSet *oload) {
+  // idempotency
+  if (idmgr.printed(oload)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("OverloadSet", oload);
+    // **** attributes
+    printEmbed(oload, set);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  travObjList_S(oload, OverloadSet, set, Variable); // Variable
+}
+
+void XmlTypeWriter::toXml(BaseClass *bc) {
+  // Since BaseClass objects are never manipulated polymorphically,
+  // that is, every BaseClass pointer's static type equals its dynamic
+  // type, 'bc' cannot actually be a BaseClassSubobj.
+
+  // idempotency
+  if (idmgr.printed(bc)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("BaseClass", bc);
+    // **** attributes
+    toXml_BaseClass_properties(bc);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  toXml_BaseClass_subtags(bc);
+}
+
+void XmlTypeWriter::toXml_BaseClass_properties(BaseClass *bc) {
+  printPtr(bc, ct);
+  printXml(access, bc->access);
+  printXml_bool(isVirtual, bc->isVirtual);
+}
+
+void XmlTypeWriter::toXml_BaseClass_subtags(BaseClass *bc) {
+  trav(bc->ct);
+}
+
+void XmlTypeWriter::toXml(BaseClassSubobj *bc) {
+  // idempotency
+  if (idmgr.printed(bc)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("BaseClassSubobj", bc);
+    // **** attributes
+    // * superclass
+    toXml_BaseClass_properties(bc);
+    // * members
+    printEmbed(bc, parents);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  // * superclass
+  toXml_BaseClass_subtags(bc);
+  // * members
+  travObjList_S(bc, BaseClassSubobj, parents, BaseClassSubobj);
+}
+
+void XmlTypeWriter::toXml(Scope *scope) {
+  // are we really a CompoundType?
+  if (CompoundType *cpd = dynamic_cast<CompoundType*>(scope)) {
+    toXml(cpd);
+    return;
+  }
+  // idempotency
+  if (idmgr.printed(scope)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("Scope", scope);
+    // **** attributes
+    toXml_Scope_properties(scope);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  toXml_Scope_subtags(scope);
+}
+
+void XmlTypeWriter::toXml_Scope_properties(Scope *scope) {
+  printEmbed(scope, variables);
+  printEmbed(scope, typeTags);
+  printXml_bool(canAcceptNames, scope->canAcceptNames);
+  printPtr(scope, parentScope);
+  printXml(scopeKind, scope->scopeKind);
+  printPtr(scope, namespaceVar);
+  printEmbed(scope, templateParams);
+  printPtr(scope, curCompound);
+  printXml_SourceLoc(curLoc, scope->curLoc);
+}
+
+void XmlTypeWriter::toXml_Scope_subtags(Scope *scope) {
+  // FIX: these are like function template "partial specializations"
+  // (if such things existed), as the 'Variable' paramter actually
+  // also changes the implementation.
+  travStringRefMap(scope, Scope, variables, Variable); // Variable
+  travStringRefMap(scope, Scope, typeTags, Variable); // Variable
+  trav(scope->parentScope);
+  trav(scope->namespaceVar);    // Variable
+  travObjList_S(scope, Scope, templateParams, Variable); // Variable
+  trav(scope->curCompound);
+}
+
+void XmlTypeWriter::toXml(STemplateArgument *sta) {
+  // idempotency
+  if (idmgr.printed(sta)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("STemplateArgument", sta);
+
+    // **** attributes
+    printXml(kind, sta->kind);
+    newline();
+
+    switch(sta->kind) {
+    default: xfailure("illegal STemplateArgument kind"); break;
+
+    case STemplateArgument::STA_TYPE:
+      printPtrUnion(sta, value.t, t);
+      break;
+
+    case STemplateArgument::STA_INT:
+      printXml_int(i, sta->value.i);
+      break;
+
+    case STemplateArgument::STA_ENUMERATOR:
+    case STemplateArgument::STA_REFERENCE:
+    case STemplateArgument::STA_POINTER:
+    case STemplateArgument::STA_MEMBER:
+      printPtrUnion(sta, value.v, v);
+      break;
+
+    case STemplateArgument::STA_DEPEXPR:
+      printPtrASTUnion(sta, value.e, e);
+      break;
+
+    case STemplateArgument::STA_TEMPLATE:
+      xfailure("template template arguments not implemented");
+      break;
+
+    case STemplateArgument::STA_ATOMIC:
+      printPtrUnion(sta, value.at, at);
+      break;
+    }
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+
+  // NOTE: I don't use the trav() macro here because it would be weird
+  // to test the member of a union for being NULL; it should have a
+  // well-defined value if it is the selected type of the tag.
+  switch(sta->kind) {
+  default: xfailure("illegal STemplateArgument kind"); break;
+  case STemplateArgument::STA_TYPE:
+    toXml(sta->value.t);
+    break;
+
+  case STemplateArgument::STA_INT:
+    // nothing to do
+    break;
+
+  case STemplateArgument::STA_ENUMERATOR:
+  case STemplateArgument::STA_REFERENCE:
+  case STemplateArgument::STA_POINTER:
+  case STemplateArgument::STA_MEMBER:
+    trav(sta->value.v);         // Variable
+    break;
+
+  case STemplateArgument::STA_DEPEXPR:
+    // (quarl) I don't get what's going on here; this looks weird.
+    if (astVisitor) {
+      sta->value.e->traverse(*astVisitor);
+    }
+    break;
+
+  case STemplateArgument::STA_TEMPLATE:
+    xfailure("template template arguments not implemented");
+    break;
+
+  case STemplateArgument::STA_ATOMIC:
+    toXml(const_cast<AtomicType*>(sta->value.at));
+    break;
+  }
+}
+
+void XmlTypeWriter::toXml(TemplateInfo *ti) {
+  // idempotency
+  if (idmgr.printed(ti)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("TemplateInfo", ti);
+    // **** attributes
+    // * superclass
+    toXml_TemplateParams_properties(ti);
+    // * members
+    printPtr(ti, var);
+    printEmbed(ti, inheritedParams);
+    printPtr(ti, instantiationOf);
+    printEmbed(ti, instantiations);
+    printPtr(ti, specializationOf);
+    printEmbed(ti, specializations);
+    printEmbed(ti, arguments);
+    printXml_SourceLoc(instLoc, ti->instLoc);
+    printPtr(ti, partialInstantiationOf);
+    printEmbed(ti, partialInstantiations);
+    printEmbed(ti, argumentsToPrimary);
+    printPtr(ti, defnScope);
+    printPtr(ti, definitionTemplateInfo);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  // * superclass
+  toXml_TemplateParams_subtags(ti);
+  // * members
+  trav(ti->var);                // Variable
+  travObjList(ti, TemplateInfo, inheritedParams, InheritedTemplateParams);
+  trav(ti->instantiationOf);    // Variable
+  travObjList_S(ti, TemplateInfo, instantiations, Variable); // Variable
+  trav(ti->specializationOf);   // Variable
+  travObjList_S(ti, TemplateInfo, specializations, Variable); // Variable
+  travObjList(ti, TemplateInfo, arguments, STemplateArgument);
+  trav(ti->partialInstantiationOf); // Variable
+  travObjList_S(ti, TemplateInfo, partialInstantiations, Variable); // Variable
+  travObjList(ti, TemplateInfo, argumentsToPrimary, STemplateArgument);
+  trav(ti->defnScope);
+  trav(ti->definitionTemplateInfo);
+}
+
+void XmlTypeWriter::toXml(InheritedTemplateParams *itp) {
+  // idempotency
+  if (idmgr.printed(itp)) return;
+  XmlTagPrinter tagPrinter(*this);
+  if (writingP()) {
+    tagPrinter.printOpenTag("InheritedTemplateParams", itp);
+    // **** attributes
+    // * superclass
+    toXml_TemplateParams_properties(itp);
+    // * members
+    printPtr(itp, enclosing);
+    tagPrinter.tagEnd();
+  }
+
+  // **** subtags
+  // * superclass
+  toXml_TemplateParams_subtags(itp);
+  // * members
+  trav(itp->enclosing);
+}
+
+void XmlTypeWriter::toXml_TemplateParams_properties(TemplateParams *tp) {
+  printEmbed(tp, params);
+}
+
+void XmlTypeWriter::toXml_TemplateParams_subtags(TemplateParams *tp) {
+  travObjList_S(tp, TemplateParams, params, Variable); // Variable
+}
+
+
+// **** shouldSerialize
+
+bool XmlTypeWriter::XTW_SerializeOracle::shouldSerialize(AtomicType const *obj) {
+  if (CompoundType const *cpd = dynamic_cast<CompoundType const *>(obj)) {
+    return shouldSerialize(cpd);
+  }
+  return true;
+}
+
+bool XmlTypeWriter::XTW_SerializeOracle::shouldSerialize(Scope const *obj) {
+  if (CompoundType const *cpd = dynamic_cast<CompoundType const *>(obj)) {
+    return shouldSerialize(cpd);
+  }
+  return true;
+}
+
+
+// **** class XmlTypeWriter_AstVisitor
+
+XmlTypeWriter_AstVisitor::XmlTypeWriter_AstVisitor
+  (XmlTypeWriter &ttx0,
+   ostream &out0,
+   int &depth0,
+   bool indent0)
+    : XmlAstWriter_AstVisitor(out0, ttx0.idmgr, depth0, indent0)
+    , ttx(ttx0)
+{}
+
+// Note that idempotency is handled in XmlTypeWriter
+// #define PRINT_ANNOT(A) if (A) {ttx.toXml(A);}
+#define PRINT_ANNOT_MAYBE(A) if (A && (!ttx.serializeOracle || ttx.serializeOracle->shouldSerialize(A))) {ttx.toXml(A);}
+
+  // this was part of the macro
+//    printASTBiLink((void**)&(A), (A));
+
+  // print the link between the ast node and the annotating node
+//    void printASTBiLink(void **astField, void *annotation) {
+//      out << "<__Link from=\"";
+//      // this is not from an ast *node* but from the *field* of one
+//      xmlPrintPointer(out, "FLD", uniqueId(astField));
+//      out << "\" to=\"";
+//      xmlPrintPointer(out, "TY", uniqueId(annotation));
+//      out << "\"/>\n";
+//    }
+
+bool XmlTypeWriter_AstVisitor::visitTranslationUnit(TranslationUnit *unit) {
+  if (!XmlAstWriter_AstVisitor::visitTranslationUnit(unit)) return false;
+  PRINT_ANNOT_MAYBE(unit->globalScope);
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitTypeSpecifier(TypeSpecifier *ts) {
+  if (!XmlAstWriter_AstVisitor::visitTypeSpecifier(ts)) return false;
+  if (ts->isTS_type()) {
+    PRINT_ANNOT_MAYBE(ts->asTS_type()->type);
+  } else if (ts->isTS_name()) {
+    PRINT_ANNOT_MAYBE(ts->asTS_name()->var); // Variable
+    PRINT_ANNOT_MAYBE(ts->asTS_name()->nondependentVar); // Variable
+  } else if (ts->isTS_elaborated()) {
+    PRINT_ANNOT_MAYBE(ts->asTS_elaborated()->atype);
+  } else if (ts->isTS_classSpec()) {
+    PRINT_ANNOT_MAYBE(ts->asTS_classSpec()->ctype);
+  } else if (ts->isTS_enumSpec()) {
+    PRINT_ANNOT_MAYBE(ts->asTS_enumSpec()->etype);
+  }
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitFunction(Function *f) {
+  if (!XmlAstWriter_AstVisitor::visitFunction(f)) return false;
+  PRINT_ANNOT_MAYBE(f->funcType);
+  PRINT_ANNOT_MAYBE(f->receiver); // Variable
+  PRINT_ANNOT_MAYBE(f->retVar); // Variable
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitMemberInit(MemberInit *memberInit) {
+  if (!XmlAstWriter_AstVisitor::visitMemberInit(memberInit)) return false;
+  PRINT_ANNOT_MAYBE(memberInit->member); // Variable
+  PRINT_ANNOT_MAYBE(memberInit->base);
+  PRINT_ANNOT_MAYBE(memberInit->ctorVar); // Variable
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitBaseClassSpec(BaseClassSpec *bcs) {
+  if (!XmlAstWriter_AstVisitor::visitBaseClassSpec(bcs)) return false;
+  PRINT_ANNOT_MAYBE(bcs->type);
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitDeclarator(Declarator *d) {
+  if (!XmlAstWriter_AstVisitor::visitDeclarator(d)) return false;
+  PRINT_ANNOT_MAYBE(d->var);    // Variable
+  PRINT_ANNOT_MAYBE(d->type);
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitExpression(Expression *e) {
+  if (!XmlAstWriter_AstVisitor::visitExpression(e)) return false;
+  PRINT_ANNOT_MAYBE(e->type);
+  if (e->isE_this()) {
+    PRINT_ANNOT_MAYBE(e->asE_this()->receiver); // Variable
+  } else if (e->isE_variable()) {
+    PRINT_ANNOT_MAYBE(e->asE_variable()->var); // Variable
+    PRINT_ANNOT_MAYBE(e->asE_variable()->nondependentVar); // Variable
+  } else if (e->isE_constructor()) {
+    PRINT_ANNOT_MAYBE(e->asE_constructor()->ctorVar); // Variable
+  } else if (e->isE_fieldAcc()) {
+    PRINT_ANNOT_MAYBE(e->asE_fieldAcc()->field); // Variable
+  } else if (e->isE_new()) {
+    PRINT_ANNOT_MAYBE(e->asE_new()->ctorVar); // Variable
+    PRINT_ANNOT_MAYBE(e->asE_new()->heapVar); // Variable
+  } else if (e->isE_throw()) {
+    PRINT_ANNOT_MAYBE(e->asE_throw()->globalVar); // Variable
+  }
+  return true;
+}
+
+#ifdef GNU_EXTENSION
+bool XmlTypeWriter_AstVisitor::visitASTTypeof(ASTTypeof *a) {
+  if (!XmlAstWriter_AstVisitor::visitASTTypeof(a)) return false;
+  PRINT_ANNOT_MAYBE(a->type);
+  return true;
+}
+#endif // GNU_EXTENSION
+
+bool XmlTypeWriter_AstVisitor::visitPQName(PQName *pqn) {
+  if (!XmlAstWriter_AstVisitor::visitPQName(pqn)) return false;
+  if (pqn->isPQ_qualifier()) {
+    PRINT_ANNOT_MAYBE(pqn->asPQ_qualifier()->qualifierVar); // Variable
+    ttx.toXml(&(pqn->asPQ_qualifier()->sargs));
+  } else if (pqn->isPQ_template()) {
+    ttx.toXml(&(pqn->asPQ_template()->sargs));
+  } else if (pqn->isPQ_variable()) {
+    PRINT_ANNOT_MAYBE(pqn->asPQ_variable()->var); // Variable
+  }
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitEnumerator(Enumerator *e) {
+  if (!XmlAstWriter_AstVisitor::visitEnumerator(e)) return false;
+  PRINT_ANNOT_MAYBE(e->var);    // Variable
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitInitializer(Initializer *e) {
+  if (!XmlAstWriter_AstVisitor::visitInitializer(e)) return false;
+  if (e->isIN_ctor()) {
+    PRINT_ANNOT_MAYBE(e->asIN_ctor()->ctorVar); // Variable
+  }
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitTemplateParameter(TemplateParameter *tparam) {
+  if (!XmlAstWriter_AstVisitor::visitTemplateParameter(tparam)) return false;
+  PRINT_ANNOT_MAYBE(tparam->var); // Variable
+  return true;
+}
+
+bool XmlTypeWriter_AstVisitor::visitHandler(Handler *h) {
+  if (!XmlAstWriter_AstVisitor::visitHandler(h)) return false;
+  PRINT_ANNOT_MAYBE(h->globalVar); // Variable
+  return true;
+}
+
+// #undef PRINT_ANNOT
+#undef PRINT_ANNOT_MAYBE

Added: vendor/elsa/current/elsa/xml_type_writer.h
===================================================================
--- vendor/elsa/current/elsa/xml_type_writer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_type_writer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,135 @@
+// xml_type_writer.h            see license.txt for copyright and terms of use
+
+// Serialization for the type system, template system, and variables.
+
+#ifndef XML_TYPE_WRITER_H
+#define XML_TYPE_WRITER_H
+
+#include "cc_type.h"            // Type
+#include "template.h"           // Template stuff is only forward-declared in cc_type.h
+#include "xml_writer.h"         // XmlWriter
+#include "xml_type_id.h"        // identity_decl(Type) etc.
+#include "cc_ast.h"             // XmlAstWriter_AstVisitor
+
+class OverloadSet;
+class ASTVisitor;
+
+//  char const *toXml(CompoundType::Keyword id);
+//  string toXml(FunctionFlags id);
+//  char const *toXml(ScopeKind id);
+//  char const *toXml(STemplateArgument::Kind id);
+
+
+class XmlTypeWriter : public XmlWriter {
+  public:
+  ASTVisitor *astVisitor;       // for launching sub-traversals of AST we encounter in the Types
+
+  class XTW_SerializeOracle {
+  public:
+    virtual ~XTW_SerializeOracle() {}
+    virtual bool shouldSerialize(Type const *) {return true;}
+    virtual bool shouldSerialize(CompoundType const *) {return true;}
+    virtual bool shouldSerialize(FunctionType::ExnSpec const *) {return true;}
+    virtual bool shouldSerialize(EnumType::Value const *) {return true;}
+    virtual bool shouldSerialize(BaseClass const *) {return true;}
+    virtual bool shouldSerialize(Variable const *) {return true;}
+    virtual bool shouldSerialize(OverloadSet const *) {return true;}
+    virtual bool shouldSerialize(STemplateArgument const *) {return true;}
+    virtual bool shouldSerialize(TemplateInfo const *) {return true;}
+    virtual bool shouldSerialize(InheritedTemplateParams const *) {return true;}
+    // deal with Scott's multiple-inheritance funkyness
+    virtual bool shouldSerialize(AtomicType const *obj);
+    virtual bool shouldSerialize(Scope const *obj);
+    // FIX: dsw: how do I make these virtual??  I don't have to override
+    // them right now, but they should be virtual; perhaps that is not
+    // possible because it would be too hard for the compiler to compute
+    // the vtable
+    template<class T> bool shouldSerialize(ObjList<T> const *) {return true;}
+    template<class T> bool shouldSerialize(SObjList<T> const *) {return true;}
+    template<class T> bool shouldSerialize(StringRefMap<T> const *) {return true;}
+    template<class T> bool shouldSerialize(StringObjDict<T> const *) {return true;}
+  };
+
+  XTW_SerializeOracle *serializeOracle_m;
+
+  public:
+  XmlTypeWriter(IdentityManager &idmgr0, ASTVisitor *astVisitor0,
+                ostream *out0, int &depth0, bool indent0,
+                XTW_SerializeOracle *serializeOracle0);
+  virtual ~XmlTypeWriter() {}
+
+  public:
+  // in the AST
+  virtual void toXml(ObjList<STemplateArgument> *list);
+
+  virtual void toXml(Type *t);
+  virtual void toXml(AtomicType *atom);
+  virtual void toXml(CompoundType *ct); // disambiguates the overloading
+  void toXml_Variable_properties(Variable *var);
+  void toXml_Variable_subtags(Variable *var);
+  // dsw: For Oink it matters that this one is virtual; the rest are
+  // just for consistency as I have to override all of the other
+  // methods named toXml() at the same time as overriding one hides
+  // the whole overload set.
+  virtual void toXml(Variable *var);
+
+  void toXml_FunctionType_ExnSpec(void /*FunctionType::ExnSpec*/ *exnSpec);
+
+  void toXml_EnumType_Value(void /*EnumType::Value*/ *eValue0);
+  void toXml_NamedAtomicType_properties(NamedAtomicType *nat);
+  void toXml_NamedAtomicType_subtags(NamedAtomicType *nat);
+
+  virtual void toXml(OverloadSet *oload);
+
+  virtual void toXml(BaseClass *bc);
+  void toXml_BaseClass_properties(BaseClass *bc);
+  void toXml_BaseClass_subtags(BaseClass *bc);
+  virtual void toXml(BaseClassSubobj *bc);
+
+  virtual void toXml(Scope *scope);
+  void toXml_Scope_properties(Scope *scope);
+  void toXml_Scope_subtags(Scope *scope);
+
+  virtual void toXml(STemplateArgument *sta);
+  virtual void toXml(TemplateInfo *ti);
+  virtual void toXml(InheritedTemplateParams *itp);
+  void toXml_TemplateParams_properties(TemplateParams *tp);
+  void toXml_TemplateParams_subtags(TemplateParams *tp);
+};
+
+// print out type annotations for every ast node that has a type
+class XmlTypeWriter_AstVisitor : public XmlAstWriter_AstVisitor {
+//    ostream &out;                 // for the <Link/> tags
+  XmlTypeWriter &ttx;
+
+  public:
+  XmlTypeWriter_AstVisitor
+    (XmlTypeWriter &ttx0,
+     ostream &out0,
+     int &depth0,
+     bool indent0 = false);
+
+  virtual bool shouldSerialize(Variable const *var) {
+    return !ttx.serializeOracle_m || ttx.serializeOracle_m->shouldSerialize(var);
+  }
+  IdentityManager &getIdMgr() { return ttx.idmgr; }
+
+  // **** visit methods
+  virtual bool visitTranslationUnit(TranslationUnit *unit);
+  virtual bool visitTypeSpecifier(TypeSpecifier *ts);
+  virtual bool visitFunction(Function *f);
+  virtual bool visitMemberInit(MemberInit *memberInit);
+  virtual bool visitBaseClassSpec(BaseClassSpec *bcs);
+  virtual bool visitDeclarator(Declarator *d);
+  virtual bool visitExpression(Expression *e);
+#ifdef GNU_EXTENSION
+  virtual bool visitASTTypeof(ASTTypeof *a);
+#endif // GNU_EXTENSION
+  virtual bool visitPQName(PQName *pqn);
+  virtual bool visitEnumerator(Enumerator *e);
+  virtual bool visitInitializer(Initializer *e);
+  virtual bool visitTemplateParameter(TemplateParameter *tparam);
+  virtual bool visitHandler(Handler *h);
+};
+
+#endif // XML_TYPE_WRITER_H

Added: vendor/elsa/current/elsa/xml_writer.cc
===================================================================
--- vendor/elsa/current/elsa/xml_writer.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_writer.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// xml_writer.cc            see license.txt for copyright and terms of use
+
+#include "xml_writer.h"
+#include "xmlhelp.h"            // writeSpaces
+#include "exc.h"                // xBase
+
+
+bool sortNameMapDomainWhenSerializing = true;
+
+XmlWriter::XmlWriter(IdentityManager &idmgr0, ostream *out0, int &depth0, bool indent0)
+  : idmgr(idmgr0)
+  , out(out0)
+  , depth(depth0)
+  , indent(indent0)
+{}
+
+void XmlWriter::newline() {
+  xassert(out != NULL);
+  *out << '\n';
+  // FIX: turning off indentation makes the output go way faster, so
+  // this loop is worth optimizing, probably by printing chunks of 10
+  // if you can or something logarithmic like that.
+  if (indent) {
+    writeSpaces(*out, depth);
+  }
+}
+

Added: vendor/elsa/current/elsa/xml_writer.h
===================================================================
--- vendor/elsa/current/elsa/xml_writer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/elsa/xml_writer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,427 @@
+
+// xml_writer.h            see license.txt for copyright and terms of use
+
+// Support for XML serialization
+
+// FIX: this module should eventually go into the ast repository.
+
+// FIX: many of these macros could be changed into function templates.
+
+#ifndef XML_WRITER_H
+#define XML_WRITER_H
+
+#include "strtable.h"           // StringRef
+#include "xmlhelp.h"            // toXml_int etc.
+#include "strmap.h"             // StringRefMap
+#include "sobjset.h"            // SObjSet
+#include "xml_type_id.h"        // IdentityManager
+
+// FIX: this is a hack; I want some place to set a flag to tell me if
+// I want the xml serialization of name-maps to be canonical (names in
+// sorted order)
+extern bool sortNameMapDomainWhenSerializing;
+
+
+// to Xml for enums
+#define PRINTENUM(X) case X: return #X
+#define PRINTFLAG(X) if (id & (X)) b << #X
+
+// Manage the output stream.
+//
+// It takes a SerializeOracle which tells whether to serialize; if it is NULL
+// we serialize all.
+//
+// The IdentityManager encapsulates the functionality to generate unique IDs
+// and also, importantly, to check which nodes have been visited.  A new
+// IdentityManager must be passed in for every new traversal.
+//
+// If OUT is NULL then we don't actually write anything; we just traverse.
+// (This used to be only used for serialization, but now we also reuse it to
+// traverse the AST in the same order.  TODO: rename XmlWriter; even better
+// refactor xml writing in visitors.)
+
+class XmlWriter {
+public:
+  IdentityManager &idmgr;       // unique id manager
+
+protected:
+  ostream *out;                 // output stream to which to print
+
+  int &depth;                   // ref so we can share our indentation depth with other printers
+  bool indent;                  // should we print indentation?
+
+public:
+  XmlWriter(IdentityManager &idmgr0, ostream *out0, int &depth0, bool indent0);
+
+  // whether we are writing or not.
+  bool writingP() const { return out != NULL; }
+
+protected:
+  // print a newline and indent if the user wants indentation; NOTE:
+  // the convention is that you don't print a newline until you are
+  // *sure* you have something to print that goes onto the next line;
+  // that is, most lines do *not* end in a newline
+  void newline();
+  friend class XmlTagPrinter;
+};
+
+// Manage XML tags:
+//   Either print both the open and close tags, or neither.  The close tag is
+//   automatically printed on destruction iff the open tag was printed.
+class XmlTagPrinter {
+  // NOTE: you must pass in a constant string, not e.g. a str.c_str(), because
+  // we need it until the end of the scope, and we do not copy the string.
+  const char *tagname;
+  XmlWriter &ttx;
+
+public:
+  XmlTagPrinter(XmlWriter &ttx0) : tagname(NULL), ttx(ttx0)
+  {
+  }
+
+  void readyTag(const char *tagname0) {
+    xassert(ttx.writingP());
+    xassert(tagname == NULL); // only call readyTag once since only one closeTag
+    tagname = tagname0;
+    ttx.depth++;
+    newline();
+  }
+
+  template <class T>
+  void printOpenTag(const char *tagname0, T const &obj) {
+    readyTag(tagname0);
+
+    // idPrefix and uniqueId are overloaded on T.
+    out() << '<' << tagname << " _id=";
+    outputXmlPointerQuoted(out(),
+                           ttx.idmgr.idPrefix(obj),
+                           ttx.idmgr.uniqueId(obj));
+  }
+
+  template <class T>
+  void printNameMapItemOpenTag(const char *objname, T const &target) {
+    readyTag("_NameMap_Item");
+    out() << "<_NameMap_Item"
+          << " name=";
+    outputXmlAttrQuoted(out(), objname);
+    out() << " item=";
+    outputXmlPointerQuoted(out(),
+                           ttx.idmgr.idPrefix(target),
+                           ttx.idmgr.uniqueId(target));
+    out() << '>';
+  }
+
+  template <class T>
+  void printListItemOpenTag(T const &target) {
+    readyTag("_List_Item");
+    out() << "<_List_Item item=";
+    outputXmlPointerQuoted(out(),
+                           ttx.idmgr.idPrefix(target),
+                           ttx.idmgr.uniqueId(target));
+    out() << '>';
+  }
+
+  template <class T>
+  void printMapItemOpenTag(const char *key, T const &value) {
+    readyTag("_Map_Item");
+    out() << "<_Map_Item"
+          << " key=";
+    outputXmlAttrQuoted(out(), key);
+    out() << " item=";
+    outputXmlPointerQuoted(out(), ttx.idmgr.idPrefix(value), ttx.idmgr.uniqueId(value));
+    out() << '>';
+  }
+
+  template <class T>
+  void printMapItemOpenTag(T const &key, T const &value) {
+    readyTag("_Map_Item");
+    out() << "<_Map_Item"
+          << " key=";
+    outputXmlPointerQuoted(out(), ttx.idmgr.idPrefix(key), ttx.idmgr.uniqueId(key));
+    out() << " item=";
+    outputXmlPointerQuoted(out(), ttx.idmgr.idPrefix(value), ttx.idmgr.uniqueId(value));
+    out() << '>';
+  }
+
+  // template <class T>
+  // void printStrRef0(const char *field, T const &target) {
+  //   if (target) {
+  //     newline();
+  //     out() << field << '=' << xmlAttrQuote(target);
+  //   }
+  // }
+
+  // for ending the open tag
+  void tagEnd() {
+    xassert(ttx.writingP());
+    out() << '>';
+  }
+
+  ~XmlTagPrinter() {
+    if (ttx.writingP())
+      closeTag();
+  }
+
+  void closeTag() {
+    xassert(tagname != NULL);
+    newline();
+    out() << '<' << '/' << tagname << '>';
+    ttx.depth--;
+  }
+
+  ostream &out() { xassert(ttx.out); return *ttx.out; }
+
+protected:
+  void newline() { ttx.newline(); }
+
+private:
+  explicit XmlTagPrinter(XmlTagPrinter &); // prohibit
+};
+
+// manage indentation depth
+class IncDec {
+  int &x;
+  public:
+  explicit IncDec(int &x0) : x(x0) {++x;}
+  private:
+  explicit IncDec(const IncDec&); // prohibit
+  public:
+  ~IncDec() {--x;}
+};
+
+#define printThing0(NAME, VALUE)                                   \
+  do {                                                             \
+    *out << #NAME "=";                                             \
+    outputXmlAttrQuoted(*out, VALUE);                              \
+  } while(0)
+
+#define printThing0_ne(NAME, VALUE)                               \
+  do {                                                            \
+    *out << #NAME "=";                                            \
+    outputXmlAttrQuotedNoEscape(*out, VALUE);                     \
+  } while(0)
+
+#define printThing(NAME, RAW, VALUE)                                           \
+  do {                                                                         \
+    if ((RAW) && (!serializeOracle || serializeOracle->shouldSerialize(RAW))) { \
+      newline();                                                               \
+      printThing0(NAME, VALUE);                                                \
+    }                                                                          \
+  } while(0)
+
+#define printThingAST(NAME, RAW, VALUE)                           \
+  do {                                                            \
+    if (astVisitor && RAW) {                                      \
+      newline();                                                  \
+      printThing0(NAME, VALUE);                                   \
+    }                                                             \
+  } while(0)
+
+// TODO: refactor uniqueIdAST into IdentityManager
+#define printPtr0(NAME, VALUE)                                    \
+  do {                                                            \
+    newline();                                                    \
+    *out << #NAME "=";                                            \
+    outputXmlPointerQuoted(*out, idmgr.idPrefix(VALUE),           \
+                           idmgr.uniqueId(VALUE));                \
+  } while(0)
+
+#define printPtr1(NAME, VALUE)                                    \
+  if (!serializeOracle ||                                         \
+      serializeOracle->shouldSerialize(VALUE)) {                  \
+    printPtr0(NAME, VALUE);                                       \
+  }
+
+// quarl 2006-05-28
+//    Don't print attributes of pointers which point to NULL.
+#define printPtr(BASE, MEM)                                       \
+  do {                                                            \
+    if ((BASE)->MEM) {                                            \
+      printPtr1(MEM, (BASE)->MEM);                                \
+    }                                                             \
+  } while(0)
+
+// NOTE: don't do this as there is no shouldSerialize infrastructre
+// for AST nodes
+//       if (!serializeOracle ||
+//           serializeOracle->shouldSerialize((BASE)->MEM)) {
+#define printPtrAST(BASE, MEM)                                    \
+  do {                                                            \
+    if (astVisitor && ((BASE)->MEM)) {                            \
+      newline();                                                  \
+      *out << #MEM "=";                                           \
+      outputXmlPointerQuoted(*out, "AST",                         \
+                             uniqueIdAST((BASE)->MEM));           \
+    }                                                             \
+  } while(0)
+
+// print an embedded thing
+#define printEmbed(BASE, MEM) printPtr1(MEM, (&((BASE)->MEM)))
+
+// for unions where the member name does not match the xml name and we
+// don't want the 'if'
+#define printPtrUnion(BASE, MEM, NAME)                            \
+  do {                                                            \
+    if (!serializeOracle ||                                       \
+        serializeOracle->shouldSerialize((BASE)->MEM)) {          \
+      newline();                                                  \
+      *out << #NAME "=";                                          \
+      outputXmlPointerQuoted(*out, idmgr.idPrefix((BASE)->MEM),   \
+                             idmgr.uniqueId((BASE)->MEM));        \
+    }                                                             \
+  } while(0)
+
+// this is only used in one place
+// NOTE: don't do this as there is no shouldSerialize infrastructre
+// for AST nodes
+//       if (!serializeOracle ||
+//           serializeOracle->shouldSerialize((BASE)->MEM)) {
+#define printPtrASTUnion(BASE, MEM, NAME)                         \
+  do {                                                            \
+    if (astVisitor) {                                             \
+      newline();                                                  \
+      *out << #NAME "=";                                          \
+      outputXmlPointerQuoted(*out, "AST",                         \
+                             uniqueIdAST((BASE)->MEM));           \
+    }                                                             \
+  } while(0)
+
+#define printXml(NAME, VALUE)                                     \
+  do {                                                            \
+    newline();                                                    \
+    printThing0(NAME, ::toXml(VALUE));                            \
+  } while(0)
+
+#define printXml_bool(NAME, VALUE)                                \
+  do {                                                            \
+    newline();                                                    \
+    printThing0_ne(NAME, ::toXml_bool(VALUE));                    \
+  } while(0)
+
+#define printXml_int(NAME, VALUE)                                 \
+  do {                                                            \
+    newline();                                                    \
+    printThing0_ne(NAME, ::toXml_int(VALUE));                     \
+  } while(0)
+
+#define printXml_SourceLoc(NAME, VALUE)                           \
+  do {                                                            \
+    newline();                                                    \
+    printThing0(NAME, ::toXml_SourceLoc(VALUE));                  \
+  } while(0)
+
+// #define printStrRef(NAME, VALUE) tagPrinter.printStrRef0(#NAME, VALUE)
+
+#define printStrRef(NAME, VALUE)                                  \
+  do {                                                            \
+    if (VALUE) {                                                  \
+      newline();                                                  \
+      *out << #NAME "=";                                          \
+      outputXmlAttrQuoted(*out, VALUE);                           \
+    }                                                             \
+  } while(0)
+
+// FIX: rename this; it also works for ArrayStacks
+#define travObjList0(OBJ, TAGNAME, FIELDTYPE, ITER_MACRO, LISTKIND)            \
+  do {                                                                         \
+    if (!idmgr.printed(&OBJ)) {                                                \
+      XmlTagPrinter tagPrinter(*this);                                         \
+      if (writingP()) {                                                        \
+        tagPrinter.printOpenTag("List_" #TAGNAME, &OBJ);                       \
+        tagPrinter.tagEnd();                                                   \
+      }                                                                        \
+      ITER_MACRO(FIELDTYPE, const_cast<LISTKIND<FIELDTYPE>&>(OBJ), iter) {     \
+        FIELDTYPE *obj0 = iter.data();                                         \
+        if (!serializeOracle || serializeOracle->shouldSerialize(obj0)) {      \
+          travListItem(obj0);                                                  \
+        }                                                                      \
+      }                                                                        \
+    }                                                                          \
+  } while(0)
+
+#define travObjList1(OBJ, BASETYPE, FIELD, FIELDTYPE, ITER_MACRO, LISTKIND) \
+  travObjList0(OBJ, BASETYPE ##_ ##FIELD, FIELDTYPE, ITER_MACRO, LISTKIND)
+
+#define travObjList_S(BASE, BASETYPE, FIELD, FIELDTYPE) \
+  travObjList1(BASE->FIELD, BASETYPE, FIELD, FIELDTYPE, SFOREACH_OBJLIST_NC, SObjList)
+
+#define travObjListPtr_S(BASE, BASETYPE, FIELD, FIELDTYPE) \
+  travObjList1(*(BASE->FIELD), BASETYPE, FIELD, FIELDTYPE, SFOREACH_OBJLIST_NC, SObjList)
+
+#define travObjList(BASE, BASETYPE, FIELD, FIELDTYPE) \
+  travObjList1(BASE->FIELD, BASETYPE, FIELD, FIELDTYPE, FOREACH_OBJLIST_NC, ObjList)
+
+// Not tested; put the backslash back after the first line
+//  #define travArrayStack(BASE, BASETYPE, FIELD, FIELDTYPE)
+//  travObjList1(BASE->FIELD, BASETYPE, FIELD, FIELDTYPE, FOREACH_ARRAYSTACK_NC, ArrayStack)
+
+#define travObjList_standalone(OBJ, BASETYPE, FIELD, FIELDTYPE) \
+  travObjList1(OBJ, BASETYPE, FIELD, FIELDTYPE, FOREACH_OBJLIST_NC, ObjList)
+
+#define travStringRefMap0(OBJ, BASETYPE, FIELD, RANGETYPE)                     \
+  do {                                                                         \
+    if (!idmgr.printed(OBJ)) {                                                 \
+      XmlTagPrinter tagPrinter(*this);                                         \
+      if (writingP()) {                                                        \
+        tagPrinter.printOpenTag("NameMap_" #BASETYPE "_" #FIELD, OBJ);         \
+        tagPrinter.tagEnd();                                                   \
+      }                                                                        \
+      if (sortNameMapDomainWhenSerializing) {                                  \
+        for(StringRefMap<RANGETYPE>::SortedKeyIter iter(*(OBJ));               \
+            !iter.isDone(); iter.adv()) {                                      \
+          RANGETYPE *obj = iter.value();                                       \
+          if (!serializeOracle || serializeOracle->shouldSerialize(obj)) {     \
+            XmlTagPrinter tagPrinter2(*this);                                  \
+            if (writingP()) {                                                  \
+              tagPrinter2.printNameMapItemOpenTag(iter.key(), obj);            \
+            }                                                                  \
+            trav(obj);                                                         \
+          }                                                                    \
+        }                                                                      \
+      } else {                                                                 \
+        for(PtrMap<char const, RANGETYPE>::Iter iter(*(OBJ));                  \
+            !iter.isDone(); iter.adv()) {                                      \
+          RANGETYPE *obj = iter.value();                                       \
+          if (!serializeOracle || serializeOracle->shouldSerialize(obj)) {     \
+            XmlTagPrinter tagPrinter2(*this);                                  \
+            if (writingP()) {                                                  \
+              tagPrinter2.printNameMapItemOpenTag(iter.key(), obj);            \
+            }                                                                  \
+            trav(obj);                                                         \
+          }                                                                    \
+        }                                                                      \
+      }                                                                        \
+    }                                                                          \
+  } while(0)
+
+#define travStringRefMap(BASE, BASETYPE, FIELD, RANGETYPE) \
+  travStringRefMap0(&((BASE)->FIELD), BASETYPE, FIELD, RANGETYPE)
+
+
+#define trav(TARGET)                                                           \
+  do {                                                                         \
+    if (TARGET && (!serializeOracle || serializeOracle->shouldSerialize(TARGET))) { \
+      toXml(TARGET);                                                           \
+    }                                                                          \
+  } while(0)
+
+// NOTE: you must not wrap this one in a 'do {} while(0)': the dtor
+// for the XmlCloseTagPrinter fires too early.
+
+#define travListItem(TARGET)                                      \
+  XmlTagPrinter tagPrinter(*this);                                \
+  if (writingP()) {                                               \
+    tagPrinter.printListItemOpenTag(TARGET);                      \
+  }                                                               \
+  IncDec depthManager(this->depth);                               \
+  trav(TARGET)
+
+#define travAST(TARGET)                                           \
+  do {                                                            \
+    if (TARGET) {                                                 \
+      if (astVisitor) (TARGET)->traverse(*astVisitor);            \
+    }                                                             \
+  } while(0)
+
+
+#endif // XML_WRITER_H

Added: vendor/elsa/current/license.txt
===================================================================
--- vendor/elsa/current/license.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/license.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,32 @@
+The software in this directory is
+Copyright (c) 2002, Regents of the University of California
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above 
+      copyright notice, this list of conditions and the following 
+      disclaimer in the documentation and/or other materials provided 
+      with the distribution.
+
+    * Neither the name of the University of California, Berkeley nor 
+      the names of its contributors may be used to endorse or promote 
+      products derived from this software without specific prior 
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: vendor/elsa/current/readme.txt
===================================================================
--- vendor/elsa/current/readme.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/readme.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,33 @@
+readme.txt for Elkhound/Elsa distribution
+-----------------------------------------
+
+This release is provided under the BSD license.  See license.txt.
+
+Elkhound is a parser generator.  
+Elsa is a C/C++ parser that uses Elkhound.
+
+See additional documentation in index.html in the various 
+subdirectories.
+
+Alternatively, see the Documentation section of
+http://www.cs.berkeley.edu/~smcpeak/elkhound/ .
+
+
+Build instructions:
+
+  $ ./configure 
+  $ make
+  $ make check     (optional but a good idea)
+
+This simply does each of these activities in each of the directories:
+smbase, ast, elkhound and elsa.  If a command fails you can restart it
+in a particular directory just by going into the failing directory and
+issuing it there.
+
+After building, the interesting binary is elsa/ccparse.  See
+elsa/index.html for more info on what to do with it.
+
+
+If you run into problems you can email me: smcpeak at cs.berkeley.edu
+But be aware I'm usually pretty busy so responses may take a couple
+of days.

Added: vendor/elsa/current/smbase/.gdbinit
===================================================================
--- vendor/elsa/current/smbase/.gdbinit	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/.gdbinit	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,6 @@
+
+file srcloc
+
+break main
+break breaker
+run

Added: vendor/elsa/current/smbase/SMBASE.IDE
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/smbase/SMBASE.IDE
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/smbase/array.h
===================================================================
--- vendor/elsa/current/smbase/array.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/array.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,535 @@
+// array.h            see license.txt for copyright and terms of use
+// some array classes
+
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#include "xassert.h"      // xassert
+#include <stdlib.h>       // qsort
+
+
+// -------------------- Array ----------------------
+// This is the same as C++'s built-in array, but automatically deallocates.
+// If you want bounds checking too, use GrowArray, below.
+template <class T>
+class Array {
+private:     // data
+  T *arr;
+
+private:     // not allowed
+  Array(Array&);
+  void operator=(Array&);
+
+public:
+  Array(int len) : arr(new T[len]) {}
+  ~Array() { delete[] arr; }
+
+  T const &operator[] (int i) const { return arr[i]; }
+  T &operator[] (int i) { return arr[i]; }
+
+  operator T const* () const { return arr; }
+  operator T const* () { return arr; }
+  operator T * () { return arr; }
+
+  T const *ptrC() const { return arr; }
+  T *ptr() { return arr; }
+
+  T const* operator+ (int i) const { return arr+i; }
+  T * operator+ (int i) { return arr+i; }
+
+  // convenience
+  void setAll(T val, int len) {
+    for (int i=0; i<len; i++) {
+      arr[i] = val;
+    }
+  }
+};
+
+
+// ------------------ GrowArray --------------------
+// This class implements an array of T's; it automatically expands
+// when 'ensureAtLeast' or 'ensureIndexDoubler' is used; it does not
+// automatically contract.  All accesses are bounds-checked.
+//
+// class T must have:
+//   T::T();           // default ctor for making arrays
+//   operator=(T&);    // assignment for copying to new storage
+//   T::~T();          // dtor for when old array is cleared
+template <class T>
+class GrowArray {
+private:     // data
+  T *arr;                 // underlying array; NULL if sz==0
+  int sz;                 // # allocated entries in 'arr'
+
+private:     // funcs
+  void bc(int i) const    // bounds-check an index
+    { xassert((unsigned)i < (unsigned)sz); }
+  void eidLoop(int index);
+
+  // make 'this' equal to 'obj'
+  void copyFrom(GrowArray<T> const &obj) {
+    setSize(obj.size());     // not terribly efficient, oh well
+    copyFrom_limit(obj, sz);
+  }
+
+protected:   // funcs
+  void copyFrom_limit(GrowArray<T> const &obj, int limit);
+
+private:     // disallowed
+  void operator=(GrowArray&);
+  void operator==(GrowArray&);
+
+public:      // funcs
+  GrowArray(int initSz);
+  GrowArray(GrowArray const &obj) : arr(0), sz(0) { copyFrom(obj); }
+  ~GrowArray();
+
+  GrowArray& operator=(GrowArray const &obj) { copyFrom(obj); return *this; }
+
+  // allocated space
+  int size() const { return sz; }
+
+  // element access
+  T const& operator[] (int i) const   { bc(i); return arr[i]; }
+  T      & operator[] (int i)         { bc(i); return arr[i]; }
+
+  // set size, reallocating if old size is different; if the
+  // array gets bigger, existing elements are preserved; if the
+  // array gets smaller, elements are truncated
+  void setSize(int newSz);
+
+  // make sure there are at least 'minSz' elements in the array;
+  void ensureAtLeast(int minSz)
+    { if (minSz > sz) { setSize(minSz); } }
+
+  // grab a read-only pointer to the raw array
+  T const *getArray() const { return arr; }
+
+  // grab a writable pointer; use with care
+  T *getDangerousWritableArray() { return arr; }
+  T *getArrayNC() { return arr; }     // ok, not all that dangerous..
+
+  // make sure the given index is valid; if this requires growing,
+  // do so by doubling the size of the array (repeatedly, if
+  // necessary)
+  void ensureIndexDoubler(int index)
+    { if (sz-1 < index) { eidLoop(index); } }
+
+  // set an element, using the doubler if necessary
+  void setIndexDoubler(int index, T const &value)
+    { ensureIndexDoubler(index); arr[index] = value; }
+
+  // swap my data with the data in another GrowArray object
+  void swapWith(GrowArray<T> &obj) {
+    T *tmp1 = obj.arr; obj.arr = this->arr; this->arr = tmp1;
+    int tmp2 = obj.sz; obj.sz = this->sz; this->sz = tmp2;
+  }
+
+  // set all elements to a single value
+  void setAll(T val) {
+    for (int i=0; i<sz; i++) {
+      arr[i] = val;
+    }
+  }
+};
+
+
+template <class T>
+GrowArray<T>::GrowArray(int initSz)
+{
+  sz = initSz;
+  if (sz > 0) {
+    arr = new T[sz];
+  }
+  else {
+    arr = NULL;
+  }
+}
+
+
+template <class T>
+GrowArray<T>::~GrowArray()
+{
+  if (arr) {
+    delete[] arr;
+  }
+}
+
+
+template <class T>
+void GrowArray<T>::copyFrom_limit(GrowArray<T> const &obj, int limit)
+{
+  for (int i=0; i<limit; i++) {
+    arr[i] = obj.arr[i];
+  }
+}
+
+
+template <class T>
+void GrowArray<T>::setSize(int newSz)
+{
+  if (newSz != sz) {
+    // keep track of old
+    int oldSz = sz;
+    T *oldArr = arr;
+
+    // make new
+    sz = newSz;
+    if (sz > 0) {
+      arr = new T[sz];
+    }
+    else {
+      arr = NULL;
+    }
+
+    // copy elements in common
+    for (int i=0; i<sz && i<oldSz; i++) {
+      arr[i] = oldArr[i];
+    }
+
+    // get rid of old
+    if (oldArr) {
+      delete[] oldArr;
+    }
+  }
+}
+
+
+// this used to be ensureIndexDoubler's implementation, but
+// I wanted the very first check to be inlined
+template <class T>
+void GrowArray<T>::eidLoop(int index)
+{
+  if (sz-1 >= index) {
+    return;
+  }
+
+  int newSz = sz;
+  while (newSz-1 < index) {
+    #ifndef NDEBUG_NO_ASSERTIONS    // silence warning..
+      int prevSz = newSz;
+    #endif
+    if (newSz == 0) {
+      newSz = 1;
+    }
+    newSz = newSz*2;
+    xassert(newSz > prevSz);        // otherwise overflow -> infinite loop
+  }
+
+  setSize(newSz);
+}
+
+
+// ---------------------- ArrayStack ---------------------
+// This is an array where some of the array is unused.  Specifically,
+// it maintains a 'length', and elements 0 up to length-1 are
+// considered used, whereas length up to size-1 are unused.  The
+// expected use is as a stack, where "push" adds a new (used) element.
+template <class T>
+class ArrayStack : public GrowArray<T> {
+private:
+  int len;               // # of elts in the stack
+
+public:
+  ArrayStack(int initArraySize = 10)
+    : GrowArray<T>(initArraySize),
+      len(0)
+    {}
+  ArrayStack(ArrayStack<T> const &obj)
+    : GrowArray<T>(obj),
+      len(obj.len)
+    {}
+  ~ArrayStack();
+
+  // copies contents of 'obj', but the allocated size of 'this' will
+  // only change when necessary
+  ArrayStack& operator=(ArrayStack<T> const &obj)
+  {
+    this->ensureIndexDoubler(obj.length() - 1);
+    this->copyFrom_limit(obj, obj.length());
+    len = obj.len;
+    return *this;
+  }
+
+  // element access; these declarations are necessary because
+  // the uses of 'operator[]' below are not "dependent", hence
+  // they can't use declarations inherited from GrowArray<T>
+  T const& operator[] (int i) const { return GrowArray<T>::operator[](i); }
+  T      & operator[] (int i)       { return GrowArray<T>::operator[](i); }
+
+  void push(T const &val)
+    { setIndexDoubler(len++, val); }
+  T pop()
+    { return operator[](--len); }
+  T const &top() const
+    { return operator[](len-1); }
+  T &top()
+    { return operator[](len-1); }
+  T &nth(int which)
+    { return operator[](len-1-which); }
+
+  // alternate interface, where init/deinit is done explicitly
+  // on returned references
+  T &pushAlt()    // returns newly accessible item
+    { GrowArray<T>::ensureIndexDoubler(len++); return top(); }
+  T &popAlt()     // returns item popped
+    { return operator[](--len); }
+
+  // items stored
+  int length() const
+    { return len; }
+
+  bool isEmpty() const
+    { return len==0; }
+  bool isNotEmpty() const
+    { return !isEmpty(); }
+
+  void popMany(int ct)
+    { len -= ct; xassert(len >= 0); }
+  void empty()
+    { len = 0; }
+
+  // useful when someone has used 'getDangerousWritableArray' to
+  // fill the array's internal storage
+  void setLength(int L) { len = L; }
+
+  // consolidate allocated space to match length
+  void consolidate() { this->setSize(length()); }
+
+  // swap
+  void swapWith(ArrayStack<T> &obj) {
+    GrowArray<T>::swapWith(obj);
+    int tmp = obj.len; obj.len = this->len; this->len = tmp;
+  }
+
+  void sort(int (*compare)(T const *t1, T const *t2)) {
+    qsort(GrowArray<T>::getArrayNC(), len, sizeof(T),
+          (int (*)(void const*, void const*))compare );
+  }
+};
+
+template <class T>
+ArrayStack<T>::~ArrayStack()
+{}
+
+
+// iterator over contents of an ArrayStack, to make it easier to
+// switch between it and SObjList as a representation
+template <class T>
+class ArrayStackIterNC {
+  NO_OBJECT_COPIES(ArrayStackIterNC);   // for now
+
+private:     // data
+  ArrayStack<T> /*const*/ &arr;   // array being accessed
+  int index;                      // current element
+
+public:      // funcs
+  ArrayStackIterNC(ArrayStack<T> /*const*/ &a) : arr(a), index(0) {}
+
+  // iterator actions
+  bool isDone() const             { return index >= arr.length(); }
+  void adv()                      { xassert(!isDone()); index++; }
+  T /*const*/ *data() const       { return &(arr[index]); }
+};
+
+#define FOREACH_ARRAYSTACK_NC(T, list, iter) \
+  for(ArrayStackIterNC< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// I want const polymorphism!
+
+
+// pop (and discard) a value off a stack at end of scope
+template <class T>
+class ArrayStackPopper {
+private:
+  ArrayStack<T> &stk;
+
+public:
+  ArrayStackPopper(ArrayStack<T> &s) : stk(s) {}
+  ArrayStackPopper(ArrayStack<T> &s, T const &pushVal)
+    : stk(s) { stk.push(pushVal); }
+  ~ArrayStackPopper()
+    { stk.pop(); }
+};
+
+template <class T> class ObjArrayStackIterNC;
+
+// ------------------- ObjArrayStack -----------------
+// an ArrayStack of owner pointers
+template <class T>
+class ObjArrayStack {
+  friend class ObjArrayStackIterNC<T>;
+private:    // data
+  ArrayStack<T*> arr;
+
+public:     // funcs
+  ObjArrayStack(int initArraySize = 10)
+    : arr(initArraySize)
+    {}
+  ~ObjArrayStack() { deleteAll(); }
+
+  void push(T *ptr)          { arr.push(ptr); }
+  // synonym of 'push', for compatibility with ObjList
+  void append(T *ptr)        { arr.push(ptr); }
+  T *pop()                   { return arr.pop(); }
+
+  T const *topC() const      { return arr.top(); }
+  T       *top()             { return arr.top(); }
+
+  T const * operator[](int index) const  { return arr[index]; }
+  T *       operator[](int index)        { return arr[index]; }
+
+  int length() const         { return arr.length(); }
+  bool isEmpty() const       { return arr.isEmpty(); }
+  bool isNotEmpty() const    { return !isEmpty(); }
+
+  void deleteTopSeveral(int ct);
+  void deleteAll()           { deleteTopSeveral(length()); }
+
+  // remove an element from the middle, shifting others down to
+  // maintain the original order
+  T *removeIntermediate(int toRemove);
+
+  // will not delete any items
+  void consolidate()         { arr.consolidate(); }
+
+  void swapWith(ObjArrayStack<T> &obj)   { arr.swapWith(obj.arr); }
+};
+
+
+template <class T>
+void ObjArrayStack<T>::deleteTopSeveral(int ct)
+{
+  while (ct--) {
+    delete pop();
+  }
+}
+
+
+template <class T>
+T *ObjArrayStack<T>::removeIntermediate(int toRemove)
+{
+  T *ret = arr[toRemove];
+
+  // shift remaining elements down
+  for (int i=toRemove+1; i < length(); i++) {
+    arr[i-1] = arr[i];
+  }
+
+  // remove and throw away the final (now redundant) pointer
+  pop();
+
+  return ret;
+}
+
+template <class T>
+class ObjArrayStackIterNC {
+  NO_OBJECT_COPIES(ObjArrayStackIterNC);
+
+private:     // data
+  ObjArrayStack<T> /*const*/ &arr;   // array being accessed
+  int index;                      // current element
+
+public:      // funcs
+  ObjArrayStackIterNC(ObjArrayStack<T> /*const*/ &a) : arr(a), index(0) {}
+
+  // iterator actions
+  bool isDone() const             { return index >= arr.length(); }
+  void adv()                      { xassert(!isDone()); index++; }
+  T /*const*/ *data() const       { return arr[index]; }
+};
+
+#define FOREACH_OBJARRAYSTACK_NC(T, list, iter) \
+  for(ObjArrayStackIterNC< T > iter(list); !iter.isDone(); iter.adv())
+
+// ------------------------- ArrayStackEmbed --------------------------
+// This is like ArrayStack, but the first 'n' elements are stored
+// embedded in this object, instead of allocated on the heap; in some
+// circumstances, this lets us avoid allocating memory in common cases.
+//
+// For example, suppose you have an algorithm that is usually given a
+// small number of elements, say 1 or 2, but occasionally needs to
+// work with more.  If you put the array of elements in the heap, then
+// even in the common case a heap allocation is required, which is
+// bad.  But by using ArrayStackEmbed<T,2>, you can be sure that if
+// the number of elements is <= 2 there will be no heap allocation,
+// even though you still get a uniform (array-like) interface to all
+// the elements.
+template <class T, int n>
+class ArrayStackEmbed {
+private:      // data
+  // embedded storage
+  T embed[n];
+
+  // heap-allocated storage
+  GrowArray<T> heap;
+
+  // total number of elements in the stack; if this
+  // exceeds 'n', then heap.arr is non-NULL
+  int len;
+
+private:      // funcs
+  void bc(int i) const    // bounds-check an index
+    { xassert((unsigned)i < (unsigned)len); }
+
+public:       // funcs
+  ArrayStackEmbed()
+    : /*embed is default-init'd*/
+      heap(0),    // initially a NULL ptr
+      len(0)
+  {}
+  ~ArrayStackEmbed()
+  {}              // heap auto-deallocs its internal data
+
+  void push(T const &val)
+  {
+    if (len < n) {
+      embed[len++] = val;
+    }
+    else {
+      heap.setIndexDoubler(len++ - n, val);
+    }
+  }
+
+  T pop()
+  {
+    xassert(len > 0);
+    if (len <= n) {
+      return embed[--len];
+    }
+    else {
+      return heap[--len - n];
+    }
+  }
+
+  int length() const
+    { return len; }
+  bool isEmpty() const
+    { return len==0; }
+  bool isNotEmpty() const
+    { return !isEmpty(); }
+
+  // direct element access
+  T const &getElt(int i) const
+  {
+    bc(i);
+    if (i < n) {
+      return embed[i];
+    }
+    else {
+      return heap[i - n];
+    }
+  }
+
+  T const& operator[] (int i) const
+    { return getElt(i); }
+  T & operator[] (int i)
+    { return const_cast<T&>(getElt(i)); }
+
+  T const &top() const
+    { return getElt(len-1); }
+};
+
+
+#endif // ARRAY_H

Added: vendor/elsa/current/smbase/arraymap.h
===================================================================
--- vendor/elsa/current/smbase/arraymap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/arraymap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,126 @@
+// arraymap.h            see license.txt for copyright and terms of use
+// template class to maintain an array-based map from
+// integers to object pointers; the map owns all of
+// the objects referred-to
+
+// as far as I know, nothing currently uses this file, but
+// I believe it *has* been tested (whatever once used it now
+// uses something else)
+
+#ifndef ARRAYMAP_H
+#define ARRAYMAP_H
+
+#include "xassert.h"     // xassert
+
+// map: int -> T
+template <class T>
+class ArrayMap {
+private:     // data
+  T **map;               // array[0,nextId-1] of owner ptr
+  int nextId;            // next id to assign
+  int mapSize;           // allocated size of 'map'
+
+private:     // funcs
+  void make();
+  void del();
+  void validate(int index) const;
+
+public:      // data
+  ArrayMap() { make(); }
+  ~ArrayMap() { del(); }
+
+  // # of elements defined
+  int count() const { return nextId; }
+
+  // insert a new element and yield its assigned id
+  int insert(T * /*owner*/ t);
+
+  // retrieve by id
+  T const *lookupC(int id) const;
+  T *lookup(int id) { return const_cast<T*>(lookupC(id)); }
+  T *&lookupRef(int id) { validate(id); return map[id]; }
+
+  // throw everything away
+  void empty() { del(); make(); }
+};
+
+template <class T>
+void ArrayMap<T>::make()
+{
+  mapSize = 100;
+  nextId = 0;
+  map = new T* [mapSize];
+}
+
+template <class T>
+void ArrayMap<T>::del()
+{
+  for (int i=0; i<nextId; i++) {
+    delete map[i];
+  }
+  delete[] map;
+}
+
+template <class T>
+int ArrayMap<T>::insert(T *t)
+{
+  if (nextId == mapSize) {
+    // make it bigger
+    int newMapSize = mapSize * 2;
+    T **newMap = new T* [newMapSize];
+
+    // copy the old contents to the new map
+    for (int i=0; i<mapSize; i++) {
+      newMap[i] = map[i];
+    }
+    mapSize = newMapSize;
+
+    // blow away the old map
+    delete[] map;
+
+    // grab the new map
+    map = newMap;
+  }
+
+  int ret = nextId++;
+  map[ret] = t;
+  return ret;
+}
+
+template <class T>
+void ArrayMap<T>::validate(int id) const
+{
+  xassert(0 <= id && id < nextId);
+}
+
+template <class T>
+T const *ArrayMap<T>::lookupC(int id) const
+{
+  validate(id);
+  return map[id];
+}
+
+
+#define FOREACH_ARRAYMAP(type, array, var)       \
+  type const *var = NULL;                        \
+  for (int var##id=0;                            \
+       var##id<(array).count() &&                \
+         (var=(array).lookupC(var##id), true);   \
+       var##id++)
+
+
+#define FOREACH_ARRAYMAP_INDEX(array, var)   \
+  for (int var=0;                            \
+       var<(array).count();                  \
+       var++)
+
+
+#define MUTATE_EACH_ARRAYMAP(type, array, var)   \
+  type *var = NULL;                              \
+  for (int var##id=0;                            \
+       var##id<(array).count() &&                \
+         (var=(array).lookup(var##id), true);    \
+       var##id++)
+
+
+#endif // ARRAYMAP_H

Added: vendor/elsa/current/smbase/arrayqueue.h
===================================================================
--- vendor/elsa/current/smbase/arrayqueue.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/arrayqueue.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,180 @@
+// arrayqueue.h
+// queue, implemented with an array
+
+#ifndef ARRAYQUEUE_H
+#define ARRAYQUEUE_H
+
+#include "xassert.h"           // xassert
+
+// needed operations on T:
+//   T()                       // default ctor
+//   operator=(T&)             // assignment
+//   bool operator==(T&)       // comparison
+
+template <class T>
+class ArrayQueue {
+private:     // data
+  T *arr;                      // working storage
+  int arrSize;                 // allocated length of 'arr'
+  int head;                    // index of first element to dequeue
+  int tail;                    // index+1 of last element to dequeue
+
+  // NOTE: If head == tail then the queue is empty.  If head > tail,
+  // then the queue elements circularly wrap around the end of 'arr'.
+  // At all times, 0 <= head,tail < arrSize.
+
+public:      // funcs
+  ArrayQueue(int initSize = 10);
+  ~ArrayQueue();
+
+  // test # of elements in queue
+  int length() const
+    { return head<=tail? tail-head : arrSize-(head-tail); }
+  bool isEmpty() const                  { return head==tail; }
+  bool isNotEmpty() const               { return !isEmpty(); }
+
+  // add/remove elements in FIFO order
+  void enqueue(T const &t);
+  T dequeue();
+
+  // remove all elements
+  void empty()                          { head = tail = 0; }
+
+  // access elements of the queue in dequeue order; that is,
+  // element 0 is the next element to be dequeued, and element
+  // length()-1 is the element most recently enqueued
+  //
+  // as this interface is O(1), it is the intended method
+  // of iterating over the elements in the queue
+  T const &eltC(int index) const;
+  T &elt(int index)                     { return const_cast<T&>(eltC(index)); }
+  T &operator[] (int index)             { return elt(index); }
+  T const &operator[] (int index) const { return eltC(index); }
+
+  // reverse the sequence of stored elements
+  void reverse();
+
+  // true if a specific element is among the queue elements
+  bool contains(T const &t) const;
+};
+
+
+template <class T>
+ArrayQueue<T>::ArrayQueue(int initSize)
+{
+  // initial size must be positive, since array growth is
+  // simply by doubling the size
+  xassert(initSize > 0);
+
+  arr = new T[initSize];
+  arrSize = initSize;
+  head = tail = 0;
+}
+
+
+template <class T>
+ArrayQueue<T>::~ArrayQueue()
+{
+  delete[] arr;
+}
+
+
+template <class T>
+void ArrayQueue<T>::enqueue(T const &t)
+{
+  if (length() == arrSize-1) {
+    // must expand the queue
+
+    // make new array
+    int newArrSize = arrSize * 2;
+    T *newArr = new T[newArrSize];
+
+    // copy elements sequentially
+    int oldLength = length();
+    for (int i=0; i<oldLength; i++) {
+      newArr[i] = eltC(i);
+    }
+
+    // discard old array
+    delete[] arr;
+
+    // put new one in its place
+    arr = newArr;
+    arrSize = newArrSize;
+    head = 0;
+    tail = oldLength;
+  }
+  
+  // store the new element where 'tail' points
+  arr[tail] = t;
+  
+  // advance 'tail'
+  if (++tail == arrSize) {
+    tail = 0;
+  }
+}
+
+
+template <class T>
+T ArrayQueue<T>::dequeue()
+{
+  if (isEmpty()) {
+    xfailure("attempt to dequeue an empty queue");
+  }
+
+  // advance 'head' while yielding the element it currently points at;
+  // avoid making an intermediate copy (for performance)
+  if (head == arrSize-1) {
+    head = 0;
+    return arr[arrSize-1];
+  }
+  else {
+    return arr[head++];
+  }
+}
+
+  
+template <class T>
+T const &ArrayQueue<T>::eltC(int index) const
+{                         
+  xassert(0 <= index && index < length());
+
+  if (head+index < arrSize) {
+    return arr[head+index];
+  }
+  else {
+    return arr[head+index - arrSize];
+  }
+}
+
+
+template <class T>
+void ArrayQueue<T>::reverse()
+{
+  int i = 0, j = length()-1;
+  while (i < j) {
+    // swap i,j elements
+    T tmp = elt(i);
+    elt(i) = elt(j);
+    elt(j) = tmp;
+
+    i++;
+    j--;
+  }
+}
+
+
+template <class T>
+bool ArrayQueue<T>::contains(T const &t) const
+{                                 
+  int len=length();
+  for (int i=0; i<len; i++) {
+    if (t == eltC(i)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+#endif // ARRAYQUEUE_H

Added: vendor/elsa/current/smbase/astlist.h
===================================================================
--- vendor/elsa/current/smbase/astlist.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/astlist.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,225 @@
+// astlist.h            see license.txt for copyright and terms of use
+// owner list wrapper around VoidTailList
+// name 'AST' is because the first application is in ASTs
+
+#ifndef ASTLIST_H
+#define ASTLIST_H
+
+#include "vdtllist.h"     // VoidTailList
+
+template <class T> class ASTListIter;
+template <class T> class ASTListIterNC;
+template <class T> class ASTListMutator;
+
+// a list which owns the items in it (will deallocate them), and
+// has constant-time access to the last element
+template <class T>
+class ASTList {
+private:
+  friend class ASTListIter<T>;
+  friend class ASTListIterNC<T>;
+  friend class ASTListMutator<T>;
+
+protected:
+  VoidTailList list;                    // list itself
+
+private:
+  ASTList(ASTList const &obj);          // not allowed
+  void operator=(ASTList const &obj);   // not allowed
+
+public:
+  ASTList()                             : list() {}
+  ~ASTList()                            { deleteAll(); }
+
+  // ctor to make singleton list; often quite useful
+  ASTList(T *elt)                       : list() { prepend(elt); }
+
+  // stealing ctor; among other things, since &src->list is assumed to
+  // point at 'src', this class can't have virtual functions;
+  // these ctors delete 'src'
+  ASTList(ASTList<T> *src)              : list(&src->list) {}
+  void steal(ASTList<T> *src)           { deleteAll(); list.steal(&src->list); }
+
+  // selectors
+  int count() const                     { return list.count(); }
+  bool isEmpty() const                  { return list.isEmpty(); }
+  bool isNotEmpty() const               { return list.isNotEmpty(); }
+  T *nth(int which)                     { return (T*)list.nth(which); }
+  T const *nthC(int which) const        { return (T const*)list.nth(which); }
+  T *first()                            { return (T*)list.first(); }
+  T const *firstC() const               { return (T const*)list.first(); }
+  T *last()                             { return (T*)list.last(); }
+  T const *lastC() const                { return (T const*)list.last(); }
+
+  // insertion
+  void prepend(T *newitem)              { list.prepend(newitem); }
+  void append(T *newitem)               { list.append(newitem); }
+  void appendAll(ASTList<T> &tail)      { list.appendAll(tail.list); }
+  void insertAt(T *newitem, int index)  { list.insertAt(newitem, index); }
+  void concat(ASTList<T> &tail)         { list.concat(tail.list); }
+
+  // removal
+  T *removeFirst()                      { return (T*)list.removeFirst(); }
+  T *removeLast()                       { return (T*)list.removeLast(); }
+  T *removeAt(int index)                { return (T*)list.removeAt(index); }
+  void removeItem(T *item)              { list.removeItem((void*)item); }
+  bool removeIfPresent(T *item)         { return list.removeIfPresent((void*)item); }
+
+  // this one is awkwardly named to remind the user that it's
+  // contrary to the usual intent of this class
+  void removeAll_dontDelete()           { return list.removeAll(); }
+
+  // deletion
+  void deleteFirst()                    { delete (T*)list.removeFirst(); }
+  void deleteAll();
+  void deleteItem(T* item)              { removeItem(item); delete item; }
+
+  // list-as-set: selectors
+  int indexOf(T const *item) const      { return list.indexOf((void*)item); }
+  int indexOfF(T const *item) const     { return list.indexOfF((void*)item); }
+  bool contains(T const *item) const    { return list.contains((void*)item); }
+
+  // list-as-set: mutators
+  bool prependUnique(T *newitem)        { return list.prependUnique(newitem); }
+  bool appendUnique(T *newitem)         { return list.appendUnique(newitem); }
+
+  // debugging: two additional invariants
+  void selfCheck() const                { list.selfCheck(); }
+};
+
+
+template <class T>
+void ASTList<T>::deleteAll()
+{
+  while (!list.isEmpty()) {
+    deleteFirst();
+  }
+}
+
+
+template <class T>
+class ASTListIter {
+protected:
+  VoidTailListIter iter;      // underlying iterator
+
+public:
+  ASTListIter()                        {} // initially done
+  ASTListIter(ASTList<T> const &list) : iter(list.list) {}
+  ~ASTListIter()                       {}
+
+  void reset(ASTList<T> const &list)   { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  ASTListIter(ASTListIter const &obj)             : iter(obj.iter) {}
+  ASTListIter& operator=(ASTListIter const &obj)  { iter = obj.iter;  return *this; }
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T const *data() const                 { return (T const*)iter.data(); }
+};
+
+#define FOREACH_ASTLIST(T, list, iter) \
+  for(ASTListIter<T> iter(list); !iter.isDone(); iter.adv())
+
+
+// version of the above, but for non-const-element traversal
+template <class T>
+class ASTListIterNC {
+protected:
+  VoidTailListIter iter;      // underlying iterator
+
+public:
+  ASTListIterNC()                      {} // initially done
+  ASTListIterNC(ASTList<T> &list)      : iter(list.list) {}
+  ~ASTListIterNC()                     {}
+
+  void reset(ASTList<T> &list)         { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  ASTListIterNC(ASTListIterNC const &obj)             : iter(obj.iter) {}
+  ASTListIterNC& operator=(ASTListIterNC const &obj)  { iter = obj.iter;  return *this; }
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T *data() const                       { return (T*)iter.data(); }
+  T *&dataRef()                         { return (T*&)iter.dataRef(); }
+
+  // iterator mutation; use with caution
+  void setDataLink(T *newData)          { iter.setDataLink((void*)newData); }
+};
+
+#define FOREACH_ASTLIST_NC(T, list, iter) \
+  for(ASTListIterNC<T> iter(list); !iter.isDone(); iter.adv())
+
+
+// this function is somewhat at odds with the nominal purpose
+// of ASTLists, but I need it in a weird situation so ...
+template <class T>
+ASTList<T> *shallowCopy(ASTList<T> *src)
+{
+  ASTList<T> *ret = new ASTList<T>;
+  FOREACH_ASTLIST_NC(T, *src, iter) {
+    ret->append(iter.data());
+  }
+  return ret;
+}
+
+// for traversing the list and modifying it (nodes and/or structure)
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists, and only one such iterator should exist for
+//       any given list
+template <class T>
+class ASTListMutator {
+  friend class ASTListIter<T>;
+
+protected:
+  VoidTailListMutator mut;       // underlying mutator
+
+public:
+  ASTListMutator(ASTList<T> &lst)     : mut(lst.list) { reset(); }
+  ~ASTListMutator()                    {}
+
+  void reset()                          { mut.reset(); }
+
+  // iterator copying; safe *only* until one of the mutators modifies
+  // the list structure (by inserting or removing), at which time all
+  // other iterators might be in limbo
+  ASTListMutator(ASTListMutator const &obj)             : mut(obj.mut) {}
+  ASTListMutator& operator=(ASTListMutator const &obj)  { mut = obj.mut;  return *this; }
+    // requires that 'this' and 'obj' already refer to the same 'list'
+
+  // iterator actions
+  bool isDone() const                   { return mut.isDone(); }
+  void adv()                            { mut.adv(); }
+  T *data()                             { return (T*)mut.data(); }
+  T *&dataRef()                         { return (T*&)mut.dataRef(); }
+
+  // insertion
+  void insertBefore(T *item)            { mut.insertBefore((void*)item); }
+    // 'item' becomes the new 'current', and the current 'current' is
+    // pushed forward (so the next adv() will make it current again)
+
+  void insertAfter(T *item)             { mut.insertAfter((void*)item); }
+    // 'item' becomes what we reach with the next adv();
+    // isDone() must be false
+
+  void append(T *item)                  { mut.append((void*)item); }
+    // only valid while isDone() is true, it inserts 'item' at the end of
+    // the list, and advances such that isDone() remains true; equivalent
+    // to { xassert(isDone()); insertBefore(item); adv(); }
+
+  // removal
+  T *remove()                           { return (T*)mut.remove(); }
+    // 'current' is removed from the list and returned, and whatever was
+    // next becomes the new 'current'
+
+  void deleteIt()                       { delete (T*)mut.remove(); }
+    // same as remove(), except item is deleted also
+
+  // debugging
+  void selfCheck() const                { mut.selfCheck(); }
+};
+
+#endif // ASTLIST_H

Added: vendor/elsa/current/smbase/autofile.cc
===================================================================
--- vendor/elsa/current/smbase/autofile.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/autofile.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,64 @@
+// autofile.cc            see license.txt for copyright and terms of use
+// code for autofile.h
+
+#include "autofile.h"     // this module
+#include "exc.h"          // throw_XOpen
+
+#include <errno.h>        // errno
+#include <string.h>       // strerror
+
+
+FILE *xfopen(char const *fname, char const *mode)
+{
+  FILE *ret = fopen(fname, mode);
+  if (!ret) {
+    throw_XOpenEx(fname, mode, strerror(errno));
+  }
+
+  return ret;
+}
+
+
+AutoFILE::AutoFILE(char const *fname, char const *mode)
+  : AutoFclose(xfopen(fname, mode))
+{}
+
+AutoFILE::~AutoFILE()
+{
+  // ~AutoFclose closes the file
+}
+
+
+// -------------------- test code -------------------
+// really this code is to test XOpenEx and strerror
+#ifdef TEST_AUTOFILE
+
+#include "test.h"         // ARGS_MAIN
+#include <iostream.h>     // cout
+
+void entry(int argc, char *argv[])
+{                         
+  if (argc < 2) {
+    cout << "usage: " << argv[0] << " filename [mode]\n";
+    return;
+  }
+
+  char const *mode = "r";
+  if (argc >= 3) {
+    mode = argv[2];
+  }
+
+  cout << "about to open " << argv[1] << " with mode " << mode << endl;
+
+  {
+    AutoFILE fp(argv[1], mode);
+    cout << argv[1] << " is now open" << endl;
+  }
+
+  cout << argv[1] << " is now closed" << endl;
+}
+
+ARGS_MAIN
+
+
+#endif // TEST_AUTOFILE

Added: vendor/elsa/current/smbase/autofile.h
===================================================================
--- vendor/elsa/current/smbase/autofile.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/autofile.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// autofile.h            see license.txt for copyright and terms of use
+// little wrapper around FILE*
+
+// I have chosen to use 'char const *' here instead of 'rostring'
+// to reduce dependencies on other modules ...
+
+#ifndef AUTOFILE_H
+#define AUTOFILE_H
+
+#include <stdio.h>      // FILE
+
+
+// fopen, but throw an XOpen exception (see exc.h) on failure instead
+// of returning NULL
+FILE *xfopen(char const *fname, char const *mode);
+
+
+// automatically close a file in the destructor
+class AutoFclose {
+private:       // data
+  FILE *fp;           
+  
+private:       // disallowed
+  AutoFclose(AutoFclose&);
+  void operator=(AutoFclose&);
+  
+public:
+  AutoFclose(FILE *f) : fp(f) {}
+  ~AutoFclose() { fclose(fp); }
+
+  // may as well allow access to my storage
+  FILE *getFP() { return fp; }
+};
+
+
+// simple wrapper on FILE*
+class AutoFILE : private AutoFclose {
+public:
+  // open, throwing an XOpen exception on failure
+  AutoFILE(char const *fname, char const *mode);
+
+  // close the file
+  ~AutoFILE();
+
+  // behave like FILE* in between
+  operator FILE* () { return getFP(); }
+};
+
+
+#endif // AUTOFILE_H

Added: vendor/elsa/current/smbase/bflatten.cc
===================================================================
--- vendor/elsa/current/smbase/bflatten.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/bflatten.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,171 @@
+// bflatten.cc            see license.txt for copyright and terms of use
+// code for bflatten.h
+
+#include "bflatten.h"     // this module
+#include "exc.h"          // throw_XOpen
+#include "syserr.h"       // xsyserror
+
+
+BFlatten::BFlatten(char const *fname, bool r)
+  : readMode(r),
+    ownerTable(!r? &BFlatten::getOwnerPtrKeyFn : &BFlatten::getIntNameKeyFn,
+               HashTable::lcprngHashFn,
+               HashTable::pointerEqualKeyFn),
+    nextUniqueName(1)
+{
+  fp = fopen(fname, readMode? "rb" : "wb");
+  if (!fp) {
+    throw_XOpen(fname);
+  }
+}
+
+BFlatten::~BFlatten()
+{
+  fclose(fp);
+}
+
+
+STATICDEF void const* BFlatten::getOwnerPtrKeyFn(OwnerMapping *data)
+{
+  return data->ownerPtr;
+}
+
+STATICDEF void const* BFlatten::getIntNameKeyFn(OwnerMapping *data)
+{ 
+  return (void const*)(data->intName);
+}
+
+
+void BFlatten::xferSimple(void *var, unsigned len)
+{
+  if (writing()) {
+    if (fwrite(var, 1, len, fp) < len) {
+      xsyserror("fwrite");
+    }
+  }
+  else {
+    if (fread(var, 1, len, fp) < len) {
+      xsyserror("fread");
+    }
+  }
+}
+
+
+void BFlatten::noteOwner(void *ownerPtr)
+{
+  // make a new mapping
+  OwnerMapping *map = new OwnerMapping;
+  map->ownerPtr = ownerPtr;
+  map->intName = nextUniqueName++;
+
+  // add it to the table 
+  if (writing()) {
+    // index by pointer
+    ownerTable.add(ownerPtr, map);
+  }
+  else {
+    // index by int name
+    ownerTable.add((void const*)(map->intName), map);
+  }
+}
+
+
+void BFlatten::xferSerf(void *&serfPtr, bool isNullable)
+{
+  if (writing()) {
+    xassert(isNullable || serfPtr!=NULL);
+                                       
+    if (serfPtr == NULL) {
+      // encode as 0; the names start with 1
+      writeInt(0);
+    }
+    else {
+      // lookup the mapping
+      OwnerMapping *map = ownerTable.get(serfPtr);
+
+      // we must have already written the owner pointer
+      xassert(map != NULL);
+
+      // write the int name
+      writeInt(map->intName);
+    }
+  }
+  else /*reading*/ {
+    // read the int name
+    int name = readInt();
+
+    if (name == 0) {      // null
+      xassert(isNullable);
+      serfPtr = NULL;
+    }
+    else {
+      // lookup the mapping
+      OwnerMapping *map = ownerTable.get((void const*)name);
+      formatAssert(map != NULL);
+
+      // return the pointer
+      serfPtr = map->ownerPtr;
+    }
+  }
+}
+
+
+// ------------------------ test code ---------------------
+#ifdef TEST_BFLATTEN
+
+#include "test.h"      // USUAL_MAIN
+
+void entry()
+{                    
+  // make up some data
+  int x = 9, y = 22;
+  string s("foo bar");
+  int *px = &x, *py = &y;
+
+  // open a file for writing them
+  {
+    BFlatten flat("bflat.tmp", false /*reading*/);
+    flat.xferInt(x);
+    flat.noteOwner(&x);
+    s.xfer(flat);
+    flat.xferSerf((void*&)px);
+    flat.xferInt(y);
+    flat.noteOwner(&y);
+    flat.xferSerf((void*&)py);
+  }
+
+  // place to put the data we read
+  int x2, y2;
+  string s2;
+  int *px2, *py2;
+
+  // read them back
+  {
+    BFlatten flat("bflat.tmp", true /*reading*/);
+    flat.xferInt(x2);
+    flat.noteOwner(&x2);
+    s2.xfer(flat);
+    flat.xferSerf((void*&)px2);
+    flat.xferInt(y2);
+    flat.noteOwner(&y2);
+    flat.xferSerf((void*&)py2);
+  }
+
+  // compare
+  xassert(x == x2);
+  xassert(y == y2);
+  xassert(s.equals(s2));
+  xassert(px2 == &x2);
+  xassert(py2 == &y2);
+
+  // delete the temp file
+  remove("bflat.tmp");
+  
+  printf("bflatten works\n");
+}
+
+
+USUAL_MAIN
+
+
+#endif // TEST_BFLATTEN

Added: vendor/elsa/current/smbase/bflatten.h
===================================================================
--- vendor/elsa/current/smbase/bflatten.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/bflatten.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,62 @@
+// bflatten.h            see license.txt for copyright and terms of use
+// binary file flatten implementation
+
+#ifndef BFLATTEN_H
+#define BFLATTEN_H
+
+#include "flatten.h"      // Flatten
+#include "ohashtbl.h"     // OwnerHashTable
+#include <stdio.h>        // FILE
+
+class BFlatten : public Flatten {
+private:     // data
+  FILE *fp;               // file being read/written
+  bool readMode;          // true=read, false=write
+
+  struct OwnerMapping {
+    void *ownerPtr;       // a pointer
+    int intName;          // a unique integer name
+  };
+  OwnerHashTable<OwnerMapping> ownerTable;      // owner <-> int mapping
+  int nextUniqueName;     // counter for making int names
+
+private:     // funcs
+  static void const* getOwnerPtrKeyFn(OwnerMapping *data);
+  static void const* getIntNameKeyFn(OwnerMapping *data);
+
+public:      // funcs
+  // throws XOpen if cannot open 'fname'
+  BFlatten(char const *fname, bool reading);
+  virtual ~BFlatten();
+
+  // Flatten funcs
+  virtual bool reading() const { return readMode; }
+  virtual void xferSimple(void *var, unsigned len);
+  virtual void noteOwner(void *ownerPtr);
+  virtual void xferSerf(void *&serfPtr, bool nullable=false);
+};
+
+                  
+// for debugging, write and then read something
+template <class T>
+T *writeThenRead(T &obj)
+{
+  char const *fname = "flattest.tmp";
+
+  // write
+  {
+    BFlatten out(fname, false /*reading*/);
+    obj.xfer(out);
+  }
+
+  // read
+  BFlatten in(fname, true /*reading*/);
+  T *ret = new T(in);
+  ret->xfer(in);
+
+  remove(fname);
+
+  return ret;
+}
+
+#endif // BFLATTEN_H

Added: vendor/elsa/current/smbase/bit2d.cc
===================================================================
--- vendor/elsa/current/smbase/bit2d.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/bit2d.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,212 @@
+// bit2d.cc            see license.txt for copyright and terms of use
+// code for bit2d.h
+
+#include "bit2d.h"      // this module
+#include "xassert.h"    // xassert
+#include "flatten.h"    // Flatten
+
+#include <string.h>     // memset, memcpy
+#include <stdio.h>      // printf
+
+
+Bit2d::Bit2d(point const &aSize)
+  : owning(true),
+    size(aSize)
+{
+  xassert(size.x > 0 && size.y > 0);
+  stride = (size.x+7)/8;
+  data = new byte[datasize()];
+}
+
+
+Bit2d::~Bit2d()
+{
+  if (owning) {
+    delete data;
+  }
+}
+
+
+Bit2d::Bit2d(Bit2d const &obj)
+{
+  size = obj.size;
+  stride = obj.stride;
+  data = new byte[datasize()];
+  owning = true;
+  memcpy(data, obj.data, datasize());
+}
+
+
+Bit2d& Bit2d::operator= (Bit2d const &obj)
+{
+  if (this != &obj) {
+    xassert(size == obj.size);
+    memcpy(data, obj.data, datasize());
+  }
+  return *this;
+}
+
+
+bool Bit2d::operator== (Bit2d const &obj) const
+{
+  return (size == obj.size) &&
+         (0==memcmp(data, obj.data, datasize()));
+}
+
+
+Bit2d::Bit2d(Flatten &)
+  : data(NULL),
+    owning(true)
+{}
+
+void Bit2d::xfer(Flatten &flat)
+{
+  flat.xferInt(size.x);
+  flat.xferInt(size.y);
+  flat.xferInt(stride);
+
+  flat.xferHeapBuffer((void*&)data, datasize());
+}
+
+
+void Bit2d::setall(int val)
+{
+  memset(data, val? 0xFF : 0, datasize());
+}
+
+
+int Bit2d::get(point const &p) const
+{
+  xassert(okpt(p));
+  return ( *(byteptrc(p)) >> (p.x&7) ) & 1;
+}
+
+void Bit2d::set(point const &p)
+{
+  xassert(okpt(p));
+  *(byteptr(p)) |= (byte)  ( 1 << (p.x&7) ) ;
+}
+
+void Bit2d::reset(point const &p)
+{
+  xassert(okpt(p));
+  *(byteptr(p)) &= (byte)(~( 1 << (p.x&7) ));
+}
+
+void Bit2d::setto(point const &p, int val)
+{
+  if (val) { set(p); }
+  else { reset(p); }
+}
+
+int Bit2d::testAndSet(point const &p)
+{
+  byte *b = byteptr(p);
+  int ret = (*b >> (p.x&7)) & 1;
+  *b |= (byte)( 1 << (p.x&7) );
+  return ret;
+}
+
+void Bit2d::toggle(point const &p)
+{
+  xassert(okpt(p));
+  *(byteptr(p)) ^= (byte) ( 1 << (p.x&7) );
+}
+
+ 
+// count the number of digits required to represent a positive
+// integer in base 10
+static int digits(int value)
+{
+  xassert(value > 0);
+  int ct=0;
+  while (value > 0) {
+    ct++;
+    value /= 10;
+  }
+  return ct;
+}
+
+
+/*
+ * Goal is to draw something like this:
+ *
+ *     	 1  2  3
+ *  1 [	 0  0  0  ]
+ *  2 [	 0  1  1  ]
+ *  3 [	 0  1  0  ]
+ *
+ */
+void Bit2d::print() const
+{
+  // compute column widths
+  int rowLabelWidth = digits(size.y-1);
+  int colLabelWidth = digits(size.x-1);
+
+  // column legend
+  printf("%*s   ", rowLabelWidth, "");
+  loopi(size.x) {
+    printf("%*d ", colLabelWidth, i);
+  }
+  printf("\n");
+
+  for (int row=0; row<size.y; row++) {
+    printf("%*d [ ", rowLabelWidth, row);
+    loopi(size.x) {
+      printf("%*s ", colLabelWidth, 
+                     get(point(i, row))? "1" : ".");    // "." so easier to see patterns
+    }
+    printf("]\n");
+  }
+}
+
+
+// hack
+Bit2d::Bit2d(byte * /*serf*/ d, point const &sz, int str)
+  : data(d),
+    owning(false),    // since it's a serf ptr
+    size(sz),
+    stride(str)
+{}
+
+
+
+// ------------------------ test code ------------------------
+#ifdef TEST_BIT2D
+
+#include "bflatten.h"     // BFlatten
+
+int main()
+{
+  Bit2d bits(point(17,3));
+  xassert(bits.okpt(point(16,2)) &&
+         !bits.okpt(point(17,3)) &&
+         !bits.okpt(point(2,16)));
+
+  bits.setall(0);
+  xassert(!bits.testAndSet(point(9,1)));
+  xassert(bits.testAndSet(point(9,1)));
+
+  xassert(!bits.testAndSet(point(2,0)));
+  xassert(bits.testAndSet(point(2,0)));
+
+  xassert(!bits.testAndSet(point(16,2)));
+  xassert(bits.testAndSet(point(16,2)));
+
+  bits.toggle(point(3,2));
+  xassert(bits.get(point(3,2)));
+
+  bits.print();
+
+  // test read/write
+  Bit2d *another = writeThenRead(bits);
+  xassert(*another == bits);
+  delete another;
+
+  printf("bit2d works\n");
+
+  return 0;
+}
+
+#endif // TEST_BIT2D
+

Added: vendor/elsa/current/smbase/bit2d.h
===================================================================
--- vendor/elsa/current/smbase/bit2d.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/bit2d.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,70 @@
+// bit2d.h            see license.txt for copyright and terms of use
+// 2-d array of bits
+
+#ifndef __BIT2D_H
+#define __BIT2D_H
+
+#include "typ.h"             // byte, bool
+#include "point.h"           // point
+
+class Flatten;
+
+class Bit2d {        
+private:     // data
+  byte *data;  	    // bits; [0..stride-1] is first row, etc.
+  bool owning;      // when false, 'data' is not owned by this object
+  point size;       // size.x is # of cols, size.y is # of rows
+  int stride;       // bytes between starts of adjacent rows;
+                    // computable from size.x but stored for quick access
+
+private:     // funcs
+  byte *byteptr(point const &p)               { return data + p.y * stride + (p.x>>3); }
+  byte const *byteptrc(point const &p) const  { return data + p.y * stride + (p.x>>3); }
+
+  // this is the number of bytes allocated in 'data'
+  int datasize() const                        { return size.y * stride; }
+
+public:      // funcs
+  // NOTE: does *not* clear the bitmap!  use 'setall' to do that
+  Bit2d(point const &aSize);
+  Bit2d(Bit2d const &obj);
+
+  Bit2d& operator= (Bit2d const &obj);     // sizes must be equal already
+  ~Bit2d();
+
+  Bit2d(Flatten&);
+  void xfer(Flatten &flat);
+
+  bool okpt(point const &p) const    { return p.gtez() && p < size; }
+  point const &Size() const          { return size; }
+
+  bool operator== (Bit2d const &obj) const;     // compare sizes and data
+
+  // bit access (these were inline earlier, but they expand to a huge amount
+  // of code (more than 100 bytes), so I've un-inlined them)
+  int get(point const &p) const;
+  void set(point const &p);     // to 1
+  void reset(point const &p);   // to 0
+  void setto(point const &p, int val);
+  void toggle(point const &p);
+
+  // set the bit, but return what it was previously
+  int testAndSet(point const &p);
+
+  // set everything
+  void setall(int val);
+
+  // debugging
+  void print() const;
+
+  // bit of a hack: I want to be able to save the data as code which,
+  // when compiled, will build a bit2d from static data.. for this
+  // I need access to some private fields and a special ctor
+  Bit2d(byte * /*serf*/ data, point const &size, int stride);
+  byte *private_data() { return data; }
+  int private_datasize() const { return datasize(); }
+  int private_stride() const { return stride; }
+};
+
+#endif // __BIT2D_H
+

Added: vendor/elsa/current/smbase/bitarray.cc
===================================================================
--- vendor/elsa/current/smbase/bitarray.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/bitarray.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,373 @@
+// bitarray.cc            see license.txt for copyright and terms of use
+// code for bitarray.h
+
+#include "bitarray.h"     // this module
+#include "flatten.h"      // Flatten
+
+#include <string.h>       // memset
+
+
+BitArray::BitArray(int n)
+  : numBits(n)
+{
+  allocBits();
+  clearAll();
+}
+
+void BitArray::allocBits()
+{
+  bits = new unsigned char[allocdBytes()];
+}
+
+
+BitArray::~BitArray()
+{
+  delete[] bits;
+}
+
+
+BitArray::BitArray(Flatten&)
+  : bits(NULL)
+{}
+
+void BitArray::xfer(Flatten &flat)
+{
+  flat.xferInt(numBits);
+
+  if (flat.reading()) {
+    allocBits();
+  }
+  flat.xferSimple(bits, allocdBytes());
+}
+
+
+BitArray::BitArray(BitArray const &obj)
+  : numBits(obj.numBits)
+{
+  allocBits();
+  memcpy(bits, obj.bits, allocdBytes());
+}
+
+void BitArray::operator=(BitArray const &obj)
+{
+  if (numBits != obj.numBits) {
+    delete[] bits;
+    numBits = obj.numBits;
+    allocBits();
+  }
+  memcpy(bits, obj.bits, allocdBytes());
+}
+
+
+bool BitArray::operator== (BitArray const &obj) const
+{
+  if (numBits != obj.numBits) {
+    return false;
+  }
+  
+  // this relies on the invariant that the unused trailing
+  // bits are always set to 0
+  return 0==memcmp(bits, obj.bits, allocdBytes());
+}
+
+
+void BitArray::clearAll()
+{
+  memset(bits, 0, allocdBytes());
+}
+
+
+void BitArray::invert()
+{
+  int allocd = allocdBytes();
+  for (int i=0; i<allocd; i++) {
+    bits[i] = ~(bits[i]);
+  }
+
+  if (numBits & 7) {
+    // there are some trailing bits that I need to flip back
+    unsigned char mask = (1 << (numBits & 7)) - 1;     // bits to *not* flip
+    bits[allocd-1] ^= ~mask;
+  }
+}
+
+
+void BitArray::selfCheck() const
+{
+  if (numBits & 7) {
+    // there are some trailing bits that I need to check
+    unsigned char mask = (1 << (numBits & 7)) - 1;     // bits to *not* check
+    unsigned char zero = bits[allocdBytes()-1] & ~mask;
+    xassert(zero == 0);
+  }
+}
+
+
+void BitArray::unionWith(BitArray const &obj)
+{
+  xassert(numBits == obj.numBits);
+
+  int allocd = allocdBytes();
+  for (int i=0; i<allocd; i++) {
+    bits[i] |= obj.bits[i];
+  }
+}
+
+
+void BitArray::intersectWith(BitArray const &obj)
+{
+  xassert(numBits == obj.numBits);
+
+  int allocd = allocdBytes();
+  for (int i=0; i<allocd; i++) {
+    bits[i] &= obj.bits[i];
+  }
+}
+
+
+// it's a little strange to export this function, since it is not
+// very general-purpose, but that is the price of encapsulation
+bool BitArray::anyEvenOddBitPair() const
+{
+  int allocd = allocdBytes();
+  for (int i=0; i<allocd; i++) {
+    unsigned char b = bits[i];
+    if (b & (b >> 1) & 0x55) {        // 01010101
+      return true;
+    }
+  }
+  
+  return false;    // no such pair
+}
+
+
+BitArray stringToBitArray(char const *src)
+{
+  int len = strlen(src);
+  BitArray ret(len);
+  for (int i=0; i<len; i++) {
+    if (src[i]=='1') {
+      ret.set(i);
+    }
+  }
+  return ret;
+}
+
+string toString(BitArray const &b)
+{
+  int len = b.length();
+  stringBuilder ret(len);
+  for (int i=0; i<len; i++) {
+    ret[i] = b.test(i)? '1' : '0';
+  }
+  return ret;
+}
+
+
+// ----------------------- BitArray::Iter ------------------------
+void BitArray::Iter::adv()
+{
+  curBit++;
+
+  while (curBit < arr.numBits) {
+    if ((curBit & 7) == 0) {
+      // beginning a new byte; is it entirely empty?
+      while (arr.bits[curBit >> 3] == 0) {
+        // yes, skip to next
+        curBit += 8;
+
+        if (curBit >= arr.numBits) {
+          return;     // done iterating
+        }
+      }
+    }
+
+    // this could be made a little faster by using the trick to scan
+    // for the first nonzero bit.. but since I am only going to scan
+    // within a single byte, it shouldn't make that much difference
+    if (arr.test(curBit)) {
+      return;         // found element
+    }
+
+    curBit++;
+  }
+}
+
+
+// -------------------- test code -------------------
+#ifdef TEST_BITARRAY
+
+#include "test.h"     // USUAL_MAIN
+
+string toStringViaIter(BitArray const &b)
+{ 
+  stringBuilder sb;
+  int index = 0;
+
+  for (BitArray::Iter iter(b); !iter.isDone(); iter.adv()) {
+    while (index < iter.data()) {
+      sb << "0";
+      index++;
+    }
+    sb << "1";
+    index++;
+  }
+  
+  while (index < b.length()) {
+    sb << "0";
+    index++;
+  }
+  
+  return sb;
+}
+
+
+void testIter(char const *str)
+{                             
+  BitArray b = stringToBitArray(str);
+  b.selfCheck();
+
+  string s1 = toString(b);
+  string s2 = toStringViaIter(b);
+  if (s1 != s2 ||
+      !s1.equals(str)) {
+    cout << "str: " << str << endl;
+    cout << " s1: " << s1 << endl;
+    cout << " s2: " << s2 << endl;
+    xbase("testIter failed");
+  }
+
+  // also test the inverter
+  BitArray c = ~b;
+  c.selfCheck();
+  
+  stringBuilder inv;                 
+  int len = strlen(str);
+  for (int i=0; i<len; i++) {
+    inv << (str[i]=='0'? '1' : '0');
+  }
+
+  string cStr = toString(c);
+  if (!inv.equals(cStr)) {
+    cout << " inv: " << inv << endl;
+    cout << "cStr: " << cStr << endl;
+    xbase("test inverter failed");
+  }
+}
+
+
+void testUnionIntersection(char const *s1, char const *s2)
+{
+  int len = strlen(s1);
+  xassert(len == (int)strlen(s2));
+
+  BitArray b1 = stringToBitArray(s1);
+  BitArray b2 = stringToBitArray(s2);
+
+  stringBuilder expectUnion, expectIntersection;
+  for (int i=0; i<len; i++) {
+    expectUnion        << ((s1[i]=='1' || s2[i]=='1')? '1' : '0');
+    expectIntersection << ((s1[i]=='1' && s2[i]=='1')? '1' : '0');
+  }
+  
+  BitArray u = b1 | b2;
+  BitArray i = b1 & b2;
+  
+  string uStr = toString(u);
+  string iStr = toString(i);
+
+  if (!uStr.equals(expectUnion)) {
+    cout << "         s1: " << s1 << endl;
+    cout << "         s2: " << s2 << endl;
+    cout << "       uStr: " << uStr << endl;
+    cout << "expectUnion: " << expectUnion << endl;
+    xbase("test union failed");
+  }
+
+  if (!iStr.equals(expectIntersection)) {
+    cout << "                s1: " << s1 << endl;
+    cout << "                s2: " << s2 << endl;
+    cout << "              iStr: " << iStr << endl;
+    cout << "expectIntersection: " << expectIntersection << endl;
+    xbase("test intersection failed");
+  }
+}
+
+
+void testAnyEvenOddBitPair(char const *s, bool expect)
+{
+  BitArray b = stringToBitArray(s);
+  bool answer = b.anyEvenOddBitPair();
+  if (answer != expect) {
+    static char const *boolName[] = { "false", "true" };
+    cout << "     s: " << s << endl;
+    cout << "answer: " << boolName[answer] << endl;
+    cout << "expect: " << boolName[expect] << endl;
+    xbase("test anyEvenOddBitPair failed");
+  }
+}
+
+
+void entry()
+{
+        //            1111111111222222222233333333334444444444555555555566
+        //  01234567890123456789012345678901234567890123456789012345678901
+  testIter("00000000111111111111000000000000");
+  testIter("00000000000000000000000000000000000000111111111111000000000000");
+  testIter("000000000000000000000000000000000000000111111111111000000000000");
+  testIter("0000000000000000000000000000000000000000111111111111000000000000");
+  testIter("00000000000000000000000000000000000000000111111111111000000000000");
+  testIter("000000000000000000000000000000000000000000111111111111000000000000");
+  testIter("0000000000000000000000000000000000000000000111111111111000000000000");
+  testIter("00000000000000000000000000000000000000000000111111111111000000000000");
+  testIter("000000000000000000000000000000000000000000000111111111111000000000000");
+  testIter("0000000000000000000000000000000000000000000000111111111111000000000000");
+  testIter("00000000000000000000000000000000000000000000000111111111111000000000000");
+  testIter("000000000000000000000000000000000000000000000000111111111111000000000000");
+
+  testIter("0101");
+  testIter("1");
+  testIter("0");
+  testIter("");
+  testIter("1111");
+  testIter("0000");
+  testIter("000000000000111111111111000000000000");
+  testIter("111111111111111000000000000011111111");
+  testIter("10010110010101010100101010101010100110001000100001010101111");
+
+  testUnionIntersection("", 
+                        "");
+
+  testUnionIntersection("1",
+                        "0");
+
+  testUnionIntersection("10",
+                        "00");
+
+  testUnionIntersection("1001000100111110101001001001011111",
+                        "0001100101011101011010000111010110");
+
+  testUnionIntersection("1111111111111111111111111111111111",
+                        "0000000000000000000000000000000000");
+
+  testUnionIntersection("0000111111000001111110000011110000",
+                        "1111000000111110000001111100001111");
+            
+  testAnyEvenOddBitPair("0000", false);
+  testAnyEvenOddBitPair("0001", false);
+  testAnyEvenOddBitPair("0010", false);
+  testAnyEvenOddBitPair("0100", false);
+  testAnyEvenOddBitPair("1000", false);
+  testAnyEvenOddBitPair("0110", false);
+  testAnyEvenOddBitPair("1110", true);
+  testAnyEvenOddBitPair("0111", true);
+  testAnyEvenOddBitPair("1111", true);
+  testAnyEvenOddBitPair("11110", true);
+  testAnyEvenOddBitPair("01100", false);
+
+  cout << "bitarray is ok\n";
+}
+
+USUAL_MAIN
+
+#endif // TEST_BITARRAY

Added: vendor/elsa/current/smbase/bitarray.h
===================================================================
--- vendor/elsa/current/smbase/bitarray.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/bitarray.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,131 @@
+// bitarray.h            see license.txt for copyright and terms of use
+// one-dimensional array of bits
+
+#ifndef BITARRAY_H
+#define BITARRAY_H
+
+#include "xassert.h"      // xassert
+#include "str.h"          // string
+
+class Flatten;            // flatten.h
+
+class BitArray {
+private:    // data
+  unsigned char *bits;
+  int numBits;              // # of bits in the array
+  
+  // invariant: the bits in the last allocated byte that are beyond
+  // 'numBits' (if any) are always 0
+
+private:    // funcs
+  void bc(int i) const { xassert((unsigned)i < (unsigned)numBits); }
+  int allocdBytes() const { return (numBits+7) / 8; }
+  void allocBits();
+
+public:     // funcs
+  BitArray(int n);          // create with given # of bits, initially zeroed
+  ~BitArray();
+
+  BitArray(Flatten&);
+  void xfer(Flatten &flat);
+
+  BitArray(BitArray const &obj);
+  void operator=(BitArray const &obj);
+
+  bool operator== (BitArray const &obj) const;
+  bool operator!= (BitArray const &obj) const { return !operator==(obj); }
+
+  int length() const
+    { return numBits; }
+
+  // test a bit, return 0 or 1
+  int test(int i) const
+    { bc(i); return ((bits[i >> 3]) >> (i & 7)) & 1; }
+
+  // set a bit to a specific value
+  void set(int i)
+    { bc(i); bits[i >> 3] |= (1 << (i & 7)); }
+  void reset(int i)
+    { bc(i); bits[i >> 3] &= ~(1 << (i & 7)); }
+
+  // set a bit to an arbitrary value
+  void setTo(int i, int val) {
+    if (val) {
+      set(i);
+    }
+    else {
+      reset(i);
+    }
+  }
+
+  // clear all bits
+  void clearAll();
+  
+  // invert the bits
+  void invert();
+
+  // bitwise OR ('obj' must be same length)
+  void unionWith(BitArray const &obj);
+  
+  // bitwise AND
+  void intersectWith(BitArray const &obj);
+                                 
+  // true if there is any pair of bits 2n,2n+1 where both are set
+  bool anyEvenOddBitPair() const;
+
+  // debug check
+  void selfCheck() const;
+
+  // operators
+  BitArray operator~ () const {
+    BitArray ret(*this);
+    ret.invert();
+    return ret;
+  }
+
+  BitArray& operator|= (BitArray const &obj) {
+    unionWith(obj);
+    return *this;
+  }
+
+  BitArray operator| (BitArray const &obj) const {
+    BitArray ret(*this);
+    ret.unionWith(obj);
+    return ret;
+  }
+
+  BitArray& operator&= (BitArray const &obj) {
+    intersectWith(obj);
+    return *this;
+  }
+
+  BitArray operator& (BitArray const &obj) const {
+    BitArray ret(*this);
+    ret.intersectWith(obj);
+    return ret;
+  }
+
+public:     // types
+  class Iter {
+  private:    // data
+    BitArray const &arr;    // array we are reading
+    int curBit;             // bit at 'data'; is >= 'numBits' when done
+
+  public:     // funcs
+    Iter(BitArray const &a)
+      : arr(a), curBit(-1) { adv(); }
+
+    bool isDone() const   { return curBit >= arr.numBits; }
+    int data() const      { return curBit; }
+
+    void adv();
+  };
+  friend class Iter;
+};
+
+
+BitArray stringToBitArray(char const *src);
+string toString(BitArray const &b);
+
+
+#endif // BITARRAY_H

Added: vendor/elsa/current/smbase/bitwise_array.h
===================================================================
--- vendor/elsa/current/smbase/bitwise_array.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/bitwise_array.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,333 @@
+// bitwise_array.h            see license.txt for copyright and terms of use
+// some array classes that use bitwise copying when expanding
+
+#ifndef BITWISE_ARRAY_H
+#define BITWISE_ARRAY_H
+
+#include "xassert.h"      // xassert
+#include <stdlib.h>       // qsort
+#include <string.h>       // memcpy
+#include <new.h>          // new
+
+
+// ------------------ BitwiseGrowArray --------------------
+// This class implements an array of T's; it automatically expands
+// when 'ensureAtLeast' or 'ensureIndexDoubler' is used; it does not
+// automatically contract.  All accesses are bounds-checked.
+//
+// class T must have:
+//   T::T();           // default ctor for making arrays
+//   T::~T();          // dtor for when old array is cleared
+//
+// to use copyFrom, T must have:
+//   T::operator=(T const&);
+//
+// quarl 2006-06-01
+//   BitwiseGrowArray uses malloc/free and manually calls T() and ~T(), so that we
+//   don't need to have T::operator=(T&); this is also faster since we only do
+//   a shallow copy.
+
+template <class T>
+class BitwiseGrowArray {
+private:     // data
+  T *arr;                 // underlying array; NULL if sz==0
+  int sz;                 // # allocated entries in 'arr'
+
+private:     // funcs
+  void bc(int i) const    // bounds-check an index
+    { xassert((unsigned)i < (unsigned)sz); }
+  void eidLoop(int index);
+
+  // make 'this' equal to 'obj'
+  void copyFrom(BitwiseGrowArray<T> const &obj) {
+    setSize(obj.size());     // not terribly efficient, oh well
+    copyFrom_limit(obj, sz);
+  }
+
+protected:   // funcs
+  void copyFrom_limit(BitwiseGrowArray<T> const &obj, int limit);
+
+private:     // disallowed
+  void operator=(BitwiseGrowArray&);
+  void operator==(BitwiseGrowArray&);
+
+public:      // funcs
+  BitwiseGrowArray(int initSz);
+  BitwiseGrowArray(BitwiseGrowArray const &obj) : arr(0), sz(0) { copyFrom(obj); }
+  ~BitwiseGrowArray();
+
+  BitwiseGrowArray& operator=(BitwiseGrowArray const &obj) { copyFrom(obj); return *this; }
+
+  // allocated space
+  int size() const { return sz; }
+
+  // element access
+  T const& operator[] (int i) const   { bc(i); return arr[i]; }
+  T      & operator[] (int i)         { bc(i); return arr[i]; }
+
+  // set size, reallocating if old size is different; if the
+  // array gets bigger, existing elements are preserved; if the
+  // array gets smaller, elements are truncated
+  void setSize(int newSz);
+
+  // make sure there are at least 'minSz' elements in the array;
+  void ensureAtLeast(int minSz)
+    { if (minSz > sz) { setSize(minSz); } }
+
+  // grab a read-only pointer to the raw array
+  T const *getArray() const { return arr; }
+
+  // grab a writable pointer; use with care
+  T *getDangerousWritableArray() { return arr; }
+  T *getArrayNC() { return arr; }     // ok, not all that dangerous..
+
+  // make sure the given index is valid; if this requires growing,
+  // do so by doubling the size of the array (repeatedly, if
+  // necessary)
+  void ensureIndexDoubler(int index)
+    { if (sz-1 < index) { eidLoop(index); } }
+
+  // set an element, using the doubler if necessary
+  void setIndexDoubler(int index, T const &value)
+    { ensureIndexDoubler(index); arr[index] = value; }
+
+  // swap my data with the data in another BitwiseGrowArray object
+  void swapWith(BitwiseGrowArray<T> &obj) {
+    T *tmp1 = obj.arr; obj.arr = this->arr; this->arr = tmp1;
+    int tmp2 = obj.sz; obj.sz = this->sz; this->sz = tmp2;
+  }
+
+  // set all elements to a single value
+  void setAll(T val) {
+    for (int i=0; i<sz; i++) {
+      arr[i] = val;
+    }
+  }
+
+private:
+  // call T constructor on [p, end)
+  static void ctor(T* p, T *end) {
+    for (; p < end; ++p) {
+      ::new(static_cast<void*>(p)) T();
+    }
+  }
+
+  // call T destructor on [p, end)
+  static void dtor(T* p, T *end) {
+    for (; p < end; ++p) {
+      p->~T();
+    }
+  }
+
+  // shallow copy data from src to dest
+  static void copy(T *dest, T *src, size_t count) {
+    memcpy(dest, src, sizeof(T)*count);
+  }
+
+  // uninitialized alloc
+  static T *alloc(size_t count) {
+    void *m = malloc(sizeof(T)*count);
+    if (!m) throw bad_alloc();
+    return (T*) m;
+  }
+
+  // dealloc
+  static void dealloc(T *ary) {
+    free(ary);
+  }
+};
+
+
+template <class T>
+BitwiseGrowArray<T>::BitwiseGrowArray(int initSz)
+{
+  sz = initSz;
+  if (sz > 0) {
+    // arr = new T[sz];
+    arr = alloc(sz);
+    ctor(arr, arr+sz);
+  }
+  else {
+    arr = NULL;
+  }
+}
+
+
+template <class T>
+BitwiseGrowArray<T>::~BitwiseGrowArray()
+{
+  if (arr) {
+    // delete[] arr;
+    dtor(arr, arr+sz);
+    dealloc(arr);
+  }
+}
+
+
+template <class T>
+void BitwiseGrowArray<T>::copyFrom_limit(BitwiseGrowArray<T> const &obj, int limit)
+{
+  for (int i=0; i<limit; i++) {
+    arr[i] = obj.arr[i];
+  }
+}
+
+
+template <class T>
+void BitwiseGrowArray<T>::setSize(int newSz)
+{
+  if (newSz != sz) {
+    // keep track of old
+    int oldSz = sz;
+    T *oldArr = arr;
+
+    // make new
+    sz = newSz;
+
+    if (sz > 0) {
+      // arr = new T[sz];
+      arr = alloc(sz);
+    }
+    else {
+      arr = NULL;
+    }
+
+    // // copy elements in common
+    // for (int i=0; i<sz && i<oldSz; i++) {
+    //   arr[i] = oldArr[i];
+    // }
+
+    if (sz < oldSz) {
+      // shrinking; copy elements to keep and destroy the rest
+      copy(arr, oldArr, sz);
+      dtor(oldArr + sz, oldArr + oldSz);
+    } else if (sz > oldSz) {
+      // expanding; copy elements and construct new ones
+      copy(arr, oldArr, oldSz);
+      ctor(arr + oldSz, arr + sz);
+    }
+
+    // get rid of old
+    if (oldArr) {
+      // delete[] oldArr;
+      dealloc(oldArr);
+    }
+  }
+}
+
+
+// this used to be ensureIndexDoubler's implementation, but
+// I wanted the very first check to be inlined
+template <class T>
+void BitwiseGrowArray<T>::eidLoop(int index)
+{
+  if (sz-1 >= index) {
+    return;
+  }
+
+  int newSz = sz;
+  while (newSz-1 < index) {
+    #ifndef NDEBUG_NO_ASSERTIONS    // silence warning..
+      int prevSz = newSz;
+    #endif
+    if (newSz == 0) {
+      newSz = 1;
+    }
+    newSz = newSz*2;
+    xassert(newSz > prevSz);        // otherwise overflow -> infinite loop
+  }
+
+  setSize(newSz);
+}
+
+
+// ---------------------- BitwiseArrayStack ---------------------
+// quarl 2006-06-03
+// Analogous to ArrayStack, but uses a BitwiseGrowArray instead of GrowArray.
+// TODO: make ArrayStack templatized on the base class
+template <class T>
+class BitwiseArrayStack : public BitwiseGrowArray<T> {
+private:
+  int len;               // # of elts in the stack
+
+public:
+  BitwiseArrayStack(int initArraySize = 10)
+    : BitwiseGrowArray<T>(initArraySize),
+      len(0)
+    {}
+  BitwiseArrayStack(BitwiseArrayStack<T> const &obj)
+    : BitwiseGrowArray<T>(obj),
+      len(obj.len)
+    {}
+  ~BitwiseArrayStack() {}
+
+  // copies contents of 'obj', but the allocated size of 'this' will
+  // only change when necessary
+  BitwiseArrayStack& operator=(BitwiseArrayStack<T> const &obj)
+  {
+    this->ensureIndexDoubler(obj.length() - 1);
+    this->copyFrom_limit(obj, obj.length());
+    len = obj.len;
+    return *this;
+  }
+
+  // element access; these declarations are necessary because
+  // the uses of 'operator[]' below are not "dependent", hence
+  // they can't use declarations inherited from GrowArray<T>
+  T const& operator[] (int i) const { return BitwiseGrowArray<T>::operator[](i); }
+  T      & operator[] (int i)       { return BitwiseGrowArray<T>::operator[](i); }
+
+  void push(T const &val)
+    { setIndexDoubler(len++, val); }
+  T pop()
+    { return operator[](--len); }
+  T const &top() const
+    { return operator[](len-1); }
+  T &top()
+    { return operator[](len-1); }
+  T &nth(int which)
+    { return operator[](len-1-which); }
+
+  // alternate interface, where init/deinit is done explicitly
+  // on returned references
+  T &pushAlt()    // returns newly accessible item
+    { BitwiseGrowArray<T>::ensureIndexDoubler(len++); return top(); }
+  T &popAlt()     // returns item popped
+    { return operator[](--len); }
+
+  // items stored
+  int length() const
+    { return len; }
+
+  bool isEmpty() const
+    { return len==0; }
+  bool isNotEmpty() const
+    { return !isEmpty(); }
+
+  void popMany(int ct)
+    { len -= ct; xassert(len >= 0); }
+  void empty()
+    { len = 0; }
+
+  // useful when someone has used 'getDangerousWritableArray' to
+  // fill the array's internal storage
+  void setLength(int L) { len = L; }
+
+  // consolidate allocated space to match length
+  void consolidate() { this->setSize(length()); }
+
+  // swap
+  void swapWith(BitwiseArrayStack<T> &obj) {
+    BitwiseGrowArray<T>::swapWith(obj);
+    int tmp = obj.len; obj.len = this->len; this->len = tmp;
+  }
+
+  void sort(int (*compare)(T const *t1, T const *t2)) {
+    qsort(BitwiseGrowArray<T>::getArrayNC(), len, sizeof(T),
+          (int (*)(void const*, void const*))compare );
+  }
+};
+
+
+
+#endif // BITWISE_ARRAY_H

Added: vendor/elsa/current/smbase/boxprint.cc
===================================================================
--- vendor/elsa/current/smbase/boxprint.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/boxprint.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,554 @@
+// boxprint.cc
+// code for boxprint.h
+
+#include "boxprint.h"       // this module
+#include "strutil.h"        // quoted
+
+#include <string.h>         // strlen
+
+
+// ----------------------- BPRender ----------------------
+BPRender::BPRender()
+  : sb(),         // initially empty
+    margin(72),
+    curCol(0),
+    lineStartText("")
+{}
+
+BPRender::~BPRender()
+{}
+
+
+void BPRender::reset()
+{
+  sb.clear();
+  sb << lineStartText;
+}
+
+
+void BPRender::add(rostring text)
+{
+  int len = strlen(text);
+  sb << text;
+  curCol += len;
+}
+
+void BPRender::breakLine(int ind)
+{
+  sb << "\n" << lineStartText;
+
+  for (int i=0; i < ind; i++) {
+    sb << ' ';
+  }
+
+  curCol = ind;
+}
+
+
+string BPRender::takeAndRender(BoxPrint &bld)
+{
+  BPBox* /*owner*/ tree = bld.takeTree();
+  tree->render(*this);
+  string ret(sb);
+  sb.clear();
+  delete tree;
+  return ret;
+}
+
+
+// ----------------------- BPElement ---------------------
+int BPElement::oneLineWidth()
+{
+  bool dummy;
+  return oneLineWidthEx(dummy);
+}
+
+bool BPElement::isBreak() const
+{
+  return false;
+}
+
+bool BPElement::isForcedBreak() const
+{
+  return false;
+}
+
+BPElement::~BPElement()
+{}
+
+
+// ------------------------- BPText ----------------------
+BPText::BPText(rostring t)
+  : text(t)
+{}
+
+BPText::~BPText()
+{}
+
+
+int BPText::oneLineWidthEx(bool &forced)
+{
+  forced = false;
+  return text.length();
+}
+
+void BPText::render(BPRender &mgr)
+{
+  mgr.add(text);
+}
+
+
+void BPText::debugPrint(ostream &os, int /*ind*/) const
+{
+  os << "text(" << quoted(text) << ")";
+}
+
+
+// ------------------------ BPBreak ---------------------
+BPBreak::BPBreak(BreakType e, int i)
+  : enabled(e),
+    indent(i)
+{}
+
+BPBreak::~BPBreak()
+{}
+
+int BPBreak::oneLineWidthEx(bool &forced)
+{
+  if (enabled >= BT_FORCED) {
+    forced = true;
+    return 0;
+  }
+  else {
+    forced = false;
+    return 1;
+  }
+}
+
+void BPBreak::render(BPRender &mgr)
+{
+  // if we're being asked to render, then this break must not be taken
+  if (enabled != BT_LINE_START) {
+    mgr.add(" ");
+  }
+}
+
+bool BPBreak::isBreak() const
+{
+  return enabled;
+}
+
+bool BPBreak::isForcedBreak() const
+{
+  return enabled == BT_FORCED;
+}
+
+void BPBreak::debugPrint(ostream &os, int /*ind*/) const
+{
+  os << "break(en=" << (int)enabled << ", ind=" << indent << ")";
+}
+
+
+// ------------------------- BPBox ------------------------
+BPBox::BPBox(BPKind k)
+  : elts(),      // initially empty
+    kind(k)
+{
+  xassert((unsigned)k < NUM_BPKINDS);
+}
+
+BPBox::~BPBox()
+{}
+
+
+int BPBox::oneLineWidthEx(bool &forced)
+{
+  forced = false;
+  int sum = 0;
+  FOREACH_ASTLIST_NC(BPElement, elts, iter) {
+    sum += iter.data()->oneLineWidthEx(forced);
+    if (forced) {
+      break;
+    }
+  }
+  return sum;
+}
+
+
+void takeBreak(BPRender &mgr, int &startCol, BPBreak *brk)
+{
+  startCol += brk->indent;
+
+  if (brk->enabled == BT_LINE_START &&
+      mgr.curCol == startCol) {
+    // do not add a line
+  }
+  else {
+    // add the newline
+    mgr.breakLine(startCol);
+  }
+}
+
+
+// this function is the heart of the rendering engine
+void BPBox::render(BPRender &mgr)
+{
+  int startCol = mgr.getCurCol();
+
+  bool fbreak = false;
+  if (kind == BP_vertical ||
+      (kind == BP_correlated && (oneLineWidthEx(/*OUT*/fbreak) > mgr.remainder() ||
+                                 fbreak))) {
+    // take all of the breaks
+    FOREACH_ASTLIST_NC(BPElement, elts, iter) {
+      BPElement *elt = iter.data();
+      if (elt->isBreak()) {
+        takeBreak(mgr, startCol, static_cast<BPBreak*>(elt));
+      }
+      else {
+        elt->render(mgr);
+      }
+    }
+    return;
+  }
+
+  if (kind == BP_correlated) {
+    // if we got here, we're taking none of the breaks
+    FOREACH_ASTLIST_NC(BPElement, elts, iter) {
+      BPElement *elt = iter.data();
+      elt->render(mgr);
+    }
+    return;
+  }
+
+  xassert(kind == BP_sequence);
+
+  // this cursor points to the next element that has not been rendered
+  ASTListIterNC<BPElement> cursor(elts);
+
+  // when not NULL, the cursor has just passed a break, but we haven't
+  // actually decided whether to take it or not
+  BPBreak *pendingBreak = NULL;
+
+  while (!cursor.isDone()) {
+    // is there room for the elements up to the first break?
+    int segmentWidth = pendingBreak? 1 : 0;
+    ASTListIterNC<BPElement> lookahead(cursor);
+    while (!lookahead.isDone() && !lookahead.data()->isBreak()) {
+      segmentWidth += lookahead.data()->oneLineWidth();
+      lookahead.adv();
+    }
+
+    if (pendingBreak && segmentWidth > mgr.remainder()) {
+      // take the pending break
+      takeBreak(mgr, startCol, pendingBreak);
+      pendingBreak = NULL;
+    }
+
+    // the segment will be put here without a preceding break
+    else if (pendingBreak) {
+      startCol += pendingBreak->indent;
+      pendingBreak->render(mgr);
+      pendingBreak = NULL;
+    }
+
+    xassert(pendingBreak == NULL);
+
+    // render the segment
+    while (!cursor.isDone() && !cursor.data()->isBreak()) {
+      cursor.data()->render(mgr);
+      cursor.adv();
+    }
+
+    if (!cursor.isDone()) {
+      // we stopped on a break
+      pendingBreak = static_cast<BPBreak*>(cursor.data());
+
+      if (pendingBreak->isForcedBreak()) {
+        // take the forced break
+        takeBreak(mgr, startCol, pendingBreak);
+        pendingBreak = NULL;
+      }
+
+      cursor.adv();
+    }
+  }
+
+  if (pendingBreak) {
+    // ended with a break.. strange, but harmless I suppose
+    pendingBreak->render(mgr);
+
+    if (pendingBreak->isForcedBreak()) {
+      takeBreak(mgr, startCol, pendingBreak);
+    }
+  }
+}
+
+
+void BPBox::debugPrint(ostream &os, int ind) const
+{
+  static char const * const map[] = {
+    "vert",
+    "seq",
+    "corr"
+  };
+
+  os << "box(kind=" << map[kind] << ") {\n";
+  ind += 2;
+
+  FOREACH_ASTLIST(BPElement, elts, iter) {
+    for (int i=0; i<ind; i++) {
+      os << " ";
+    }
+
+    iter.data()->debugPrint(os, ind);
+    os << "\n";
+  }
+
+  ind -= 2;
+  for (int i=0; i<ind; i++) {
+    os << " ";
+  }
+  os << "}";
+}
+
+
+// ------------------------ BoxPrint ----------------------
+BPKind const BoxPrint::vert = BP_vertical;
+BPKind const BoxPrint::seq  = BP_sequence;
+BPKind const BoxPrint::hv   = BP_correlated;
+BPKind const BoxPrint::end  = NUM_BPKINDS;
+
+
+BoxPrint::BoxPrint()
+  : boxStack(),
+    levelIndent(2)
+{
+  // initial vert box
+  boxStack.push(new BPBox(BP_vertical));
+}
+
+BoxPrint::~BoxPrint()
+{}
+
+
+void BoxPrint::append(BPElement *elt)
+{
+  box()->elts.append(elt);
+}
+
+
+BoxPrint& BoxPrint::operator<< (rostring s)
+{
+  append(new BPText(s));
+  return *this;
+}
+
+BoxPrint& BoxPrint::operator<< (char const *s)
+{
+  append(new BPText(s));
+  return *this;
+}
+
+BoxPrint& BoxPrint::operator<< (int i)
+{
+  return operator<< (stringc << i);
+}
+
+
+BoxPrint& BoxPrint::operator<< (BPKind k)
+{
+  if (k == NUM_BPKINDS) {
+    // close current box
+    append(boxStack.pop());
+  }
+  else {
+    // open new box
+    boxStack.push(new BPBox(k));
+  }
+  return *this;
+}
+
+
+BoxPrint& BoxPrint::operator<< (Cmd c)
+{
+  switch (c) {
+    default: xfailure("bad cmd");
+    case sp:        append(new BPBreak(BT_DISABLED, 0 /*indent*/)); break;
+    case br:        append(new BPBreak(BT_ENABLED, 0 /*indent*/)); break;
+    case fbr:       append(new BPBreak(BT_FORCED, 0 /*indent*/)); break;
+    case lineStart: append(new BPBreak(BT_LINE_START, 0 /*indent*/)); break;
+    case ind:       append(new BPBreak(BT_ENABLED, levelIndent)); break;
+    case und:       append(new BPBreak(BT_ENABLED, -levelIndent)); break;
+  }
+  return *this;
+}
+
+
+BoxPrint& BoxPrint::operator<< (IBreak b)
+{
+  append(new BPBreak(BT_ENABLED, b.indent /*indent*/));
+  return *this;
+}
+
+
+BoxPrint& BoxPrint::operator<< (Op o)
+{
+  return *this << sp << o.text << br;
+}
+
+
+BPBox* /*owner*/ BoxPrint::takeTree()
+{
+  // all boxes must be closed
+  xassert(boxStack.length() == 1);
+
+  BPBox *ret = boxStack.pop();
+
+  // initialize the box stack again, in case the user wants
+  // to build another tree
+  boxStack.push(new BPBox(BP_vertical));
+
+  return ret;
+}
+
+
+void BoxPrint::debugPrint(ostream &os) const
+{
+  for (int i=0; i < boxStack.length(); i++) {
+    os << "----- frame -----\n";
+    boxStack[i]->debugPrint(os, 0 /*ind*/);
+    os << "\n";
+  }
+}
+
+void BoxPrint::debugPrintCout() const
+{
+  debugPrint(cout);
+}
+
+
+// ------------------------ test code ----------------------
+#ifdef TEST_BOXPRINT
+
+#include <stdlib.h>       // atoi
+#include "ckheap.h"       // malloc_stats
+
+void doit(int argc, char *argv[])
+{
+  BoxPrint bp;
+
+  bp << "int foo()" << bp.br
+     << "{" << bp.ind;
+
+  bp << bp.lineStart
+     << "// wazoo"
+     << bp.fbr;
+
+  bp << "printf(" << bp.seq
+        << "\"hello there %d!\\n\"," << bp.br
+        << "123456789"
+     << bp.end << ");" << bp.br;
+
+  bp << "bar(" << bp.seq
+        << "1" << bp.op("+")
+        << "2" << bp.op("+")
+        << "3" << bp.op("+")
+        << "4" << bp.op("+")
+        << "5" << bp.op("+")
+        << "6" << bp.op("+")
+        << "7" << bp.op("+")
+        << "8" << bp.op("+")
+        << "9" << bp.op("+")
+        << "10"
+     << bp.end << ");" << bp.br;
+
+  bp << "baz(" << bp.seq
+        << "\"a really long line that has no optional breaks at all\""
+     << bp.end << ");" << bp.br;
+
+  bp << "zoo(" << bp.seq
+        << "\"one break is here, but it is very\"," << bp.br
+        << "\"far from the start\""
+     << bp.end << ");" << bp.br;
+
+  bp << "assert(" << bp.seq
+        << bp.seq << "x" << bp.op("=") << "y" << bp.end << bp.op("&&")
+        << bp.seq << "z" << bp.op("=") << "w" << bp.end << bp.op("&&")
+        << "(" << bp.seq
+           << bp.seq << "moron" << bp.op("!=") << "fool" << bp.end << bp.op("||")
+           << "taxes->theRich"
+        << bp.end << ")"
+     << bp.end << ")" << bp.br;
+
+  bp << bp.hv
+        << "forall(" << bp.seq
+           << "x," << bp.br << "y," << bp.br << "z"
+        << bp.end << "). if {" << bp.ind
+        << bp.seq << "x" << bp.op("==") << "yooey_more" << bp.end << ";" << bp.br
+        << bp.seq << "yowza" << bp.op("!=") << "fooey" << bp.end << ";"
+        << bp.und << "} /*==>*/ {" << bp.ind
+        << bp.seq << "z(x,y,z)" << bp.op("==") << "3" << bp.end << ";" << bp.br
+        << "ay_caramba" << ";"
+        << bp.und << "};"
+     << bp.end << bp.br;
+
+  // here is a 'forall' with a comment surrounded by forced breaks
+  bp << bp.hv
+        << bp.lineStart
+        << "// forced break comment"
+        << bp.fbr
+        << "forall(" << bp.seq
+           << "x," << bp.br << "y," << bp.br << "z"
+        << bp.end << "). if {" << bp.ind
+        << bp.seq << "x" << bp.op("==") << "yooey_more" << bp.end << ";" << bp.br
+        << bp.seq << "yowza" << bp.op("!=") << "fooey" << bp.end << ";"
+        << bp.und << "} /*==>*/ {" << bp.ind
+        << bp.seq << "z(x,y,z)" << bp.op("==") << "3" << bp.end << ";" << bp.br
+        << "ay_caramba" << ";"
+        << bp.und << "};"
+     << bp.end << bp.br;
+
+  // here is a 'forall' with a comment surrounded by forced breaks
+  bp << bp.hv
+        << bp.lineStart
+        << "// forced break comment"
+        << bp.fbr
+        << "forall(" << bp.seq
+           << "x," << bp.br << "y," << bp.br << "z"
+        << bp.end << "). if {" << bp.ind
+        << bp.seq << "x" << bp.op("==") << "yooey_more" << bp.end << ";" << bp.br
+        << bp.seq << "yowza" << bp.op("!=") << "fooey" << bp.end << ";"
+        << bp.und << "} /*==>*/ {" << bp.ind
+        << bp.seq << "z(x,y,z)" << bp.op("==") << "3" << bp.end << ";" << bp.br
+        << "ay_caramba" << ";"
+        << bp.und << "};"
+     << bp.end;
+
+  bp << bp.und << "}" << bp.br;
+
+  BPBox *tree = bp.takeTree();
+
+  BPRender ren;
+  ren.margin = 30;
+  if (argc >= 2) {
+    ren.margin = atoi(argv[1]);
+  }
+  cout << "margin: " << ren.margin << "\n";
+
+  tree->render(ren);
+  delete tree;
+
+  cout << "         1    1    2    2    3    3    4    4    5    5    6    6    7\n";
+  cout << "1---5----0----5----0----5----0----5----0----5----0----5----0----5----0\n";
+  cout << ren.takeString();
+}
+
+int main(int argc, char *argv[])
+{
+  doit(argc, argv);
+  //malloc_stats();
+  return 0;
+}
+
+#endif // TEST_BOXPRINT

Added: vendor/elsa/current/smbase/boxprint.h
===================================================================
--- vendor/elsa/current/smbase/boxprint.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/boxprint.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,272 @@
+// boxprint.h
+// another pretty-printing module, this one based on the box model
+// described at http://caml.inria.fr/FAQ/format-eng.html
+
+#ifndef BOXPRINT_H
+#define BOXPRINT_H
+
+#include "str.h"          // stringBuilder
+#include "astlist.h"      // ASTList
+#include "array.h"        // ObjArrayStack
+  
+
+// fwd
+class BoxPrint;
+
+
+// manages the process of rendering a boxprint tree to a string
+class BPRender {
+public:
+  // output string
+  stringBuilder sb;
+
+  // right margin column; defaults to 72
+  int margin;
+
+  // column for next output; equal to the number of characters
+  // after the last newline in 'sb'
+  int curCol;
+
+  // text to begin every line with; not counted towards column
+  // counts; defaults to ""
+  string lineStartText;
+
+public:
+  BPRender();
+  ~BPRender();
+
+  // chars in the current line
+  int getCurCol() const { return curCol; }
+
+  // chars remaining on current line before the margin; might
+  // be negative if the input didn't have enough breaks
+  int remainder() const { return margin - getCurCol(); }
+
+  // add some text (that doesn't include newlines) to the output
+  void add(rostring text);
+
+  // add a newline, plus indentation to get to column 'ind'
+  void breakLine(int ind);
+
+  // take the string out of the rendering engine, replacing it
+  // with the empty string
+  string takeString() {
+    string ret(sb);
+    reset();
+    return ret;
+  }
+
+  // just clear the buffer to its original state; must do this
+  // manually after changing 'lineStartText'
+  void reset();
+
+  // take the tree out of a boxprint builder, convert it to a string,
+  // and delete the tree
+  string takeAndRender(BoxPrint &bld);
+};
+
+
+// interface for elements in a boxprint tree
+class BPElement {
+public:
+  // if no breaks are taken, compute the # of columns;
+  // return with 'forcedBreak' true if we stopped because of
+  // a forced break
+  virtual int oneLineWidthEx(bool &forcedBreak)=0;
+
+  // as above, but without the forcedBreak info
+  int oneLineWidth();
+
+  // render this element as a string with newlines, etc.
+  virtual void render(BPRender &mgr)=0;
+
+  // true if this element is a BPBreak and is enabled; returns false
+  // by default
+  virtual bool isBreak() const;
+
+  // true if is BPBreak and BT_FORCED
+  virtual bool isForcedBreak() const;
+
+  // print the boxprint tree; for debugging code that produces them;
+  // these methods do not emit leading or trailing whitespace
+  virtual void debugPrint(ostream &os, int ind) const =0;
+
+  // deallocate the element
+  virtual ~BPElement();
+};
+
+
+// leaf in the tree: text to print
+class BPText : public BPElement {
+public:
+  string text;
+
+public:
+  BPText(rostring t);
+  ~BPText();
+
+  // BPElement funcs
+  virtual int oneLineWidthEx(bool &forcedBreak);
+  virtual void render(BPRender &mgr);
+  virtual void debugPrint(ostream &os, int ind) const;
+};
+
+
+enum BreakType {
+  BT_DISABLED = 0,       // never taken
+  BT_ENABLED = 1,        // might be taken
+  BT_FORCED = 2,         // always taken
+  BT_LINE_START = 3,     // taken if the cursor is not at line start
+};
+
+// leaf in the tree: a "break", which might end up being a
+// space or a newline+indentation
+class BPBreak : public BPElement {
+public:
+  // When true, this is a conditional break, and whether it is taken
+  // or not depends on the prevailing break strategy of the box in
+  // which it is located.  When false, the break is never taken, so
+  // this is effectively just a space.
+  BreakType enabled;
+
+  // Nominally, when a break is taken, the indentation used is such
+  // that the next char in the box is directly below the first char
+  // in the box.  When this break is passed, however, it can add to
+  // that nominal indent of 0; these adjustments accumulate as the
+  // box is rendered.
+  int indent;
+
+public:
+  BPBreak(BreakType e, int i);
+  ~BPBreak();
+
+  // BPElement funcs
+  virtual int oneLineWidthEx(bool &forcedBreak);
+  virtual void render(BPRender &mgr);
+  virtual bool isBreak() const;
+  virtual bool isForcedBreak() const;
+  virtual void debugPrint(ostream &os, int ind) const;
+};
+
+
+// kinds of boxes
+enum BPKind {
+  // enabled breaks are always taken
+  BP_vertical,
+
+  // enabled breaks are individually taken or not taken depending
+  // on how much room is available; "hov"
+  BP_sequence,
+
+  // either all enabled breaks are taken, or none are taken; "h/v"
+  BP_correlated,
+
+  // # of kinds, also used to signal the end of a box in some cases
+  NUM_BPKINDS
+};
+
+// internal node in the tree: a list of subtrees, some of which
+// may be breaks
+class BPBox : public BPElement {
+public:
+  // subtrees
+  ASTList<BPElement> elts;
+
+  // break strategy for this box
+  BPKind kind;
+
+public:
+  BPBox(BPKind k);
+  ~BPBox();
+
+  // BPElement funcs
+  virtual int oneLineWidthEx(bool &forcedBreak);
+  virtual void render(BPRender &mgr);
+  virtual void debugPrint(ostream &os, int ind) const;
+};
+
+
+// assists in the process of building a box tree by providing
+// a number of syntactic shortcuts
+class BoxPrint {
+public:      // types
+  // additional command besides BPKind
+  enum Cmd {
+    sp,          // insert disabled break
+    br,          // insert enabled break
+    fbr,         // insert forced break
+    lineStart,   // insert lineStart break
+    ind,         // ibr(levelIndent)
+    und,         // ibr(-levelIndent) ("unindent")
+  };
+
+  // insert enabled break with indentation
+  struct IBreak {
+    int indent;
+    IBreak(int i) : indent(i) {}
+    // use default copy ctor
+  };
+
+  // operator sequence
+  struct Op {
+    char const *text;
+    Op(char const *t) : text(t) {}
+    // default copy ctor
+  };
+
+private:     // data
+  // stack of open boxes; always one open vert box at the top
+  ObjArrayStack<BPBox> boxStack;
+
+public:      // data
+  // convenient names for the box kinds
+  static BPKind const vert;       // = BP_vertical
+  static BPKind const seq;        // = BP_sequence
+  static BPKind const hv;         // = BP_correlated ("h/v")
+  static BPKind const end;        // = NUM_BPKINDS
+
+  // indentation amount for the ind/und commands; defaults to 2
+  int levelIndent;
+
+private:     // funcs
+  // innermost box being built
+  BPBox *box() { return boxStack.top(); }
+
+public:      // funcs
+  BoxPrint();
+  ~BoxPrint();
+
+  // append another element to the current innermost box
+  void append(BPElement *elt);
+
+  // add BPText nodes to current box
+  BoxPrint& operator<< (rostring s);
+  BoxPrint& operator<< (char const *s);
+  BoxPrint& operator<< (int i);
+
+  // open/close boxes
+  BoxPrint& operator<< (BPKind k);
+
+  // insert breaks
+  BoxPrint& operator<< (Cmd c);
+
+  // insert break with indentation
+  static IBreak ibr(int i) { return IBreak(i); }
+  BoxPrint& operator<< (IBreak b);
+
+  // op(text) is equivalent to sp << text << br
+  static Op op(char const *text) { return Op(text); }
+  BoxPrint &operator << (Op o);
+
+  // take the accumulated box tree out; all opened boxes must have
+  // been closed; the builder is left in a state where it can be used
+  // to build a new tree if desired, or it can be simply destroyed
+  BPBox* /*owner*/ takeTree();
+  
+  // print the current stack of trees
+  void debugPrint(ostream &os) const;
+  void debugPrintCout() const;      // for gdb
+};
+
+
+#endif // BOXPRINT_H

Added: vendor/elsa/current/smbase/breaker.cpp
===================================================================
--- vendor/elsa/current/smbase/breaker.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/breaker.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// breaker.cc            see license.txt for copyright and terms of use
+// code for breaker.h
+// Scott McPeak, 1997,1998  This file is public domain.
+
+#include "breaker.h"      // this module
+
+#ifdef __BORLANDC__
+# pragma warn -use
+#endif
+
+void ackackack(int*) {}
+
+void breaker()
+{
+  static int i=0;
+  int a=1;               // all this junk is just to make sure
+                         // that this function has a complete
+  ackackack(&a);         // stack frame, so the debugger can unwind
+  i++;                   // the stack
+}
+
+#ifdef __BORLANDC__
+#  pragma warn .use
+#endif
+
+// (tweak for CVS)

Added: vendor/elsa/current/smbase/breaker.h
===================================================================
--- vendor/elsa/current/smbase/breaker.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/breaker.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,40 @@
+// breaker.h            see license.txt for copyright and terms of use
+// function stub through which critical event code flow is directed
+//   for easy breakpoints
+// Scott McPeak, 1997,1998  This file is public domain.
+
+#ifndef __BREAKER_H
+#define __BREAKER_H
+
+extern "C" void breaker();
+
+// bassert = breaker assert; failure simply calls breaker, which is
+// a breakpoint in the debugger and is ignored when not in debugger;
+// useful mainly for places I want to ensure something is true during
+// initial testing, but after that it's ok if it's false
+template <class T>          // allow possibly null pointers, etc
+inline void bassert(T cond)
+{
+  if (!cond) {
+    breaker();
+  }
+}
+
+
+// this will call breaker on the first pass, but not any subsequent (unless
+// it's called MAXINT*2 times...)
+#define BREAK_FIRST_PASS     \
+  {                          \
+    static int passCount=0;  \
+    bassert(passCount++);    \
+  } /*no semicolon*/
+
+
+// this is obsolete...
+void _breaker_assert(char * __cond, char * __file, int __line);
+  // this will be called on failed assertions instead of _assert
+  // only if BREAKER_ASSERT is defined (due to a modification to
+  // assert.h directly)
+
+#endif // __BREAKER_H
+

Added: vendor/elsa/current/smbase/check-malloc-trace.pl
===================================================================
--- vendor/elsa/current/smbase/check-malloc-trace.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/check-malloc-trace.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,54 @@
+#!/usr/bin/perl -w
+# check the output of a malloc trace for malloc usage bugs
+
+use strict 'subs';
+
+$mallocs=0;
+$frees=0;                           
+$verbose=0;
+
+if ($#ARGV >= 0 && $ARGV[0] eq "-v") {
+  $verbose=1;
+}
+
+while ($line = <STDIN>) {
+  if (($size, $addr) = ($line =~ /malloc\((\d+)\) yielded (0x.*)$/)) {
+    #print ("malloc yielded $addr, size $size\n");
+    $mallocs++;
+
+    if (!$size) {
+      print ("strange: malloc(0) at $addr\n");
+    }
+
+    if ($valid{$addr}) {
+      print ("strange: malloc yielded already-valid $addr\n");
+    }
+    $valid{$addr} = $size;
+  }
+
+  elsif (($addr) = ($line =~ /free\((0x.*)\)$/)) {
+    #print ("free of $addr\n");
+    $frees++;
+
+    if ($valid{$addr}) {
+      $valid{$addr} = 0;     # not valid now
+    }
+    else {
+      print ("free of invalid addr $addr\n");
+    }
+  }
+}
+
+if ($verbose) {
+  # print all unfreed addresses
+  foreach $addr (sort keys %valid) {          
+    $size = $valid{$addr};
+    if ($size) {
+      print ("unfreed addr $addr, size was $size\n");
+    }
+  }
+}
+
+# for some reason, perl was complaining until I said 'STDOUT' too ..
+print STDOUT ("saw $mallocs mallocs and $frees frees" .
+              ($verbose? "" : " (-v to see unfreed)") . "\n");


Property changes on: vendor/elsa/current/smbase/check-malloc-trace.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/ckheap.h
===================================================================
--- vendor/elsa/current/smbase/ckheap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/ckheap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,60 @@
+// ckheap.h            see license.txt for copyright and terms of use
+// interface to check heap integrity, etc.
+
+#ifndef CKHEAP_H
+#define CKHEAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __WIN32__
+  // don't want to try to get dlmalloc working...
+  #define checkHeapNode(n) /*nothing*/
+  #define malloc_stats() ((void)0)
+#else
+  
+
+// check heap integrity, and fail an assertion if it's bad
+void checkHeap();
+
+// check that a given pointer is a valid allocated object;
+// fail assertion if not
+void checkHeapNode(void *node);
+
+// prints allocation statistics to stderr
+void malloc_stats();
+
+// count # of malloc/free calls in program
+unsigned numMallocCalls();
+unsigned numFreeCalls();
+
+
+// actions the heap walk iterator might request
+enum HeapWalkOpts {
+  HW_GO   = 0,         // keep going
+  HW_STOP = 1,         // stop iterating
+  HW_FREE = 2,         // free the block I just examined
+};
+
+// function for walking the heap
+//   block:   pointer to the malloc'd block of memory
+//   size:    # of bytes in the block; possibly larger than
+//            what was requested
+//   returns: bitwise OR of HeapWalkOpts options
+// NOTE: you cannot call malloc or free inside this function
+// (you can cause 'block' to be freed by returning HW_FREE)
+typedef enum HeapWalkOpts (*HeapWalkFn)(void *block, int size);
+
+// heap walk entry
+void walkMallocHeap(HeapWalkFn func);
+
+
+#endif // !__WIN32__
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // CKHEAP_H

Added: vendor/elsa/current/smbase/codepatch.pl
===================================================================
--- vendor/elsa/current/smbase/codepatch.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/codepatch.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,341 @@
+#!/usr/bin/perl -w
+# codepatch.pl
+#
+# This is sort of like 'patch' but a little higher-level.  I plan
+# to extend the script language with constructs as I need them.
+#
+# 2005-08-04: I am creating a new version in smbase, based on the
+# version in verifier but with different command-line syntax.
+
+use strict 'subs';
+
+sub usage {
+  print("usage: $0 -o output input script.patch [script2.patch [...]]\n");
+  exit(0);
+}
+
+if (@ARGV < 4 || $ARGV[0] ne "-o") {
+  usage();
+}
+
+$output = $ARGV[1];
+$input  = $ARGV[2];
+$nextArgIndex = 3;        # next script to apply
+
+
+# read all input
+open(INPUT, "<$input") or die("cannot read $input: $!\n");
+ at lines = <INPUT>;
+close(INPUT) or die;
+
+
+# apply each script in turn
+while ($nextArgIndex < @ARGV) {
+  $script = $ARGV[$nextArgIndex++];
+  open(SCRIPT, "<$script") or die("cannot read $script: $!\n");
+
+  # parse the script
+  $slineNum = 0;
+  while ($sline = <SCRIPT>) {
+    chomp($sline);
+    $slineNum++;
+
+    # skip blank lines, comments
+    if ($sline =~ m|^\s*(//.*)?$|) { next; }
+
+    # syntax:
+    #   replace_line
+    #   <source line>
+    #   with
+    #   <destination line>
+    #
+    # This is essentially just sed s/^<source>$/<dest>/ except we
+    # require that <source> occur exactly once in the input.
+    if ($sline eq "replace_line") {
+      my $src = <SCRIPT>; chomp($src);
+      my $with = <SCRIPT>; chomp($with);
+      my $dest = <SCRIPT>; chomp($dest);
+      if (!defined($dest) || $with ne "with") {
+        fail("malformed replace_line");
+      }
+
+      replaceLine($src, $dest);
+
+      $slineNum += 3;
+      next;
+    }
+
+    # syntax:
+    #   add_after_line
+    #   <match line>
+    #   the_line
+    #   <line to put after it>
+    if ($sline eq "add_after_line") {
+      my $match = <SCRIPT>; chomp($match);
+      my $the_line = <SCRIPT>; chomp($the_line);
+      my $after = <SCRIPT>; chomp($after);
+      if (!defined($after) || $the_line ne "the_line") {
+        fail("malformed add_after_line");
+      }
+
+      addAfterLine($match, $after);
+
+      $slineNum += 3;
+      next;
+    }
+
+    # syntax:
+    #   comment_function
+    #   <function name>
+    #
+    # Find the given function, and comment it out.
+    if ($sline eq "comment_function") {
+      my $name = <SCRIPT>;
+      chomp($name);
+
+      surroundFunction($name,
+                       "#if 0     // comment_function: $name",
+                       "#endif // 0");
+
+      $slineNum += 1;
+      next;
+    }
+
+    # syntax:
+    #   add_before_function
+    #   <function name>
+    #   the_line
+    #   <line to add before>
+    if ($sline eq "add_before_function") {
+      my $name = <SCRIPT>; chomp($name);
+      my $the_line = <SCRIPT>; chomp($the_line);
+      my $toAdd = <SCRIPT>; chomp($toAdd);
+      if (!defined($toAdd) || $the_line ne "the_line") {
+        fail("malformed add_before_function");
+      }
+
+      surroundFunction($name, $toAdd, "");
+
+      $slineNum += 3;
+      next;
+    }
+
+    # syntax:
+    #   add_after_function
+    #   <function name>
+    #   the_line
+    #   <line to add after>
+    if ($sline eq "add_after_function") {
+      my $name = <SCRIPT>; chomp($name);
+      my $the_line = <SCRIPT>; chomp($the_line);
+      my $toAdd = <SCRIPT>; chomp($toAdd);
+      if (!defined($toAdd) || $the_line ne "the_line") {
+        fail("malformed add_after_function");
+      }
+
+      surroundFunction($name, "", $toAdd);
+
+      $slineNum += 3;
+      next;
+    }
+
+    # syntax:
+    #   comment_line
+    #   <exact line text to comment out>
+    if ($sline eq "comment_line") {
+      my $text = <SCRIPT>;
+      chomp($text);
+
+      replaceLine($text, "//$text");
+
+      $slineNum += 1;
+      next;
+    }
+
+    fail("unknown directive");
+  }
+
+  close(SCRIPT) or die;
+}
+
+
+# emit the modified input
+if (-f $output && ! -w $output) {
+  # This is expected when this script is being run for the second or
+  # later time; change its permissions.
+  #
+  # I choose this approach rather than removing the file so that the
+  # inode gets re-used, which is sometimes useful.
+  makeWritable($output);
+}
+
+open(OUTPUT, ">$output") or die("cannot write $output: $!\n");
+print OUTPUT (@lines);
+close(OUTPUT) or die;
+
+makeNonWritable($output);
+
+exit(0);
+
+
+# ---------------------- subroutines --------------------------
+sub makeWritable {
+  my ($fname) = @_;
+
+  # I'm sure there's a fun and complicated way to do this using Perl's
+  # system calls, and respecting umask and all that, but I'm lazy.
+
+  if (0!=system("chmod", "u+w", $fname)) {
+    exit(4);     # chmod should have printed an error message
+  }
+}
+
+sub makeNonWritable {
+  my ($fname) = @_;
+
+  if (0!=system("chmod", "a-w", $fname)) {
+    exit(4);     # chmod should have printed an error message
+  }
+}
+
+
+sub fail {
+  my ($msg) = @_;
+  print STDERR ("$script:$slineNum: $msg\n");
+  close(SCRIPT);
+  exit(4);
+}
+
+
+sub replaceLine {
+  my ($src, $dest) = @_;
+
+  my $found = 0;
+  for (my $i=0; $i < @lines; $i++) {
+    my $tmp = $lines[$i];
+    chomp($tmp);
+    if ($tmp eq $src) {
+      $lines[$i] = $dest . "\n";
+      $found++;
+    }
+  }
+
+  if ($found == 0) {
+    fail("replaceLine: didn't find any matching lines");
+  }
+  if ($found > 1) {
+    fail("replaceLine: found $found matches (only want to find one)");
+  }
+}
+
+
+sub addAfterLine {
+  my ($match, $after) = @_;
+
+  my @destLines = ();
+
+  my $found = 0;
+  for (my $i=0; $i < @lines; $i++) {
+    push @destLines, $lines[$i];
+
+    my $tmp = $lines[$i];
+    chomp($tmp);
+    if ($tmp eq $match) {
+      push @destLines, ($after . "\n");
+      $found++;
+    }
+  }
+
+  if ($found == 0) {
+    fail("addAfterLine: didn't find any matching lines");
+  }
+  if ($found > 1) {
+    fail("addAfterLine: found $found matches (only want to find one)");
+  }
+
+  @lines = @destLines;
+}
+
+
+# Find a function definition and bracket it with two given lines.
+# Either line may be empty, indicating no insertion to be done.
+# Heuristics for finding the start and end are a little fragile,
+# but are sufficient for my present needs.
+sub surroundFunction {
+  my ($name, $startLine, $endLine) = @_;
+
+  my $i=0;
+  my @destLines = ();
+
+  # find the function header
+  while ($i < @lines && !atFuncHeader($i, $name)) {
+    push @destLines, ($lines[$i++]);
+  }
+  if ($i == @lines) {
+    fail("surroundFunction $name: did not find function header");
+  }
+
+  # insert begin-comment
+  if ($startLine) {
+    push @destLines, ($startLine . "\n");
+  }
+
+  # and function header as before
+  push @destLines, ($lines[$i++]);
+
+  # the next line should have an open-brace, with some indentation
+  my ($braceInd) = ($lines[$i] =~ m/^(\s*)\{/);
+  if (!defined($braceInd)) {
+    # should not happen now that 'atFuncHeader' checks for this too
+    fail("surroundFunction $name: did not find opening brace");
+  }
+  push @destLines, ($lines[$i++]);
+
+  # look for the close brace
+  while ($i < @lines &&
+         $lines[$i] !~ m/^$braceInd\}/) {
+    push @destLines, ($lines[$i++]);
+  }
+  if ($i == @lines) {
+    fail("surroundFunction $name: did not find closing brace");
+  }
+
+  # emit the closing brace
+  push @destLines, ($lines[$i++]);
+
+  # close the comment
+  if ($endLine) {
+    push @destLines, ($endLine . "\n");
+  }
+
+  # copy rest of file
+  while ($i < @lines && !atFuncHeader($i, $name)) {
+    push @destLines, ($lines[$i++]);
+  }
+  if ($i != @lines) {
+    fail("surroundFunction $name: found second function header on line $i");
+  }
+
+  # put it all back into 'lines'
+  @lines = @destLines;
+}
+
+
+sub atFuncHeader {
+  my ($i, $name) = @_;
+  my $line = $lines[$i];
+
+  # if name is followed by '(', say yes.
+  # don't allow line to begin with '#'.
+  if ($line =~ m/^[^\#]*$name\s*\(/) {
+    # check next line for open-brace
+    if ($lines[$i+1] =~ m/^\s*\{/) {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+
+# EOF

Added: vendor/elsa/current/smbase/configure.pl
===================================================================
--- vendor/elsa/current/smbase/configure.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/configure.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,187 @@
+#!/usr/bin/perl -w
+# configure script for smbase
+
+use strict 'subs';
+
+require sm_config;
+
+$SMBASE = ".";
+get_sm_config_version();
+$thisPackage = "smbase";
+
+sub usage {
+  standardUsage();
+
+  print(<<"EOF");
+package options:
+  -prof              enable profiling
+  -devel             add options useful while developing smbase
+  -debugheap         turn on heap usage debugging
+  -traceheap         print messages on each malloc and free
+EOF
+# this option is obscure, so I won't print it in the usage string
+# -icc               turn on options for Intel's compiler
+}
+
+# defaults (also see sm_config.pm)
+$DEBUG_HEAP = 0;
+$TRACE_HEAP = 0;
+
+
+# global variables holding information about the current command-line
+# option being processed
+$option = "";
+$value = "";
+
+# process command-line arguments
+foreach $optionAndValue (@ARGV) {
+  # ignore leading '-' characters, and split at first '=' (if any)
+  ($option, $value) =
+    ($optionAndValue =~ m/^-*([^-][^=]*)=?(.*)$/);
+                      #      option     = value
+                      
+  my $arg = $option;
+
+  if (handleStandardOption()) {
+    # handled by sm_config.pm
+  }
+
+  elsif ($arg eq "prof") {
+    push @CCFLAGS, "-pg";
+  }
+
+  elsif ($arg eq "devel") {
+    push @CCFLAGS, "-Werror";
+  }
+
+  elsif ($arg eq "debugheap") {
+    $DEBUG_HEAP = 1;
+  }
+  elsif ($arg eq "traceheap") {
+    $TRACE_HEAP = 1;
+  }
+
+  # 9/19/04: I spent some time getting smbase to build under
+  # the Intel C++ 8.1 compiler; these are the options I used.
+  elsif ($arg eq "icc") {
+    # compiler executables
+    $CC = "icc";
+    $CXX = "icpc";
+
+    # diagnostic suppression:
+    #  444: Wants virtual destructors
+    #  1418: external definition with no prior declaration
+    #  810: Conversion might lose sig.digs (can't suppress with cast!)
+    #  271: trailing comma is nonstandard
+    #  981: operands are evaluated in unspecified order
+    #  279: controlling expression is constant
+    #  383: value copied to temporary, reference to temporary used
+    #  327: NULL reference is not allowed
+    #  1419: external declaration in primary source file
+    push @CCFLAGS, "-wd444,1418,810,271,981,279,383,327,1419";
+  }
+  
+  else {
+    print STDERR ("unknown option: $arg\n");
+    exit(2);
+  }
+}
+
+finishedOptionProcessing();
+
+
+# -------------- external tools tests ---------------------
+test_CXX_compiler();
+
+
+# ------------------ config.summary -----------------
+$summary = getStandardConfigSummary();
+
+if ($DEBUG_HEAP) {
+  $summary .= "echo \"  DEBUG_HEAP:  $DEBUG_HEAP\"\n";
+}
+if ($TRACE_HEAP) {
+  $summary .= "echo \"  TRACE_HEAP:  $TRACE_HEAP\"\n";
+}
+
+writeConfigSummary($summary);
+
+
+# ------------------- config.status ------------------
+writeConfigStatus("DEBUG_HEAP" => "$DEBUG_HEAP",
+                  "TRACE_HEAP" => "$TRACE_HEAP");
+
+
+# ----------------- final actions -----------------
+# run the output file generator
+run("./config.status");
+
+print("\nYou can now run make, usually called 'make' or 'gmake'.\n");
+
+exit(0);
+
+
+# silence warnings
+pretendUsed($thisPackage);
+pretendUsed($CC);
+pretendUsed($CXX);
+
+
+# the code below is never executed as part of smbase/configure.pl;
+# it is here so it can be easily found to copy into the client
+# configuration scripts
+
+# -------------- BEGIN common block ---------------
+# do an initial argument scan to find if smbase is somewhere else
+for (my $i=0; $i < @ARGV; $i++) {
+  my ($d) = ($ARGV[$i] =~ m/-*smbase=(.*)/);
+  if (defined($d)) {
+    $SMBASE = $d;
+  }
+}
+
+# try to load the sm_config module
+eval {
+  push @INC, ($SMBASE);
+  require sm_config;
+};
+if ($@) {
+  die("$@" .     # ends with newline, usually
+      "\n" .
+      "I looked for smbase in \"$SMBASE\".\n" .
+      "\n" .
+      "You can explicitly specify the location of smbase with the -smbase=<dir>\n" .
+      "command-line argument.\n");
+}
+
+# check version number
+$smcv = get_sm_config_version();
+if ($smcv < $req_smcv) {
+  die("This package requires version $req_smcv of sm_config, but found\n" .
+      "only version $smcv.\n");
+}
+# -------------- END common block ---------------
+
+# -------------- BEGIN common block 2 -------------
+# global variables holding information about the current command-line
+# option being processed
+$option = "";
+$value = "";
+
+# process command-line arguments
+foreach $optionAndValue (@ARGV) {
+  # ignore leading '-' characters, and split at first '=' (if any)
+  ($option, $value) =
+    ($optionAndValue =~ m/^-*([^-][^=]*)=?(.*)$/);
+                      #      option     = value
+
+  my $arg = $option;
+
+  if (handleStandardOption()) {
+    # handled by sm_config.pm
+  }
+  # -------------- END common block 2 -------------
+}
+
+
+# EOF


Property changes on: vendor/elsa/current/smbase/configure.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/crc.cpp
===================================================================
--- vendor/elsa/current/smbase/crc.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/crc.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,173 @@
+// crc.cc            see license.txt for copyright and terms of use
+// adapted slightly by Scott McPeak
+
+// originally was:
+/* crc32h.c -- package to compute 32-bit CRC one byte at a time using   */
+/*             the high-bit first (Big-Endian) bit ordering convention  */
+/*                                                                      */
+/* Synopsis:                                                            */
+/*  gen_crc_table() -- generates a 256-word table containing all CRC    */
+/*                     remainders for every possible 8-bit byte.  It    */
+/*                     must be executed (once) before any CRC updates.  */
+/*                                                                      */
+/*  unsigned update_crc(crc_accum, data_blk_ptr, data_blk_size)         */
+/*           unsigned crc_accum; char *data_blk_ptr; int data_blk_size; */
+/*           Returns the updated value of the CRC accumulator after     */
+/*           processing each byte in the addressed block of data.       */
+/*                                                                      */
+/*  It is assumed that an unsigned long is at least 32 bits wide and    */
+/*  that the predefined type char occupies one 8-bit byte of storage.   */
+/*                                                                      */
+/*  The generator polynomial used for this version of the package is    */
+/*  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 */
+/*  as specified in the Autodin/Ethernet/ADCCP protocol standards.      */
+/*  Other degree 32 polynomials may be substituted by re-defining the   */
+/*  symbol POLYNOMIAL below.  Lower degree polynomials must first be    */
+/*  multiplied by an appropriate power of x.  The representation used   */
+/*  is that the coefficient of x^0 is stored in the LSB of the 32-bit   */
+/*  word and the coefficient of x^31 is stored in the most significant  */
+/*  bit.  The CRC is to be appended to the data most significant byte   */
+/*  first.  For those protocols in which bytes are transmitted MSB      */
+/*  first and in the same order as they are encountered in the block    */
+/*  this convention results in the CRC remainder being transmitted with */
+/*  the coefficient of x^31 first and with that of x^0 last (just as    */
+/*  would be done by a hardware shift register mechanization).          */
+/*                                                                      */
+/*  The table lookup technique was adapted from the algorithm described */
+/*  by Avram Perez, Byte-wise CRC Calculations, IEEE Micro 3, 40 (1983).*/
+
+#define POLYNOMIAL 0x04c11db7L
+
+static unsigned long crc_table[256];
+
+void gen_crc_table()
+ /* generate the table of CRC remainders for all possible bytes */
+ { register int i, j;  register unsigned long crc_accum;
+   for ( i = 0;  i < 256;  i++ )
+       { crc_accum = ( (unsigned long) i << 24 );
+         for ( j = 0;  j < 8;  j++ )
+              { if ( crc_accum & 0x80000000L )
+                   crc_accum =
+                     ( crc_accum << 1 ) ^ POLYNOMIAL;
+                else
+                   crc_accum =
+                     ( crc_accum << 1 ); }
+         crc_table[i] = crc_accum; }
+   return; }
+
+unsigned long update_crc(unsigned long crc_accum, char const *data_blk_ptr,
+                                                    int data_blk_size)
+ /* update the CRC on the data block one byte at a time */
+ { register int i, j;
+   for ( j = 0;  j < data_blk_size;  j++ )
+       { i = ( (int) ( crc_accum >> 24) ^ *data_blk_ptr++ ) & 0xff;
+         crc_accum = ( crc_accum << 8 ) ^ crc_table[i]; }
+   return crc_accum; }
+
+
+// SM: block-level application
+static int made_table = 0;
+unsigned long crc32(unsigned char const *data, int length)
+{
+  if (!made_table) {
+    gen_crc_table();
+    made_table = 1;
+  }
+
+  return update_crc(0xFFFFFFFF, (char*)data, length);
+}
+
+
+// ----------------- test code ------------------------------
+#ifdef TEST_CRC
+
+#include <stdio.h>     // printf, FILE, etc.
+#include <stdlib.h>    // malloc
+
+
+int errors=0;
+
+void testCrc(char const *data, int length, unsigned long crc)
+{     
+  unsigned long val = crc32((unsigned char*)data, length);
+  printf("computed crc is 0x%08lX, expected is 0x%08lX\n",
+         val, ~crc);       // why is 'crc' inverted?
+  if (val != ~crc) {
+    errors++;
+  }
+}
+
+
+int main(int argc, char *argv[])
+{
+  // if there's an argument, crc that
+  if (argc >= 2) {
+    FILE *fp = fopen(argv[1], "r");
+    if (!fp) {
+      printf("error opening %s: %m\n", argv[1]);
+      return 2;
+    }
+
+    // get length
+    fseek(fp, 0, SEEK_END);
+    int len = ftell(fp);
+    fseek(fp, 0, SEEK_SET);
+
+    // read the entire contents
+    unsigned char *buf = (unsigned char*)malloc(len);
+    if (fread(buf, 1, len, fp) != (size_t)len) {
+      printf("read error, or short count..\n");
+      return 2;
+    }
+
+    // crc it
+    long val = crc32(buf, len);
+    printf("crc32: 0x%08lX\n", val);
+
+    return 0;
+  }
+
+  /* 40 Octets filled with "0" */
+  /* CPCS-UU = 0, CPI = 0, Length = 40, CRC-32 = 864d7f99 */
+  char pkt_data1[48]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                      0x00,0x00,0x00,0x28,0x86,0x4d,0x7f,0x99};
+
+  /* 40 Octets filled with "1" */
+  /* CPCS-UU = 0, CPI = 0, Length = 40, CRC-32 = c55e457a */
+  char pkt_data2[48]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+                      0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+                      0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+                      0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+                      0x00,0x00,0x00,0x28,0xc5,0x5e,0x45,0x7a};
+
+  /* 40 Octets counting: 1 to 40 */
+  /* CPCS-UU = 0, CPI = 0, Length = 40, CRC-32 = bf671ed0 */
+  char pkt_data3[48]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,
+                      0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,
+                      0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,
+                      0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
+                      0x00,0x00,0x00,0x28,0xbf,0x67,0x1e,0xd0};
+
+  /* 40 Octets counting: 1 to 40 */
+  /* CPCS-UU = 11, CPI = 22, CRC-32 = acba602a */
+  char pkt_data4[48]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,
+                      0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,
+                      0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,
+                      0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
+                      0x11,0x22,0x00,0x28,0xac,0xba,0x60,0x2a};
+
+  testCrc(pkt_data1, 44, 0x864d7f99);
+  testCrc(pkt_data2, 44, 0xc55e457a);
+  testCrc(pkt_data3, 44, 0xbf671ed0);
+  testCrc(pkt_data4, 44, 0xacba602a);
+
+  return errors;
+}
+
+#endif // TEST_CRC
+
+
+

Added: vendor/elsa/current/smbase/crc.h
===================================================================
--- vendor/elsa/current/smbase/crc.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/crc.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// crc.h            see license.txt for copyright and terms of use
+// simple crc function
+
+#ifndef __CRC_H
+#define __CRC_H
+
+unsigned long crc32(unsigned char const *data, int length);
+
+#endif // __CRC_H
+

Added: vendor/elsa/current/smbase/cycles.c
===================================================================
--- vendor/elsa/current/smbase/cycles.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/cycles.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,134 @@
+// cycles.c            see license.txt for copyright and terms of use
+// code for cycles.h
+
+#include "cycles.h"      // this module
+
+// -------------------- x86 -------------------------
+#if defined(__i386__)
+// use the 'rdtsc' (read time-stamp count) instruction
+// NOTE: this entire file assumes we're compiling to a 32-bit machine
+// (i.e. 'unsigned' is a 32-bit quantity)
+
+// see also:
+//   http://cedar.intel.com/software/idap/media/pdf/rdtscpm1.pdf
+//   http://www.x86-64.org/lists/bugs/msg00621.html
+//   http://www.dc.uba.ar/people/materias/oc2/LaboLinux/docs/intel/RDTSC.pdf
+
+
+#ifdef RDTSC_SOURCE
+// this function yields a 64-bit cycle count, writing into
+// two variables passed by address
+void getCycles(unsigned *lowp, unsigned *highp)
+{
+  unsigned int low, high;
+
+  // this is gcc inline assembler syntax; it says that the
+  // instruction writes to EAX ("=a") and EDX ("=d"), but that
+  // I would like it to then copy those values into 'low' and
+  // 'high', respectively
+  asm volatile ("rdtsc" : "=a" (low), "=d" (high));
+
+  // now copy into the variables passed by address
+  *lowp = low;
+  *highp = high;
+}
+
+#else // RDTSC_SOURCE
+
+// this is the binary instructions that gcc-2.95.3 (optimization -O2)
+// produces for the above code; it will work regardless of the current
+// compiler's assembler syntax (even if the current compiler doesn't
+// have *any* inline assembler)
+static char const rdtsc_instructions[] = {
+  0x55,                                 // push   %ebp
+  0x89, 0xe5,                           // mov    %esp,%ebp
+  0x53,                                 // push   %ebx
+  0x8b, 0x4d, 0x08,                     // mov    0x8(%ebp),%ecx
+  0x8b, 0x5d, 0x0c,                     // mov    0xc(%ebp),%ebx
+  0x0f, 0x31,                           // rdtsc
+  0x89, 0x01,                           // mov    %eax,(%ecx)
+  0x89, 0x13,                           // mov    %edx,(%ebx)
+  0x5b,                                 // pop    %ebx
+  0xc9,                                 // leave
+  0xc3,                                 // ret
+  0x90,                                 // nop
+};
+
+// external entry point
+void getCycles(unsigned *lowp, unsigned *highp)
+{
+  return ((void (*)(unsigned*, unsigned*))rdtsc_instructions)(lowp, highp);
+}
+
+#endif // RDTSC_SOURCE
+
+
+// ------------------ unknown architecture -----------------
+#else
+
+// some preprocessors choke on this..
+//#warn unknown architecture in cycles.c
+
+void getCycles(unsigned *lowp, unsigned *highp)
+{
+  *lowp = 0;
+  *highp = 0;
+}
+
+#endif // architecture
+
+
+// ------------------- getCycles_ll ----------------------
+#ifdef __GNUC__
+// this uses gcc's "long long" to represent the 64-bit
+// quantity a little more easily
+unsigned long long getCycles_ll()
+{
+  unsigned int low, high;
+  unsigned long long ret;
+
+  getCycles(&low, &high);
+
+  ret = high;
+  ret <<= 32;
+  ret += low;
+
+  return ret;
+}
+#endif // __GNUC__
+
+
+// ----------------------- test code ---------------------
+#ifdef TEST_CYCLES
+
+#include <stdio.h>    // printf
+
+int main()
+{
+  #ifdef __GNUC__
+    unsigned long long v = getCycles_ll();
+    printf("getCycles: %llu\n", v);
+  #endif // __GNUC__
+
+  // this segment should work on any compiler, by virtue
+  // of only using 32-bit quantities
+  {
+    unsigned low, high;
+    getCycles(&low, &high);
+    printf("getCycles high=%u, low=%u\n", high, low);
+  }
+
+  // test whether the instruction causes a privileged instruction
+  // fault; on my machine I get 33 cycles per call, which clearly
+  // is too few for it to be trapping on each one
+  {
+    unsigned low1, low2, low3, high;
+    getCycles(&low1, &high);
+    getCycles(&low2, &high);
+    getCycles(&low3, &high);
+    printf("three lows in a row: %u, %u, %u\n", low1, low2, low3);
+  }
+
+  return 0;
+}
+#endif // TEST_CYCLES

Added: vendor/elsa/current/smbase/cycles.h
===================================================================
--- vendor/elsa/current/smbase/cycles.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/cycles.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,26 @@
+// cycles.h            see license.txt for copyright and terms of use
+// read processor cycle count
+// interface is portable, implementation is not
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// read the processor's cycle-count register, and store the count
+// into these two 'unsigned' variables; if the count isn't available,
+// yields zero in both
+void getCycles(unsigned *lowp, unsigned *highp);
+
+
+#ifdef __GNUC__
+// if we're using gcc, so the 'long long' type is available,
+// here's a more convenient version
+unsigned long long getCycles_ll(void);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+

Added: vendor/elsa/current/smbase/d2vector.c
===================================================================
--- vendor/elsa/current/smbase/d2vector.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/d2vector.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,312 @@
+// d2vector.c
+// some simple 2d vector code
+//
+// author: Scott McPeak, July 2001
+// minor changes (renaming, etc.): 2005-12-31
+//
+// This file is hereby placed in the public domain.
+
+#include "d2vector.h"   // this module
+
+#include <assert.h>     // assert
+#include <stdio.h>      // printf
+#include <math.h>       // isnan, isinf, sin, cos, M_PI
+
+double lengthD2Vector(D2Vector const *v)
+{
+  return sqrt(v->x * v->x + v->y * v->y);
+}
+
+void rotD2Vector90(D2Vector *v)
+{
+  double tmp = v->x;
+  v->x = -(v->y);
+  v->y = tmp;
+}
+
+void rotD2Vector180(D2Vector *v)
+{
+  v->x = -(v->x);
+  v->y = -(v->y);
+}
+
+void rotD2Vector270(D2Vector *v)
+{
+  double tmp = v->x;
+  v->x = v->y;
+  v->y = -tmp;
+}
+
+void rotD2VectorAngle(D2Vector *ret, D2Vector const *v, double theta)
+{
+  double cos_t = cos(theta);
+  double sin_t = sin(theta);
+  assert(ret != v);
+  ret->x = (v->x * cos_t) - (v->y * sin_t);
+  ret->y = (v->x * sin_t) + (v->y * cos_t);
+}
+
+
+// this fn (and the below) are specifically written so it works
+// to have p1, p2, and/or ret aliased
+void addD2Points(D2Point *ret, D2Point const *p1, D2Point const *p2)
+{
+  ret->x = p1->x + p2->x;
+  ret->y = p1->y + p2->y;
+}
+
+void subD2Points(D2Point *ret, D2Point const *p1, D2Point const *p2)
+{
+  ret->x = p1->x - p2->x;
+  ret->y = p1->y - p2->y;
+}
+
+void scaleD2Vector(D2Vector *ret, D2Vector const *p, double scalar)
+{
+  ret->x = p->x * scalar;
+  ret->y = p->y * scalar;
+}
+
+void scaleD2VectorTo(D2Vector *v, double finalLength)
+{
+  scaleD2Vector(v, v, finalLength / lengthD2Vector(v));
+}
+
+void pointOnD2Line(D2Point *ret, D2Line const *line, double t)
+{
+  assert(ret != &line->origin && ret != &line->vector);
+  scaleD2Vector(ret, &line->vector, t);
+  addD2Points(ret, ret, &line->origin);
+}
+
+
+double dotProdD2Vector(D2Vector const *a, D2Vector const *b)
+{
+  return a->x * b->x + a->y * b->y;
+}
+
+double projectD2PointLine(D2Point const *pt, D2Line const *line)
+{
+  double bLen, dot;
+
+  // let a be the vector from line->origin to pt
+  D2Vector a;
+  subD2Points(&a, pt, &line->origin);
+
+  // let b be line->vector
+  bLen = lengthD2Vector(&line->vector);          // |b|
+
+  dot = dotProdD2Vector(&a, &line->vector);      // |a||b|cos(theta)
+  return dot/bLen;                               // |a|cos(theta)
+}
+
+
+double crossProdZD2Vector(D2Vector const *v1, D2Vector const *v2)
+{
+  return (v1->x * v2->y) - (v1->y * v2->x);
+}
+
+double distanceD2PointLine(D2Point const *pt, D2Line const *line)
+{
+  double bLen, cross;
+
+  // let a be the vector from line->origin to pt
+  D2Vector a;
+  subD2Points(&a, pt, &line->origin);
+
+  // let b be line->vector
+  bLen = lengthD2Vector(&line->vector);          // |b|
+
+  cross = crossProdZD2Vector(&a, &line->vector); // |a||b|sin(theta)
+  return cross/bLen;                             // |a|sin(theta)
+}
+
+
+bool nonzeroD2Vector(D2Vector const *v)
+{
+  return v->x != 0 || v->y != 0;
+}
+
+double const d2_nan = 0.0/0.0;
+
+bool isSpecial(double value)
+{
+  return isnan(value) || isinf(value);
+}
+
+
+double intersectD2Lines(D2Line const *pvline, D2Line const *qwline)
+{
+  // some convenient names
+  D2Point const *p = &pvline->origin;
+  D2Vector const *v = &pvline->vector;
+  D2Point const *q = &qwline->origin;
+  D2Vector const *w = &qwline->vector;
+  double t;
+
+  // sanity check
+  assert(nonzeroD2Vector(v) && nonzeroD2Vector(w));
+
+  // solve for t, the multiplier considered to apply to 'qwline',
+  // at the intersection point (this formula was worked out on paper)
+  t = ((p->x - q->x) + (v->x / v->y) * (q->y - p->y)) /
+   // -----------------------------------------------
+               (w->x - (v->x / v->y) * w->y) ;
+
+  if (isSpecial(t)) {
+    // the computation failed, either because 'v' is vertical, or
+    // because the lines are parallel; so try to solve for 's'
+    // instead, the multiplier considered to apply to 'pvline'
+    // (same formula as above except p<->q and v<->w swapped)
+    double s = ((q->x - p->x) + (w->x / w->y) * (p->y - q->y)) /
+            // -----------------------------------------------
+                      (v->x - (w->x / w->y) * v->y) ;
+
+    if (isSpecial(s)) {    
+      // the lines must be parallel
+      return d2_nan;
+    }
+
+    // the point given by p + v*s is the intersection point; use
+    // 's' to compute 't', the multiplier for 'line'
+    t = (p->x + (v->x * s) - q->x) / w->x;
+
+    if (isSpecial(t)) {
+      // try the other formula, using the 'y' components
+      t = (p->y + (v->y * s) - q->y) / w->y;
+
+      if (isSpecial(t)) {
+        // I don't know what would cause this (other than some
+        // malformation of v or w that nonzeroD2Vector doesn't cover,
+        // like nan)
+        assert(!"Unexpected failure in intersection computation");
+      }
+    }
+  }
+
+  assert(!isSpecial(t));
+  return t;
+}
+
+
+void printD2Point(D2Point const *p)
+{
+  printf("(%g,%g)", p->x, p->y);
+}
+
+void printD2Line(D2Line const *line)
+{
+  printf("from (%g,%g) along (%g,%g)",
+         line->origin.x, line->origin.y,
+         line->vector.x, line->vector.y);
+}
+
+
+// -------------------- test code --------------------
+#ifdef TEST_D2VECTOR
+
+void runIntersect(double px, double py, double vx, double vy,
+                  double qx, double qy, double wx, double wy)
+{
+  D2Line L1, L2;
+  double t;
+
+  printf("computing intersection:\n");
+
+  L1.origin.x = px;
+  L1.origin.y = py;
+  L1.vector.x = vx;
+  L1.vector.y = vy;
+  printf("  L1: "); printD2Line(&L1); printf("\n");
+
+  L2.origin.x = qx;
+  L2.origin.y = qy;
+  L2.vector.x = wx;
+  L2.vector.y = wy;
+  printf("  L2: "); printD2Line(&L2); printf("\n");
+
+  t = intersectD2Lines(&L1, &L2);
+  if (isSpecial(t)) {
+    printf("  these lines are parallel\n");
+  }
+  else {
+    D2Point p;
+
+    printf("  t is %g\n", t);
+
+    // compute it as a point
+    pointOnD2Line(&p, &L2, t);
+    printf("  intersection is (%g,%g)\n", p.x, p.y);
+  }
+}
+
+void rotTest()
+{
+  D2Vector v;
+  int i;
+
+  printf("\nrot test\n");
+
+  v.x = 2;
+  v.y = 1;
+  printD2Point(&v);
+  rotD2Vector90(&v);
+  printD2Point(&v);
+  rotD2Vector180(&v);
+  printD2Point(&v);
+  rotD2Vector270(&v);
+  printD2Point(&v);
+  printf("\n");
+
+  v.x = 1;
+  v.y = 0;
+  printD2Point(&v);
+  for (i=0; i<12; i++) {
+    D2Vector tmp;
+    if (i % 3 == 0) {
+      printf("\n");
+    }
+    rotD2VectorAngle(&tmp, &v, 30.0 * M_PI / 180.0);   // 30 degrees
+    v = tmp;
+    printD2Point(&v);
+  }
+  printf("\n");
+}
+
+int main()
+{
+  // from (1,0) pointing up, intersected with
+  // from (0,1) pointing right
+  runIntersect(1,0, 0,1,  0,1, 1,0);
+  runIntersect(0,1, 1,0,  1,0, 0,1);
+
+  // vertical and diagonal
+  runIntersect(1,0, 0,1,  0,0, 1,1);
+
+  // vertical and diagonal
+  runIntersect(1,0, 0,1,  0,0, 1,2);
+
+  // vertical and diagonal
+  runIntersect(2,0, 0,1,  0,0, 1,2);
+
+  // parallel vertical
+  runIntersect(1,0, 0,1,  0,0, 0,1);
+
+  // parallel horizontal
+  runIntersect(0,1, 1,0,  0,0, 1,0);
+
+  // horizontal and diagonal
+  runIntersect(0,1, 1,0,  0,10, 1,-0.1);
+
+  // both diagonal, not parallel
+  runIntersect(1,0, 1,2,  0,1, 2,1);
+
+  // diagonal and parallel (but the vector isn't identical)
+  runIntersect(1,0, 1,2,  0,1, 2,4);
+
+  rotTest();
+
+  return 0;
+}
+
+#endif // TEST_D2VECTOR

Added: vendor/elsa/current/smbase/d2vector.h
===================================================================
--- vendor/elsa/current/smbase/d2vector.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/d2vector.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,97 @@
+// d2vector.h
+// simple 2d points, lines, and vectors using doubles
+// author: Scott McPeak, July 2001
+// This file is hereby placed in the public domain.
+
+#ifndef D2VECTOR_H
+#define D2VECTOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#else
+  #ifndef bool
+    #define bool int
+    #define true 1
+    #define false 0
+  #endif
+#endif
+
+// test if something is a special value (+inf/-inf/nan)
+// (I'm assuming IEEE floats here!)
+bool isSpecial(double value);
+
+// single point in 2d space
+typedef struct {
+  double x;
+  double y;
+} D2Point;
+
+// I use the same representation for vectors
+typedef D2Point D2Vector;
+
+// parameteric description of a line
+typedef struct {
+  D2Point origin;      // a single point on the line
+  D2Vector vector;     // all points are origin + vector*t, -INF < t < +INF
+} D2Line;
+
+
+// length ("norm") of the vector
+double lengthD2Vector(D2Vector const *v);
+
+// simple reorientation of a vector by clockwise rotation
+// of 90 degree increments (source and dest are same)
+// (these are given specially because they avoid roundoff errors)
+void rotD2Vector90(D2Vector *v);
+void rotD2Vector180(D2Vector *v);
+void rotD2Vector270(D2Vector *v);
+
+// and arbitrary rotation (does *not* work when ret and v are aliased)
+void rotD2VectorAngle(D2Vector *ret, D2Vector const *v, double theta);
+
+// it is *legal* for the various pointers passed to these
+// functions to be aliased (point to the same thing)
+void addD2Points(D2Point *ret, D2Point const *p1, D2Point const *p2);
+void subD2Points(D2Point *ret, D2Point const *p1, D2Point const *p2);
+void scaleD2Vector(D2Vector *ret, D2Vector const *p, double scalar);
+
+// change the length of a vector w/o changing its orientation
+void scaleD2VectorTo(D2Vector *v, double finalLength);
+
+// here, 'ret' can't be aliased with line's coordinates
+void pointOnD2Line(D2Point *ret, D2Line const *line, double t);
+
+// dot product = |a||b|cos(theta)
+double dotProdD2Vector(D2Vector const *a, D2Vector const *b);
+
+// project a point into a line, yielding the parameter 't' that
+// denotes the point in the line
+double projectD2PointLine(D2Point const *pt, D2Line const *line);
+
+// return the z component of the cross product of v1 and v2,
+// when considered to be vectors in the x-y plane; one way to
+// interpret this: when it's positive, v2 is within 180 degrees
+// counterclockwise of v1
+//
+// another identity: |a x b| = |a||b|sin(theta)
+double crossProdZD2Vector(D2Vector const *a, D2Vector const *b);
+
+// distance between a point and a line
+double distanceD2PointLine(D2Point const *pt, D2Line const *line);
+
+// true if either of v's components is not 0
+bool nonzeroD2Vector(D2Vector const *v);
+
+// given two lines in parametric form, return the value 't' such that
+// qwline->origin + (qwline->vector * t) is the intersection point;
+// if the lines are parallel, returns NAN
+double intersectD2Lines(D2Line const *pvline, D2Line const *qwline);
+
+void printD2Point(D2Point const *p);         // (x,y)
+void printD2Line(D2Line const *line);        // from (x,y) along (v,w)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // D2VECTOR_H

Added: vendor/elsa/current/smbase/datablok.cpp
===================================================================
--- vendor/elsa/current/smbase/datablok.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/datablok.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,487 @@
+// datablok.cc            see license.txt for copyright and terms of use
+// code for datablok.h
+// Scott McPeak, 1998-2000  This file is public domain.
+
+#include "datablok.h"     // this module
+#include "exc.h"          // xassert, CAUTIOUS_RELAY
+#include "crc.h"          // crc32
+#include "syserr.h"       // xsyserror
+
+#include <stdio.h>        // printf
+#include <string.h>       // memcpy
+#include <ctype.h>        // isprint
+    
+    
+// define the endpost byte as something we hope is
+// unlikely to coincidentally be written during an
+// overrun
+byte const DataBlock::endpost = 0xBB;
+    
+    
+void DataBlock::init(int allocatedSize)
+{
+  xassert(allocatedSize >= 0);
+  dataLen = 0;
+  allocated = allocatedSize;
+  if (allocated) {
+    data = allocate(allocated);
+  }
+  else {
+    data = NULL;
+  }
+    
+  SELFCHECK();
+}
+    
+    
+STATICDEF byte *DataBlock::allocate(int size)
+{
+  byte *ret = new byte[size+1];
+  ret[size] = endpost;
+  return ret;
+}
+    
+    
+void DataBlock::selfCheck() const
+{
+  if (!( 0 <= dataLen && dataLen <= allocated )) {
+    breaker();    // having trouble discovering the precise state under gdb
+  }
+  xassert(0 <= dataLen && dataLen <= allocated);
+  xassert( (data==NULL) == (allocated==0) );
+  xassert( data==NULL || data[allocated]==endpost );
+}
+    
+    
+DataBlock::DataBlock(int allocatedSize)
+{
+  init(allocatedSize);
+  SELFCHECK();
+}
+    
+
+DataBlock::DataBlock(char const *srcString)
+{
+  init(0);
+  setFromString(srcString);
+  SELFCHECK();
+}
+    
+    
+void DataBlock::ctor(byte const *srcData, int dataLen)
+{
+  init(0);
+  setFromBlock(srcData, dataLen);
+  SELFCHECK();
+}
+
+
+void DataBlock::ctor(byte const *srcData, int srcDataLen, int allocatedSize)
+{
+  init(allocatedSize);
+  dataLen = srcDataLen;
+  memcpy(data, srcData, dataLen);
+  SELFCHECK();
+}
+    
+    
+DataBlock::DataBlock(DataBlock const &obj)
+{
+  init(obj.allocated);
+  copyCtorShared(obj);
+}
+
+void DataBlock::copyCtorShared(DataBlock const &obj)
+{
+  dataLen = obj.dataLen;
+  if (dataLen > 0) {
+    memcpy(data, obj.data, dataLen);
+  }
+  SELFCHECK();
+}
+
+
+DataBlock::DataBlock(DataBlock const &obj, int minToAllocate)
+{
+  init(max(obj.getAllocated(), minToAllocate));
+  copyCtorShared(obj);
+}
+    
+    
+DataBlock::~DataBlock()
+{
+  try {
+    SELFCHECK();
+    if (data) {
+      delete[] data;
+    }
+  }
+  CAUTIOUS_RELAY
+}
+    
+    
+bool DataBlock::allEqual(DataBlock const &obj) const
+{
+  SELFCHECK();
+  return allocated == obj.allocated &&
+         dataEqual(obj);
+}
+
+
+bool DataBlock::dataEqual(DataBlock const &obj) const
+{
+  SELFCHECK();
+  if (dataLen != obj.dataLen ||
+      (dataLen > 0 &&
+       0 != memcmp(data, obj.data, dataLen))) {
+    return false;
+  }
+  else {
+    return true;
+  }
+}
+
+
+
+void DataBlock::setDataLen(int newLen)
+{
+  SELFCHECK();
+  xassert(0 <= newLen && newLen <= allocated);
+  dataLen = newLen;
+  SELFCHECK();
+}
+    
+    
+void DataBlock::setAllocated(int newAllocated)
+{
+  SELFCHECK();
+  xassert(newAllocated >= 0);
+  if (allocated != newAllocated) {
+    // allocate new buffer
+    byte *newData = NULL;
+    if (newAllocated > 0) {
+      newData = allocate(newAllocated);
+    }
+
+    // truncate defined data
+    if (dataLen > newAllocated) {
+      dataLen = newAllocated;
+    }
+    
+    // transfer data
+    if (dataLen > 0) {
+      memcpy(newData, data, dataLen);
+    }
+    
+    // deallocate old buffer and replace with new buffer
+    delete[] data;
+    data = newData;
+    allocated = newAllocated;
+  }
+  SELFCHECK();
+}
+    
+
+void DataBlock::ensureAtLeast(int minAllocated)
+{
+  if (allocated < minAllocated) {
+    setAllocated(minAllocated);
+  }
+}
+
+
+void DataBlock::growDataLen(int changeAmount)
+{
+  ensureAtLeast(getDataLen() + changeAmount);
+  changeDataLen(changeAmount);
+}
+
+
+void DataBlock::addNull()
+{
+  SELFCHECK();
+  data[dataLen] = 0;
+  setDataLen(dataLen + 1);
+  SELFCHECK();
+}
+    
+
+void DataBlock::setFromString(char const *srcString)
+{
+  SELFCHECK();
+  int len = strlen(srcString)+1;
+    // a string is its contents and the null terminator
+  setFromBlock((byte const*)srcString, len);
+  SELFCHECK();
+}
+    
+void DataBlock::setFromBlock(byte const *srcData, int len)
+{
+  SELFCHECK();
+  if (len > allocated) {
+    setAllocated(len);
+  }
+  setDataLen(len);
+  if (len > 0) {
+    memcpy(data, srcData, len);
+  }
+  SELFCHECK();
+}
+
+
+DataBlock& DataBlock::operator= (DataBlock const &obj)
+{
+  SELFCHECK();
+  if (this != &obj) {
+    setAllocated(obj.allocated);
+    dataLen = obj.dataLen;
+    memcpy(data, obj.data, dataLen);
+  }
+  SELFCHECK();
+  return *this;
+}
+
+
+void DataBlock::print(char const *label, int bytesPerLine) const
+{
+  xassert(bytesPerLine >= 1);
+  SELFCHECK();
+
+  if (label) {
+    printf("---- %s, length = %d, crc32 = 0x%lX ---- {\n",
+           label, getDataLen(),
+           crc32(getDataC(), getDataLen()));
+  }
+
+  int cursor = 0;
+  while (cursor < getDataLen()) {
+    int linelen = min(bytesPerLine, getDataLen() - cursor);
+    xassert(linelen >= 1);    // ensure can't loop infinitely
+
+    printf("  ");     // indent
+    printHexLine(getDataC() + cursor, linelen, bytesPerLine);
+    printf("   ");
+    printPrintableLine(getDataC() + cursor, linelen);
+    printf("\n");
+
+    cursor += linelen;
+  }
+
+  if (label) {
+    printf("}\n");
+  }
+  SELFCHECK();
+}
+
+
+// print 'length' bytes of 'data' in hex
+// blank-pad the output as if 'linelen' bytes were present
+STATICDEF void DataBlock::printHexLine(byte const *data, int length, int linelen)
+{
+  xassert(data != NULL &&
+          length >= 1 &&
+          linelen >= length);
+
+  for (int i=0; i<linelen; i++) {
+    if (i < length) {
+      printf("%02X ", (byte)*data);
+      data++;
+    }
+    else {
+      printf("   ");
+    }
+  }
+}
+
+
+// print 'length' bytes of 'data', substituting 'unprintable' for bytes for
+// which 'isprint' is false
+STATICDEF void DataBlock::printPrintableLine(byte const *data, int length,
+                                             char unprintable)
+{
+  xassert(data != NULL &&
+          length >= 1);
+
+  while (length--) {
+    if (isprint(*data)) {
+      printf("%c", *data);
+    }
+    else {
+      printf("%c", unprintable);
+    }
+    data++;
+  }
+}
+
+
+#if 0
+void DataBlock::print(char const *label) const
+{
+  enum { MARGIN = 70 };
+
+  if (label) {
+    printf("------ %s (length=%d) -------\n", label, getDataLen());
+  }
+
+  byte *p = data;
+  int i;
+  int column=0;
+  for (i=0; i<dataLen; i++, p++) {
+    if (isprint(*p)) {
+      if (*p != '\\') {
+        column += printf("%c", *p);
+      }
+      else {
+        printf("\\\\");     // otherwise '\\','x','nn','nn' would be ambiguous
+      }
+    }
+    else {
+      column += printf("\\x%02X", *p);
+    }
+
+    if (column >= MARGIN && (i+1) < dataLen) {
+      printf("\\\n");       // continuation lines end with backslash
+      column = 0;
+    }
+  }
+
+  // this makes spaces at the end of a buffer invisible.. oh well..
+  if (column != 0) {    // if didn't just newline...
+    printf("\n");
+  }
+
+  if (label) {
+    printf("------ end of %s -------\n", label);
+  }
+}
+#endif // 0
+
+
+void DataBlock::dontPrint(char const *, int) const
+{}
+
+
+void DataBlock::writeToFile(char const *fname) const
+{
+  FILE *fp = fopen(fname, "wb");
+  if (!fp) {
+    xsyserror("fopen", fname);
+  }
+
+  // finally giving in and silencing those *stupid* g++ warnings
+  // about comparing signed and unsigned for EQUALITY!!!
+  // I'll get you yet, you big stinking GNU!!
+  if ((int)fwrite(getDataC(), 1, getDataLen(), fp) != getDataLen()) {
+    xsyserror("fwrite", fname);
+  }
+
+  if (fclose(fp) != 0) {
+    xsyserror("fclose", fname);
+  }
+}
+
+
+void DataBlock::readFromFile(char const *fname)
+{
+  FILE *fp = fopen(fname, "rb");
+  if (!fp) {
+    xsyserror("fopen", fname);
+  }
+
+  // seek to end to know how much to allocate
+  if (fseek(fp, 0, SEEK_END) != 0) {
+    xsyserror("fseek", fname);
+  }
+
+  long len = ftell(fp);
+  if (len < 0) {
+    xsyserror("ftell", fname);
+  }
+
+  setAllocated(len);
+
+  // read data
+  if (fseek(fp, 0, SEEK_SET) != 0) {
+    xsyserror("fseek", fname);
+  }
+
+  if ((long)fread(getData(), 1, len, fp) != len) {
+    xsyserror("fread", fname);
+  }
+
+  setDataLen(len);
+
+  if (fclose(fp) != 0) {
+    xsyserror("fclose", fname);
+  }
+}
+
+
+// ------------- self test code --------------
+#ifdef DATABLOK_TEST
+
+int doit()
+{
+  // nest everything so the dtors are inside
+  {
+    // test printing function
+    {
+      DataBlock b(260);
+      for (int i=0; i<260; i++) {
+        b.getData()[i] = (byte)i;
+      }
+      b.setDataLen(260);
+      b.print("all bytes plus 4 extra");
+    }
+
+    DataBlock block("yadda smacker");
+    xassert(block.getDataLen() == 14);
+
+    DataBlock block2((byte*)"yadda smacker", 13, 14);
+    block2.addNull();
+    xassert(block == block2);
+
+    DataBlock block3;
+    block3 = block2;
+    xassert(block3 == block);
+
+    block3.setAllocated(5);       // truncates
+    block2.setAllocated(25);
+    xassert(block3 != block2);
+
+    // test file save/load
+    block.writeToFile("tempfile.blk");
+    DataBlock block4;
+    block4.readFromFile("tempfile.blk");
+    xassert(block == block4);
+
+    // test overrun detection
+    try {
+      {
+        DataBlock b(block);
+        b.getData()[block.getAllocated()] = 0;   // overrun
+
+        printf("this should cause an assertion failure:\n");
+        // invoke selfcheck in destructor
+      }
+      return printf("failed to detect overrun\n");
+    }
+    catch (...) {}
+  }
+    
+  printf("test succeeded\n");
+  return 0;
+}
+    
+int main()
+{
+  try {
+    return doit();
+  }
+  catch (xBase &x) {
+    return printf("failed: %s\n", x.why());
+  }
+}
+    
+#endif // DATABLOK_TEST
+

Added: vendor/elsa/current/smbase/datablok.h
===================================================================
--- vendor/elsa/current/smbase/datablok.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/datablok.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,150 @@
+// datablok.h            see license.txt for copyright and terms of use
+// arbitrary block of data
+// Scott McPeak, 1998-2000  This file is public domain.
+
+#ifndef __DATABLOK_H
+#define __DATABLOK_H
+
+#include "typ.h"      // byte, bool
+
+class DataBlock {
+private:      // data
+  byte *data;                  // data itself (may be NULL)
+  int dataLen;                 // length of data, starting at data[0]
+  int allocated;               // amount of memory allocated at 'data'
+
+  // invariants: 0 <= dataLen <= allocated
+  //             (data==NULL) == (allocated==0)
+
+  // endpost: 'data' will be kept allocated with one extra byte at the
+  // end, where an endpost byte is written.  thus, we have another
+  // invariant:
+  //             (data!=NULL) implies data[allocated] == endpost
+  static byte const endpost;
+
+private:      // funcs
+  void init(int allocatedSize);
+    // base ctor
+
+  static byte *allocate(int size);
+    // allocate a block of memory, writing endpost
+
+  void copyCtorShared(DataBlock const &obj);
+    // shared by both copy constructors (actually, only one is the true
+    // copy ctor...)
+
+  void ctor(byte const *srcData, int dataLen);
+  void ctor(byte const *srcData, int dataLen, int allocatedSize);
+    // shared ctor calls as a workaround for char casting problems
+
+  void selfCheck() const;
+    // confirm that invariants are true
+
+public:       // funcs
+  // constructors
+  DataBlock(int allocatedSize = 0);
+    // make an empty datablock holder; when allocatedSize is 0, 'data'
+    // is initially set to NULL
+
+  EXPLICIT DataBlock(char const *srcString);
+    // make a copy of 'srcString' data, which is null-terminated
+
+  DataBlock(byte const *srcData, int dataLen) { ctor(srcData, dataLen); }
+  DataBlock(char const *srcData, int dataLen) { ctor((byte const*)srcData, dataLen); }
+    // make a copy of 'srcData', which is 'dataLen' bytes long
+
+  DataBlock(byte const *srcData, int dataLen, int allocatedSize)
+    { ctor(srcData, dataLen, allocatedSize); }
+  DataBlock(char const *srcData, int dataLen, int allocatedSize)
+    { ctor((byte const*)srcData, dataLen, allocatedSize); }
+    // make a copy of 'srcData', which is 'dataLen' bytes long, in a buffer
+    // that is 'allocatedSize' bytes long
+
+  DataBlock(DataBlock const &obj);
+    // copy data, allocate same amount as 'obj'
+
+  DataBlock(DataBlock const &obj, int minToAllocate);
+    // copy obj's contents; allocate either obj.getAllocated() or
+    // minToAllocate, whichever is larger (this turns out to be a
+    // common idiom)
+
+  ~DataBlock();
+
+  // selectors
+  byte const *getDataC() const { return data; }
+  int getDataLen() const { return dataLen; }
+  int getAllocated() const { return allocated; }
+
+  bool dataEqual(DataBlock const &obj) const;
+    // compares data length and data-length bytes of data
+
+  bool allEqual(DataBlock const &obj) const;
+    // compares data, length, and allocation length
+
+  bool operator== (DataBlock const &obj) const
+    { return dataEqual(obj); }
+  bool operator!= (DataBlock const &obj) const
+    { return !operator==(obj); }
+    // SM, 1/24/99: with the coding of blokutil, I've finally clarified that
+    // allocation length is a concern of efficiency, not correctness, and so
+    // have changed the meaning of == to just look at data.  The old behavior
+    // is available as 'allEqual()'.
+
+  // mutators
+  byte *getData() { return data; }
+  void setDataLen(int newLen);
+    // asserts that 0 <= newLen <= allocated
+  void setAllocated(int newAllocated);     // i.e. realloc
+  void addNull();
+    // add a null ('\0') to the end; there must be sufficient allocated space
+
+  void changeDataLen(int changeAmount)
+    { setDataLen(getDataLen() + changeAmount); }
+
+  void ensureAtLeast(int minAllocated);
+    // if 'allocated' is currently less than minAllocated, then
+    // set 'allocated' to minAllocated (preserving existing contents)
+
+  void growDataLen(int changeAmount);
+    // grows allocated data if necessary, whereas changeDataLen will throw
+    // an exception if there isn't already enough allocated space
+
+  void setFromString(char const *srcString);
+  void setFromBlock(byte const *srcData, int dataLen);
+  void setFromBlock(char const *srcData, int dataLen)
+    { setFromBlock((byte const*)srcData, dataLen); }
+
+  DataBlock& operator= (DataBlock const &obj);
+    // causes data AND allocation length equality
+
+  // convenient file read/write
+  void writeToFile(char const *fname) const;
+  void readFromFile(char const *fname);
+
+  // for debugging
+  enum { DEFAULT_PRINT_BYTES = 16 };
+  void print(char const *label = NULL,
+             int bytesPerLine = DEFAULT_PRINT_BYTES) const;
+    // write a simple representation to stdout
+    // if label is not NULL, the data is surrounded by '---'-style delimiters
+
+  void dontPrint(char const *label = NULL,
+                 int bytesPerLine = DEFAULT_PRINT_BYTES) const;
+    // does nothing; useful for two reasons:
+    //   1. lets me define macros that expand to 'print' during debug
+    //      and dontPrint during non-debug
+    //   2. plays a vital role in a g++ bug workaround (g++ sucks!!)
+
+  // utility, defined here for no good reason
+  static void printHexLine(byte const *data, int length, int lineLength);
+    // print 'length' bytes of 'data' in hex
+    // blank-pad the output as if 'linelen' bytes were present
+
+  static void printPrintableLine(byte const *data, int length,
+                                 char unprintable = '.');
+    // print 'length' bytes of 'data', substituting 'unprintable' for bytes for
+    // which 'isprint' is false
+};
+
+#endif // __DATABLOK_H
+

Added: vendor/elsa/current/smbase/depend.pl
===================================================================
--- vendor/elsa/current/smbase/depend.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/depend.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -w
+# depend.pl
+# given some compiler command-line args (including source file),
+# output a Makefile line of dependencies for compiling that source file
+
+# see
+#   http://www.tip.net.au/~millerp/rmch/recu-make-cons-harm.html
+#   http://www.cs.berkeley.edu/~smcpeak/autodepend/autodepend.html
+
+if (@ARGV == 0) {
+  print(<<"EOF");
+usage: $0 -o file.o <gcc compilation arguments>
+
+This script uses 'gcc -MM' to produce compilation dependency
+Makefile rules, modifies them a little, and emits them to
+stdandard output.
+
+Use the '-o' option to tell this script to which target the rules
+should add dependencies; it's not the name of this script's
+own output file.
+EOF
+  exit(0);
+}
+
+
+# Get the output file name, by checking the first option.  If I
+# don't find it there, then I won't make any changes to the gcc
+# output.  If I *do* find the output file, I have to remove it from
+# the argument list because otherwise gcc interprets it as the
+# destination of the dependency output.
+$outputName = '';
+if ($ARGV[0] eq '-o') {
+  # syntax where the name is in the next argument
+  $outputName = $ARGV[1];
+  shift @ARGV;
+  shift @ARGV;
+}
+elsif (substr($ARGV[0], 0, 2) eq '-o') {
+  # syntax where the name follows, in the same argument
+  $outputName = substr($ARGV[0], 2);
+  shift @ARGV;
+}
+
+
+# remove -Wall and add -w so that we don't see warnings when
+# preprocessing to find dependencies
+ at ARGV = grep(!/^-Wall$/, @ARGV);    # remove -Wall
+push @ARGV, "-w";                   # add -w
+
+# icc hack: remove -wd too
+ at ARGV = grep(!/^-wd/, @ARGV);       # remove -wdXXX
+
+
+# invoke gcc's preprocessor to discover dependencies:
+#   -MM   output Makefile rule, ignoring "#include <...>" lines
+#         (so as to avoid dependencies on system headers)
+$args = join(' ', @ARGV);
+#print STDERR ("running: gcc -MM $args\n");
+ at deps = `gcc -MM $args`;     # unfortunately this does shell interpretation again..
+if ($? != 0) {
+  # gcc failed, exit similarly
+  if ($? >> 8) {
+    exit($? >> 8);   # regular exit code
+  }
+  else {
+    exit(&? & 127);  # signal
+  }
+}
+
+
+# if we know the gcc output file name, insert that in the
+# right place 
+if ($outputName) {
+  $deps[0] =~ s|.*:|$outputName:|;
+}
+
+
+# Now, for each file on which the target depends, we make a
+# command-less, prerequiste-less rule with that file as the target.
+# 'make' interprets this to mean that if the file is missing and
+# cannot be remade, to regard it as changed but otherwise not an error
+# condition.
+#
+# This is useful because if a .h file is deleted, and the .cc file
+# changed to not refer to it, the .d file will still name the old file
+# so if we didn't do this trick then 'make' would complain.
+ at extraRules = ();
+for my $line (@deps) {
+  @words = split(' ', $line);
+  for my $word (@words) {
+    if (!$word) {
+      # it's an empty word because there was an extra space
+      # somewhere; ignore it
+    }
+    elsif (substr($word, -1) eq ':') {
+      # this is the target of the overall dependency list; don't
+      # make a special rule for it
+    }
+    elsif ($word eq '\\') {
+      # this is the continuation backslash that 'gcc -M' inserted
+      # to try to make the lines fit into 80 columns
+    }
+    else {
+      # make a special rule
+      push @extraRules, "$word:\n";
+    }
+  }
+}
+
+
+print(@deps);
+print(@extraRules);
+exit(0);
+


Property changes on: vendor/elsa/current/smbase/depend.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/depend.sh
===================================================================
--- vendor/elsa/current/smbase/depend.sh	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/depend.sh	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,20 @@
+#!/bin/sh
+# given some compiler command-line args (including source file),
+# output a Makefile line of dependencies for compiling that source file
+
+echo "do not use me" >&2
+exit 2
+
+# stolen from http://www.tip.net.au/~millerp/rmch/recu-make-cons-harm.html
+
+# invoke gcc's preprocessor to discover dependencies:
+#   -MM   output Makefile rule, ignoring "#include <...>" lines
+#         (so as to avoid dependencies on system headers)
+# then invoke sed:
+#   - remove any occurrences of system headers if they sneak in
+gcc -MM "$@" |
+  sed -e 's@ /[^ ]*@@g'
+
+# obsolete:
+#   - make the .d file itself depend on the same things the .o does
+#  -e 's@^\(.*\)\.o:@\1.d \1.o:@'


Property changes on: vendor/elsa/current/smbase/depend.sh
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/do_strhash_test
===================================================================
--- vendor/elsa/current/smbase/do_strhash_test	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/do_strhash_test	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,41 @@
+#!/usr/bin/bash
+# do_strhash_test     see license.txt for copyright and terms of use
+
+# dsw: compare two different implementations of smbase/strhash
+
+# FIX: it would be nice to tee the output to a file and have a perl
+# script compute the time ratio for us automatically
+
+SMBASE=.
+
+set -x
+
+# using the longest .cc file in smbase
+TEST_FILE=srcloc.cc
+if ! test -f $TEST_FILE; then
+    echo "Test file does not exist: " $TEST_FILE
+    exit 1;
+fi
+
+function buildit() {
+    STRHASH_ALG=$1
+    echo "Building hashing algorithm $STRHASH_ALG"
+    # I'm pretty sure I have to rebuild the whole of smbase to make
+    # sure that, say, profiling is off
+    ./configure.pl -nodebug -DSTRHASH_ALG=$STRHASH_ALG -DSAY_STRHASH_ALG
+    make -C $SMBASE clean all strhash
+    rm -f strhash_$STRHASH_ALG
+    mv $SMBASE/strhash strhash_$STRHASH_ALG
+}
+
+function testit() {
+    STRHASH_ALG=$1
+    echo "Testing hashing algorithm $STRHASH_ALG"
+    ./strhash_$STRHASH_ALG --no-testCor --numPerfRuns 30000 --file $TEST_FILE
+}
+
+buildit 1
+buildit 2
+
+testit 1
+testit 2


Property changes on: vendor/elsa/current/smbase/do_strhash_test
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/exc.cpp
===================================================================
--- vendor/elsa/current/smbase/exc.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/exc.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,302 @@
+// exc.cc            see license.txt for copyright and terms of use
+// code for exc.h
+// Scott McPeak, 1996-1998  This file is public domain.
+
+#include "exc.h"          // this module
+
+#include <string.h>       // strlen, strcpy
+#include <iostream.h>     // clog
+#include <stdarg.h>       // va_xxx
+#include <ctype.h>        // toupper, tolower
+
+
+// ------------------------- xBase -----------------
+bool xBase::logExceptions = true;
+int xBase::creationCount = 0;
+
+
+xBase::xBase(rostring m)
+  : msg(m)
+{
+  if (logExceptions) {
+    clog << "Exception thrown: " << m << endl;
+  }
+
+  // done at very end when we know this object will
+  // successfully be created
+  creationCount++;
+}
+
+
+xBase::xBase(xBase const &obj)
+  : msg(obj.msg)
+{
+  creationCount++;
+}
+
+
+xBase::~xBase()
+{
+  creationCount--;
+}
+
+
+// this is obviously not perfect, since exception objects can be
+// created and not thrown; I heard the C++ standard is going to,
+// or already does, include (by this name?) a function that does this
+// correctly; until then, this will serve as a close approximation
+// (this kind of test is, IMO, not a good way to handle the underlying
+// problem, but it does reasonably handle 70-90% of the cases that
+// arise in practice, so I will endorse it for now)
+bool unwinding()
+{
+  return xBase::creationCount != 0;
+}
+
+
+// tweaked version
+bool unwinding_other(xBase const &)
+{
+  // we know the passed xBase exists.. any others?
+  return xBase::creationCount > 1;
+}
+
+
+void xBase::insert(ostream &os) const
+{
+  os << why();
+}
+
+
+void xbase(rostring msg)
+{
+  xBase x(msg);
+  THROW(x);
+}
+
+
+void xBase::addContext(rostring context)
+{
+  // for now, fairly simple
+  msg = stringc << "while " << context << ",\n" << msg;
+}
+
+
+void xBase::addContextLeft(rostring context)
+{
+  msg = stringc << context << msg;
+}
+
+
+// ------------------- x_assert -----------------
+x_assert::x_assert(rostring cond, rostring fname, int line)
+  : xBase(stringb(
+      "Assertion failed: " << cond <<
+      ", file " << fname <<
+      " line " << line)),
+    condition(cond),
+    filename(fname),
+    lineno(line)
+{}
+
+x_assert::x_assert(x_assert const &obj)
+  : xBase(obj),
+    condition(obj.condition),
+    filename(obj.filename),
+    lineno(obj.lineno)
+{}
+
+x_assert::~x_assert()
+{}
+
+
+// failure function, declared in xassert.h
+void x_assert_fail(char const *cond, char const *file, int line)
+{
+  THROW(x_assert(cond, file, line));
+}
+
+
+// --------------- xFormat ------------------
+xFormat::xFormat(rostring cond)
+  : xBase(stringb("Formatting error: " << cond)),
+    condition(cond)
+{}
+
+xFormat::xFormat(xFormat const &obj)
+  : xBase(obj),
+    condition(obj.condition)
+{}
+
+xFormat::~xFormat()
+{}
+
+
+void xformat(rostring condition)
+{
+  xFormat x(condition);
+  THROW(x);
+}
+
+void formatAssert_fail(char const *cond, char const *file, int line)
+{
+  xFormat x(stringc << "format assertion failed, "
+                    << file << ":" << line << ": "
+                    << cond);
+  THROW(x);
+}
+
+
+// -------------------- XOpen -------------------
+XOpen::XOpen(rostring fname)
+  : xBase(stringc << "failed to open file: " << fname),
+    filename(fname)
+{}
+
+XOpen::XOpen(XOpen const &obj)
+  : xBase(obj),
+    DMEMB(filename)
+{}
+
+XOpen::~XOpen()
+{}
+
+
+void throw_XOpen(rostring fname)
+{
+  XOpen x(fname);
+  THROW(x);
+}
+
+
+// -------------------- XOpenEx ---------------------
+XOpenEx::XOpenEx(rostring fname, rostring m, rostring c)
+  : XOpen(fname),
+    mode(m),
+    cause(c)
+{
+  msg = stringc << "failed to open file \"" << fname
+                << "\" for " << interpretMode(mode)
+                << ": " << cause;
+}
+
+XOpenEx::XOpenEx(XOpenEx const &obj)
+  : XOpen(obj),
+    DMEMB(mode),
+    DMEMB(cause)
+{}
+
+XOpenEx::~XOpenEx()
+{}
+
+
+STATICDEF string XOpenEx::interpretMode(rostring mode)
+{
+  if (mode[0]=='r') {
+    if (mode[1]=='+') {
+      return "reading and writing";
+    }
+    else {
+      return "reading";
+    }
+  }
+
+  if (mode[0]=='w') {
+    if (mode[1]=='+') {
+      return "reading and writing";
+    }
+    else {
+      return "writing";
+    }
+  }
+
+  if (mode[0]=='a') {
+    if (mode[1]=='+') {
+      return "reading and appending";
+    }
+    else {
+      return "appending";
+    }
+  }
+
+  return stringc << "(unknown action mode \"" << mode << "\")";
+}
+
+
+void throw_XOpenEx(rostring fname, rostring mode, rostring cause)
+{
+  XOpenEx x(fname, mode, cause);
+  THROW(x);
+}
+
+
+// -------------------- XUnimp -------------------
+XUnimp::XUnimp(rostring msg)
+  : xBase(stringc << "unimplemented: " << msg)
+{}
+
+XUnimp::XUnimp(XUnimp const &obj)
+  : xBase(obj)
+{}
+
+XUnimp::~XUnimp()
+{}
+
+
+void throw_XUnimp(rostring msg)
+{
+  XUnimp x(msg);
+  THROW(x);
+}
+
+
+void throw_XUnimp(char const *msg, char const *file, int line)
+{
+  throw_XUnimp(stringc << file << ":" << line << ": " << msg);
+}
+
+
+// -------------------- XFatal -------------------
+// That this error is "fatal" need not be stated in the error message
+// itself.  Doing so would unnecessarily alarm novice users, and the
+// fatal-ness is sufficiently expressed by the fact that an exception
+// is thrown, as opposed to simply printing the message and continuing.
+XFatal::XFatal(rostring msg)
+  : xBase(stringc << "error: " << msg)
+{}
+
+XFatal::XFatal(XFatal const &obj)
+  : xBase(obj)
+{}
+
+XFatal::~XFatal()
+{}
+
+
+void throw_XFatal(rostring msg)
+{
+  XFatal x(msg);
+  THROW(x);
+}
+
+
+// ---------------- test code ------------------
+#ifdef TEST_EXC
+
+int main()
+{
+  xBase x("yadda");
+  cout << x << endl;
+
+  try {
+    THROW(x);
+  }
+  catch (xBase &x) {
+    cout << "caught xBase: " << x << endl;
+  }
+
+  return 0;
+}
+
+#endif // TEST_EXC
+

Added: vendor/elsa/current/smbase/exc.h
===================================================================
--- vendor/elsa/current/smbase/exc.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/exc.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,211 @@
+// exc.h            see license.txt for copyright and terms of use
+// exception classes for SafeTP project
+// Scott McPeak, 1996-1998  This file is public domain.
+
+// I apologize for the inconsistent naming in this module.  It is
+// the product of an extended period of experimenting with naming
+// conventions for exception-related concepts.  The names near the
+// end of the file reflect my current preferences.
+
+#ifndef EXC_H
+#define EXC_H
+
+#include "breaker.h"     // breaker
+#include "typ.h"         // bool
+#include "xassert.h"     // xassert, for convenience for #includers
+#include "str.h"         // string
+#include <iostream.h>    // ostream
+
+// by using this macro, the debugger gets a shot before the stack is unwound
+#ifdef THROW
+#undef THROW
+#endif
+#define THROW(obj) \
+  { breaker(); throw (obj); }
+
+
+// My intention is to put a call to this macro at the beginning of
+// every catch block.  Its (default) definition is to call breaker so
+// that in the debugger I can easily get to the point where an
+// exception is caught.
+#define HANDLER() breaker() /* user ; */
+
+
+// this function returns true if we're in the process of unwinding the
+// stack, and therefore destructors may want to avoid throwing new exceptions;
+// for now, may return false positives, but won't return false negatives
+bool unwinding();
+
+// inside a catch expression, the unwinding() function needs a tweak; pass
+// the caught expression, and this returns whether there any *additional*
+// exceptions currently in flight
+class xBase;
+bool unwinding_other(xBase const &x);
+
+// using unwinding() in destructors to avoid abort()
+#define CAUTIOUS_RELAY           \
+  catch (xBase &x) {             \
+    if (!unwinding_other(x)) {   \
+      throw;   /* re-throw */    \
+    }                            \
+  }
+
+
+// -------------------- xBase ------------------
+// intent is to derive all exception objects from this
+class xBase {
+protected:
+  // the human-readable description of the exception
+  string msg;
+
+public:
+  // initially true; when true, we write a record of the thrown exception
+  // to clog
+  static bool logExceptions;
+
+  // current # of xBases running about; used to support unrolling()
+  static int creationCount;
+
+public:
+  xBase(rostring m);       // create exception object with message 'm'
+  xBase(xBase const &m);   // copy ctor
+  virtual ~xBase();
+
+  rostring why() const
+    { return msg; }
+
+  // print why
+  void insert(ostream &os) const;
+  friend ostream& operator << (ostream &os, xBase const &obj)
+    { obj.insert(os); return os; }
+
+  // add a string describing what was going on at the time the
+  // exception was thrown; this should be called with the innermost
+  // context string first, i.e., in the normal unwind order
+  void addContext(rostring context);
+  // dsw: sometimes I want the context to be, say a "file:line" number
+  // on the left
+  void addContextLeft(rostring context);
+};
+
+// equivalent to THROW(xBase(msg))
+void xbase(rostring msg) NORETURN;
+
+
+// -------------------- x_assert -----------------------
+// thrown by _xassert_fail, declared in xassert.h
+// throwing this corresponds to detecting a bug in the program
+class x_assert : public xBase {
+  string condition;          // text of the failed condition
+  string filename;           // name of the source file
+  int lineno;                // line number
+
+public:
+  x_assert(rostring cond, rostring fname, int line);
+  x_assert(x_assert const &obj);
+  ~x_assert();
+
+  rostring cond() const { return condition; }
+  rostring fname() const { return filename; }
+  int line() const { return lineno; }
+};
+
+
+// ---------------------- xFormat -------------------
+// throwing this means a formatting error has been detected
+// in some input data; the program cannot process it, but it
+// is not a bug in the program
+class xFormat : public xBase {
+  string condition;          // what is wrong with the input
+
+public:
+  xFormat(rostring cond);
+  xFormat(xFormat const &obj);
+  ~xFormat();
+
+  rostring cond() const { return condition; }
+};
+
+// compact way to throw an xFormat
+void xformat(rostring condition) NORETURN;
+
+// convenient combination of condition and human-readable message
+#define checkFormat(cond, message) \
+  ((cond)? (void)0 : xformat(message))
+
+// assert-like interface to xFormat
+void formatAssert_fail(char const *cond, char const *file, int line) NORETURN;
+
+#define formatAssert(cond) \
+  ((cond)? (void)0 : formatAssert_fail(#cond, __FILE__, __LINE__))
+
+
+// -------------------- XOpen ---------------------
+// thrown when we fail to open a file
+class XOpen : public xBase {
+public:
+  string filename;
+
+public:
+  XOpen(rostring fname);
+  XOpen(XOpen const &obj);
+  ~XOpen();
+};
+
+void throw_XOpen(rostring fname) NORETURN;
+
+
+// -------------------- XOpenEx ---------------------
+// more informative
+class XOpenEx : public XOpen {
+public:
+  string mode;         // fopen-style mode string, e.g. "r"
+  string cause;        // errno-derived failure cause, e.g. "no such file"
+
+public:
+  XOpenEx(rostring fname, rostring mode, rostring cause);
+  XOpenEx(XOpenEx const &obj);
+  ~XOpenEx();
+
+  // convert a mode string as into human-readable participle,
+  // e.g. "r" becomes "reading"
+  static string interpretMode(rostring mode);
+};
+
+void throw_XOpenEx(rostring fname, rostring mode, rostring cause) NORETURN;
+
+
+// ------------------- XUnimp ---------------------
+// thrown in response to a condition that is in principle
+// allowed but not yet handled by the existing code
+class XUnimp : public xBase {
+public:
+  XUnimp(rostring msg);
+  XUnimp(XUnimp const &obj);
+  ~XUnimp();
+};
+
+void throw_XUnimp(rostring msg) NORETURN;
+
+// throw XUnimp with file/line info
+void throw_XUnimp(char const *msg, char const *file, int line) NORETURN;
+
+#define xunimp(msg) throw_XUnimp(msg, __FILE__, __LINE__)
+
+
+// ------------------- XFatal ---------------------
+// thrown in response to a user action that leads to an unrecoverable
+// error; it is not due to a bug in the program
+class XFatal : public xBase {
+public:
+  XFatal(rostring msg);
+  XFatal(XFatal const &obj);
+  ~XFatal();
+};
+
+void throw_XFatal(rostring msg) NORETURN;
+#define xfatal(msg) throw_XFatal(stringc << msg)
+
+
+#endif // EXC_H
+

Added: vendor/elsa/current/smbase/flatten.cc
===================================================================
--- vendor/elsa/current/smbase/flatten.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/flatten.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,104 @@
+// flatten.cc            see license.txt for copyright and terms of use
+// code for flatten.h
+
+// basically, this file provides some reasonable defaults
+// assuming we are reading/writing binary files
+
+#include "flatten.h"     // this module
+#include "exc.h"         // formatAssert
+#include <string.h>      // strlen
+
+Flatten::Flatten()
+  : version(0)
+{}
+
+Flatten::~Flatten()
+{}
+
+
+void Flatten::xferChar(char &c)
+{
+  xferSimple(&c, sizeof(c));
+}
+
+void Flatten::xferInt(int &i)
+{
+  xferSimple(&i, sizeof(i));
+}
+
+void Flatten::xferLong(long &l)
+{
+  xferSimple(&l, sizeof(l));
+}
+
+void Flatten::xferBool(bool &b)
+{
+  xferSimple(&b, sizeof(b));
+}
+
+
+void Flatten::xferHeapBuffer(void *&buf, int len)
+{
+  if (reading()) {
+    buf = new unsigned char[len];
+  }
+  xassert(len >= 0);
+  xferSimple(buf, len);
+}
+
+
+void Flatten::xferCharString(char *&str)
+{
+  if (writing()) {
+    if (!str) {
+      writeInt(-1);     // representation of NULL
+      return;
+    }
+
+    int len = strlen(str);
+    writeInt(len);
+
+    // write the null terminator too, as a simple
+    // sanity check when reading
+    xferSimple(str, len+1);
+  }
+  else {
+    int len = readInt();
+    if (len == -1) {
+      str = NULL;
+      return;
+    }
+
+    str = new char[len+1];
+    xferSimple(str, len+1);
+    formatAssert(str[len] == '\0');
+  }
+}
+
+
+void Flatten::checkpoint(int code)
+{
+  if (writing()) {
+    writeInt(code);
+  }
+  else {
+    int c = readInt();
+    formatAssert(c == code);
+  }
+}
+
+
+void Flatten::writeInt(int i)
+{
+  xassert(writing());
+  xferInt(i);
+}
+
+int Flatten::readInt()
+{
+  xassert(reading());
+  int i;
+  xferInt(i);
+  return i;
+}
+

Added: vendor/elsa/current/smbase/flatten.h
===================================================================
--- vendor/elsa/current/smbase/flatten.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/flatten.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,76 @@
+// flatten.h            see license.txt for copyright and terms of use
+// interface to automate process of flattening structures made of objects with
+//   arbitrary types, and possibly circular references
+// this is a trimmed-down version of the one in 'proot'
+
+// Has a number of similarities with boost::serialize,
+//   http://www.boost.org/libs/serialization/doc/index.html
+// The main difference is I don't want to use templates.  Also,
+// I don't care about STL.
+
+#ifndef FLATTEN_H
+#define FLATTEN_H
+
+#include "trdelete.h"   // TRASHINGDELETE
+
+class Flatten {
+public:      // data
+  // version of the file being xferred; app must set it if it
+  // wants to use it
+  int version;
+
+public:      // funcs
+  Flatten();
+  virtual ~Flatten();
+
+  TRASHINGDELETE;
+
+  // query the read/write state
+  virtual bool reading() const = 0;
+  bool writing() const { return !reading(); }
+
+  // transferring xfer a simple data type of fixed length
+  // 'len', in bytes
+  virtual void xferSimple(void *var, unsigned len)=0;
+
+  // syntactic sugar
+  //#define xferVar(varname) xferSimple(&varname, sizeof(varname))
+  //#define XFERV(varname) flat.xferVar(varname)
+
+  // xfer various C built-in data types (will add them as I need them)
+  virtual void xferChar(char &c);
+  virtual void xferInt(int &i);
+  virtual void xferLong(long &l);
+  virtual void xferBool(bool &b);
+
+  // read or write a null-terminated character buffer, allocated with
+  // new; this works if 'str' is NULL (in other words, a NULL string
+  // is distinguished from an empty string, and both are legal)
+  virtual void xferCharString(char *&str);
+
+  // xfer a buffer allocated with 'new', of a given length; the buffer
+  // may not be NULL (when writing), and len must be nonnegative
+  virtual void xferHeapBuffer(void *&buf, int len);
+
+  // read: write the code; write: read & compare to code, fail if != ;
+  // the code is arbitrary, but should be unique across the source tree
+  // (I usually make the code with my Emacs' Ctl-Alt-R, which inserts a random number)
+  virtual void checkpoint(int code);
+
+  // ------------- utilities ---------
+  // for when we already know whether we're reading or writing; internally,
+  // these assert which state we're in
+  void writeInt(int i);
+  int readInt();
+   
+  // ------------- owner/serf ------------
+  // take note of an owner pointer where we expect to xfer serfs to it
+  virtual void noteOwner(void *ownerPtr) = 0;
+
+  // xfer a serf pointer that we've previously taken note of
+  virtual void xferSerf(void *&serfPtr, bool nullable=false) = 0;
+  void writeSerf(void *serfPtr);
+  void *readSerf();
+};
+
+#endif // FLATTEN_H

Added: vendor/elsa/current/smbase/flatutil.h
===================================================================
--- vendor/elsa/current/smbase/flatutil.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/flatutil.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,87 @@
+// flatutil.h
+// additional utilities layered upon 'flatten' interface
+
+#ifndef FLATUTIL_H
+#define FLATUTIL_H
+
+#include "flatten.h"         // underlying module
+#include "objlist.h"         // ObjList
+#include "xassert.h"         // xassert
+
+
+// Nominal way to create a 'T' object for unflattening; but you
+// can overload to do things differently where needed.
+template <class T>
+T *createForUnflat(Flatten &flat)
+{
+  return new T(flat);
+}
+
+// Nominal way to flatten.  Again, overload to override.
+template <class T>
+void xfer(Flatten &flat, T &t)
+{
+  t.xfer(flat);
+}
+
+
+// Transfer an owner list.  First we transfer the number of elements,
+// then each element in sequence.  If 'noteOwner' is true, the
+// pointers are noted so that it is possible to later transfer serf
+// aliases.
+template <class T>
+void xferObjList(Flatten &flat, ObjList<T> &list, bool noteOwner = false)
+{
+  if (flat.writing()) {
+    flat.writeInt(list.count());
+    FOREACH_OBJLIST_NC(T, list, iter) {
+      T *t = iter.data();
+      xfer(flat, *t);
+      if (noteOwner) {
+        flat.noteOwner(t);
+      }
+    }
+  }
+  else {
+    list.deleteAll();
+    int ct = flat.readInt();
+    while (ct--) {
+      T *t = createForUnflat<T>(flat);
+      xfer(flat, *t);
+      if (noteOwner) {
+        flat.noteOwner(t);
+      }
+      list.prepend(t);
+    }
+    list.reverse();
+  }
+}
+
+
+// Cast from one scalar to another, asserting representability of
+// the value in the target type.
+template <class DEST, class SRC>
+inline DEST value_cast(SRC s)
+{
+  DEST d = (DEST)s;      // convert to DEST
+  xassert((SRC)d == s);  // convert back, assert equal
+  return d;
+}
+
+
+// Transfer an enum value.  This is safer than just casting to int
+// reference, since it works when 'int' is not the same size as the
+// enum.
+template <class E>
+void xferEnum(Flatten &flat, E &e)
+{
+  if (flat.writing()) {
+    flat.writeInt(value_cast<int>(e));
+  }
+  else {
+    e = value_cast<E>(flat.readInt());
+  }
+}
+
+
+#endif // FLATUTIL_H

Added: vendor/elsa/current/smbase/gprintf.c
===================================================================
--- vendor/elsa/current/smbase/gprintf.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/gprintf.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,407 @@
+/* gprintf.c */
+/* originally from: http://www.efgh.com/software/gprintf.htm */
+/* this file is in the public domain */
+
+/* modified by Scott McPeak, April 2003:
+ *   - use va_list instead of 'const int*' for the 
+ *     pointer-to-argument type (for portability)
+ *   - implement conservative estimates for unknown format
+ *     chars, particularly 'f' (CONSERVATIVE_ESTIMATE flag)
+ *   - add a few test vectors
+ */
+
+/* NOTE: There are quite a few differences among the *printf
+ * implementations running around in the various libcs.  The
+ * implementation in this module doesn't know about all of those
+ * variations and extensions.  So, if you're using this to estimate
+ * the # of chars your libc's printf will use, be sure to compare
+ * libc's printf's actual return value, to make sure something doesn't
+ * slip through the cracks. */
+
+/* Code for general_printf() */
+/* Change extension to .c before compiling */
+
+#include "gprintf.h"     /* this module */
+#include <assert.h>      /* assert */
+
+/* when this is true, unknown fields are filled with Xs, in an attempt
+ * to print at least as many characters as libc's sprintf */
+#define CONSERVATIVE_ESTIMATE 1
+
+#define BITS_PER_BYTE           8
+
+struct parameters
+{
+  int number_of_output_chars;
+  short minimum_field_width;
+  char options;
+    #define MINUS_SIGN    1
+    #define RIGHT_JUSTIFY 2
+    #define ZERO_PAD      4
+    #define CAPITAL_HEX   8
+  short edited_string_length;
+  short leading_zeros;
+  int (*output_function)(void *, int);
+  void *output_pointer;
+};
+
+static void output_and_count(struct parameters *p, int c)
+{
+  if (p->number_of_output_chars >= 0)
+  {
+    int n = (*p->output_function)(p->output_pointer, c);
+    if (n>=0) p->number_of_output_chars++;
+    else p->number_of_output_chars = n;
+  }
+}
+
+static void output_field(struct parameters *p, char const *s)
+{
+  short justification_length =
+    p->minimum_field_width - p->leading_zeros - p->edited_string_length;
+  if (p->options & MINUS_SIGN)
+  {
+    if (p->options & ZERO_PAD)
+      output_and_count(p, '-');
+    justification_length--;
+  }
+  if (p->options & RIGHT_JUSTIFY)
+    while (--justification_length >= 0)
+      output_and_count(p, p->options & ZERO_PAD ? '0' : ' ');
+  if (p->options & MINUS_SIGN && !(p->options & ZERO_PAD))
+    output_and_count(p, '-');
+  while (--p->leading_zeros >= 0)
+    output_and_count(p, '0');
+  while (--p->edited_string_length >= 0)
+    output_and_count(p, *s++);
+  while (--justification_length >= 0)
+    output_and_count(p, ' ');
+}
+
+
+int general_vprintf(Gprintf_output_function output_function, 
+                    void *output_pointer,
+                    const char *control_string, 
+                    va_list argument_pointer)
+{
+  struct parameters p;
+  char control_char;
+  p.number_of_output_chars = 0;
+  p.output_function = output_function;
+  p.output_pointer = output_pointer;
+  control_char = *control_string++;
+  while (control_char != '\0')
+  {
+    if (control_char == '%')
+    {
+      short precision = -1;
+      short long_argument = 0;
+      short base = 0;
+      control_char = *control_string++;
+      p.minimum_field_width = 0;
+      p.leading_zeros = 0;
+      p.options = RIGHT_JUSTIFY;
+      if (control_char == '-')
+      {
+        p.options = 0;
+        control_char = *control_string++;
+      }
+      if (control_char == '0')
+      {
+        p.options |= ZERO_PAD;
+        control_char = *control_string++;
+      }
+      if (control_char == '*')
+      {
+        p.minimum_field_width = va_arg(argument_pointer, int);
+        control_char = *control_string++;
+      }
+      else
+      {
+        while ('0' <= control_char && control_char <= '9')
+        {
+          p.minimum_field_width =
+            p.minimum_field_width * 10 + control_char - '0';
+          control_char = *control_string++;
+        }
+      }
+      if (control_char == '.')
+      {
+        control_char = *control_string++;
+        if (control_char == '*')
+        {
+          precision = va_arg(argument_pointer, int);
+          control_char = *control_string++;
+        }
+        else
+        {
+          precision = 0;
+          while ('0' <= control_char && control_char <= '9')
+          {
+            precision = precision * 10 + control_char - '0';
+            control_char = *control_string++;
+          }
+        }
+      }
+      if (control_char == 'l')
+      {
+        long_argument = 1;
+        control_char = *control_string++;
+      }
+      if (control_char == 'd')
+        base = 10;
+      else if (control_char == 'x')
+        base = 16;
+      else if (control_char == 'X')
+      {
+        base = 16;
+        p.options |= CAPITAL_HEX;
+      }
+      else if (control_char == 'u')
+        base = 10;
+      else if (control_char == 'o')
+        base = 8;
+      else if (control_char == 'b')
+        base = 2;
+      else if (control_char == 'c')
+      {
+        base = -1;
+        p.options &= ~ZERO_PAD;
+      }
+      else if (control_char == 's')
+      {
+        base = -2;
+        p.options &= ~ZERO_PAD;
+      }
+      if (base == 0)  /* invalid conversion type */
+      {
+        if (control_char != '\0')
+        {
+          #if !CONSERVATIVE_ESTIMATE
+            /* sm: this was the original code; it just prints the
+             * format character itself */
+            output_and_count(&p, control_char);
+
+          #else
+            /* since my goal is actually to compute a conservative
+             * upper bound on the # of chars output by sprintf, I want
+             * to fill unknown fields with Xs */
+            static char const * const XXX =
+              "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";  /* 50 Xs */
+            assert(precision <= 30);     /* otherwise I need more Xs */
+
+            /* I'm assuming that printing floating-point is the worst case.
+             * I further assume non-fractional parts (integer part,
+             * exponent, decimal, sign) won't exceed 20 chars.  Finally,
+             * up to 30 characters of decimal part are supported (this
+             * is checked with the assertion above). */
+            if (precision == -1) {
+              p.edited_string_length = 20 + 6;    /* 6 is default precision for 'f' */
+            }
+            else {
+              p.edited_string_length = 20 + precision;
+            }
+            output_field(&p, XXX);
+          #endif
+
+          control_char = *control_string++;
+        }
+      }
+      else
+      {
+        if (base == -1)  /* conversion type c */
+        {                
+          /* 'char' is passed as 'int' through '...' */
+          char c = (char)va_arg(argument_pointer, int);
+          p.edited_string_length = 1;
+          output_field(&p, &c);
+        }
+        else if (base == -2)  /* conversion type s */
+        {
+          char *string;
+          p.edited_string_length = 0;
+          string = va_arg(argument_pointer, char*);
+          while (string[p.edited_string_length] != 0)
+            p.edited_string_length++;
+          if (precision >= 0 && p.edited_string_length > precision)
+            p.edited_string_length = precision;
+          output_field(&p, string);
+        }
+        else  /* conversion type d, b, o or x */
+        {
+          unsigned long x;
+          char buffer[BITS_PER_BYTE * sizeof(unsigned long) + 1];
+          p.edited_string_length = 0;
+          if (long_argument) 
+          {
+            x = va_arg(argument_pointer, unsigned long);
+          }
+          else if (control_char == 'd')
+            x = va_arg(argument_pointer, long);
+          else
+            x = va_arg(argument_pointer, unsigned);
+          if (control_char == 'd' && (long) x < 0)
+          {
+            p.options |= MINUS_SIGN;
+            x = - (long) x;
+          }
+          do 
+          {
+            int c;
+            c = x % base + '0';
+            if (c > '9')
+            {
+              if (p.options & CAPITAL_HEX)
+                c += 'A'-'9'-1;
+              else
+                c += 'a'-'9'-1;
+            }
+            buffer[sizeof(buffer) - 1 - p.edited_string_length++] = c;
+          }
+          while ((x/=base) != 0);
+          if (precision >= 0 && precision > p.edited_string_length)
+            p.leading_zeros = precision - p.edited_string_length;
+          output_field(&p, buffer + sizeof(buffer) - p.edited_string_length);
+        }
+        control_char = *control_string++;
+      }
+    }
+    else
+    {
+      output_and_count(&p, control_char);
+      control_char = *control_string++;
+    }
+  }
+  return p.number_of_output_chars;
+}
+
+
+int general_printf(Gprintf_output_function output,
+                   void *extra, const char *format, ...)
+{
+  va_list args;
+  int ret;
+
+  va_start(args, format);
+  ret = general_vprintf(output, extra, format, args);
+  va_end(args);
+  
+  return ret;
+}
+
+
+/* ------------------ test code --------------------- */
+#ifdef TEST_GPRINTF
+
+#include <stdio.h>     /* fputc, printf, vsprintf */
+#include <string.h>    /* strcmp, strlen */
+#include <stdlib.h>    /* exit */
+
+
+int string_output(void *extra, int ch)
+{                          
+  /* the 'extra' argument is a pointer to a pointer to the
+   * next character to write */
+  char **s = (char**)extra;
+
+  **s = ch;     /* write */
+  (*s)++;       /* advance */
+
+  return 0;
+}
+
+int general_vsprintf(char *dest, char const *format, va_list args)
+{
+  char *s = dest;
+  int ret;
+
+  ret = general_vprintf(string_output, &s, format, args);
+  *s = 0;
+
+  return ret;
+}
+
+
+char output1[1024];    /* for libc */
+char output2[1024];    /* for this module */
+
+
+void expect_vector_len(int expect_len, char const *expect_output,
+                       char const *format, va_list args)
+{
+  int len;
+  static int vectors = 0;
+
+  /* keep track of how many vectors we've tried, to make it
+   * a little easier to correlate failures with the inputs
+   * in this file */
+  vectors++;
+
+  /* run the generalized vsprintf */
+  len = general_vsprintf(output2, format, args);
+
+  /* compare */
+  if (len!=expect_len ||
+      0!=strcmp(expect_output, output2)) {
+    printf("outputs differ for vector %d!\n", vectors);
+    printf("  format: %s\n", format);
+    printf("  expect: %s (%d)\n", expect_output, expect_len);
+    printf("      me: %s (%d)\n", output2, len);
+    exit(2);
+  }
+}
+
+
+void expect_vector(char const *expect_output,
+                   char const *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  expect_vector_len(strlen(expect_output), expect_output, format, args);
+  va_end(args);
+}
+
+
+void vector(char const *format, ...)
+{
+  va_list args;
+  int len;
+
+  /* run the real vsprintf */
+  va_start(args, format);
+  len = vsprintf(output1, format, args);
+  va_end(args);
+
+  /* test against the generalized vsprintf */
+  va_start(args, format);
+  expect_vector_len(len, output1, format, args);
+  va_end(args);
+}
+
+
+int main()
+{
+  printf("testing gprintf...\n");
+
+  /* test against libc */
+  vector("simple");
+  vector("a %s more", "little");
+  vector("some %4d more %s complicated %c stuff",
+         33, "yikes", 'f');
+                      
+  /* test unknown format chars */
+  expect_vector("XXXXXXXXXXXXXXXXXXXXXXXXXX", "%f", 3.4);
+  expect_vector("XXXXXXXXXXXXXXXXXXXXXXX", "%.3f", 3.4);
+  expect_vector("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "%.10f", 3.4);
+  expect_vector("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "%.30f", 3.4);
+
+  /* fails assertion, as it should */
+  /* expect_vector("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "%.31f", 3.4); */
+
+  /* TODO: add more tests */
+
+  printf("gprintf works\n");
+  return 0;
+}
+
+#endif /* TEST_GPRINTF */

Added: vendor/elsa/current/smbase/gprintf.h
===================================================================
--- vendor/elsa/current/smbase/gprintf.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/gprintf.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+/* gprintf.h
+ * generalized printf interface
+ * http://www.efgh.com/software/gprintf.htm 
+ * this file is in the public domain */
+
+#ifndef GPRINTF_H
+#define GPRINTF_H
+
+#include <stdarg.h>      /* va_list */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This is called once for each output character.  It returns >=0 for
+ * success or <0 for failure, in which case that code will end up as
+ * the return value from general_printf.  'extra' is user-defined
+ * context, and is passed the same value as the 'extra' arg to
+ * general_printf.  'ch' is of course the character to output. */
+typedef int (*Gprintf_output_function)(void *extra, int ch);
+
+/* Interpret 'format' and 'args' as printf does, but calling
+ * 'output' for each rendered character.  Returns the # of characters
+ * output (not including final NUL), or <0 for failure (same code
+ * that 'output' returns if it fails). */
+int general_vprintf(Gprintf_output_function output,
+                    void *extra, const char *format, va_list args);
+
+/* same thing but accepting variable # of args directly */
+int general_printf(Gprintf_output_function output,
+                   void *extra, const char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GPRINTF_H */

Added: vendor/elsa/current/smbase/growbuf.cc
===================================================================
--- vendor/elsa/current/smbase/growbuf.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/growbuf.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,51 @@
+// growbuf.cc            see license.txt for copyright and terms of use
+// code for growbuf.h
+
+#include "growbuf.h"      // this module
+
+#include <string.h>       // memcpy
+
+void GrowBuffer::append(byte const *str, int len)
+{
+  // test length
+  int newLen = getDataLen() + len;
+  if (newLen > getAllocated()) {
+    // must grow
+    int newAlloc = max(getAllocated(), 16);
+    while (newLen > newAlloc) {
+      newAlloc *= 2;      // would like an overflow test here..
+    }
+
+    setAllocated(newAlloc);
+  }
+
+  // do copy
+  memcpy(getData()+getDataLen(), str, len);
+  setDataLen(newLen);
+}
+
+
+// ----------------- test code ----------------
+#ifdef TEST_GROWBUF
+#include "test.h"
+
+void entry()
+{
+  byte const str[] = "crazy like a mad cow!";
+  int len = sizeof(str);
+
+  GrowBuffer buf;
+  loopi(10) {
+    buf.append(str, len);
+  }
+  loopi(10) {
+    if (0!=memcmp(str, buf.getData()+len*i, len)) {
+      xfailure("buffer contents are wrong");
+    }
+  }
+  cout << "growbuf ok\n";
+}
+
+USUAL_MAIN
+
+#endif // TEST_GROWBUF

Added: vendor/elsa/current/smbase/growbuf.h
===================================================================
--- vendor/elsa/current/smbase/growbuf.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/growbuf.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// growbuf.h            see license.txt for copyright and terms of use
+// buffer that grows as needed by doubling in size
+
+#ifndef __GROWBUF_H
+#define __GROWBUF_H
+
+#include "datablok.h"       // DataBlock
+
+class GrowBuffer : public DataBlock {
+public:
+  GrowBuffer(int allocSize=0)
+    : DataBlock(allocSize) {}
+  ~GrowBuffer() {}
+
+  // append to the end, at least doubling allocated
+  // size if growth is needed
+  void append(byte const *str, int len);
+  void append(char const *str, int len)
+    { append((byte const*)str, len); }
+};
+
+#endif // __GROWBUF_H

Added: vendor/elsa/current/smbase/hashline.cc
===================================================================
--- vendor/elsa/current/smbase/hashline.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/hashline.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,192 @@
+// hashline.cc
+// code for hashline.h
+
+#include "hashline.h"      // this module
+
+#include <string.h>        // memcpy
+
+
+HashLineMap::HashLineMap(rostring pf)
+  : ppFname(pf),
+    filenames(),     // empty
+    directives(),    // empty
+    prev_ppLine(-1)  // user shouldn't have negative line numbers
+{}
+
+
+HashLineMap::~HashLineMap()
+{}
+
+char const *HashLineMap::canonizeFilename(char const *fname)
+{
+  // map 'fname' to a canonical reference
+  return filenames(fname);
+}
+
+void HashLineMap::addHashLine(int ppLine, int origLine, char const *origFname)
+{
+  // check that entries are being added in sorted order
+  xassert(ppLine > prev_ppLine);
+  prev_ppLine = ppLine;
+
+  // map 'origFname' to a canonical reference
+  origFname = canonizeFilename(origFname);
+
+  // add the entry to the array
+  directives.push(HashLine(ppLine, origLine, origFname));
+}
+
+
+void HashLineMap::doneAdding()
+{
+  // printf("## HashLineMap::doneAdding: directives.length() = %d, directives.size() = %d\n",
+  //        directives.length(), directives.size());
+  directives.setSize(directives.length());
+
+  // // make a new array of exactly the right size
+  // ArrayStack<HashLine> tmp(directives.length());
+
+  // // copy all the entries into the new array
+  // memcpy(tmp.getDangerousWritableArray(), directives.getArray(),
+  //        directives.length() * sizeof(HashLine));
+  // tmp.setLength(directives.length());
+
+  // // swap the internal contents of the two arrays, so 'directives'
+  // // becomes the consolidated one
+  // tmp.swapWith(directives);
+
+  // // now tmp's internal storage will be automatically deleted
+}
+
+
+// for queries exactly on #line directives we return the specified
+// origLine minus 1, but I don't specify any behavior in that case
+// so it's not a problem
+void HashLineMap::map(int ppLine, int &origLine, char const *&origFname) const
+{
+  // check for a ppLine that precedes any in the array
+  if (directives.isEmpty() ||
+      ppLine < directives[0].ppLine) {
+    // it simply refers to the pp file
+    origLine = ppLine;
+    origFname = ppFname.c_str();
+    return;
+  }
+
+  // perform binary search on the 'directives' array
+  int low = 0;                        // index of lowest candidate
+  int high = directives.length()-1;   // index of highest candidate
+
+  while (low < high) {
+    // check the midpoint (round up to ensure progress when low+1 == high)
+    int mid = (low+high+1)/2;
+    if (directives[mid].ppLine > ppLine) {
+      // too high
+      high = mid-1;
+    }
+    else {
+      // too low or just right
+      low = mid;
+    }
+  }
+  xassert(low == high);
+  HashLine const &hl = directives[low];
+
+  // the original line is the origLine in the array entry, plus the
+  // offset between the ppLine passed in and the ppLine in the array,
+  // minus 1 because the #line directive itself occupies one pp line
+  origLine = hl.origLine + (ppLine - hl.ppLine - 1);
+
+  origFname = hl.origFname;
+}
+
+
+int HashLineMap::mapLine(int ppLine) const
+{
+  int origLine;
+  char const *origFname;
+  map(ppLine, origLine, origFname);
+  return origLine;
+}
+
+char const *HashLineMap::mapFile(int ppLine) const
+{
+  int origLine;
+  char const *origFname;
+  map(ppLine, origLine, origFname);
+  return origFname;
+}
+
+
+// --------------------- test code ---------------------
+#ifdef TEST_HASHLINE
+
+#include <stdio.h>     // printf
+#include <stdlib.h>    // exit
+
+void query(HashLineMap &hl, int ppLine,
+           int expectOrigLine, char const *expectOrigFname)
+{
+  int origLine;
+  char const *origFname;
+  hl.map(ppLine, origLine, origFname);
+
+  if (origLine != expectOrigLine ||
+      0!=strcmp(origFname, expectOrigFname)) {
+    printf("map(%d) yielded %s:%d, but I expected %s:%d\n",
+           ppLine, origFname, origLine,
+           expectOrigFname, expectOrigLine);
+    exit(2);
+  }
+}
+
+
+int main()
+{
+  // insert #line directives:
+  //    foo.i
+  //    +----------
+  //   1|// nothing; it's in the pp file
+  //   2|#line 1 foo.cc
+  //   3|
+  //   4|
+  //   5|#line 1 foo.h
+  //   ..
+  //  76|#line 5 foo.cc
+  //   ..
+  // 100|#line 101 foo.i
+
+  HashLineMap hl("foo.i");
+  hl.addHashLine(2, 1, "foo.cc");
+  hl.addHashLine(5, 1, "foo.h");
+  hl.addHashLine(76, 5, "foo.cc");
+  hl.addHashLine(100, 101, "foo.i");
+  hl.doneAdding();
+
+  // make queries, and check for expected results
+  query(hl, 1, 1, "foo.i");
+
+  query(hl, 3, 1, "foo.cc");
+  query(hl, 4, 2, "foo.cc");
+
+  query(hl, 6, 1, "foo.h");
+  query(hl, 7, 2, "foo.h");
+  // ...
+  query(hl, 75, 70, "foo.h");
+
+  query(hl, 77, 5, "foo.cc");
+  query(hl, 78, 6, "foo.cc");
+  // ...
+  query(hl, 99, 27, "foo.cc");
+
+  query(hl, 101, 101, "foo.i");
+  query(hl, 102, 102, "foo.i");
+  // ...
+
+  // printf("unique filenames: %d\n", hl.numUniqueFilenames());
+  printf("hashline seems to work\n");
+
+  return 0;
+}
+
+#endif // TEST_HASHLINE

Added: vendor/elsa/current/smbase/hashline.h
===================================================================
--- vendor/elsa/current/smbase/hashline.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/hashline.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,94 @@
+// hashline.h
+// module for maintaining and using #line info in source files
+
+// terminology:
+//   pp source: preprocessed source, i.e. whatever had the #line
+//              info sprinkled throughout it
+//   orig source: original source, the files to which the #line
+//                directives refer
+
+#ifndef HASHLINE_H
+#define HASHLINE_H
+
+#include "strtable.h"       // StringTable
+#include "array.h"          // ArrayStack
+
+// map from lines in some given pp source file to lines in
+// orig source files; there should be one HashLineMap object
+// for each pp source file of interest
+class HashLineMap {
+  // dsw: Scott, I need this to be public so I can serialize it;
+  // private data I can get with an accessor, but private classes are
+  // a problem.  I could make the xml serialization a friend, but that
+  // would make a dependency of smbase on elsa.
+  public:
+//  private:    // types
+  // records a single #line directive
+  class HashLine {
+  public:
+    int ppLine;              // pp source line where it appears
+    int origLine;            // orig line it names
+    char const *origFname;   // orig fname it names
+
+  public:
+    HashLine()
+      : ppLine(0), origLine(0), origFname(NULL) {}
+    HashLine(int pl, int ol, char const *of)
+      : ppLine(pl), origLine(ol), origFname(of) {}
+    HashLine(HashLine const &obj)
+      : DMEMB(ppLine), DMEMB(origLine), DMEMB(origFname) {}
+  };
+
+public:
+  char const *canonizeFilename(char const *fname);
+
+private:    // data
+  // name of the pp file; this is needed for queries to lines
+  // before any #line is encountered
+  string ppFname;
+
+  // map for canonical storage of orig filenames
+  StringTable filenames;
+
+public:
+// dsw: it is a real pain to do de-serialization without making this
+// public
+
+  // growable array of HashLine objects
+  ArrayStack<HashLine> directives;
+
+private:                        // more data
+  // previously-added ppLine; used to verify the entries are
+  // being added in sorted order
+  int prev_ppLine;
+
+public:     // funcs
+  HashLineMap(rostring ppFname);
+  ~HashLineMap();
+
+  // call this time each time a #line directive is encountered;
+  // successive calls must have strictly increasing values of 'ppLine'
+  void addHashLine(int ppLine, int origLine, char const *origFname);
+
+  // call this when all the #line directives have been added; this
+  // consolidates the 'directives' array to reclaim any space created
+  // during the growing process but that is now not needed
+  void doneAdding();
+
+  // map from pp line to orig line/file; note that queries exactly on
+  // #line lines have undefined results
+  void map(int ppLine, int &origLine, char const *&origFname) const;
+  int mapLine(int ppLine) const;           // returns 'origLine'
+  char const *mapFile(int ppLine) const;   // returns 'origFname'
+
+  // for curiosity, find out how many unique filenames are recorded in
+  // the 'filenames' dictionary
+  // int numUniqueFilenames() { return filenames.size(); }
+
+  // XML serialization only
+  string &serializationOnly_get_ppFname() { return ppFname; }
+  void serializationOnly_set_ppFname(string const &ppFname0) { ppFname = ppFname0; }
+  ArrayStack<HashLine> &serializationOnly_get_directives() { return directives; }
+};
+
+#endif // HASHLINE_H

Added: vendor/elsa/current/smbase/hashtbl.cc
===================================================================
--- vendor/elsa/current/smbase/hashtbl.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/hashtbl.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,288 @@
+// hashtbl.cc            see license.txt for copyright and terms of use
+// code for hashtbl.h
+
+#include "hashtbl.h"     // this module
+#include "xassert.h"     // xassert
+
+#include <string.h>      // memset
+
+
+unsigned HashTable::hashFunction(void const *key) const
+{
+  return coreHashFn(key) % (unsigned)tableSize;
+}
+
+
+HashTable::HashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek, int initSize)
+  : getKey(gk),
+    coreHashFn(hf),
+    equalKeys(ek),
+    enableShrink(true)
+{
+  makeTable(initSize);
+}
+
+HashTable::~HashTable()
+{
+  delete[] hashTable;
+}
+
+
+void HashTable::makeTable(int size)
+{
+  hashTable = new void*[size];
+  tableSize = size;
+  memset(hashTable, 0, sizeof(void*) * tableSize);
+  numEntries = 0;
+}
+
+
+inline int HashTable::getEntry(void const *key) const
+{
+  int index = hashFunction(key);
+  int originalIndex = index;
+  for(;;) {
+    if (hashTable[index] == NULL) {
+      // unmapped
+      return index;
+    }
+    if (equalKeys(key, getKey(hashTable[index]))) {
+      // mapped here
+      return index;
+    }
+
+    // this entry is mapped, but not with this key, i.e.
+    // we have a collision -- so just go to the next entry,
+    // wrapping as necessary
+    index = nextIndex(index);
+
+    // detect infinite looping
+    xassert(index != originalIndex);
+  }
+}
+
+
+void *HashTable::get(void const *key) const
+{
+  return hashTable[getEntry(key)];
+}
+
+
+void HashTable::resizeTable(int newSize)
+{
+  // Make sure newSize is not the result of an overflowed computation, and
+  // that we're not going to resizeTable again right away in the add() call.
+  xassert(newSize >= numEntries);
+  xassert(newSize/3*2 >= numEntries-1);
+
+  // save old stuff
+  void **oldTable = hashTable;
+  int oldSize = tableSize;
+  int oldEntries = numEntries;
+
+  // make the new table (sets 'numEntries' to 0)
+  makeTable(newSize);
+
+  // set this now, rather than incrementing it with each add
+  numEntries = oldEntries;
+
+  // move entries to the new table
+  for (int i=0; i<oldSize; i++) {
+    if (oldTable[i] != NULL) {
+      // This function is worth optimizing; it accounts for 12% of qualcc
+      // runtime.  This simple inlining reduces resizeTable()'s impact from
+      // 12% to 2%.
+      if (0) {
+        // original code:
+        add(getKey(oldTable[i]), oldTable[i]);
+      }
+      else {
+        // inlined version:
+        int newIndex = getEntry(getKey(oldTable[i]));
+        xassertdb(hashTable[newIndex] == NULL);    // must not be a mapping yet
+        hashTable[newIndex] = oldTable[i];
+      }
+
+      oldEntries--;
+    }
+  }
+  xassert(oldEntries == 0);
+
+  // deallocate the old table
+  delete[] oldTable;
+}
+
+
+void HashTable::add(void const *key, void *value)
+{
+  if (numEntries+1 > tableSize*2/3) {
+    // We're over the usage threshold; increase table size.
+    //
+    // Note: Resizing by numEntries*4 instead of tableSize*2 gives 42% speedup
+    // in total time used by resizeTable(), at the expense of more memory used.
+    resizeTable(tableSize * 2 + 1);
+  }
+  // make sure above didn't fail due to integer overflow
+  xassert(numEntries+1 < tableSize);
+
+  int index = getEntry(key);
+  xassert(hashTable[index] == NULL);    // must not be a mapping yet
+
+  hashTable[index] = value;
+  numEntries++;
+}
+
+
+void *HashTable::remove(void const *key)
+{
+  if (enableShrink                &&
+      numEntries-1 < tableSize/5  &&
+      tableSize > defaultSize) {
+    // we're below threshold; reduce table size
+    resizeTable(tableSize / 2);
+  }
+
+  int index = getEntry(key);
+  xassert(hashTable[index] != NULL);    // must be a mapping to remove
+
+  // remove this entry
+  void *retval = hashTable[index];
+  hashTable[index] = NULL;
+  numEntries--;
+
+  // now, if we ever inserted something and it collided with this one,
+  // leaving things like this would prevent us from finding that other
+  // mapping because the search stops as soon as a NULL entry is
+  // discovered; so we must examine all entries that could have
+  // collided, and re-insert them
+  int originalIndex = index;
+  for(;;) {
+    index = nextIndex(index);
+    xassert(index != originalIndex);    // prevent infinite loops
+
+    if (hashTable[index] == NULL) {
+      // we've reached the end of the list of possible colliders
+      break;
+    }
+
+    // remove this one
+    void *data = hashTable[index];
+    hashTable[index] = NULL;
+    numEntries--;
+
+    // add it back
+    add(getKey(data), data);
+  }
+
+  return retval;
+}
+
+
+void HashTable::empty(int initSize)
+{
+  delete[] hashTable;
+  makeTable(initSize);
+}
+
+
+void HashTable::selfCheck() const
+{
+  int ct=0;
+  for (int i=0; i<tableSize; i++) {
+    if (hashTable[i] != NULL) {
+      checkEntry(i);
+      ct++;
+    }
+  }
+
+  xassert(ct == numEntries);
+}
+
+void HashTable::checkEntry(int entry) const
+{
+  int index = getEntry(getKey(hashTable[entry]));
+  int originalIndex = index;
+  for(;;) {
+    if (index == entry) {
+      // the entry lives where it will be found, so that's good
+      return;
+    }
+    if (hashTable[index] == NULL) {
+      // the search for this entry would stop before finding it,
+      // so that's bad!
+      xfailure("checkEntry: entry in wrong slot");
+    }
+
+    // collision; keep looking
+    index = nextIndex(index);
+    xassert(index != originalIndex);
+  }
+}
+
+
+// ------------------ HashTableIter --------------------
+HashTableIter::HashTableIter(HashTable &t)
+  : table(t)
+{
+  index = 0;
+  moveToSth();
+}
+
+void HashTableIter::adv()
+{
+  xassert(!isDone());
+
+  // move off the current item
+  index++;
+
+  // keep moving until we find something
+  moveToSth();
+}
+
+void HashTableIter::moveToSth()
+{
+  while (index < table.tableSize &&
+         table.hashTable[index] == NULL) {
+    index++;
+  }
+
+  if (index == table.tableSize) {
+    index = -1;    // mark as done
+  }
+}
+
+
+void *HashTableIter::data() const
+{
+  xassert(!isDone());
+  return table.hashTable[index];
+}
+
+
+STATICDEF void const *HashTable::identityKeyFn(void *data)
+{
+  return data;
+}
+
+unsigned lcprngTwoSteps(unsigned v)
+{
+  // this is the core of the LC PRNG in one of the many libcs
+  // running around the net
+  v = (v * 1103515245) + 12345;
+
+  // do it again for good measure
+  v = (v * 1103515245) + 12345;
+
+  return v;
+}
+
+STATICDEF unsigned HashTable::lcprngHashFn(void const *key)
+{
+  return lcprngTwoSteps((unsigned)pointerToInteger(key));
+}
+
+STATICDEF bool HashTable::
+  pointerEqualKeyFn(void const *key1, void const *key2)
+{
+  return key1 == key2;
+}

Added: vendor/elsa/current/smbase/hashtbl.h
===================================================================
--- vendor/elsa/current/smbase/hashtbl.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/hashtbl.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,161 @@
+// hashtbl.h            see license.txt for copyright and terms of use
+// hash table mapping arbitrary keys to void*, where
+// the stored pointers can be used to derive the key,
+// and cannot be NULL
+
+#ifndef HASHTBL_H
+#define HASHTBL_H
+
+#include "typ.h"     // STATICDEF
+
+class HashTable {
+private:    // types
+  friend class HashTableIter;
+
+public:     // types
+  // given a stored data pointer, retrieve the associated key
+  typedef void const* (*GetKeyFn)(void *data);
+
+  // given a key, retrieve the associated hash value;
+  // this should be a 32-bit integer ready to be mod'd by the table size
+  typedef unsigned (*HashFn)(void const *key);
+
+  // compare two keys; this is needed so we can handle collisions
+  // in the hash function; return true if they are equal
+  typedef bool (*EqualKeyFn)(void const *key1, void const *key2);
+
+  // constants
+  enum {
+    defaultSize = 33
+  };
+
+private:    // data
+  // maps
+  GetKeyFn getKey;
+  HashFn coreHashFn;
+  EqualKeyFn equalKeys;
+
+  // array of pointers to data, indexed by the hash value,
+  // with collisions resolved by moving to adjacent entries;
+  // some entries are NULL, meaning that hash value has no mapping
+  void **hashTable;
+
+  // Why use linear hashing instead of double hashing?  To support
+  // deletion.  Since every probe sequence that goes through index k
+  // will have a tail of k+1,k+2,... (mod tableSize) I can easily find
+  // and re-insert all the elements whose position might have depended
+  // on the presence of a now-deleted element.  Excessive clustering
+  // is (hopefully) avoided through load factor control.
+
+  // number of slots in the hash table
+  int tableSize;
+
+  // number of mapped (non-NULL) entries
+  int numEntries;
+
+  // when false, we never make the table smaller (default: true)
+  bool enableShrink;
+
+private:    // funcs
+  // disallowed
+  HashTable(HashTable&);
+  void operator=(HashTable&);
+  void operator==(HashTable&);
+
+  // hash fn for the current table size; always in [0,tableSize-1]
+  unsigned hashFunction(void const *key) const;
+
+  // given a collision at 'index', return the next index to try
+  int nextIndex(int index) const { return (index+1) % tableSize; }
+
+  // resize the table, transferring all the entries to their
+  // new positions
+  void resizeTable(int newSize);
+
+  // return the index of the entry corresponding to 'data' if it
+  // is mapped, or a pointer to the entry that should be filled
+  // with its mapping, if unmapped
+  int getEntry(void const *key) const;
+
+  // make a new table with the given size
+  void makeTable(int size);
+
+  // check a single entry for integrity
+  void checkEntry(int entry) const;
+
+public:     // funcs
+  HashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek,
+            int initSize = HashTable::defaultSize);
+  ~HashTable();
+
+  // return # of mapped entries
+  int getNumEntries() const { return numEntries; }
+
+  // if this hash value has a mapping, return it; otherwise,
+  // return NULL
+  void *get(void const *key) const;
+
+  // add a mapping from 'key' to 'value'; there must not already
+  // be a mapping for this key
+  void add(void const *key, void *value);
+
+  // remove the mapping for 'key' -- it must exist
+  // returns the removed item
+  void *remove(void const *key);
+
+  // remove all mappings
+  void empty(int initSize = HashTable::defaultSize);
+
+  // set whether shrinkage is allowed; it's useful to be able to
+  // disable this to avoid any allocation in certain situations
+  void setEnableShrink(bool en) { enableShrink = en; }
+
+  // allow external access to an accessor function
+  void const *callGetKeyFn(void *data) { return getKey(data); }
+
+  // check the data structure's invariants, and throw an exception
+  // if there is a problem
+  void selfCheck() const;
+
+  // ------ useful default functions -------
+  // returns its argument
+  static void const* identityKeyFn(void *data);
+
+  // puts the argument through two cycles of a linear
+  // congruential pseudo-random number generator
+  static unsigned lcprngHashFn(void const *key);
+
+  // does pointer equality comparison
+  static bool pointerEqualKeyFn(void const *key1, void const *key2);
+};
+
+unsigned lcprngTwoSteps(unsigned v);
+
+// inlined copy of lcprngTwoSteps
+static inline unsigned lcprngTwoSteps_inline(unsigned v)
+{
+  v = (v * 1103515245) + 12345;
+  v = (v * 1103515245) + 12345;
+  return v;
+}
+
+// iterate over all stored values in a HashTable
+// NOTE: you can't change the table while an iter exists
+class HashTableIter {
+private:      // data
+  HashTable &table;      // table we're iterating over
+  int index;             // current slot to return in adv(); -1 when done
+
+private:      // funcs
+  void moveToSth();
+
+public:       // funcs
+  HashTableIter(HashTable &table);
+
+  bool isDone() const { return index == -1; }
+  void adv();
+  void *data() const;          // returns a value stored in the table
+};
+
+
+#endif // HASHTBL_H

Added: vendor/elsa/current/smbase/index.html
===================================================================
--- vendor/elsa/current/smbase/index.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/index.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,663 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+
+<HEAD>
+  <TITLE>smbase</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 150% }
+    H2 { font-size: 125% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175% }
+  </style>
+</HEAD>
+
+<body>
+
+<center>
+<p class="title"><b>smbase: A Utility Library</b></p>
+</center>
+
+<h1>Introduction</h1>
+
+<p>
+"smbase" stands for Scott McPeak's Base Library (sorry, naming things
+is not my specialty).  It's a bunch of
+utility modules I use in virtually all of my projects.  The entire
+library is in the public domain.
+
+<p>
+There is some overlap in functionality between smbase and the C++
+Standard Library.  Partly this is because smbase predates the standard
+library, and partly this is because that library has aspects to its
+design that I disagree with (for example, I think it is excessively
+templatized, given flaws in the C++ template mechanism).  However, the
+intent is that client code can use smbase and the standard library at
+the same time.
+
+<p>
+smbase has developed organically, in response to specific needs.
+While each module individually has been reasonably carefully designed,
+the library as a whole has not.  Consequently, the modules to not
+always orthogonally cover a given design space, and some of the
+modules are now considered obsolete (marked below as such).
+
+<p>
+Some of the links below refer to generated documentation files.  If
+you are reading this from your local filesystem, you may have to
+say <tt>"make gendoc"</tt> (after <tt>"./configure"</tt>) to get them.
+
+<h1>Build Instructions</h1>
+
+<p>
+<pre>
+  $ ./configure
+  $ make
+  $ make check
+</pre>
+<a href="configure.pl"><tt>./configure</tt></a> understands
+<a href="gendoc/configure.txt">these options</a>.  You can also
+look at the <a href="Makefile.in">Makefile</a>.
+
+<h1>Modules</h1>
+
+<p>
+The following sections list all the smbase modules, grouped by
+functionality.
+
+<h2>Linked Lists</h2>
+
+<p>
+Linked lists are sequences of objects with O(1) insertion at the front
+and iterators for traversal.  Most also have <em>mutators</em> for
+traversing and modifying.  
+
+<p>
+The two main lists classes are ObjList and SObjList.  Both are lists
+of pointers to objects; the former <em>owns</em> the objects, and will
+delete them when it goes away, while the latter does not.
+
+<ul>
+<li><a href="objlist.h">objlist.h</a>:
+ObjList, a general linked list of objects.  ObjList considers itself
+to "own" (be responsible for deallocating) the things on its list.
+See also <a href="sobjlist.h">sobjlist.h</a>.
+
+<li><a href="sobjlist.h">sobjlist.h</a>:
+SObjList, a general linked list of objects.  SObjList does <em>not</em>
+consider itself the owner of the list elements.  The "s" in the
+name stands for "serf", which I use to mean the opposite of "owner".
+See also <a href="objlist.h">objlist.h</a>.
+
+<li><a href="xobjlist.h">xobjlist.h</a>:
+This file is processed by <a href="http://www.gnu.org/software/m4/">M4</a>
+to make <a href="objlist.h">objlist.h</a> and <a href="sobjlist.h">sobjlist.h</a>.
+
+<li><a href="voidlist.h">voidlist.h</a>,
+    <a href="voidlist.cc">voidlist.cc</a>:
+The core of the linked list implementation used by
+<a href="objlist.h">objlist.h</a> and <a href="sobjlist.h">sobjlist.h</a>.
+
+</ul>
+
+<p>
+There are a couple of variants that support O(1) appending.
+
+<ul>
+<li><a href="vdtllist.h">vdtllist.h</a>,
+    <a href="vdtllist.cc">vdtllist.cc</a>:
+VoidTailList, the core of a linked list implementation which maintains
+a pointer to the last node for O(1) appends.
+Used by <a href="astlist.h">astlist.h</a> and <a href="taillist.h">taillist.h</a>.
+
+<li><a href="taillist.h">taillist.h</a>:
+Template class built on top of VoidTailList (<a href="vdtllist.h">vdtllist.h</a>).
+
+<li><a href="astlist.h">astlist.h</a>:
+ASTList, a list class for use in abstract syntax trees.
+
+</ul>
+
+<p>
+Finally, two stacks implemented with lists.  Recently, I've been
+preferring to use array-based stacks (<a href="array.h">array.h</a>),
+so these are somewhat obsolete.
+
+<ul>
+
+<li><a href="objstack.h">objstack.h</a>:
+ObjStack, a stack of owned objects.  Built with a linked list.
+
+<li><a href="sobjstack.h">sobjstack.h</a>:
+SObjStack, a stack of non-owned objects.  Built with a linked list.
+
+</ul>
+
+<h2>Arrays</h2>
+
+<p>
+Arrays are sequences of objects with O(1) random access and replacement.
+
+<p>
+The main array header, <a href="array.h">array.h</a>, contains several
+array classes.  GrowArray supports bounds checking and a method to
+grow the array.  ArrayStack supports a distinction between the <em>length</em>
+of the sequence and the <em>size</em> of the array allocated to store it,
+and grows the latter automatically.
+
+<ul>
+
+<li><a href="array.h">array.h</a>:
+Several array-like template classes, including growable arrays.
+
+<li><a href="bitwise_array.h">bitwise_array.h</a>:
+Similar classes which use bitwise copying semantics when growing.
+
+</ul>
+
+<p>
+The other array modules are less-used.
+
+<ul>
+
+<li><a href="arrayqueue.h">arrayqueue.h</a>:
+ArrayQueue, a template class implementing a queue with an array.
+Supports O(1) enqueue and dequeue.
+
+<li><a href="datablok.h">datablok.h</a>,
+    <a href="datablok.cpp">datablok.cpp</a>:
+DataBlock, an array of characters of a given length.  Useful when the
+data may contain NUL ('\0') bytes.
+
+<li><a href="growbuf.h">growbuf.h</a>,
+    <a href="growbuf.cc">growbuf.cc</a>:
+Extension of DataBlock (<a href="datablok.h">datablok.h</a>) that
+provides an append() function.
+
+</ul>
+
+<p>
+This is obsolete.
+
+<ul>
+
+<li><a href="arraymap.h">arraymap.h</a>:
+ArrayMap, a map from integers to object pointers. Obsolete.
+
+</ul>
+
+
+<h2>Arrays of Bits</h2>
+
+<p>
+Arrays of bits are handled specially, because they are implemented by
+storing multiple bits per byte.
+
+<ul>
+
+<li><a href="bit2d.h">bit2d.h</a>,
+    <a href="bit2d.cc">bit2d.cc</a>:
+Two-dimensional array of bits.
+
+<li><a href="bitarray.h">bitarray.h</a>,
+    <a href="bitarray.cc">bitarray.cc</a>:
+One-dimensional array of bits.
+
+</ul>
+
+<h2>Hash Tables and Maps</h2>
+
+<p>
+Maps support mapping from arbitrary domains to arbitrary ranges.  Mappings
+can be added and queried in amortized O(1) time, but the constant factor
+is considerably higher than for arrays and lists.
+
+<p>
+Probably the most common map is the PtrMap template, which will map
+from pointers to pointers, for arbitrary pointed-to types.
+
+<ul>
+
+<li><a href="ptrmap.h">ptrmap.h</a>:
+Template class built on top of VoidPtrMap (<a href="vptrmap.h">vptrmap.h</a>).
+
+<li><a href="objmap.h">objmap.h</a>:
+Variant of PtrMap (<a href="ptrmap.h">ptrmap.h</a>) that owns the values.
+
+<li><a href="vptrmap.h">vptrmap.h</a>,
+    <a href="vptrmap.cc">vptrmap.cc</a>:
+Hashtable-based map from void* to void*.
+Used by <a href="ptrmap.h">ptrmap.h</a> and <a href="objmap.h">objmap.h</a>.
+
+</ul>
+
+<p>
+If the key can always be derived from the data (for example, the key
+is stored in the data object), then it is inefficient to store both in
+the table.  The following variants require a function pointer to map
+from data to keys.
+
+<ul>
+
+<li><a href="hashtbl.h">hashtbl.h</a>,
+    <a href="hashtbl.cc">hashtbl.cc</a>:
+HashTable, a hash table.  Maps void* to void*.
+
+<li><a href="thashtbl.h">thashtbl.h</a>:
+Template class built on top of HashTable.  Maps KEY* to VALUE*.
+
+<li><a href="ohashtbl.h">ohashtbl.h</a>:
+OwnerHashTable, a hash table that owns the values, built on top
+of HashTable.  Maps void* to T*.
+
+</ul>
+
+<p>
+The above can be used to efficiently implement a set of T*.
+
+<ul>
+
+<li><a href="sobjset.h">sobjset.h</a>:
+SObjSet, a non-owning set of objects implemented on top of HashTable.
+
+</ul>
+
+<p>
+There are two specialized versions that combine O(1) insertion
+and query of a hash table with O(1) enqueue and dequeue of an
+array.
+
+<ul>
+
+<li><a href="okhasharr.h">okhasharr.h</a>:
+OwnerKHashArray, a combination of an owner hash table and an array/stack.
+
+<li><a href="okhashtbl.h">okhashtbl.h</a>:
+OwnerKHashTable, a version of <a href="okhasharr.h">okhasharr.h</a>
+with type-safe keys ("k" for keys).
+
+</ul>
+
+<h2>Maps with Strings as Keys</h2>
+
+<p>
+Mapping from strings is a nontrivial extension of the above maps
+because comparison is more than a pointer equality test.  So there
+are some specialized maps from strings.
+
+<p>
+If you have a function that can map from data to (string) key,
+then StringHash and TStringHash (the template version) are the
+most efficient:
+
+<ul>
+<li><a href="strhash.h">strhash.h</a>,
+    <a href="strhash.cc">strhash.cc</a>:
+StringHash, a case-sensitive map from strings to void* pointers.
+Built on top of HashTable.
+</ul>
+
+<p>
+The StringVoidDict and templates wrapped around it are more general.
+They do not require a function to map from data to key, support
+query-then-modify-result, and alphabetic iteration.
+
+<ul>
+
+<li><a href="strobjdict.h">strobjdict.h</a>:
+StringObjDict, a case-sensitive map from strings to object pointers.
+The dictionary owns the referred-to objects.
+
+<li><a href="strsobjdict.h">strsobjdict.h</a>:
+StringSObjDict, a case-sensitive map from strings to object pointers.
+The dictionary does <em>not</em> own the referred-to objects.
+
+<li><a href="svdict.h">svdict.h</a>,
+    <a href="svdict.cc">svdict.cc</a>:
+StringVoidDict, a case-sensitive map from strings to void* pointers.
+Built on top of StringHash.
+
+</ul>
+
+<p>
+Finally, there is a module to map from strings to strings.
+
+<ul>
+<li><a href="strdict.h">strdict.h</a>,
+    <a href="strdict.cc">strdict.cc</a>:
+StringDict, a case-sensitive map from strings to strings.
+Currently, this is implemented with a linked list and consequently
+not efficient.  But it will work when efficiency does not matter,
+and could be reimplemented (preserving the interface) with something
+better.
+
+</ul>
+
+
+<h2>Strings</h2>
+
+<p>
+Strings are sequences of characters.
+
+<ul>
+
+<li><a href="str.h">str.h</a>,
+    <a href="str.cpp">str.cpp</a>:
+The string class itself.  Using the string class instead of
+<tt>char*</tt> makes handling strings as convenent as manipulating
+fundamental types like <tt>int</tt> or <tt>float</tt>.
+See also <a href="string.txt">string.txt</a>.
+
+<li><a href="stringset.h">stringset.h</a>,
+    <a href="stringset.cc">stringset.cc</a>:
+StringSet, a set of strings.
+
+<li><a href="strtokp.h">strtokp.h</a>,
+    <a href="strtokp.cpp">strtokp.cpp</a>:
+StrtokParse, a class that parses a string similar to how strtok()
+works, but provides a more convenient (and thread-safe) interface.
+Similar to Java's StringTokenizer.
+
+<li><a href="strutil.h">strutil.h</a>,
+    <a href="strutil.cc">strutil.cc</a>:
+A set of generic string utilities, including replace(), translate(),
+trimWhitespace(), encodeWithEscapes(), etc.
+
+<li><a href="smregexp.h">smregexp.h</a>,
+    <a href="smregexp.cc">smregexp.cc</a>:
+Regular expression matching.
+
+</ul>
+
+<h2>System Utilities</h2>
+
+<p>
+The following modules provide access to or wrappers around various
+low-level system services.
+
+<ul>
+
+<li><a href="autofile.h">autofile.h</a>,
+    <a href="autofile.cc">autofile.cc</a>:
+AutoFILE, a simple wrapper around FILE* to open it or throw
+an exception, and automatically close it.
+
+<li><a href="cycles.h">cycles.h</a>
+    <a href="cycles.c">cycles.c</a>:
+Report total number of processor cycles since the machine was turned on.
+Uses the RDTSC instruction on x86.
+
+<li><a href="missing.h">missing.h</a>,
+    <a href="missing.cpp">missing.cpp</a>:
+Implementations of a few C library functions that are not present
+on all platforms.
+
+<li><a href="mypopen.h">mypopen.h</a>,
+    <a href="mypopen.c">mypopen.c</a>:
+Open a process, yielding two pipes: one for writing, one for reading.
+
+<li><a href="mysig.h">mysig.h</a>,
+    <a href="mysig.cc">mysig.cc</a>:
+Some signal-related utilities.
+
+<li><a href="syserr.h">syserr.h</a>,
+    <a href="syserr.cpp">syserr.cpp</a>:
+Intended to be a portable encapsulation of system-dependent error
+facilities like UNIX's errno and Win32's GetLastError().  It's not
+very complete right now.
+
+<li><a href="unixutil.h">unixutil.h</a>,
+    <a href="unixutil.c">unixutil.c</a>:
+Some utilities on top of unix functions: writeAll(), readString().
+
+</ul>
+
+<h2>Portability</h2>
+
+<p>
+These modules help insulate client code from the details of the system
+it is running on.
+
+<ul>
+
+<li><a href="nonport.h">nonport.h</a>,
+    <a href="nonport.cpp">nonport.cpp</a>:
+A library of utility functions whose implementation is system-specific.
+Generally, I try to encapsulate all system depenencies as functions
+defined in nonport.
+
+<li><a href="macros.h">macros.h</a>:
+A bunch of useful macros.
+
+<li><a href="typ.h">typ.h</a>:
+Some type definitions like <tt>byte</tt> and <tt>bool</tt>, plus a few
+utility macros.  Not clearly distinguished from <a href="macros.h">macros.h</a>
+in purpose.
+
+</ul>
+
+<h2>Allocation</h2>
+
+<p>
+These modules provide additional control over the allocator.
+
+<ul>
+
+<li><a href="ckheap.h">ckheap.h</a>:
+Interface to check heap integrity.  The underlying malloc implementation
+must support these entry points for it to work.  I've extended Doug
+Lea's malloc (<a href="malloc.c">malloc.c</a>) to do so.
+
+<li><a href="malloc.c">malloc.c</a>:
+Version 2.7.0 of
+<a href="http://gee.cs.oswego.edu/dl/html/malloc.html">Doug Lea's malloc</a>.
+I've made some modifications to help with debugging of memory errors
+in client code.
+
+<li><a href="objpool.h">objpool.h</a>:
+ObjPool, a custom allocator for fixed-size objects with embedded
+'next' links.
+
+</ul>
+
+<h2>Exceptions</h2>
+
+<p>
+These modules define or throw exceptions.
+
+<ul>
+
+<li><a href="exc.h">exc.h</a>,
+    <a href="exc.cpp">exc.cpp</a>:
+Various exception classes.  The intent is derive everything from xBase,
+so a program can catch this one exception type in main() and be assured
+no exception will propagate out of the program (or any other unit of
+granularity you want).
+
+<li><a href="xassert.h">xassert.h</a>:
+xassert is an assert()-like macro that throws an exception when it
+fails, instead of calling abort().
+
+</ul>
+
+<h2>Serialization</h2>
+
+<p>
+The "flatten" serialization scheme is intended to allow sets of objects
+to read and write themselves to files.
+
+<ul>
+
+<li><a href="bflatten.h">bflatten.h</a>,
+    <a href="bflatten.cc">bflatten.cc</a>:
+Implementation of the Flatten interface (<a href="flatten.h">flatten.h</a>)
+for reading/writing binary files.
+
+<li><a href="flatten.h">flatten.h</a>,
+    <a href="flatten.cc">flatten.cc</a>:
+Generic interface for serializing in-memory data structures to files.
+Similar to Java's Serializable, but independently conceived, and has
+superior version control facilities.
+
+</ul>
+
+<h2>Compiler/Translator Support</h2>
+
+<p>
+smbase has a number of modules that are of use to programs that
+read and/or write source code.
+
+<ul>
+
+<li><a href="hashline.h">hashline.h</a>,
+    <a href="hashline.cc">hashline.cc</a>:
+HashLineMap, a mechanism for keeping track of #line directives in C
+source files.  Provides efficient queries with respect to a set of
+such directives.
+
+<li><a href="srcloc.h">srcloc.h</a>,
+    <a href="srcloc.cc">srcloc.cc</a>:
+This module maintains a one-word data type called SourceLoc.
+SourceLoc is a location within some file, e.g. line/col or character
+offset information.  SourceLoc also encodes <em>which</em> file it
+refers to.  This type is very useful for language processors (like
+compilers) because it efficiently encodes location formation.
+Decoding this into human-readable form is slower than incrementally
+updating it, but decoding is made somewhat efficient with some
+appropriate index structures.
+
+<li><a href="boxprint.h">boxprint.h</a>
+    <a href="boxprint.cc">boxprint.cc</a>:
+BoxPrint functions as an output stream (sort of like <tt>cout</tt>)
+with operations to indicate structure within the emitted text, so that
+it can break lines intelligently.  It's used as part of a source-code
+pretty-printer.
+
+<li><a href="warn.h">warn.h</a>,
+    <a href="warn.cpp">warn.cpp</a>:
+Intended to provide a general interface for user-level warnings; the
+design never really worked well.
+
+</ul>
+
+<h2>Testing and Debugging</h2>
+
+<ul>
+
+<li><a href="breaker.h">breaker.h</a>
+    <a href="breaker.cpp">breaker.cpp</a>:
+Function for putting a breakpoint in, to get debugger control just
+before an exception is thrown.
+
+<li><a href="test.h">test.h</a>:
+A few test-harness macros.
+
+<li><a href="trace.h">trace.h</a>,
+    <a href="trace.cc">trace.cc</a>:
+Module for recording and querying a set of debug tracing flags.
+It is documented in <a href="trace.html">trace.html</a>.
+
+<li><a href="trdelete.h">trdelete.h</a>,
+    <a href="trdelete.cc">trdelete.cc</a>:
+An <tt>operator delete</tt> which overwrites the deallocated memory with
+0xAA before deallocating it.
+
+</ul>
+
+<h2>Miscellaneous</h2>
+
+<ul>
+
+<li><a href="crc.h">crc.h</a>
+    <a href="crc.cpp">crc.cpp</a>:
+32-bit cyclic redundancy check.
+
+<li><a href="gprintf.h">gprintf.h</a>,
+    <a href="gprintf.c">gprintf.c</a>:
+General printf; calls a function to emit each piece.
+
+<li><a href="owner.h">owner.h</a>:
+Owner, a pointer that deallocates its referrent in its destructor.
+Similar to auto_ptr in the C++ Standard.
+
+<li><a href="point.h">point.h</a>,
+    <a href="point.cc">point.cc</a>:
+Point, a pair of integers.
+
+</ul>
+
+<h2>Test Drivers</h2>
+
+<p>
+Test drivers.  Below are the modules that are purely test drivers
+for other modules.  They're separated out from the list above to
+avoid the clutter.
+
+<ul>
+
+<li><a href="testmalloc.cc">testmalloc.cc</a>:
+A program to test the interface exposed by <a href="ckheap.h">ckheap.h</a>.
+
+<li><a href="tmalloc.c">tmalloc.c</a>:
+Test my debugging enhancements to <a href="malloc.c">malloc.c</a>.
+
+<li><a href="tarrayqueue.cc">tarrayqueue.cc</a>:
+Test driver for <a href="arrayqueue.h">arrayqueue.h</a>.
+
+<li><a href="testarray.cc">testarray.cc</a>:
+Test driver for <a href="array.h">array.h</a>.
+
+<li><a href="testcout.cc">testcout.cc</a>:
+This is a little test program for use by <a href="configure.pl">configure.pl</a>.
+
+<li><a href="tobjlist.cc">tobjlist.cc</a>:
+Test driver for <a href="objlist.h">objlist.h</a>.
+
+<li><a href="tobjpool.cc">tobjpool.cc</a>
+Test driver for <a href="objpool.h">objpool.h</a>.
+
+<li><a href="tsobjlist.cc">tsobjlist.cc</a>:
+Test driver for <a href="sobjlist.h">sobjlist.h</a>.
+
+</ul>
+
+<h2>Utility Scripts</h2>
+
+<ul>
+
+<li><a href="run-flex.pl">run-flex.pl</a>:
+Perl script to run flex and massage its output for portability.
+
+<li><a href="sm_config.pm">sm_config.pm</a>:
+This is a Perl module, intended to be used by configure scripts.
+It is mostly a library of useful routines, but also reads and writes
+some of the main script's global variables.
+
+</ul>
+
+
+<h1>Module Dependencies</h1>
+
+<p>
+The <a href="scan-depends.pl">scan-depends.pl</a> script is capable
+of generating a
+<a href="gendoc/dependencies.dot">module dependency description</a> in the
+<a href="http://www.research.att.com/sw/tools/graphviz/">Dot</a>
+format.  Not all the modules appear; I try to show the most important
+modules, and try to avoid making Dot do weird things.
+Below is its output.
+
+<p>
+<img src="gendoc/dependencies.png" alt="Module Dependencies"><br>
+There's also a <a href="gendoc/dependencies.ps">Postscript version</a>.
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+    
+</body>
+
+</HTML>

Added: vendor/elsa/current/smbase/license.txt
===================================================================
--- vendor/elsa/current/smbase/license.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/license.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,2 @@
+All of the modules in the smbase directory are
+hereby placed in the public domain.

Added: vendor/elsa/current/smbase/macros.h
===================================================================
--- vendor/elsa/current/smbase/macros.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/macros.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,277 @@
+// macros.h            see license.txt for copyright and terms of use
+// grab-bag of useful macros, stashed here to avoid mucking up
+//   other modules with more focus; there's no clear rhyme or
+//   reason for why some stuff is here and some in typ.h
+// (no configuration stuff here!)
+
+#ifndef __MACROS_H
+#define __MACROS_H
+
+#include "typ.h"        // bool
+
+// complement of ==
+#define NOTEQUAL_OPERATOR(T)             \
+  bool operator != (T const &obj) const  \
+    { return !operator==(obj); }
+
+// toss this into a class that already has == and < defined, to
+// round out the set of relational operators (assumes a total
+// order, i.e.  a < b  <=>  b < a)
+#define RELATIONAL_OPERATORS(T)                    \
+  NOTEQUAL_OPERATOR(T)                             \
+  bool operator <= (T const &obj) const            \
+    { return !obj.operator<(*this); }              \
+  bool operator > (T const &obj) const             \
+    { return obj.operator<(*this); }               \
+  bool operator >= (T const &obj) const            \
+    { return !operator<(obj); }
+
+
+// member copy in constructor initializer list
+#define DMEMB(var) var(obj.var)
+
+// member copy in operator =
+#define CMEMB(var) var = obj.var
+
+// member comparison in operator ==
+#define EMEMB(var) var == obj.var
+
+
+// standard insert operator
+// (note that you can put 'virtual' in front of the macro call if desired)
+#define INSERT_OSTREAM(T)                                \
+  void insertOstream(ostream &os) const;                 \
+  friend ostream& operator<< (ostream &os, T const &obj) \
+    { obj.insertOstream(os); return os; }
+
+
+// usual declarations for a data object (as opposed to control object)
+#define DATA_OBJ_DECL(T)                \
+  T();                                  \
+  T(T const &obj);                      \
+  ~T();                                 \
+  T& operator= (T const &obj);          \
+  bool operator== (T const &obj) const; \
+  NOTEQUAL_OPERATOR(T)                  \
+  INSERTOSTREAM(T)
+
+
+// copy this to the .cc file for implementation of DATA_OBJ_DECL
+#if 0
+T::T()
+{}
+
+T::T(T const &obj)
+  : DMEMB(),
+    DMEMB(),
+    DMEMB()
+{}
+
+T::~T()
+{}
+
+T& T::operator= (T const &obj)
+{
+  if (this != &obj) {
+    CMEMB();
+  }
+  return *this;
+}
+
+bool T::operator== (T const &obj) const
+{
+  return
+    EMEMB() &&
+    EMEMB();
+}
+
+void T::insertOstream(ostream &os) const
+{}
+#endif // 0
+
+
+// assert something at compile time (must use this inside a function);
+// works because compilers won't let us declare negative-length arrays
+// (the expression below works with egcs-1.1.2, gcc-2.x, gcc-3.x)
+#define STATIC_ASSERT(cond) \
+  { (void)((int (*)(char failed_static_assertion[(cond)?1:-1]))0); }
+
+// assert that a table is an expected size; the idea is to make sure
+// that static data in some table gets updated when a corresponding
+// symbolic constant is changed
+#define ASSERT_TABLESIZE(table, size) \
+  STATIC_ASSERT(TABLESIZE(table) == (size))
+
+  
+// for silencing variable-not-used warnings
+template <class T>
+inline void pretendUsedFn(T const &) {}
+#define PRETEND_USED(arg) pretendUsedFn(arg) /* user ; */
+
+
+// appended to function declarations to indicate they do not
+// return control to their caller; e.g.:
+//   void exit(int code) NORETURN;
+#ifdef __GNUC__
+  #define NORETURN __attribute__((noreturn))
+#else             
+  // just let the warnings roll if we can't suppress them
+  #define NORETURN
+#endif
+
+
+// these two are a common idiom in my code for typesafe casts;
+// they are essentially a roll-your-own RTTI
+#define CAST_MEMBER_FN(destType)                                                \
+  destType const &as##destType##C() const;                                      \
+  destType &as##destType() { return const_cast<destType&>(as##destType##C()); }
+
+#define CAST_MEMBER_IMPL(inClass, destType)         \
+  destType const &inClass::as##destType##C() const  \
+  {                                                 \
+    xassert(is##destType());                        \
+    return (destType const&)(*this);                \
+  }
+
+
+// same as the above, but returning pointers; I think returning
+// references was a mistake
+#define DOWNCAST_FN(destType)                                                   \
+  destType const *as##destType##C() const;                                      \
+  destType *as##destType() { return const_cast<destType*>(as##destType##C()); }
+
+#define DOWNCAST_IMPL(inClass, destType)            \
+  destType const *inClass::as##destType##C() const  \
+  {                                                 \
+    xassert(is##destType());                        \
+    return static_cast<destType const*>(this);      \
+  }
+
+
+// keep track of a count and a high water mark
+#define INC_HIGH_WATER(count, highWater)  \
+  count++;                                \
+  if (count > highWater) {                \
+    highWater = count;                    \
+  }
+
+
+// egcs has the annoying "feature" that it warns
+// about switches on enums where not all cases are
+// covered .... what is this, f-ing ML??
+#define INCL_SWITCH \
+  default: break; /*silence warning*/ 
+
+
+// for a class that maintains allocated-node stats
+#define ALLOC_STATS_DECLARE                     \
+  static int numAllocd;                         \
+  static int maxAllocd;                         \
+  static void printAllocStats(bool anyway);
+
+// these would go in a .cc file, whereas above goes in .h file
+#define ALLOC_STATS_DEFINE(classname)                      \
+  int classname::numAllocd = 0;                            \
+  int classname::maxAllocd = 0;                            \
+  STATICDEF void classname::printAllocStats(bool anyway)   \
+  {                                                        \
+    if (anyway || numAllocd != 0) {                        \
+      cout << #classname << " nodes: " << numAllocd        \
+           << ", max  nodes: " << maxAllocd                \
+           << endl;                                        \
+    }                                                      \
+  }
+
+#define ALLOC_STATS_IN_CTOR                     \
+  INC_HIGH_WATER(numAllocd, maxAllocd);
+
+#define ALLOC_STATS_IN_DTOR                     \
+  numAllocd--;
+
+  
+// ----------- automatic data value restorer -------------
+// used when a value is to be set to one thing now, but restored
+// to its original value on return (even when the return is by
+// an exception being thrown)
+template <class T>
+class Restorer {
+  T &variable;
+  T prevValue;
+  
+public:
+  Restorer(T &var, T newValue)
+    : variable(var),
+      prevValue(var)
+  {
+    variable = newValue;
+  }
+   
+  // this one does not set it to a new value, just remembers the current
+  Restorer(T &var)
+    : variable(var),
+      prevValue(var)
+  {}
+
+  ~Restorer()
+  {
+    variable = prevValue;
+  }
+};
+
+
+// declare a bunch of a set-like operators for enum types
+#define ENUM_BITWISE_AND(Type)                  \
+  inline Type operator& (Type f1, Type f2)      \
+    { return (Type)((int)f1 & (int)f2); }       \
+  inline Type& operator&= (Type &f1, Type f2)   \
+    { return f1 = f1 & f2; }
+
+#define ENUM_BITWISE_OR(Type)                   \
+  inline Type operator| (Type f1, Type f2)      \
+    { return (Type)((int)f1 | (int)f2); }       \
+  inline Type& operator|= (Type &f1, Type f2)   \
+    { return f1 = f1 | f2; }
+
+#define ENUM_BITWISE_XOR(Type)                  \
+  inline Type operator^ (Type f1, Type f2)      \
+    { return (Type)((int)f1 ^ (int)f2); }       \
+  inline Type& operator^= (Type &f1, Type f2)   \
+    { return f1 = f1 ^ f2; }
+
+#define ENUM_BITWISE_NOT(Type, ALL)             \
+  inline Type operator~ (Type f)                \
+    { return (Type)((~(int)f) & ALL); }
+
+#define ENUM_BITWISE_OPS(Type, ALL)             \
+  ENUM_BITWISE_AND(Type)                        \
+  ENUM_BITWISE_OR(Type)                         \
+  ENUM_BITWISE_XOR(Type)                        \
+  ENUM_BITWISE_NOT(Type, ALL)
+
+
+// macro to conditionalize something on NDEBUG; I typically use this
+// to hide the declaration of a variable whose value is only used by
+// debugging trace statements (and thus provokes warnings about unused
+// variables if NDEBUG is set)
+#ifdef NDEBUG
+  #define IFDEBUG(stuff)
+#else
+  #define IFDEBUG(stuff) stuff
+#endif
+
+
+// put at the top of a class for which the default copy ctor
+// and operator= are not desired; then don't define these functions
+#define NO_OBJECT_COPIES(name)   \
+  private:                       \
+    name(name&);                 \
+    void operator=(name&) /*user ;*/
+
+
+// The intended semantics of 'override' is that the function is
+// overriding a virtual member of a base class.  I intend to write
+// a checker for this annotation at some point.
+#define override virtual
+
+
+#endif // __MACROS_H

Added: vendor/elsa/current/smbase/make-preproc
===================================================================
--- vendor/elsa/current/smbase/make-preproc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/make-preproc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+#!/bin/sh
+# this builds preprocessed copies of all the C++ source;
+# it's really part of the C++ parser testing suite, but
+# it's most convenient to have it in this directory
+
+set -e
+set -x
+
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  breaker.cpp -o breaker.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  crc.cpp -o crc.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  datablok.cpp -o datablok.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  exc.cpp -o exc.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  missing.cpp -o missing.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  nonport.cpp -o nonport.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  str.cpp -o str.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  syserr.cpp -o syserr.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  voidlist.cc -o voidlist.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  warn.cpp -o warn.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  bit2d.cc -o bit2d.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  point.cc -o point.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  growbuf.cc -o growbuf.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  strtokp.cpp -o strtokp.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  strutil.cc -o strutil.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  strdict.cc -o strdict.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  svdict.cc -o svdict.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  strhash.cc -o strhash.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  hashtbl.cc -o hashtbl.i
+
+# don't try malloc, because it's C code and doesn't
+# know that 'wchar_t' is a built-in
+#cpp -DNO_DEBUG -DNO_TRACE_MALLOC_CALLS -DNO_DEBUG_HEAP malloc.c -o malloc.i
+
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  trdelete.cc -o trdelete.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  flatten.cc -o flatten.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  bflatten.cc -o bflatten.i
+cpp mysig.cc -o mysig.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  trace.cc -o trace.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  vdtllist.cc -o vdtllist.i
+cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  stringset.cc -o stringset.i
+
+# same as for malloc
+#cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  mypopen.c -o mypopen.i
+#cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  unixutil.c -o unixutil.i
+#cpp -D__LINUX__ -D__UNIX__ -DNDEBUG  cycles.c -o cycles.i


Property changes on: vendor/elsa/current/smbase/make-preproc
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/malloc.c
===================================================================
--- vendor/elsa/current/smbase/malloc.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/malloc.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,5814 @@
+/*
+  This is a version (aka dlmalloc) of malloc/free/realloc written by
+  Doug Lea and released to the public domain.  Use, modify, and
+  redistribute this code without permission or acknowledgement in any
+  way you wish.  Send questions, comments, complaints, performance
+  data, etc to dl at cs.oswego.edu
+
+* VERSION 2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+           ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+         Check before installing!
+
+* Quickstart
+
+  This library is all in one file to simplify the most common usage:
+  ftp it, compile it (-O), and link it into another program. All
+  of the compile-time options default to reasonable values for use on
+  most unix platforms. Compile -DWIN32 for reasonable defaults on windows.
+  You might later want to step through various compile-time and dynamic
+  tuning options.
+
+  For convenience, an include file for code using this malloc is at:
+     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.7.0.h
+  You don't really need this .h file unless you call functions not
+  defined in your system include files.  The .h file contains only the
+  excerpts from this file needed for using this malloc on ANSI C/C++
+  systems, so long as you haven't changed compile-time options about
+  naming and tuning parameters.  If you do, then you can create your
+  own malloc.h that does include all settings by cutting at the point
+  indicated below.
+
+* Why use this malloc?
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and tunable.
+  Consistent balance across these factors results in a good general-purpose
+  allocator for malloc-intensive programs.
+
+  The main properties of the algorithms are:
+  * For large (>= 512 bytes) requests, it is a pure best-fit allocator,
+    with ties normally decided via FIFO (i.e. least recently used).
+  * For small (<= 64 bytes by default) requests, it is a caching
+    allocator, that maintains pools of quickly recycled chunks.
+  * In between, and for combinations of large and small requests, it does
+    the best it can trying to meet both goals at once.
+  * For very large requests (>= 128KB by default), it relies on system
+    memory mapping facilities, if supported.
+
+  For a longer but slightly out of date high-level description, see
+     http://gee.cs.oswego.edu/dl/html/malloc.html
+
+  You may already by default be using a C library containing a malloc
+  that is  based on some version of this malloc (for example in
+  linux). You might still want to use the one in this file in order to
+  customize settings or to avoid overheads associated with library
+  versions.
+
+* Contents, described in more detail in "description of public routines" below.
+
+  Standard (ANSI/SVID/...)  functions:
+    malloc(size_t n);
+    calloc(size_t n_elements, size_t element_size);
+    free(Void_t* p);
+    realloc(Void_t* p, size_t n);
+    memalign(size_t alignment, size_t n);
+    valloc(size_t n);
+    mallinfo()
+    mallopt(int parameter_number, int parameter_value)
+
+  Additional functions:
+    independent_calloc(size_t n_elements, size_t size, Void_t* chunks[]);
+    independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]);
+    pvalloc(size_t n);
+    cfree(Void_t* p);
+    malloc_trim(size_t pad);
+    malloc_usable_size(Void_t* p);
+    malloc_stats();
+
+* Vital statistics:
+
+  Supported pointer representation:       4 or 8 bytes
+  Supported size_t  representation:       4 or 8 bytes 
+       Note that size_t is allowed to be 4 bytes even if pointers are 8.
+       You can adjust this by defining INTERNAL_SIZE_T
+
+  Alignment:                              2 * sizeof(size_t) (default)
+       (i.e., 8 byte alignment with 4byte size_t). This suffices for
+       nearly all current machines and C compilers. However, you can
+       define MALLOC_ALIGNMENT to be wider than this if necessary.
+
+  Minimum overhead per allocated chunk:   4 or 8 bytes
+       Each malloced chunk has a hidden word of overhead holding size
+       and status information.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
+                          8-byte ptrs:  24/32 bytes (including, 4/8 overhead)
+
+       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+       needed; 4 (8) for a trailing size field and 8 (16) bytes for
+       free list pointers. Thus, the minimum allocatable size is
+       16/24/32 bytes.
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+
+       The maximum overhead wastage (i.e., number of extra bytes
+       allocated than were requested in malloc) is less than or equal
+       to the minimum size, except for requests >= mmap_threshold that
+       are serviced via mmap(), where the worst case wastage is 2 *
+       sizeof(size_t) bytes plus the remainder from a system page (the
+       minimal mmap unit); typically 4096 or 8192 bytes.
+
+  Maximum allocated size:  4-byte size_t: 2^32 minus about two pages 
+                           8-byte size_t: 2^64 minus about two pages
+
+       It is assumed that (possibly signed) size_t values suffice to
+       represent chunk sizes. `Possibly signed' is due to the fact
+       that `size_t' may be defined on a system as either a signed or
+       an unsigned type. The ISO C standard says that it must be
+       unsigned, but a few systems are known not to adhere to this.
+       Additionally, even when size_t is unsigned, sbrk (which is by
+       default used to obtain memory from system) accepts signed
+       arguments, and may not be able to handle size_t-wide arguments
+       with negative sign bit.  Generally, values that would
+       appear as negative after accounting for overhead and alignment
+       are supported only via mmap(), which does not have this
+       limitation.
+
+       Requests for sizes outside the allowed range will perform an optional
+       failure action and then return null. (Requests may also
+       also fail because a system is out of memory.)
+
+  Thread-safety: NOT thread-safe unless USE_MALLOC_LOCK defined
+
+       When USE_MALLOC_LOCK is defined, wrappers are created to
+       surround every public call with either a pthread mutex or
+       a win32 spinlock (depending on WIN32). This is not
+       especially fast, and can be a major bottleneck.
+       It is designed only to provide minimal protection
+       in concurrent environments, and to provide a basis for
+       extensions.  If you are using malloc in a concurrent program,
+       you would be far better off obtaining ptmalloc, which is
+       derived from a version of this malloc, and is well-tuned for
+       concurrent programs. (See http://www.malloc.de)
+
+  Compliance: I believe it is compliant with the 1997 Single Unix Specification
+       (See http://www.opennc.org). Also SVID/XPG, ANSI C, and probably 
+       others as well.
+
+* Synopsis of compile-time options:
+
+    People have reported using previous versions of this malloc on all
+    versions of Unix, sometimes by tweaking some of the defines
+    below. It has been tested most extensively on Solaris and
+    Linux. It is also reported to work on WIN32 platforms.
+    People also report using it in stand-alone embedded systems.
+
+    The implementation is in straight, hand-tuned ANSI C.  It is not
+    at all modular. (Sorry!)  It uses a lot of macros.  To be at all
+    usable, this code should be compiled using an optimizing compiler
+    (for example gcc -O3) that can simplify expressions and control
+    paths. (FAQ: some macros import variables as arguments rather than
+    declare locals because people reported that some debuggers
+    otherwise get confused.)
+
+    OPTION                     DEFAULT VALUE
+
+    Compilation Environment options:
+
+    __STD_C                    derived from C compiler defines
+    WIN32                      NOT defined
+    HAVE_MEMCPY                defined
+    USE_MEMCPY                 1 if HAVE_MEMCPY is defined
+    HAVE_MMAP                  defined as 1 
+    MMAP_CLEARS                1
+    HAVE_MREMAP                0 unless linux defined
+    malloc_getpagesize         derived from system #includes, or 4096 if not
+    HAVE_USR_INCLUDE_MALLOC_H  NOT defined
+    LACKS_UNISTD_H             NOT defined unless WIN32
+    LACKS_SYS_PARAM_H          NOT defined unless WIN32
+    LACKS_SYS_MMAN_H           NOT defined unless WIN32
+
+    Changing default word sizes:
+
+    INTERNAL_SIZE_T            size_t
+    MALLOC_ALIGNMENT           2 * sizeof(INTERNAL_SIZE_T)
+
+    Configuration and functionality options:
+
+    USE_DL_PREFIX              NOT defined
+    USE_PUBLIC_MALLOC_WRAPPERS NOT defined
+    USE_MALLOC_LOCK            NOT defined
+    DEBUG                      NOT defined
+    REALLOC_ZERO_BYTES_FREES   NOT defined
+    MALLOC_FAILURE_ACTION      errno = ENOMEM, if __STD_C defined, else no-op
+    TRIM_FASTBINS              0
+
+    Options for customizing MORECORE:
+
+    MORECORE                   sbrk
+    MORECORE_CONTIGUOUS        1 
+    MORECORE_CANNOT_TRIM       NOT defined
+    MMAP_AS_MORECORE_SIZE      (1024 * 1024) 
+
+    Tuning options that are also dynamically changeable via mallopt:
+
+    DEFAULT_MXFAST             64
+    DEFAULT_TRIM_THRESHOLD     128 * 1024
+    DEFAULT_TOP_PAD            0
+    DEFAULT_MMAP_THRESHOLD     128 * 1024
+    DEFAULT_MMAP_MAX           65536
+
+    There are several other #defined constants and macros that you
+    probably don't want to touch unless you are extending or adapting malloc.
+*/
+
+/*
+  WIN32 sets up defaults for MS environment and compilers.
+  Otherwise defaults are for unix.
+*/
+
+/* #define WIN32 */
+
+// sm: the cygwin-supplied gcc defines __CYGWIN__, so I'll
+// use that to imply WIN32
+#ifdef __CYGWIN__
+  #define WIN32
+#endif
+
+#ifdef WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* Win32 doesn't supply or need the following headers */
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+#define LACKS_SYS_MMAN_H
+
+/* Use the supplied emulation of sbrk */
+#define MORECORE sbrk
+#define MORECORE_CONTIGUOUS 1
+#define MORECORE_FAILURE    ((void*)(-1))
+
+/* Use the supplied emulation of mmap and munmap */
+#define HAVE_MMAP 1
+#define MUNMAP_FAILURE  (-1)
+#define MMAP_CLEARS 1
+
+/* These values don't really matter in windows mmap emulation */
+#define MAP_PRIVATE 1
+#define MAP_ANONYMOUS 2
+#define PROT_READ 1
+#define PROT_WRITE 2
+
+/* Emulation functions defined at the end of this file */
+
+/* If USE_MALLOC_LOCK, use supplied critical-section-based lock functions */
+#ifdef USE_MALLOC_LOCK
+static int slwait(int *sl);
+static int slrelease(int *sl);
+#endif
+
+static long getpagesize(void);
+static long getregionsize(void);
+static void *sbrk(long size);
+static void *mmap(void *ptr, long size, long prot, long type, long handle, long arg);
+static long munmap(void *ptr, long size);
+
+static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed);
+static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user);
+
+#endif
+
+/*
+  __STD_C should be nonzero if using ANSI-standard C compiler, a C++
+  compiler, or a C compiler sufficiently close to ANSI to get away
+  with it.
+*/
+
+#ifndef __STD_C
+#if defined(__STDC__) || defined(_cplusplus)
+#define __STD_C     1
+#else
+#define __STD_C     0
+#endif 
+#endif /*__STD_C*/
+
+
+/*
+  Void_t* is the pointer type that malloc should say it returns
+*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t      void
+#else
+#define Void_t      char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h>   /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* define LACKS_UNISTD_H if your system does not have a <unistd.h>. */
+
+/* #define  LACKS_UNISTD_H */
+
+#ifndef LACKS_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* define LACKS_SYS_PARAM_H if your system does not have a <sys/param.h>. */
+
+/* #define  LACKS_SYS_PARAM_H */
+
+
+#include <stdio.h>    /* needed for malloc_stats */
+#include <errno.h>    /* needed for optional MALLOC_FAILURE_ACTION */
+
+
+/*
+  Debugging:
+
+  Because freed chunks may be overwritten with bookkeeping fields, this
+  malloc will often die when freed memory is overwritten by user
+  programs.  This can be very effective (albeit in an annoying way)
+  in helping track down dangling pointers.
+
+  If you compile with -DDEBUG, a number of assertion checks are
+  enabled that will catch more memory errors. You probably won't be
+  able to make much sense of the actual assertion errors, but they
+  should help you locate incorrectly overwritten memory.  The
+  checking is fairly extensive, and will slow down execution
+  noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+  attempt to check every non-mmapped allocated and free chunk in the
+  course of computing the summmaries. (By nature, mmapped regions
+  cannot be checked very much automatically.)
+
+  Setting DEBUG may also be helpful if you are trying to modify
+  this code. The assertions in the check routines spell out in more
+  detail the assumptions and invariants underlying the algorithms.
+
+  Setting DEBUG does NOT provide an automated mechanism for checking
+  that all accesses to malloced memory stay within their
+  bounds. However, there are several add-ons and adaptations of this
+  or other mallocs available that do this.
+*/
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+
+/*
+  INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+  of chunk sizes.
+
+  The default version is the same as size_t.
+
+  While not strictly necessary, it is best to define this as an
+  unsigned type, even if size_t is a signed type. This may avoid some
+  artificial size limitations on some systems.
+
+  On a 64-bit machine, you may be able to reduce malloc overhead by
+  defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the
+  expense of not being able to handle more than 2^32 of malloced
+  space. If this limitation is acceptable, you are encouraged to set
+  this unless you are on a platform requiring 16byte alignments. In
+  this case the alignment requirements turn out to negate any
+  potential advantages of decreasing size_t word size.
+
+  Implementors: Beware of the possible combinations of:
+     - INTERNAL_SIZE_T might be signed or unsigned, might be 32 or 64 bits,
+       and might be the same width as int or as long
+     - size_t might have different width and signedness as INTERNAL_SIZE_T
+     - int and long might be 32 or 64 bits, and might be the same width
+  To deal with this, most comparisons and difference computations
+  among INTERNAL_SIZE_Ts should cast them to unsigned long, being
+  aware of the fact that casting an unsigned int to a wider long does
+  not sign-extend. (This also makes checking for negative numbers
+  awkward.) Some of these casts result in harmless compiler warnings
+  on some systems.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/* The corresponding word size */
+#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))
+
+
+/*
+  MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks.
+  It must be a power of two at least 2 * SIZE_SZ, even on machines
+  for which smaller alignments would suffice. It may be defined as
+  larger than this though. Note however that code and data structures
+  are optimized for the case of 8-byte alignment.
+*/
+
+
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT       (2 * SIZE_SZ)
+#endif
+
+/* The corresponding bit mask value */
+#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1)
+
+
+
+/*
+  REALLOC_ZERO_BYTES_FREES should be set if a call to
+  realloc with zero bytes should be the same as a call to free.
+  Some people think it should. Otherwise, since this malloc
+  returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+/*   #define REALLOC_ZERO_BYTES_FREES */
+
+/*
+  TRIM_FASTBINS controls whether free() of a very small chunk can
+  immediately lead to trimming. Setting to true (1) can reduce memory
+  footprint, but will almost always slow down programs that use a lot
+  of small chunks.
+
+  Define this only if you are willing to give up some speed to more
+  aggressively reduce system-level memory footprint when releasing
+  memory in programs that use many small chunks.  You can get
+  essentially the same effect by setting MXFAST to 0, but this can
+  lead to even greater slowdowns in programs using many small chunks.
+  TRIM_FASTBINS is an in-between compile-time option, that disables
+  only those chunks bordering topmost memory from being placed in
+  fastbins.
+*/
+
+#ifndef TRIM_FASTBINS
+#define TRIM_FASTBINS  0
+#endif
+
+
+/*
+  USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+  This is necessary when you only want to use this malloc in one part 
+  of a program, using your regular system malloc elsewhere.
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+  USE_MALLOC_LOCK causes wrapper functions to surround each
+  callable routine with pthread mutex lock/unlock.
+
+  USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined
+*/
+
+
+/* #define USE_MALLOC_LOCK */
+
+
+/*
+  If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is
+  actually a wrapper function that first calls MALLOC_PREACTION, then
+  calls the internal routine, and follows it with
+  MALLOC_POSTACTION. This is needed for locking, but you can also use
+  this, without USE_MALLOC_LOCK, for purposes of interception,
+  instrumentation, etc. It is a sad fact that using wrappers often
+  noticeably degrades performance of malloc-intensive programs.
+*/
+
+#ifdef USE_MALLOC_LOCK
+#define USE_PUBLIC_MALLOC_WRAPPERS
+#else
+/* #define USE_PUBLIC_MALLOC_WRAPPERS */
+#endif
+
+
+// sm: my flag: even more debugging checks
+#ifdef DEBUG_HEAP
+  #define USE_PUBLIC_MALLOC_WRAPPERS
+  #define ZONE_SIZE 128     // bytes
+#endif // DEBUG_HEAP
+
+
+/* 
+   Two-phase name translation.
+   All of the actual routines are given mangled names.
+   When wrappers are used, they become the public callable versions.
+   When DL_PREFIX is used, the callable names are prefixed.
+*/
+
+#ifndef USE_PUBLIC_MALLOC_WRAPPERS
+#define cALLOc      public_cALLOc
+#define fREe        public_fREe
+#define cFREe       public_cFREe
+#define mALLOc      public_mALLOc
+#define mEMALIGn    public_mEMALIGn
+#define rEALLOc     public_rEALLOc
+#define vALLOc      public_vALLOc
+#define pVALLOc     public_pVALLOc
+#define mALLINFo    public_mALLINFo
+#define mALLOPt     public_mALLOPt
+#define mTRIm       public_mTRIm
+#define mSTATs      public_mSTATs
+#define mUSABLe     public_mUSABLe
+#define iCALLOc     public_iCALLOc
+#define iCOMALLOc   public_iCOMALLOc
+#endif
+
+#ifdef USE_DL_PREFIX
+#define public_cALLOc    dlcalloc
+#define public_fREe      dlfree
+#define public_cFREe     dlcfree
+#define public_mALLOc    dlmalloc
+#define public_mEMALIGn  dlmemalign
+#define public_rEALLOc   dlrealloc
+#define public_vALLOc    dlvalloc
+#define public_pVALLOc   dlpvalloc
+#define public_mALLINFo  dlmallinfo
+#define public_mALLOPt   dlmallopt
+#define public_mTRIm     dlmalloc_trim
+#define public_mSTATs    dlmalloc_stats
+#define public_mUSABLe   dlmalloc_usable_size
+#define public_iCALLOc   dlindependent_calloc
+#define public_iCOMALLOc dlindependent_comalloc
+#else /* USE_DL_PREFIX */
+#define public_cALLOc    calloc
+#define public_fREe      free
+#define public_cFREe     cfree
+#define public_mALLOc    malloc
+#define public_mEMALIGn  memalign
+#define public_rEALLOc   realloc
+#define public_vALLOc    valloc
+#define public_pVALLOc   pvalloc
+#define public_mALLINFo  mallinfo
+#define public_mALLOPt   mallopt
+#define public_mTRIm     malloc_trim
+#define public_mSTATs    malloc_stats
+#define public_mUSABLe   malloc_usable_size
+#define public_iCALLOc   independent_calloc
+#define public_iCOMALLOc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+  HAVE_MEMCPY should be defined if you are not otherwise using
+  ANSI STD C, but still have memcpy and memset in your C library
+  and want to use them in calloc and realloc. Otherwise simple
+  macro versions are defined below.
+
+  USE_MEMCPY should be defined as 1 if you actually want to
+  have memset and memcpy called. People report that the macro
+  versions are faster than libc versions on some systems.
+  
+  Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks
+  (of <= 36 bytes) are manually unrolled in realloc and calloc.
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#ifdef WIN32
+/* On Win32 memset and memcpy are already declared in windows.h */
+#else
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+/*
+  MALLOC_FAILURE_ACTION is the action to take before "return 0" when
+  malloc fails to be able to return memory, either because memory is
+  exhausted or because of illegal arguments.
+  
+  By default, sets errno if running on STD_C platform, else does nothing.  
+*/
+
+#ifndef MALLOC_FAILURE_ACTION
+#if __STD_C
+#define MALLOC_FAILURE_ACTION \
+   errno = ENOMEM;
+
+#else
+#define MALLOC_FAILURE_ACTION
+#endif
+#endif
+
+/*
+  MORECORE-related declarations. By default, rely on sbrk
+*/
+
+
+#ifdef LACKS_UNISTD_H
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__CYGWIN__)
+#if __STD_C
+extern Void_t*     sbrk(ptrdiff_t);
+#else
+extern Void_t*     sbrk();
+#endif
+#endif
+#endif
+
+/*
+  MORECORE is the name of the routine to call to obtain more memory
+  from the system.  See below for general guidance on writing
+  alternative MORECORE functions, as well as a version for WIN32 and a
+  sample version for pre-OSX macos.
+*/
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+/*
+  MORECORE_FAILURE is the value returned upon failure of MORECORE
+  as well as mmap. Since it cannot be an otherwise valid memory address,
+  and must reflect values of standard sys calls, you probably ought not
+  try to redefine it.
+*/
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE (-1)
+#endif
+
+/*
+  If MORECORE_CONTIGUOUS is true, take advantage of fact that
+  consecutive calls to MORECORE with positive arguments always return
+  contiguous increasing addresses.  This is true of unix sbrk.  Even
+  if not defined, when regions happen to be contiguous, malloc will
+  permit allocations spanning regions obtained from different
+  calls. But defining this when applicable enables some stronger
+  consistency checks and space efficiencies.
+*/
+
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif
+
+/*
+  Define MORECORE_CANNOT_TRIM if your version of MORECORE
+  cannot release space back to the system when given negative
+  arguments. This is generally necessary only if you are using
+  a hand-crafted MORECORE function that cannot handle negative arguments.
+*/
+
+/* #define MORECORE_CANNOT_TRIM */
+
+
+/*
+  Define HAVE_MMAP as true to optionally make malloc() use mmap() to
+  allocate very large blocks.  These will be returned to the
+  operating system immediately after a free(). Also, if mmap
+  is available, it is used as a backup strategy in cases where
+  MORECORE fails to provide space from system.
+
+  This malloc is best tuned to work with mmap for large requests.
+  If you do not have mmap, operations involving very large chunks (1MB
+  or so) may be slower than you'd like.
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+
+/* 
+   Standard unix mmap using /dev/zero clears memory so calloc doesn't
+   need to.
+*/
+
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif
+
+#else /* no mmap */
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 0
+#endif
+#endif
+
+
+/* 
+   MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if
+   sbrk fails, and mmap is used as a backup (which is done only if
+   HAVE_MMAP).  The value must be a multiple of page size.  This
+   backup strategy generally applies only when systems have "holes" in
+   address space, so sbrk cannot perform contiguous expansion, but
+   there is still space available on system.  On systems for which
+   this is known to be useful (i.e. most linux kernels), this occurs
+   only when programs allocate huge amounts of memory.  Between this,
+   and the fact that mmap regions tend to be limited, the size should
+   be large, to avoid too many mmap calls and thus avoid running out
+   of kernel resources.
+*/
+
+#ifndef MMAP_AS_MORECORE_SIZE
+#define MMAP_AS_MORECORE_SIZE (1024 * 1024)
+#endif
+
+/*
+  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+  large blocks.  This is currently only possible on Linux with
+  kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef linux
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+
+#endif /* HAVE_MMAP */
+
+
+/*
+  The system page size. To the extent possible, this malloc manages
+  memory from the system in page-size units.  Note that this value is
+  cached during initialization into a field of malloc_state. So even
+  if malloc_getpagesize is a function, it is only called once.
+
+  The following mechanics for getpagesize were adapted from bsd/gnu
+  getpagesize.h. If none of the system-probes here apply, a value of
+  4096 is used, which should be OK: If they don't apply, then using
+  the actual value probably doesn't impact performance.
+*/
+
+
+#ifndef malloc_getpagesize
+
+#ifndef LACKS_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32 /* use supplied emulation of getpagesize */
+#        define malloc_getpagesize getpagesize() 
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else /* just guess */
+#                define malloc_getpagesize (4096) 
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/*
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing usage properties and
+  statistics. It should work on any SVID/XPG compliant system that has
+  a /usr/include/malloc.h defining struct mallinfo. (If you'd like to
+  install such a thing yourself, cut out the preliminary declarations
+  as described above and below and save them in a malloc.h file. But
+  there's no compelling reason to bother to do this.)
+
+  The main declaration needed is the mallinfo struct that is returned
+  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a
+  bunch of field that are not even meaningful in this version of
+  malloc.  These fields are are instead filled by mallinfo() with
+  other numbers that might be of interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else an SVID2/XPG2 compliant
+  version is declared below.  These must be precisely the same for
+  mallinfo() to work.  The original SVID version of this struct,
+  defined on most systems with mallinfo, declares all fields as
+  ints. But some others define as unsigned long. If your system
+  defines the fields using a type of different width than listed here,
+  you must #include your system version and #define
+  HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#ifdef HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+  int arena;    /* non-mmapped space allocated from system */
+  int ordblks;  /* number of free chunks */
+  int smblks;   /* number of fastbin blocks */
+  int hblks;    /* number of mmapped regions */
+  int hblkhd;   /* space in mmapped regions */
+  int usmblks;  /* maximum total allocated space */
+  int fsmblks;  /* space available in freed fastbin blocks */
+  int uordblks; /* total allocated space */
+  int fordblks; /* total free space */
+  int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/*
+  SVID/XPG defines four standard parameter numbers for mallopt,
+  normally defined in malloc.h.  Only one of these (M_MXFAST) is used
+  in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+  so setting them has no effect. But this malloc also supports other
+  options in mallopt described below.
+*/
+#endif
+
+
+/* ---------- description of public routines ------------ */
+
+/*
+  malloc(size_t n)
+  Returns a pointer to a newly allocated chunk of at least n bytes, or null
+  if no space is available. Additionally, on failure, errno is
+  set to ENOMEM on ANSI C systems.
+
+  If n is zero, malloc returns a minumum-sized chunk. (The minimum
+  size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit
+  systems.)  On most systems, size_t is an unsigned type, so calls
+  with negative arguments are interpreted as requests for huge amounts
+  of space, which will often fail. The maximum supported value of n
+  differs across systems, but is in all cases less than the maximum
+  representable value of a size_t.
+*/
+#if __STD_C
+Void_t*  public_mALLOc(size_t);
+#else
+Void_t*  public_mALLOc();
+#endif
+
+/*
+  free(Void_t* p)
+  Releases the chunk of memory pointed to by p, that had been previously
+  allocated using malloc or a related routine such as realloc.
+  It has no effect if p is null. It can have arbitrary (i.e., bad!)
+  effects if p has already been freed.
+
+  Unless disabled (using mallopt), freeing very large spaces will
+  when possible, automatically trigger operations that give
+  back unused memory to the system, thus reducing program footprint.
+*/
+#if __STD_C
+void     public_fREe(Void_t*);
+#else
+void     public_fREe();
+#endif
+
+/*
+  calloc(size_t n_elements, size_t element_size);
+  Returns a pointer to n_elements * element_size bytes, with all locations
+  set to zero.
+*/
+#if __STD_C
+Void_t*  public_cALLOc(size_t, size_t);
+#else
+Void_t*  public_cALLOc();
+#endif
+
+/*
+  realloc(Void_t* p, size_t n)
+  Returns a pointer to a chunk of size n that contains the same data
+  as does chunk p up to the minimum of (n, p's size) bytes, or null
+  if no space is available. 
+
+  The returned pointer may or may not be the same as p. The algorithm
+  prefers extending p when possible, otherwise it employs the
+  equivalent of a malloc-copy-free sequence.
+
+  If p is null, realloc is equivalent to malloc.  
+
+  If space is not available, realloc returns null, errno is set (if on
+  ANSI) and p is NOT freed.
+
+  if n is for fewer bytes than already held by p, the newly unused
+  space is lopped off and freed if possible.  Unless the #define
+  REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of
+  zero (re)allocates a minimum-sized chunk.
+
+  Large chunks that were internally obtained via mmap will always
+  be reallocated using malloc-copy-free sequences unless
+  the system supports MREMAP (currently only linux).
+
+  The old unix realloc convention of allowing the last-free'd chunk
+  to be used as an argument to realloc is not supported.
+*/
+#if __STD_C
+Void_t*  public_rEALLOc(Void_t*, size_t);
+#else
+Void_t*  public_rEALLOc();
+#endif
+
+/*
+  memalign(size_t alignment, size_t n);
+  Returns a pointer to a newly allocated chunk of n bytes, aligned
+  in accord with the alignment argument.
+
+  The alignment argument should be a power of two. If the argument is
+  not a power of two, the nearest greater power is used.
+  8-byte alignment is guaranteed by normal malloc calls, so don't
+  bother calling memalign with an argument of 8 or less.
+
+  Overreliance on memalign is a sure way to fragment space.
+*/
+#if __STD_C
+Void_t*  public_mEMALIGn(size_t, size_t);
+#else
+Void_t*  public_mEMALIGn();
+#endif
+
+/*
+  valloc(size_t n);
+  Equivalent to memalign(pagesize, n), where pagesize is the page
+  size of the system. If the pagesize is unknown, 4096 is used.
+*/
+#if __STD_C
+Void_t*  public_vALLOc(size_t);
+#else
+Void_t*  public_vALLOc();
+#endif
+
+
+
+/*
+  mallopt(int parameter_number, int parameter_value)
+  Sets tunable parameters The format is to provide a
+  (parameter-number, parameter-value) pair.  mallopt then sets the
+  corresponding parameter to the argument value if it can (i.e., so
+  long as the value is meaningful), and returns 1 if successful else
+  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,
+  normally defined in malloc.h.  Only one of these (M_MXFAST) is used
+  in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+  so setting them has no effect. But this malloc also supports four
+  other options in mallopt. See below for details.  Briefly, supported
+  parameters are as follows (listed defaults are for "typical"
+  configurations).
+
+  Symbol            param #   default    allowed param values
+  M_MXFAST          1         64         0-80  (0 disables fastbins)
+  M_TRIM_THRESHOLD -1         128*1024   any   (-1U disables trimming)
+  M_TOP_PAD        -2         0          any  
+  M_MMAP_THRESHOLD -3         128*1024   any   (or 0 if no MMAP support)
+  M_MMAP_MAX       -4         65536      any   (0 disables use of mmap)
+*/
+#if __STD_C
+int      public_mALLOPt(int, int);
+#else
+int      public_mALLOPt();
+#endif
+
+
+/*
+  mallinfo()
+  Returns (by copy) a struct containing various summary statistics:
+
+  arena:     current total non-mmapped bytes allocated from system 
+  ordblks:   the number of free chunks 
+  smblks:    the number of fastbin blocks (i.e., small chunks that
+               have been freed but not use resused or consolidated)
+  hblks:     current number of mmapped regions 
+  hblkhd:    total bytes held in mmapped regions 
+  usmblks:   the maximum total allocated space. This will be greater
+                than current total if trimming has occurred.
+  fsmblks:   total bytes held in fastbin blocks 
+  uordblks:  current total allocated space (normal or mmapped)
+  fordblks:  total free space 
+  keepcost:  the maximum number of bytes that could ideally be released
+               back to system via malloc_trim. ("ideally" means that
+               it ignores page restrictions etc.)
+
+  Because these fields are ints, but internal bookkeeping may
+  be kept as longs, the reported values may wrap around zero and 
+  thus be inaccurate.
+*/
+#if __STD_C
+struct mallinfo public_mALLINFo(void);
+#else
+struct mallinfo public_mALLINFo();
+#endif
+
+/*
+  independent_calloc(size_t n_elements, size_t element_size, Void_t* chunks[]);
+
+  independent_calloc is similar to calloc, but instead of returning a
+  single cleared space, it returns an array of pointers to n_elements
+  independent elements that can hold contents of size elem_size, each
+  of which starts out cleared, and can be independently freed,
+  realloc'ed etc. The elements are guaranteed to be adjacently
+  allocated (this is not guaranteed to occur with multiple callocs or
+  mallocs), which may also improve cache locality in some
+  applications.
+
+  The "chunks" argument is optional (i.e., may be null, which is
+  probably the most typical usage). If it is null, the returned array
+  is itself dynamically allocated and should also be freed when it is
+  no longer needed. Otherwise, the chunks array must be of at least
+  n_elements in length. It is filled in with the pointers to the
+  chunks.
+
+  In either case, independent_calloc returns this pointer array, or
+  null if the allocation failed.  If n_elements is zero and "chunks"
+  is null, it returns a chunk representing an array with zero elements
+  (which should be freed if not wanted).
+
+  Each element must be individually freed when it is no longer
+  needed. If you'd like to instead be able to free all at once, you
+  should instead use regular calloc and assign pointers into this
+  space to represent elements.  (In this case though, you cannot
+  independently free elements.)
+  
+  independent_calloc simplifies and speeds up implementations of many
+  kinds of pools.  It may also be useful when constructing large data
+  structures that initially have a fixed number of fixed-sized nodes,
+  but the number is not known at compile time, and some of the nodes
+  may later need to be freed. For example:
+
+  struct Node { int item; struct Node* next; };
+  
+  struct Node* build_list() {
+    struct Node** pool;
+    int n = read_number_of_nodes_needed();
+    if (n <= 0) return 0;
+    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+    if (pool == 0) die(); 
+    // organize into a linked list... 
+    struct Node* first = pool[0];
+    for (i = 0; i < n-1; ++i) 
+      pool[i]->next = pool[i+1];
+    free(pool);     // Can now free the array (or not, if it is needed later)
+    return first;
+  }
+*/
+#if __STD_C
+Void_t** public_iCALLOc(size_t, size_t, Void_t**);
+#else
+Void_t** public_iCALLOc();
+#endif
+
+/*
+  independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]);
+
+  independent_comalloc allocates, all at once, a set of n_elements
+  chunks with sizes indicated in the "sizes" array.    It returns
+  an array of pointers to these elements, each of which can be
+  independently freed, realloc'ed etc. The elements are guaranteed to
+  be adjacently allocated (this is not guaranteed to occur with
+  multiple callocs or mallocs), which may also improve cache locality
+  in some applications.
+
+  The "chunks" argument is optional (i.e., may be null). If it is null
+  the returned array is itself dynamically allocated and should also
+  be freed when it is no longer needed. Otherwise, the chunks array
+  must be of at least n_elements in length. It is filled in with the
+  pointers to the chunks.
+
+  In either case, independent_comalloc returns this pointer array, or
+  null if the allocation failed.  If n_elements is zero and chunks is
+  null, it returns a chunk representing an array with zero elements
+  (which should be freed if not wanted).
+  
+  Each element must be individually freed when it is no longer
+  needed. If you'd like to instead be able to free all at once, you
+  should instead use a single regular malloc, and assign pointers at
+  particular offsets in the aggregate space. (In this case though, you 
+  cannot independently free elements.)
+
+  independent_comallac differs from independent_calloc in that each
+  element may have a different size, and also that it does not
+  automatically clear elements.
+
+  independent_comalloc can be used to speed up allocation in cases
+  where several structs or objects must always be allocated at the
+  same time.  For example:
+
+  struct Head { ... }
+  struct Foot { ... }
+
+  void send_message(char* msg) {
+    int msglen = strlen(msg);
+    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+    void* chunks[3];
+    if (independent_comalloc(3, sizes, chunks) == 0)
+      die();
+    struct Head* head = (struct Head*)(chunks[0]);
+    char*        body = (char*)(chunks[1]);
+    struct Foot* foot = (struct Foot*)(chunks[2]);
+    // ...
+  }
+
+  In general though, independent_comalloc is worth using only for
+  larger values of n_elements. For small values, you probably won't
+  detect enough difference from series of malloc calls to bother.
+
+  Overuse of independent_comalloc can increase overall memory usage,
+  since it cannot reuse existing noncontiguous small chunks that
+  might be available for some of the elements.
+*/
+#if __STD_C
+Void_t** public_iCOMALLOc(size_t, size_t*, Void_t**);
+#else
+Void_t** public_iCOMALLOc();
+#endif
+
+
+/*
+  pvalloc(size_t n);
+  Equivalent to valloc(minimum-page-that-holds(n)), that is,
+  round up n to nearest pagesize.
+ */
+#if __STD_C
+Void_t*  public_pVALLOc(size_t);
+#else
+Void_t*  public_pVALLOc();
+#endif
+
+/*
+  cfree(Void_t* p);
+  Equivalent to free(p).
+
+  cfree is needed/defined on some systems that pair it with calloc,
+  for odd historical reasons (such as: cfree is used in example 
+  code in the first edition of K&R).
+*/
+#if __STD_C
+void     public_cFREe(Void_t*);
+#else
+void     public_cFREe();
+#endif
+
+/*
+  malloc_trim(size_t pad);
+
+  If possible, gives memory back to the system (via negative
+  arguments to sbrk) if there is unused memory at the `high' end of
+  the malloc pool. You can call this after freeing large blocks of
+  memory to potentially reduce the system-level memory requirements
+  of a program. However, it cannot guarantee to reduce memory. Under
+  some allocation patterns, some large free blocks of memory will be
+  locked between two used chunks, so they cannot be given back to
+  the system.
+  
+  The `pad' argument to malloc_trim represents the amount of free
+  trailing space to leave untrimmed. If this argument is zero,
+  only the minimum amount of memory to maintain internal data
+  structures will be left (one page or less). Non-zero arguments
+  can be supplied to maintain enough trailing space to service
+  future expected allocations without having to re-obtain memory
+  from the system.
+  
+  Malloc_trim returns 1 if it actually released any memory, else 0.
+  On systems that do not support "negative sbrks", it will always
+  rreturn 0.
+*/
+#if __STD_C
+int      public_mTRIm(size_t);
+#else
+int      public_mTRIm();
+#endif
+
+/*
+  malloc_usable_size(Void_t* p);
+
+  Returns the number of bytes you can actually use in
+  an allocated chunk, which may be more than you requested (although
+  often not) due to alignment and minimum size constraints.
+  You can use this many bytes without worrying about
+  overwriting other allocated objects. This is not a particularly great
+  programming practice. malloc_usable_size can be more useful in
+  debugging and assertions, for example:
+
+  p = malloc(n);
+  assert(malloc_usable_size(p) >= 256);
+
+*/
+#if __STD_C
+size_t   public_mUSABLe(Void_t*);
+#else
+size_t   public_mUSABLe();
+#endif
+
+/*
+  malloc_stats();
+  Prints on stderr the amount of space obtained from the system (both
+  via sbrk and mmap), the maximum amount (which may be more than
+  current if malloc_trim and/or munmap got called), and the current
+  number of bytes allocated via malloc (or realloc, etc) but not yet
+  freed. Note that this is the number of bytes allocated, not the
+  number requested. It will be larger than the number requested
+  because of alignment and bookkeeping overhead. Because it includes
+  alignment wastage as being in use, this figure may be greater than
+  zero even when no user-level chunks are allocated.
+
+  The reported current and maximum system memory can be inaccurate if
+  a program makes other calls to system memory allocation functions
+  (normally sbrk) outside of malloc.
+
+  malloc_stats prints only the most commonly interesting statistics.
+  More information can be obtained by calling mallinfo.
+
+*/
+#if __STD_C
+void     public_mSTATs();
+#else
+void     public_mSTATs();
+#endif
+
+/* mallopt tuning options */
+
+/*
+  M_MXFAST is the maximum request size used for "fastbins", special bins
+  that hold returned chunks without consolidating their spaces. This
+  enables future requests for chunks of the same size to be handled
+  very quickly, but can increase fragmentation, and thus increase the
+  overall memory footprint of a program.
+
+  This malloc manages fastbins very conservatively yet still
+  efficiently, so fragmentation is rarely a problem for values less
+  than or equal to the default.  The maximum supported value of MXFAST
+  is 80. You wouldn't want it any higher than this anyway.  Fastbins
+  are designed especially for use with many small structs, objects or
+  strings -- the default handles structs/objects/arrays with sizes up
+  to 8 4byte fields, or small strings representing words, tokens,
+  etc. Using fastbins for larger objects normally worsens
+  fragmentation without improving speed.
+
+  M_MXFAST is set in REQUEST size units. It is internally used in
+  chunksize units, which adds padding and alignment.  You can reduce
+  M_MXFAST to 0 to disable all use of fastbins.  This causes the malloc
+  algorithm to be a closer approximation of fifo-best-fit in all cases,
+  not just for larger requests, but will generally cause it to be
+  slower.
+*/
+
+
+/* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */
+#ifndef M_MXFAST
+#define M_MXFAST            1    
+#endif
+
+#ifndef DEFAULT_MXFAST
+#define DEFAULT_MXFAST     64
+#endif
+
+
+/*
+  M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+  to keep before releasing via malloc_trim in free().
+
+  Automatic trimming is mainly useful in long-lived programs.
+  Because trimming via sbrk can be slow on some systems, and can
+  sometimes be wasteful (in cases where programs immediately
+  afterward allocate more large chunks) the value should be high
+  enough so that your overall system performance would improve by
+  releasing this much memory.
+
+  The trim threshold and the mmap control parameters (see below)
+  can be traded off with one another. Trimming and mmapping are
+  two different ways of releasing unused memory back to the
+  system. Between these two, it is often possible to keep
+  system-level demands of a long-lived program down to a bare
+  minimum. For example, in one test suite of sessions measuring
+  the XF86 X server on Linux, using a trim threshold of 128K and a
+  mmap threshold of 192K led to near-minimal long term resource
+  consumption.
+
+  If you are using this malloc in a long-lived program, it should
+  pay to experiment with these values.  As a rough guide, you
+  might set to a value close to the average size of a process
+  (program) running on your system.  Releasing this much memory
+  would allow such a process to run in memory.  Generally, it's
+  worth it to tune for trimming rather tham memory mapping when a
+  program undergoes phases where several large chunks are
+  allocated and released in ways that can reuse each other's
+  storage, perhaps mixed with phases where there are no such
+  chunks at all.  And in well-behaved long-lived programs,
+  controlling release of large blocks via trimming versus mapping
+  is usually faster.
+
+  However, in most programs, these parameters serve mainly as
+  protection against the system-level effects of carrying around
+  massive amounts of unneeded memory. Since frequent calls to
+  sbrk, mmap, and munmap otherwise degrade performance, the default
+  parameters are set to relatively high values that serve only as
+  safeguards.
+
+  The trim value It must be greater than page size to have any useful
+  effect.  To disable trimming completely, you can set to 
+  (unsigned long)(-1)
+
+  Trim settings interact with fastbin (MXFAST) settings: Unless
+  TRIM_FASTBINS is defined, automatic trimming never takes place upon
+  freeing a chunk with size less than or equal to MXFAST. Trimming is
+  instead delayed until subsequent freeing of larger chunks. However,
+  you can still force an attempted trim by calling malloc_trim.
+
+  Also, trimming is not generally possible in cases where
+  the main arena is obtained via mmap.
+
+  Note that the trick some people use of mallocing a huge space and
+  then freeing it at program startup, in an attempt to reserve system
+  memory, doesn't have the intended effect under automatic trimming,
+  since that memory will immediately be returned to the system.
+*/
+
+#define M_TRIM_THRESHOLD       -1
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+  M_TOP_PAD is the amount of extra `padding' space to allocate or
+  retain whenever sbrk is called. It is used in two ways internally:
+
+  * When sbrk is called to extend the top of the arena to satisfy
+  a new malloc request, this much padding is added to the sbrk
+  request.
+
+  * When malloc_trim is called automatically from free(),
+  it is used as the `pad' argument.
+
+  In both cases, the actual amount of padding is rounded
+  so that the end of the arena is always a system page boundary.
+
+  The main reason for using padding is to avoid calling sbrk so
+  often. Having even a small pad greatly reduces the likelihood
+  that nearly every malloc request during program start-up (or
+  after trimming) will invoke sbrk, which needlessly wastes
+  time.
+
+  Automatic rounding-up to page-size units is normally sufficient
+  to avoid measurable overhead, so the default is 0.  However, in
+  systems where sbrk is relatively slow, it can pay to increase
+  this value, at the expense of carrying around more memory than
+  the program needs.
+*/
+
+#define M_TOP_PAD              -2
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD        (0)
+#endif
+
+/*
+  M_MMAP_THRESHOLD is the request size threshold for using mmap()
+  to service a request. Requests of at least this size that cannot
+  be allocated using already-existing space will be serviced via mmap.
+  (If enough normal freed space already exists it is used instead.)
+
+  Using mmap segregates relatively large chunks of memory so that
+  they can be individually obtained and released from the host
+  system. A request serviced through mmap is never reused by any
+  other request (at least not directly; the system may just so
+  happen to remap successive requests to the same locations).
+
+  Segregating space in this way has the benefits that:
+
+   1. Mmapped space can ALWAYS be individually released back 
+      to the system, which helps keep the system level memory 
+      demands of a long-lived program low. 
+   2. Mapped memory can never become `locked' between
+      other chunks, as can happen with normally allocated chunks, which
+      means that even trimming via malloc_trim would not release them.
+   3. On some systems with "holes" in address spaces, mmap can obtain
+      memory that sbrk cannot.
+
+  However, it has the disadvantages that:
+
+   1. The space cannot be reclaimed, consolidated, and then
+      used to service later requests, as happens with normal chunks.
+   2. It can lead to more wastage because of mmap page alignment
+      requirements
+   3. It causes malloc performance to be more dependent on host
+      system memory management support routines which may vary in
+      implementation quality and may impose arbitrary
+      limitations. Generally, servicing a request via normal
+      malloc steps is faster than going through a system's mmap.
+
+  The advantages of mmap nearly always outweigh disadvantages for
+  "large" chunks, but the value of "large" varies across systems.  The
+  default is an empirically derived value that works well in most
+  systems.
+*/
+
+#define M_MMAP_THRESHOLD      -3
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+  M_MMAP_MAX is the maximum number of requests to simultaneously
+  service using mmap. This parameter exists because
+. Some systems have a limited number of internal tables for
+  use by mmap, and using more than a few of them may degrade
+  performance.
+
+  The default is set to a value that serves only as a safeguard.
+  Setting to 0 disables use of mmap for servicing large requests.  If
+  HAVE_MMAP is not set, the default value is 0, and attempts to set it
+  to non-zero values in mallopt will fail.
+*/
+
+#define M_MMAP_MAX             -4
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+// sm: I want this to be the size of my mmap ptr array
+#define DEFAULT_MMAP_MAX       (200)
+//#define DEFAULT_MMAP_MAX       (65536)
+#else
+#define DEFAULT_MMAP_MAX       (0)
+#endif
+#endif
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+/* 
+  ========================================================================
+  To make a fully customizable malloc.h header file, cut everything
+  above this line, put into file malloc.h, edit to suit, and #include it 
+  on the next line, as well as in programs that use this malloc.
+  ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/* --------------------- public wrappers ---------------------- */
+
+#ifdef USE_PUBLIC_MALLOC_WRAPPERS
+
+/* Declare all routines as internal */
+#if __STD_C
+static Void_t*  mALLOc(size_t);
+static void     fREe(Void_t*);
+static Void_t*  rEALLOc(Void_t*, size_t);
+static Void_t*  mEMALIGn(size_t, size_t);
+static Void_t*  vALLOc(size_t);
+static Void_t*  pVALLOc(size_t);
+static Void_t*  cALLOc(size_t, size_t);
+static Void_t** iCALLOc(size_t, size_t, Void_t**);
+static Void_t** iCOMALLOc(size_t, size_t*, Void_t**);
+static void     cFREe(Void_t*);
+static int      mTRIm(size_t);
+static size_t   mUSABLe(Void_t*);
+static void     mSTATs();
+static int      mALLOPt(int, int);
+static struct mallinfo mALLINFo(void);
+#else
+static Void_t*  mALLOc();
+static void     fREe();
+static Void_t*  rEALLOc();
+static Void_t*  mEMALIGn();
+static Void_t*  vALLOc();
+static Void_t*  pVALLOc();
+static Void_t*  cALLOc();
+static Void_t** iCALLOc();
+static Void_t** iCOMALLOc();
+static void     cFREe();
+static int      mTRIm();
+static size_t   mUSABLe();
+static void     mSTATs();
+static int      mALLOPt();
+static struct mallinfo mALLINFo();
+#endif
+
+/*
+  MALLOC_PREACTION and MALLOC_POSTACTION should be
+  defined to return 0 on success, and nonzero on failure.
+  The return value of MALLOC_POSTACTION is currently ignored
+  in wrapper functions since there is no reasonable default
+  action to take on failure.
+*/
+
+
+#ifdef USE_MALLOC_LOCK
+
+#ifdef WIN32
+
+static int mALLOC_MUTEx;
+#define MALLOC_PREACTION   slwait(&mALLOC_MUTEx)
+#define MALLOC_POSTACTION  slrelease(&mALLOC_MUTEx)
+
+#else
+
+#include <pthread.h>
+
+static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER;
+
+#define MALLOC_PREACTION   pthread_mutex_lock(&mALLOC_MUTEx)
+#define MALLOC_POSTACTION  pthread_mutex_unlock(&mALLOC_MUTEx)
+
+#endif /* USE_MALLOC_LOCK */
+
+#else
+
+/* Substitute anything you like for these */
+
+#define MALLOC_PREACTION   (0)
+#define MALLOC_POSTACTION  (0)
+
+#endif
+
+Void_t* public_mALLOc(size_t bytes) 
+{
+  Void_t* m;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+
+  // allocate zones on either side, plus a length word up front
+  bytes += 2*ZONE_SIZE + sizeof(size_t);
+
+  m = mALLOc(bytes);
+
+  // write length
+  *((size_t*)m) = bytes;
+
+  // fill rest of area with 0xAA
+  {
+    unsigned char *p = (char*)m;
+    int i;
+    for (i=sizeof(size_t); i<bytes; i++) {
+      p[i] = 0xAA;
+    }
+  }
+
+  if (MALLOC_POSTACTION != 0) {
+  }
+
+  // the user's area is after the size and the first zone
+  return ((char*)m) + sizeof(size_t) + ZONE_SIZE;
+}
+
+static void checkZones(unsigned char *p, int bytes)
+{
+  int i;
+  for (i=0; i<ZONE_SIZE; i++) {
+    if (p[bytes - 1 - i] != 0xAA) {
+      fprintf(stderr, "trashed %d bytes\n", ZONE_SIZE-i);
+      assert(!"right allocated zone trashed");
+    }
+
+    if (p[sizeof(size_t) + i] != 0xAA) {
+      fprintf(stderr, "trashed %d bytes\n", ZONE_SIZE-i);
+      assert(!"left allocated zone trashed");
+    }
+  }
+}
+
+void public_fREe(Void_t* m)
+{
+  int i;
+
+  if (m) {
+    // get back to the real start
+    unsigned char *p = ((char*)m) - ZONE_SIZE - sizeof(size_t);
+
+    // pull off the size
+    size_t bytes = *((size_t*)p);
+
+    // check for one particularly common occurrence
+    if (p[sizeof(size_t)] == 0xBB) {
+      assert(!"double deallocation");
+    }
+
+    // check the zones; should be all 0xAA
+    checkZones(p, bytes);
+
+    // blank the entire area with 0xBB
+    // (except for the size, which I want to keep so I can
+    // check it in checkHeap)
+    for (i=sizeof(size_t); i<bytes; i++) {
+      p[i] = 0xBB;
+    }
+
+    if (MALLOC_PREACTION != 0) {
+      return;
+    }
+    #ifdef DEBUG_HEAP
+      // don't free the memory; but not re-using memory, references
+      // to free'd memory become even more apparent
+    #else
+      // usual mode; free the memory
+      fREe(p);
+    #endif
+    if (MALLOC_POSTACTION != 0) {
+    }
+  }
+}
+
+Void_t* public_rEALLOc(Void_t* m, size_t bytes) {
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  #ifdef DEBUG_HEAP
+    if (!m) {
+      m = public_mALLOc(bytes);
+    }
+    else {
+      // get previous size of user data
+      size_t prevSize = *((size_t*)(m - ZONE_SIZE - sizeof(size_t))) -
+                        (2*ZONE_SIZE + sizeof(size_t));
+
+      // make new mem, copy
+      Void_t *newMem = public_mALLOc(bytes);
+      memcpy(newMem, m, prevSize<bytes? prevSize : bytes);
+      
+      // don't deallocate
+
+      #ifdef TRACE_MALLOC_CALLS
+        fprintf(stderr, "realloc(%p, %d) (prevSize=%d) yielded %p\n",
+                        m, bytes, prevSize, newMem);
+      #endif
+
+      m = newMem;
+    }
+  #else
+    m = rEALLOc(m, bytes);
+  #endif
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return m;
+}
+
+Void_t* public_mEMALIGn(size_t alignment, size_t bytes) {
+  Void_t* m;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  m = mEMALIGn(alignment, bytes);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return m;
+}
+
+Void_t* public_vALLOc(size_t bytes) {
+  Void_t* m;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  m = vALLOc(bytes);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return m;
+}
+
+Void_t* public_pVALLOc(size_t bytes) {
+  Void_t* m;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  m = pVALLOc(bytes);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return m;
+}
+
+Void_t* public_cALLOc(size_t n, size_t elem_size) {
+  Void_t* m;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  m = cALLOc(n, elem_size);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return m;
+}
+
+
+Void_t** public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks) {
+  Void_t** m;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  m = iCALLOc(n, elem_size, chunks);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return m;
+}
+
+Void_t** public_iCOMALLOc(size_t n, size_t sizes[], Void_t** chunks) {
+  Void_t** m;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  m = iCOMALLOc(n, sizes, chunks);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return m;
+}
+
+void public_cFREe(Void_t* m) {
+  if (MALLOC_PREACTION != 0) {
+    return;
+  }
+  cFREe(m);
+  if (MALLOC_POSTACTION != 0) {
+  }
+}
+
+int public_mTRIm(size_t s) {
+  int result;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  result = mTRIm(s);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return result;
+}
+
+size_t public_mUSABLe(Void_t* m) {
+  size_t result;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  result = mUSABLe(m);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return result;
+}
+
+void public_mSTATs() {
+  if (MALLOC_PREACTION != 0) {
+    return;
+  }
+  mSTATs();
+  if (MALLOC_POSTACTION != 0) {
+  }
+}
+
+struct mallinfo public_mALLINFo() {
+  struct mallinfo m;
+  if (MALLOC_PREACTION != 0) {
+    struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    return nm;
+  }
+  m = mALLINFo();
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return m;
+}
+
+int public_mALLOPt(int p, int v) {
+  int result;
+  if (MALLOC_PREACTION != 0) {
+    return 0;
+  }
+  result = mALLOPt(p, v);
+  if (MALLOC_POSTACTION != 0) {
+  }
+  return result;
+}
+
+#endif
+
+
+
+/* ------------- Optional versions of memcopy ---------------- */
+
+
+#if USE_MEMCPY
+
+/* 
+  Note: memcpy is ONLY invoked with non-overlapping regions,
+  so the (usually slower) memmove is not needed.
+*/
+
+#define MALLOC_COPY(dest, src, nbytes)  memcpy(dest, src, nbytes)
+#define MALLOC_ZERO(dest, nbytes)       memset(dest, 0,   nbytes)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp);                           \
+  unsigned long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T);                     \
+  long mcn;                                                                   \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mzp++ = 0;                                             \
+    case 7:           *mzp++ = 0;                                             \
+    case 6:           *mzp++ = 0;                                             \
+    case 5:           *mzp++ = 0;                                             \
+    case 4:           *mzp++ = 0;                                             \
+    case 3:           *mzp++ = 0;                                             \
+    case 2:           *mzp++ = 0;                                             \
+    case 1:           *mzp++ = 0; if(mcn <= 0) break; mcn--; }                \
+  }                                                                           \
+} while(0)
+
+define MALLOC_COPY(dest,src,nbytes)                                           \
+do {                                                                          \
+  INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src;                            \
+  INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest;                           \
+  unsigned long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T);                     \
+  long mcn;                                                                   \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mcdst++ = *mcsrc++;                                    \
+    case 7:           *mcdst++ = *mcsrc++;                                    \
+    case 6:           *mcdst++ = *mcsrc++;                                    \
+    case 5:           *mcdst++ = *mcsrc++;                                    \
+    case 4:           *mcdst++ = *mcsrc++;                                    \
+    case 3:           *mcdst++ = *mcsrc++;                                    \
+    case 2:           *mcdst++ = *mcsrc++;                                    \
+    case 1:           *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; }       \
+  }                                                                           \
+} while(0)
+
+#endif
+
+/* ------------------ MMAP support ------------------  */
+
+
+#if HAVE_MMAP
+
+#include <fcntl.h>
+#ifndef LACKS_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/* 
+   Nearly all versions of mmap support MAP_ANONYMOUS, 
+   so the following is unlikely to be needed, but is
+   supplied just in case.
+*/
+
+#ifndef MAP_ANONYMOUS
+
+static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
+
+#define MMAP(addr, size, prot, flags) ((dev_zero_fd < 0) ? \
+ (dev_zero_fd = open("/dev/zero", O_RDWR), \
+  mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) : \
+   mmap((addr), (size), (prot), (flags), dev_zero_fd, 0))
+
+#else
+
+#define MMAP(addr, size, prot, flags) \
+ (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0))
+
+#endif
+
+
+#endif /* HAVE_MMAP */
+
+
+/*
+  -----------------------  Chunk representations -----------------------
+*/
+
+
+/*
+  This struct declaration is misleading (but accurate and necessary).
+  It declares a "view" into memory allowing access to necessary
+  fields at known offsets from a given base. See explanation below.
+*/
+
+struct malloc_chunk {
+
+  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
+  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */
+
+  struct malloc_chunk* fd;         /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+};
+
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+   malloc_chunk details:
+
+    (The following includes lightly edited explanations by Colin Plumb.)
+
+    Chunks of memory are maintained using a `boundary tag' method as
+    described in e.g., Knuth or Standish.  (See the paper by Paul
+    Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+    survey of such techniques.)  Sizes of free chunks are stored both
+    in the front of each chunk and at the end.  This makes
+    consolidating fragmented chunks into bigger chunks very fast.  The
+    size fields also hold bits representing whether chunks are free or
+    in use.
+
+    An allocated chunk looks like this:
+
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk, if allocated            | |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             User data starts here...                          .
+            .                                                               .
+            .             (malloc_usable_space() bytes)                     .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of chunk                                     |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+    Where "chunk" is the front of the chunk for the purpose of most of
+    the malloc code, but "mem" is the pointer that is returned to the
+    user.  "Nextchunk" is the beginning of the next contiguous chunk.
+
+    Chunks always begin on even word boundries, so the mem portion
+    (which is returned to the user) is also on an even word boundary, and
+    thus at least double-word aligned.
+
+    Free chunks are stored in circular doubly-linked lists, and look like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk in list             |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk in list            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space (may be 0 bytes long)                .
+            .                                                               .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+    chunk size (which is always a multiple of two words), is an in-use
+    bit for the *previous* chunk.  If that bit is *clear*, then the
+    word before the current chunk size contains the previous chunk
+    size, and can be used to find the front of the previous chunk.
+    The very first chunk allocated always has this bit set,
+    preventing access to non-existent (or non-owned) memory. If
+    prev_inuse is set for any given chunk, then you CANNOT determine
+    the size of the previous chunk, and might even get a memory
+    addressing fault when trying to do so.
+
+    Note that the `foot' of the current chunk is actually represented
+    as the prev_size of the NEXT chunk. This makes it easier to
+    deal with alignments etc but can be very confusing when trying
+    to extend or adapt this code.
+
+    The two exceptions to all this are
+
+     1. The special chunk `top' doesn't bother using the
+        trailing size field since there is no next contiguous chunk
+        that would have to index off it. After initialization, `top'
+        is forced to always exist.  If it would become less than
+        MINSIZE bytes long, it is replenished.
+
+     2. Chunks allocated via mmap, which have the second-lowest-order
+        bit (IS_MMAPPED) set in their size fields.  Because they are
+        allocated one-by-one, each must contain its own trailing size field.
+
+*/
+
+/*
+  ---------- Size and alignment checks and conversions ----------
+*/
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p)   ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* The smallest possible chunk */
+#define MIN_CHUNK_SIZE        (sizeof(struct malloc_chunk))
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+
+#define MINSIZE  \
+  (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m)  (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+/* 
+   Check if a request is so large that it would wrap around zero when
+   padded and aligned. To simplify some other code, the bound is made
+   low enough so that adding MINSIZE will also not wrap around sero.
+*/
+
+#define REQUEST_OUT_OF_RANGE(req)                                 \
+  ((unsigned long)(req) >=                                        \
+   (unsigned long)(INTERNAL_SIZE_T)(-2 * MINSIZE))    
+
+/* pad request bytes into a usable size -- internal version */
+
+#define request2size(req)                                         \
+  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             \
+   MINSIZE :                                                      \
+   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
+
+/*  Same, except also perform argument check */
+
+#define checked_request2size(req, sz)                             \
+  if (REQUEST_OUT_OF_RANGE(req)) {                                \
+    MALLOC_FAILURE_ACTION;                                        \
+    return 0;                                                     \
+  }                                                               \
+  (sz) = request2size(req);                                              
+
+/*
+  --------------- Physical chunk operations ---------------
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+#define PREV_INUSE 0x1
+
+/* extract inuse bit of previous chunk */
+#define prev_inuse(p)       ((p)->size & PREV_INUSE)
+
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+#define IS_MMAPPED 0x2
+
+/* check for mmap()'ed chunk */
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* 
+  Bits to mask off when extracting size 
+
+  Note: IS_MMAPPED is intentionally not masked off from size field in
+  macros for which mmapped chunks should never be seen. This should
+  cause helpful core dumps to occur if it is tried by accident by
+  people extending or adapting this malloc.
+*/
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+/* Get size, ignoring use bits */
+#define chunksize(p)         ((p)->size & ~(SIZE_BITS))
+
+
+/* Ptr to next physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk (only valid if the previous
+ * chunk is not in use, i.e. prev_inuse(p) is true) */
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+/* Treat space at ptr + offset as a chunk */
+#define chunk_at_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+
+/* extract p's inuse bit */
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* set/clear chunk as being inuse without otherwise disturbing */
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+
+/* check/set/clear inuse bits in known places */
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+/* Set size at head, without disturbing its use bit */
+#define set_head_size(p, s)  ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use field */
+#define set_head(p, s)       ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+#define set_foot(p, s)       (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+/*
+  -------------------- Internal data structures --------------------
+
+   All internal state is held in an instance of malloc_state defined
+   below. There are no other static variables, except in two optional
+   cases: 
+   * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared above. 
+   * If HAVE_MMAP is true, but mmap doesn't support
+     MAP_ANONYMOUS, a dummy file descriptor for mmap.
+
+   Beware of lots of tricks that minimize the total bookkeeping space
+   requirements. The result is a little over 1K bytes (for 4byte
+   pointers and size_t.)
+*/
+
+/*
+  Bins
+
+    An array of bin headers for free chunks. Each bin is doubly
+    linked.  The bins are approximately proportionally (log) spaced.
+    There are a lot of these bins (128). This may look excessive, but
+    works very well in practice.  Most bins hold sizes that are
+    unusual as malloc request sizes, but are more usual for fragments
+    and consolidated sets of chunks, which is what these bins hold, so
+    they can be found quickly.  All procedures maintain the invariant
+    that no consolidated chunk physically borders another one, so each
+    chunk in a list is known to be preceeded and followed by either
+    inuse chunks or the ends of memory.
+
+    Chunks in bins are kept in size order, with ties going to the
+    approximately least recently used chunk. Ordering isn't needed
+    for the small bins, which all contain the same-sized chunks, but
+    facilitates best-fit allocation for larger chunks. These lists
+    are just sequential. Keeping them in order almost never requires
+    enough traversal to warrant using fancier ordered data
+    structures.  
+
+    Chunks of the same size are linked with the most
+    recently freed at the front, and allocations are taken from the
+    back.  This results in LRU (FIFO) allocation order, which tends
+    to give each chunk an equal opportunity to be consolidated with
+    adjacent freed chunks, resulting in larger free chunks and less
+    fragmentation.
+
+    To simplify use in double-linked lists, each bin header acts
+    as a malloc_chunk. This avoids special-casing for headers.
+    But to conserve space and improve locality, we allocate
+    only the fd/bk pointers of bins, and then use repositioning tricks
+    to treat these as the fields of a malloc_chunk*.  
+*/
+
+typedef struct malloc_chunk* mbinptr;
+
+/* addressing -- note that bin_at(0) is never used */
+/*   (i)<<1: we multiply by 2 since each bin header is a fd/bk pair */
+/*   - SIZE_SZ<<1: subtract 2 words to pretend there's a complete chunk,
+ *                 when in fact only fd/bk are there */
+#define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - (SIZE_SZ<<1)))
+
+/* analog of bin+1: return the next bin by skipping this bin's fd/bk */
+#define next_bin(b)  ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1)))
+
+/* Reminders about list directionality within bins */
+#define first(b)     ((b)->fd)
+#define last(b)      ((b)->bk)
+
+/* Take a chunk off a bin list */
+#define unlink(P, BK, FD) {                                            \
+  FD = P->fd;                                                          \
+  BK = P->bk;                                                          \
+  FD->bk = BK;                                                         \
+  BK->fd = FD;                                                         \
+}
+
+/*
+  Indexing
+
+    Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+    8 bytes apart. Larger bins are approximately logarithmically spaced:
+    (sm: the first 'spaced' seems to refer to the bin header spacing,
+    while the 2nd refers to the spacing between *sizes* of chunks?)
+
+    64 bins of size       8
+    32 bins of size      64
+    16 bins of size     512
+     8 bins of size    4096
+     4 bins of size   32768
+     2 bins of size  262144
+     1 bin  of size what's left
+
+    There is actually a little bit of slop in the numbers in bin_index
+    for the sake of speed. This makes no difference elsewhere.
+
+    The bins top out around 1MB because we expect to service large
+    requests via mmap.
+*/
+
+#define NBINS             128
+#define NSMALLBINS         64
+#define SMALLBIN_WIDTH      8
+#define MIN_LARGE_SIZE    512
+
+#define in_smallbin_range(sz)  \
+  ((unsigned long)(sz) < (unsigned long)MIN_LARGE_SIZE)
+
+#define smallbin_index(sz)     (((unsigned)(sz)) >> 3)
+
+#define largebin_index(sz)                                                   \
+(((((unsigned long)(sz)) >>  6) <= 32)?  56 + (((unsigned long)(sz)) >>  6): \
+ ((((unsigned long)(sz)) >>  9) <= 20)?  91 + (((unsigned long)(sz)) >>  9): \
+ ((((unsigned long)(sz)) >> 12) <= 10)? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 15) <=  4)? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 18) <=  2)? 124 + (((unsigned long)(sz)) >> 18): \
+                                        126)
+
+#define bin_index(sz) \
+ ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz))
+
+
+/*
+  Unsorted chunks
+
+    All remainders from chunk splits, as well as all returned chunks,
+    are first placed in the "unsorted" bin. They are then placed
+    in regular bins after malloc gives them ONE chance to be used before
+    binning. So, basically, the unsorted_chunks list acts as a queue,
+    with chunks being placed on it in free (and malloc_consolidate),
+    and taken off (to be either used or placed in bins) in malloc.
+*/
+
+/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
+#define unsorted_chunks(M)          (bin_at(M, 1))
+
+/*
+  Top
+
+    The top-most available chunk (i.e., the one bordering the end of
+    available memory) is treated specially. It is never included in
+    any bin, is used only if no other chunk is available, and is
+    released back to the system if it is very large (see
+    M_TRIM_THRESHOLD).  Because top initially
+    points to its own bin with initial zero size, thus forcing
+    extension on the first malloc request, we avoid having any special
+    code in malloc to check whether it even exists yet. But we still
+    need to do so when getting memory from system, so we make
+    initial_top treat the bin as a legal but unusable chunk during the
+    interval between initialization and the first call to
+    sYSMALLOc. (This is somewhat delicate, since it relies on
+    the 2 preceding words to be zero during this interval as well.)
+*/
+
+/* Conveniently, the unsorted bin can be used as dummy top on first call */
+#define initial_top(M)              (unsorted_chunks(M))
+
+/*
+  Binmap
+
+    To help compensate for the large number of bins, a one-level index
+    structure is used for bin-by-bin searching.  `binmap' is a
+    bitvector recording whether bins are definitely empty so they can
+    be skipped over during during traversals.  The bits are NOT always
+    cleared as soon as bins are empty, but instead only
+    when they are noticed to be empty during traversal in malloc.
+*/
+
+/* Conservatively use 32 bits per map word, even if on 64bit system */
+#define BINMAPSHIFT      5
+#define BITSPERMAP       (1U << BINMAPSHIFT)
+#define BINMAPSIZE       (NBINS / BITSPERMAP)
+
+#define idx2block(i)     ((i) >> BINMAPSHIFT)
+#define idx2bit(i)       ((1U << ((i) & ((1U << BINMAPSHIFT)-1))))
+
+#define mark_bin(m,i)    ((m)->binmap[idx2block(i)] |=  idx2bit(i))
+#define unmark_bin(m,i)  ((m)->binmap[idx2block(i)] &= ~(idx2bit(i)))
+#define get_binmap(m,i)  ((m)->binmap[idx2block(i)] &   idx2bit(i))
+
+/*
+  Fastbins
+
+    An array of lists holding recently freed small chunks.  Fastbins
+    are not doubly linked.  It is faster to single-link them, and
+    since chunks are never removed from the middles of these lists,
+    double linking is not necessary. Also, unlike regular bins, they
+    are not even processed in FIFO order (they use faster LIFO) since
+    ordering doesn't much matter in the transient contexts in which
+    fastbins are normally used.
+
+    Chunks in fastbins keep their inuse bit set, so they cannot
+    be consolidated with other free chunks. malloc_consolidate
+    releases all chunks in fastbins and consolidates them with
+    other free chunks. 
+*/
+
+typedef struct malloc_chunk* mfastbinptr;
+
+/* offset 2 to use otherwise unindexable first 2 bins */
+#define fastbin_index(sz)        ((((unsigned int)(sz)) >> 3) - 2)
+
+/* The maximum fastbin request size we support */
+#define MAX_FAST_SIZE     80
+
+#define NFASTBINS  (fastbin_index(request2size(MAX_FAST_SIZE))+1)
+
+/*
+  FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free()
+  that triggers automatic consolidation of possibly-surrounding
+  fastbin chunks. This is a heuristic, so the exact value should not
+  matter too much. It is defined at half the default trim threshold as a
+  compromise heuristic to only attempt consolidation if it is likely
+  to lead to trimming. However, it is not dynamically tunable, since
+  consolidation reduces fragmentation surrounding loarge chunks even 
+  if trimming is not used.
+*/
+
+#define FASTBIN_CONSOLIDATION_THRESHOLD  (65536UL)
+
+/*
+  Since the lowest 2 bits in max_fast don't matter in size comparisons, 
+  they are used as flags.
+*/
+
+/*
+  FASTCHUNKS_BIT held in max_fast indicates that there are probably
+  some fastbin chunks. It is set true on entering a chunk into any
+  fastbin, and cleared only in malloc_consolidate.
+
+  The truth value is inverted so that have_fastchunks will be true
+  upon startup (since statics are zero-filled), simplifying
+  initialization checks.
+*/
+
+#define FASTCHUNKS_BIT        (1U)
+
+#define have_fastchunks(M)     (((M)->max_fast &  FASTCHUNKS_BIT) == 0)
+#define clear_fastchunks(M)    ((M)->max_fast |=  FASTCHUNKS_BIT)
+#define set_fastchunks(M)      ((M)->max_fast &= ~FASTCHUNKS_BIT)
+
+/*
+  NONCONTIGUOUS_BIT indicates that MORECORE does not return contiguous
+  regions.  Otherwise, contiguity is exploited in merging together,
+  when possible, results from consecutive MORECORE calls.
+
+  The initial value comes from MORECORE_CONTIGUOUS, but is
+  changed dynamically if mmap is ever used as an sbrk substitute.
+*/
+
+#define NONCONTIGUOUS_BIT     (2U)
+
+#define contiguous(M)          (((M)->max_fast &  NONCONTIGUOUS_BIT) == 0)
+#define noncontiguous(M)       (((M)->max_fast &  NONCONTIGUOUS_BIT) != 0)
+#define set_noncontiguous(M)   ((M)->max_fast |=  NONCONTIGUOUS_BIT)
+#define set_contiguous(M)      ((M)->max_fast &= ~NONCONTIGUOUS_BIT)
+
+/* 
+   Set value of max_fast. 
+   Use impossibly small value if 0.
+   Precondition: there are no existing fastbin chunks.
+   Setting the value clears fastchunk bit but preserves noncontiguous bit.
+*/
+
+#define set_max_fast(M, s) \
+  (M)->max_fast = (((s) == 0)? SMALLBIN_WIDTH: request2size(s)) | \
+  FASTCHUNKS_BIT | \
+  ((M)->max_fast &  NONCONTIGUOUS_BIT)
+
+
+/*
+   ----------- Internal state representation and initialization -----------
+*/
+
+
+struct malloc_state {
+
+  /* The maximum chunk size to be eligible for fastbin */
+  INTERNAL_SIZE_T  max_fast;   /* low 2 bits used as flags */
+
+  /* Fastbins */
+  mfastbinptr      fastbins[NFASTBINS];
+
+  /* Base of the topmost chunk -- not otherwise kept in a bin */
+  /* the 'top' node is always free; you segfault if you ask */
+  mchunkptr        top;
+
+  /* The remainder from the most recent split of a small request */
+  mchunkptr        last_remainder;
+
+  /* Normal bins packed as described above; bin 0 is not used */
+  mchunkptr        bins[NBINS * 2];
+
+  /* Bitmap of bins */
+  unsigned int     binmap[BINMAPSIZE];
+
+  /* Tunable parameters */
+  unsigned long    trim_threshold;
+  INTERNAL_SIZE_T  top_pad;
+  INTERNAL_SIZE_T  mmap_threshold;
+
+  /* Memory map support */
+  int              n_mmaps;
+  int              n_mmaps_max;
+  int              max_n_mmaps;
+
+  /* Cache malloc_getpagesize */
+  unsigned int     pagesize;
+
+  /* Statistics */
+  INTERNAL_SIZE_T  mmapped_mem;
+  INTERNAL_SIZE_T  sbrked_mem;
+  INTERNAL_SIZE_T  max_sbrked_mem;
+  INTERNAL_SIZE_T  max_mmapped_mem;
+  INTERNAL_SIZE_T  max_total_mem;
+
+  /* sm: my stuff */
+  unsigned int numMallocCalls;       /* # of calls to malloc */
+  unsigned int numFreeCalls;         /* # of calls to free */
+                                     
+  /* physically first chunk, for walking; for this to be useful,
+   * we must have gotten contiguous memory from sbrk().. */
+  mchunkptr firstChunk;
+  
+  /* maintain information about up to 200 mmap regions, for
+   * the purpose of walking them; 'n_mmaps' will tell us the
+   * next available slot in this array */
+  #define NUM_MMAP_PTRS 200
+  mchunkptr mmapPtrs[NUM_MMAP_PTRS];     /* array of pointers */
+};
+
+typedef struct malloc_state *mstate;
+
+/*
+   There is exactly one instance of this struct in this malloc.
+   If you are adapting this malloc in a way that does NOT use a static
+   malloc_state, you MUST explicitly zero-fill it before using. This
+   malloc relies on the property that malloc_state is initialized to
+   all zeroes (as is true of C statics).
+*/
+
+static struct malloc_state av_;  /* never directly referenced */
+
+/*
+   All uses of av_ are via get_malloc_state().
+   At most one "call" to get_malloc_state is made per invocation of
+   the public versions of malloc and free, but other routines
+   that in turn invoke malloc and/or free may call more then once.
+   Also, it is called in check* routines if DEBUG is set.
+*/
+
+#define get_malloc_state() (&(av_))
+
+/*
+  Initialize a malloc_state struct.
+
+  This is called only from within malloc_consolidate, which needs
+  be called in the same contexts anyway.  It is never called directly
+  outside of malloc_consolidate because some optimizing compilers try
+  to inline it at all call points, which turns out not to be an
+  optimization at all. (Inlining it in malloc_consolidate is fine though.)
+*/
+
+#if __STD_C
+static void malloc_init_state(mstate av)
+#else
+static void malloc_init_state(av) mstate av;
+#endif
+{
+  int     i;
+  mbinptr bin;
+  
+  /* Establish circular links for normal bins */
+  for (i = 1; i < NBINS; ++i) { 
+    bin = bin_at(av,i);
+    bin->fd = bin->bk = bin;
+  }
+
+  av->top_pad        = DEFAULT_TOP_PAD;
+  av->n_mmaps_max    = DEFAULT_MMAP_MAX;
+  av->mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+  av->trim_threshold = DEFAULT_TRIM_THRESHOLD;
+
+#if !MORECORE_CONTIGUOUS
+  set_noncontiguous(av);
+#endif
+
+  set_max_fast(av, DEFAULT_MXFAST);
+
+  av->top            = initial_top(av);
+  av->pagesize       = malloc_getpagesize;
+}
+
+/* 
+   Other internal utilities operating on mstates
+*/
+
+#if __STD_C
+static Void_t*  sYSMALLOc(INTERNAL_SIZE_T, mstate);
+static int      sYSTRIm(size_t, mstate);
+static void     malloc_consolidate(mstate);
+static Void_t** iALLOc(size_t, size_t*, int, Void_t**);
+#else
+static Void_t*  sYSMALLOc();
+static int      sYSTRIm();
+static void     malloc_consolidate();
+static Void_t** iALLOc();
+#endif
+
+/*
+  Debugging support
+
+  These routines make a number of assertions about the states
+  of data structures that should be true at all times. If any
+  are not true, it's very likely that a user program has somehow
+  trashed memory. (It's also possible that there is a coding error
+  in malloc. In which case, please report it!)
+*/
+
+#if ! DEBUG
+
+#define check_chunk(P)
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_remalloced_chunk(P,N)
+#define check_malloced_chunk(P,N)
+#define check_malloc_state()
+
+#else
+#define check_chunk(P)              do_check_chunk(P)
+#define check_free_chunk(P)         do_check_free_chunk(P)
+#define check_inuse_chunk(P)        do_check_inuse_chunk(P)
+#define check_remalloced_chunk(P,N) do_check_remalloced_chunk(P,N)
+#define check_malloced_chunk(P,N)   do_check_malloced_chunk(P,N)
+#define check_malloc_state()        do_check_malloc_state()
+
+/*
+  Properties of all chunks
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+  mstate av = get_malloc_state();
+  unsigned long sz = chunksize(p);
+  /* min and max possible addresses assuming contiguous allocation */
+  char* max_address = (char*)(av->top) + chunksize(av->top);
+  char* min_address = max_address - av->sbrked_mem;
+
+  if (!chunk_is_mmapped(p)) {
+    
+    /* Has legal address ... */
+    if (p != av->top) {
+      if (contiguous(av)) {
+        assert(((char*)p) >= min_address);
+        assert(((char*)p + sz) <= ((char*)(av->top)));
+      }
+    }
+    else {
+      /* top size is always at least MINSIZE */
+      assert((unsigned long)(sz) >= MINSIZE);
+      /* top predecessor always marked inuse */
+      assert(prev_inuse(p));
+    }
+      
+  }
+  else {
+#if HAVE_MMAP
+    /* address is outside main heap  */
+    if (contiguous(av) && av->top != initial_top(av)) {
+      assert(((char*)p) < min_address || ((char*)p) > max_address);
+    }
+    /* chunk is page-aligned */
+    assert(((p->prev_size + sz) & (av->pagesize-1)) == 0);
+    /* mem is aligned */
+    assert(aligned_OK(chunk2mem(p)));
+#else
+    /* force an appropriate assert violation if debug set */
+    assert(!chunk_is_mmapped(p));
+#endif
+  }
+}
+
+/*
+  Properties of free chunks
+*/
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+  mstate av = get_malloc_state();
+
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+  mchunkptr next = chunk_at_offset(p, sz);
+
+  do_check_chunk(p);
+
+  /* Chunk must claim to be free ... */
+  assert(!inuse(p));
+  assert (!chunk_is_mmapped(p));
+
+  /* Unless a special marker, must have OK fields */
+  if ((unsigned long)(sz) >= MINSIZE)
+  {
+    assert((sz & MALLOC_ALIGN_MASK) == 0);
+    assert(aligned_OK(chunk2mem(p)));
+    /* ... matching footer field */
+    assert(next->prev_size == sz);
+    /* ... and is fully consolidated */
+    assert(prev_inuse(p));
+    assert (next == av->top || inuse(next));
+
+    /* ... and has minimally sane links */
+    assert(p->fd->bk == p);
+    assert(p->bk->fd == p);
+  }
+  else /* markers are always of size SIZE_SZ */
+    assert(sz == SIZE_SZ);
+}
+
+/*
+  Properties of inuse chunks
+*/
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+  mstate av = get_malloc_state();
+  mchunkptr next;
+  do_check_chunk(p);
+
+  if (chunk_is_mmapped(p))
+    return; /* mmapped chunks have no next/prev */
+
+  /* Check whether it claims to be in use ... */
+  assert(inuse(p));
+
+  next = next_chunk(p);
+
+  /* ... and is surrounded by OK chunks.
+    Since more things can be checked with free chunks than inuse ones,
+    if an inuse chunk borders them and debug is on, it's worth doing them.
+  */
+  if (!prev_inuse(p))  {
+    /* Note that we cannot even look at prev unless it is not inuse */
+    mchunkptr prv = prev_chunk(p);
+    assert(next_chunk(prv) == p);
+    do_check_free_chunk(prv);
+  }
+
+  if (next == av->top) {
+    assert(prev_inuse(next));
+    assert(chunksize(next) >= MINSIZE);
+  }
+  else if (!inuse(next))
+    do_check_free_chunk(next);
+}
+
+/*
+  Properties of chunks recycled from fastbins
+*/
+
+#if __STD_C
+static void do_check_remalloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_remalloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+  do_check_inuse_chunk(p);
+
+  /* Legal size ... */
+  assert((sz & MALLOC_ALIGN_MASK) == 0);
+  assert((unsigned long)(sz) >= MINSIZE);
+  /* ... and alignment */
+  assert(aligned_OK(chunk2mem(p)));
+  /* chunk is less than MINSIZE more than request */
+  assert((long)(sz) - (long)(s) >= 0);
+  assert((long)(sz) - (long)(s + MINSIZE) < 0);
+}
+
+/*
+  Properties of nonrecycled chunks at the point they are malloced
+*/
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+  /* same as recycled case ... */
+  do_check_remalloced_chunk(p, s);
+
+  /*
+    ... plus,  must obey implementation invariant that prev_inuse is
+    always true of any allocated chunk; i.e., that each allocated
+    chunk borders either a previously allocated and still in-use
+    chunk, or the base of its memory arena. This is ensured
+    by making all allocations from the the `lowest' part of any found
+    chunk.  This does not necessarily hold however for chunks
+    recycled via fastbins.
+  */
+
+  assert(prev_inuse(p));
+}
+
+
+/*
+  Properties of malloc_state.
+
+  This may be useful for debugging malloc, as well as detecting user
+  programmer errors that somehow write into malloc_state.
+
+  If you are extending or experimenting with this malloc, you can
+  probably figure out how to hack this routine to print out or
+  display chunk addresses, sizes, bins, and other instrumentation.
+*/
+
+static void do_check_malloc_state()
+{
+  mstate av = get_malloc_state();
+  int i;
+  mchunkptr p;
+  mchunkptr q;
+  mbinptr b;
+  unsigned int binbit;
+  int empty;
+  unsigned int idx;
+  INTERNAL_SIZE_T size;
+  unsigned long total = 0;
+  int max_fast_bin;
+
+  /* internal size_t must be no wider than pointer type */
+  assert(sizeof(INTERNAL_SIZE_T) <= sizeof(char*));
+
+  /* alignment is a power of 2 */
+  assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0);
+
+  /* cannot run remaining checks until fully initialized */
+  if (av->top == 0 || av->top == initial_top(av))
+    return;
+
+  /* pagesize is a power of 2 */
+  assert((av->pagesize & (av->pagesize-1)) == 0);
+
+  /* properties of fastbins */
+
+  /* max_fast is in allowed range */
+  assert((av->max_fast & ~1) <= request2size(MAX_FAST_SIZE));
+
+  max_fast_bin = fastbin_index(av->max_fast);
+
+  for (i = 0; i < NFASTBINS; ++i) {
+    p = av->fastbins[i];
+
+    /* all bins past max_fast are empty */
+    if (i > max_fast_bin)
+      assert(p == 0);
+
+    while (p != 0) {
+      /* each chunk claims to be inuse, though it really is not,
+       * from the outside client's perspective */
+      do_check_inuse_chunk(p);
+      total += chunksize(p);
+      /* chunk belongs in this bin */
+      assert(fastbin_index(chunksize(p)) == i);
+      /* sm: despite being marked as 'inuse', their 'fd' fields are valid? */
+      p = p->fd;
+    }
+  }
+
+  if (total != 0)
+    assert(have_fastchunks(av));
+  if (!have_fastchunks(av))     /* sm: bugfix: removed 'else' */
+    assert(total == 0);
+
+  /* check normal bins */
+  for (i = 1; i < NBINS; ++i) {
+    b = bin_at(av,i);
+
+    /* binmap is accurate (except for bin 1 == unsorted_chunks) */
+    if (i >= 2) {
+      binbit = get_binmap(av,i);
+      empty = last(b) == b;
+      if (!binbit)
+        assert(empty);
+      if (!empty)               /* sm: removed another 'else' */
+        assert(binbit);
+    }
+
+    for (p = last(b); p != b; p = p->bk) {
+      /* each chunk claims to be free */
+      do_check_free_chunk(p);
+      size = chunksize(p);
+      total += size;
+      if (i >= 2) {
+        /* chunk belongs in bin */
+        idx = bin_index(size);
+        assert(idx == i);
+        /* lists are sorted */
+        assert(p->bk == b || 
+               (unsigned long)chunksize(p->bk) >= (unsigned long)chunksize(p));
+      }
+      /* chunk is followed by a legal chain of inuse chunks */
+      for (q = next_chunk(p);
+           (q != av->top && inuse(q) && 
+             (unsigned long)(chunksize(q)) >= MINSIZE);
+           q = next_chunk(q))
+        do_check_inuse_chunk(q);
+    }
+  }
+
+  /* top chunk is OK */
+  check_chunk(av->top);
+
+  /* sanity checks for statistics */
+
+  assert(total <= (unsigned long)(av->max_total_mem));
+  assert(av->n_mmaps >= 0);
+  assert(av->n_mmaps <= av->n_mmaps_max);
+  assert(av->n_mmaps <= av->max_n_mmaps);
+
+  assert((unsigned long)(av->sbrked_mem) <=
+         (unsigned long)(av->max_sbrked_mem));
+
+  assert((unsigned long)(av->mmapped_mem) <=
+         (unsigned long)(av->max_mmapped_mem));
+
+  assert((unsigned long)(av->max_total_mem) >=
+         (unsigned long)(av->mmapped_mem) + (unsigned long)(av->sbrked_mem));
+}
+#endif
+
+
+/* ----------- Routines dealing with system allocation -------------- */
+
+/*
+  sysmalloc handles malloc cases requiring more memory from the system.
+  On entry, it is assumed that av->top does not have enough
+  space to service request for nb bytes, thus requiring that av->top
+  be extended or replaced.
+*/
+
+#if __STD_C
+static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av)
+#else
+static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+#endif
+{
+  mchunkptr       old_top;        /* incoming value of av->top */
+  INTERNAL_SIZE_T old_size;       /* its size */
+  char*           old_end;        /* its end address */
+
+  long            size;           /* arg to first MORECORE or mmap call */
+  char*           brk;            /* return value from MORECORE */
+
+  long            correction;     /* arg to 2nd MORECORE call */
+  char*           snd_brk;        /* 2nd return val */
+
+  INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */
+  INTERNAL_SIZE_T end_misalign;   /* partial page left at end of new space */
+  char*           aligned_brk;    /* aligned offset into brk */
+
+  mchunkptr       p;              /* the allocated/returned chunk */
+  mchunkptr       remainder;      /* remainder from allocation */
+  unsigned long   remainder_size; /* its size */
+
+  unsigned long   sum;            /* for updating stats */
+
+  size_t          pagemask  = av->pagesize - 1;
+
+
+#if HAVE_MMAP
+
+  /*
+    If have mmap, and the request size meets the mmap threshold, and
+    the system supports mmap, and there are few enough currently
+    allocated mmapped regions, try to directly map this request
+    rather than expanding top.
+  */
+
+  if ((unsigned long)(nb) >= (unsigned long)(av->mmap_threshold) &&
+      (av->n_mmaps < av->n_mmaps_max)) {
+
+    char* mm;             /* return value from mmap call*/
+
+    /*
+      Round up size to nearest page.  For mmapped chunks, the overhead
+      is one SIZE_SZ unit larger than for normal chunks, because there
+      is no following chunk whose prev_size field could be used.
+    */
+    size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask;
+
+    /* Don't try if size wraps around 0 */
+    if ((unsigned long)(size) > (unsigned long)(nb)) {
+
+      mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));
+      
+      if (mm != (char*)(MORECORE_FAILURE)) {
+        
+        /*
+          The offset to the start of the mmapped region is stored
+          in the prev_size field of the chunk. This allows us to adjust
+          returned start address to meet alignment requirements here 
+          and in memalign(), and still be able to compute proper
+          address argument for later munmap in free() and realloc().
+        */
+        
+        front_misalign = (INTERNAL_SIZE_T)chunk2mem(mm) & MALLOC_ALIGN_MASK;
+        if (front_misalign > 0) {
+          correction = MALLOC_ALIGNMENT - front_misalign;
+          p = (mchunkptr)(mm + correction);
+          p->prev_size = correction;
+          set_head(p, (size - correction) |IS_MMAPPED);
+        }
+        else {
+          p = (mchunkptr)mm;
+          set_head(p, size|IS_MMAPPED);
+        }
+        
+        /* sm: add this pointer to my array */
+        assert(av->n_mmaps < NUM_MMAP_PTRS);
+        av->mmapPtrs[av->n_mmaps] = p;
+
+        /* update statistics */
+
+        if (++av->n_mmaps > av->max_n_mmaps)
+          av->max_n_mmaps = av->n_mmaps;
+
+        sum = av->mmapped_mem += size;
+        if (sum > (unsigned long)(av->max_mmapped_mem))
+          av->max_mmapped_mem = sum;
+        sum += av->sbrked_mem;
+        if (sum > (unsigned long)(av->max_total_mem))
+          av->max_total_mem = sum;
+
+        check_chunk(p);
+        
+        return chunk2mem(p);
+      }
+    }
+  }
+#endif
+
+  /* Record incoming configuration of top */
+
+  old_top  = av->top;
+  old_size = chunksize(old_top);
+  old_end  = (char*)(chunk_at_offset(old_top, old_size));
+
+  brk = snd_brk = (char*)(MORECORE_FAILURE); 
+
+  /* 
+     If not the first time through, we require old_size to be
+     at least MINSIZE and to have prev_inuse set.
+  */
+
+  assert((old_top == initial_top(av) && old_size == 0) || 
+         ((unsigned long) (old_size) >= MINSIZE &&
+          prev_inuse(old_top)));
+
+  /* Precondition: not enough current space to satisfy nb request */
+  assert((unsigned long)(old_size) < (unsigned long)(nb + MINSIZE));
+
+  /* Precondition: all fastbins are consolidated */
+  assert(!have_fastchunks(av));
+
+
+  /* Request enough space for nb + pad + overhead */
+
+  size = nb + av->top_pad + MINSIZE;
+
+  /*
+    If contiguous, we can subtract out existing space that we hope to
+    combine with new space. We add it back later only if
+    we don't actually get contiguous space.
+  */
+
+  if (contiguous(av))
+    size -= old_size;
+
+  /*
+    Round to a multiple of page size.
+    If MORECORE is not contiguous, this ensures that we only call it
+    with whole-page arguments.  And if MORECORE is contiguous and
+    this is not first time through, this preserves page-alignment of
+    previous calls. Otherwise, we correct to page-align below.
+  */
+
+  size = (size + pagemask) & ~pagemask;
+
+  /*
+    Don't try to call MORECORE if argument is so big as to appear
+    negative. Note that since mmap takes size_t arg, it may succeed
+    below even if we cannot call MORECORE.
+  */
+
+  if (size > 0) 
+    brk = (char*)(MORECORE(size));
+
+  /*
+    If have mmap, try using it as a backup when MORECORE fails or
+    cannot be used. This is worth doing on systems that have "holes" in
+    address space, so sbrk cannot extend to give contiguous space, but
+    space is available elsewhere.  Note that we ignore mmap max count
+    and threshold limits, since the space will not be used as a
+    segregated mmap region.
+  */
+
+#if HAVE_MMAP
+  if (brk == (char*)(MORECORE_FAILURE)) {
+
+    /* Cannot merge with old top, so add its size back in */
+    if (contiguous(av))
+      size = (size + old_size + pagemask) & ~pagemask;
+
+    /* If we are relying on mmap as backup, then use larger units */
+    if ((unsigned long)(size) < (unsigned long)(MMAP_AS_MORECORE_SIZE))
+      size = MMAP_AS_MORECORE_SIZE;
+
+    /* Don't try if size wraps around 0 */
+    if ((unsigned long)(size) > (unsigned long)(nb)) {
+
+      brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));
+      
+      if (brk != (char*)(MORECORE_FAILURE)) {
+        
+        /* We do not need, and cannot use, another sbrk call to find end */
+        snd_brk = brk + size;
+
+        /*
+           Record that we no longer have a contiguous sbrk region.
+           After the first time mmap is used as backup, we do not
+           ever rely on contiguous space since this could incorrectly
+           bridge regions.
+        */
+        set_noncontiguous(av);
+        
+        /* sm: I don't update my mmapPtrs array here because I don't expect
+         * it to happen, and because I don't know what to do if it does */
+      }
+    }
+  }
+#endif
+
+  if (brk != (char*)(MORECORE_FAILURE)) {
+    av->sbrked_mem += size;
+
+    /*
+      If MORECORE extends previous space, we can likewise extend top size.
+    */
+    
+    if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) {
+      set_head(old_top, (size + old_size) | PREV_INUSE);
+    }
+    
+    /*
+      Otherwise, make adjustments:
+      
+      * If the first time through or noncontiguous, we need to call sbrk
+        just to find out where the end of memory lies.
+
+      * We need to ensure that all returned chunks from malloc will meet
+        MALLOC_ALIGNMENT
+
+      * If there was an intervening foreign sbrk, we need to adjust sbrk
+        request size to account for fact that we will not be able to
+        combine new space with existing space in old_top.
+
+      * Almost all systems internally allocate whole pages at a time, in
+        which case we might as well use the whole last page of request.
+        So we allocate enough more memory to hit a page boundary now,
+        which in turn causes future contiguous calls to page-align.
+    */
+    
+    else {
+      front_misalign = 0;
+      end_misalign = 0;
+      correction = 0;
+      aligned_brk = brk;
+      
+      /* handle contiguous cases */
+      if (contiguous(av)) { 
+        
+        /* Guarantee alignment of first new chunk made from this space */
+
+        front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+        if (front_misalign > 0) {
+
+          /*
+            Skip over some bytes to arrive at an aligned position.
+            We don't need to specially mark these wasted front bytes.
+            They will never be accessed anyway because
+            prev_inuse of av->top (and any chunk created from its start)
+            is always true after initialization.
+          */
+
+          correction = MALLOC_ALIGNMENT - front_misalign;
+          aligned_brk += correction;
+        }
+        
+        /*
+          If this isn't adjacent to existing space, then we will not
+          be able to merge with old_top space, so must add to 2nd request.
+        */
+        
+        correction += old_size;
+        
+        /* Extend the end address to hit a page boundary */
+        end_misalign = (INTERNAL_SIZE_T)(brk + size + correction);
+        correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign;
+        
+        assert(correction >= 0);
+        snd_brk = (char*)(MORECORE(correction));
+        
+        /*
+          If can't allocate correction, try to at least find out current
+          brk.  It might be enough to proceed without failing.
+          
+          Note that if second sbrk did NOT fail, we assume that space
+          is contiguous with first sbrk. This is a safe assumption unless
+          program is multithreaded but doesn't use locks and a foreign sbrk
+          occurred between our first and second calls.
+        */
+        
+        if (snd_brk == (char*)(MORECORE_FAILURE)) {
+          correction = 0;
+          snd_brk = (char*)(MORECORE(0));
+        }
+      }
+      
+      /* handle non-contiguous cases */
+      else { 
+        /* MORECORE/mmap must correctly align */
+        assert(((unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK) == 0);
+        
+        /* Find out current end of memory */
+        if (snd_brk == (char*)(MORECORE_FAILURE)) {
+          snd_brk = (char*)(MORECORE(0));
+        }
+      }
+      
+      /* Adjust top based on results of second sbrk */
+      if (snd_brk != (char*)(MORECORE_FAILURE)) {
+        av->top = (mchunkptr)aligned_brk;
+        set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE);
+        av->sbrked_mem += correction;
+     
+        /*
+          If not the first time through, we either have a
+          gap due to foreign sbrk or a non-contiguous region.  Insert a
+          double fencepost at old_top to prevent consolidation with space
+          we don't own. These fenceposts are artificial chunks that are
+          marked as inuse and are in any case too small to use.  We need
+          two to make sizes and alignments work out.
+        */
+   
+        if (old_size != 0) {
+          /* 
+             Shrink old_top to insert fenceposts, keeping size a
+             multiple of MALLOC_ALIGNMENT. We know there is at least
+             enough space in old_top to do this.
+          */
+          old_size = (old_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+          set_head(old_top, old_size | PREV_INUSE);
+          
+          /*
+            Note that the following assignments completely overwrite
+            old_top when old_size was previously MINSIZE.  This is
+            intentional. We need the fencepost, even if old_top otherwise gets
+            lost.
+          */
+          chunk_at_offset(old_top, old_size          )->size =
+            SIZE_SZ|PREV_INUSE;
+
+          chunk_at_offset(old_top, old_size + SIZE_SZ)->size =
+            SIZE_SZ|PREV_INUSE;
+
+          /* If possible, release the rest. */
+          if (old_size >= MINSIZE) {
+            fREe(chunk2mem(old_top));
+          }
+
+        }
+      }
+    }
+    
+    /* Update statistics */
+    sum = av->sbrked_mem;
+    if (sum > (unsigned long)(av->max_sbrked_mem))
+      av->max_sbrked_mem = sum;
+    
+    sum += av->mmapped_mem;
+    if (sum > (unsigned long)(av->max_total_mem))
+      av->max_total_mem = sum;
+
+    check_malloc_state();
+    
+    /* finally, do the allocation */
+    p = av->top;
+    size = chunksize(p);
+    
+    /* check that one of the above allocation paths succeeded */
+    if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) {
+      remainder_size = size - nb;
+      remainder = chunk_at_offset(p, nb);
+      av->top = remainder;
+      set_head(p, nb | PREV_INUSE);
+      set_head(remainder, remainder_size | PREV_INUSE);
+      check_malloced_chunk(p, nb);
+
+      /* sm: moved the setting of 'firstChunk' in here so that it never
+       * points to a mmap'd region */
+      if (!av->firstChunk ||
+          p < av->firstChunk) {
+        /* new 'first' */
+        /*printf("new firstChunk: %p\n", p);*/
+        av->firstChunk = p;
+      }
+
+      return chunk2mem(p);
+    }
+  }
+
+  /* catch all failure paths */
+  MALLOC_FAILURE_ACTION;
+  return 0;
+}
+
+
+/*
+  sYSTRIm is an inverse of sorts to sYSMALLOc.  It gives memory back
+  to the system (via negative arguments to sbrk) if there is unused
+  memory at the `high' end of the malloc pool. It is called
+  automatically by free() when top space exceeds the trim
+  threshold. It is also called by the public malloc_trim routine.  It
+  returns 1 if it actually released any memory, else 0.
+*/
+
+#if __STD_C
+static int sYSTRIm(size_t pad, mstate av)
+#else
+static int sYSTRIm(pad, av) size_t pad; mstate av;
+#endif
+{
+  long  top_size;        /* Amount of top-most memory */
+  long  extra;           /* Amount to release */
+  long  released;        /* Amount actually released */
+  char* current_brk;     /* address returned by pre-check sbrk call */
+  char* new_brk;         /* address returned by post-check sbrk call */
+  size_t pagesz;
+
+  pagesz = av->pagesize;
+  top_size = chunksize(av->top);
+  
+  /* Release in pagesize units, keeping at least one page */
+  extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+  
+  if (extra > 0) {
+    
+    /*
+      Only proceed if end of memory is where we last set it.
+      This avoids problems if there were foreign sbrk calls.
+    */
+    current_brk = (char*)(MORECORE(0));
+    if (current_brk == (char*)(av->top) + top_size) {
+      
+      /*
+        Attempt to release memory. We ignore MORECORE return value,
+        and instead call again to find out where new end of memory is.
+        This avoids problems if first call releases less than we asked,
+        of if failure somehow altered brk value. (We could still
+        encounter problems if it altered brk in some very bad way,
+        but the only thing we can do is adjust anyway, which will cause
+        some downstream failure.)
+      */
+      
+      MORECORE(-extra);
+      new_brk = (char*)(MORECORE(0));
+      
+      if (new_brk != (char*)MORECORE_FAILURE) {
+        released = (long)(current_brk - new_brk);
+        
+        if (released != 0) {
+          /* Success. Adjust top. */
+          av->sbrked_mem -= released;
+          set_head(av->top, (top_size - released) | PREV_INUSE);
+          check_malloc_state();
+          return 1;
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+/*
+  ------------------------------ malloc ------------------------------
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+  Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+  mstate av = get_malloc_state();
+
+  INTERNAL_SIZE_T nb;               /* normalized request size */
+  unsigned int    idx;              /* associated bin index */
+  mbinptr         bin;              /* associated bin */
+  mfastbinptr*    fb;               /* associated fastbin */
+
+  mchunkptr       victim;           /* inspected/selected chunk */
+  INTERNAL_SIZE_T size;             /* its size */
+  int             victim_index;     /* its bin index */
+
+  mchunkptr       remainder;        /* remainder from a split */
+  unsigned long   remainder_size;   /* its size */
+
+  unsigned int    block;            /* bit map traverser */
+  unsigned int    bit;              /* bit map traverser */
+  unsigned int    map;              /* current word of binmap */
+
+  mchunkptr       fwd;              /* misc temp for linking */
+  mchunkptr       bck;              /* misc temp for linking */
+
+  /* sm: my stuff */
+  #ifdef TRACE_MALLOC_CALLS
+    fprintf(stderr, "malloc(%d) ", bytes);
+    #define RETURN(val)             \
+      fprintf(stderr, "yielded %p\n", val);  \
+      return val
+  #else
+    #define RETURN(val) return val
+  #endif
+
+  av->numMallocCalls++;
+
+  /*
+    Convert request size to internal form by adding SIZE_SZ bytes
+    overhead plus possibly more to obtain necessary alignment and/or
+    to obtain a size of at least MINSIZE, the smallest allocatable
+    size. Also, checked_request2size traps (returning 0) request sizes
+    that are so large that they wrap around zero when padded and
+    aligned.
+  */
+
+  checked_request2size(bytes, nb);
+
+  /*
+    If the size qualifies as a fastbin, first check corresponding bin.
+    This code is safe to execute even if av is not yet initialized, so we
+    can try it without checking, which saves some time on this fast path.
+  */
+
+  if ((unsigned long)(nb) <= (unsigned long)(av->max_fast)) { 
+    fb = &(av->fastbins[(fastbin_index(nb))]);
+    if ( (victim = *fb) != 0) {
+      *fb = victim->fd;
+      check_remalloced_chunk(victim, nb);
+      RETURN(chunk2mem(victim));
+    }
+  }
+
+  /*
+    If a small request, check regular bin.  Since these "smallbins"
+    hold one size each, no searching within bins is necessary.
+    (For a large request, we need to wait until unsorted chunks are
+    processed to find best fit. But for small ones, fits are exact
+    anyway, so we can check now, which is faster.)
+  */
+
+  if (in_smallbin_range(nb)) {
+    idx = smallbin_index(nb);
+    bin = bin_at(av,idx);
+
+    if ( (victim = last(bin)) != bin) {
+      if (victim == 0) /* initialization check */
+        malloc_consolidate(av);
+      else {
+        bck = victim->bk;
+        set_inuse_bit_at_offset(victim, nb);
+        bin->bk = bck;
+        bck->fd = bin;
+        
+        check_malloced_chunk(victim, nb);
+        RETURN(chunk2mem(victim));
+      }
+    }
+  }
+
+  /* 
+     If this is a large request, consolidate fastbins before continuing.
+     While it might look excessive to kill all fastbins before
+     even seeing if there is space available, this avoids
+     fragmentation problems normally associated with fastbins.
+     Also, in practice, programs tend to have runs of either small or
+     large requests, but less often mixtures, so consolidation is not 
+     invoked all that often in most programs. And the programs that
+     it is called frequently in otherwise tend to fragment.
+  */
+
+  else {
+    idx = largebin_index(nb);
+    if (have_fastchunks(av)) 
+      malloc_consolidate(av);
+  }
+
+  /*
+    Process recently freed or remaindered chunks, taking one only if
+    it is exact fit, or, if this a small request, the chunk is remainder from
+    the most recent non-exact fit.  Place other traversed chunks in
+    bins.  Note that this step is the only place in any routine where
+    chunks are placed in bins.
+
+    The outer loop here is needed because we might not realize until
+    near the end of malloc that we should have consolidated, so must
+    do so and retry. This happens at most once, and only when we would
+    otherwise need to expand memory to service a "small" request.
+  */
+    
+  for(;;) {    
+    
+    while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) {
+      bck = victim->bk;
+      size = chunksize(victim);
+
+      /* 
+         If a small request, try to use last remainder if it is the
+         only chunk in unsorted bin.  This helps promote locality for
+         runs of consecutive small requests. This is the only
+         exception to best-fit, and applies only when there is
+         no exact fit for a small chunk.
+      */
+
+      if (in_smallbin_range(nb) && 
+          bck == unsorted_chunks(av) &&
+          victim == av->last_remainder &&
+          (unsigned long)(size) > (unsigned long)(nb + MINSIZE)) {
+
+        /* split and reattach remainder */
+        remainder_size = size - nb;
+        remainder = chunk_at_offset(victim, nb);
+        unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+        av->last_remainder = remainder; 
+        remainder->bk = remainder->fd = unsorted_chunks(av);
+        
+        set_head(victim, nb | PREV_INUSE);
+        set_head(remainder, remainder_size | PREV_INUSE);
+        set_foot(remainder, remainder_size);
+        
+        check_malloced_chunk(victim, nb);
+        RETURN(chunk2mem(victim));
+      }
+
+      /* remove from unsorted list */
+      unsorted_chunks(av)->bk = bck;
+      bck->fd = unsorted_chunks(av);
+      
+      /* Take now instead of binning if exact fit */
+      
+      if (size == nb) {
+        set_inuse_bit_at_offset(victim, size);
+        check_malloced_chunk(victim, nb);
+        RETURN(chunk2mem(victim));
+      }
+      
+      /* place chunk in bin */
+      
+      if (in_smallbin_range(size)) {
+        victim_index = smallbin_index(size);
+        bck = bin_at(av, victim_index);
+        fwd = bck->fd;
+      }
+      else {
+        victim_index = largebin_index(size);
+        bck = bin_at(av, victim_index);
+        fwd = bck->fd;
+
+        /* maintain large bins in sorted order */
+        if (fwd != bck) {
+          size |= PREV_INUSE; /* Or with inuse bit to speed comparisons */
+          /* if smaller than smallest, bypass loop below */
+          if ((unsigned long)(size) <= (unsigned long)(bck->bk->size)) {
+            fwd = bck;
+            bck = bck->bk;
+          }
+          else {
+            while ((unsigned long)(size) < (unsigned long)(fwd->size)) 
+              fwd = fwd->fd;
+            bck = fwd->bk;
+          }
+        }
+      }
+      
+      mark_bin(av, victim_index);
+      victim->bk = bck;
+      victim->fd = fwd;
+      fwd->bk = victim;
+      bck->fd = victim;
+    }
+   
+    /*
+      If a large request, scan through the chunks of current bin in
+      sorted order to find smallest that fits.  This is the only step
+      where an unbounded number of chunks might be scanned without doing
+      anything useful with them. However the lists tend to be short.
+    */
+      
+    if (!in_smallbin_range(nb)) {
+      bin = bin_at(av, idx);
+
+      /* skip scan if empty or largest chunk is too small */
+      if ((victim = last(bin)) != bin &&
+          (unsigned long)(first(bin)->size) >= (unsigned long)(nb)) {
+
+        while (((unsigned long)(size = chunksize(victim)) < 
+                (unsigned long)(nb)))
+          victim = victim->bk;
+
+        remainder_size = size - nb;
+        unlink(victim, bck, fwd);
+        
+        /* Exhaust */
+        if (remainder_size < MINSIZE)  {
+          set_inuse_bit_at_offset(victim, size);
+          check_malloced_chunk(victim, nb);
+          RETURN(chunk2mem(victim));
+        }
+        /* Split */
+        else {
+          remainder = chunk_at_offset(victim, nb);
+          unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+          remainder->bk = remainder->fd = unsorted_chunks(av);
+          set_head(victim, nb | PREV_INUSE);
+          set_head(remainder, remainder_size | PREV_INUSE);
+          set_foot(remainder, remainder_size);
+          check_malloced_chunk(victim, nb);
+          RETURN(chunk2mem(victim));
+        } 
+      }
+    }    
+
+    /*
+      Search for a chunk by scanning bins, starting with next largest
+      bin. This search is strictly by best-fit; i.e., the smallest
+      (with ties going to approximately the least recently used) chunk
+      that fits is selected.
+      
+      The bitmap avoids needing to check that most blocks are nonempty.
+      The particular case of skipping all bins during warm-up phases
+      when no chunks have been returned yet is faster than it might look.
+    */
+    
+    ++idx;
+    bin = bin_at(av,idx);
+    block = idx2block(idx);
+    map = av->binmap[block];
+    bit = idx2bit(idx);
+    
+    for (;;) {
+
+      /* Skip rest of block if there are no more set bits in this block.  */
+      if (bit > map || bit == 0) {
+        do {
+          if (++block >= BINMAPSIZE)  /* out of bins */
+            goto use_top;
+        } while ( (map = av->binmap[block]) == 0);
+
+        bin = bin_at(av, (block << BINMAPSHIFT));
+        bit = 1;
+      }
+      
+      /* Advance to bin with set bit. There must be one. */
+      while ((bit & map) == 0) {
+        bin = next_bin(bin);
+        bit <<= 1;
+        assert(bit != 0);
+      }
+      
+      /* Inspect the bin. It is likely to be non-empty */
+      victim = last(bin);
+      
+      /*  If a false alarm (empty bin), clear the bit. */
+      if (victim == bin) {
+        av->binmap[block] = map &= ~bit; /* Write through */
+        bin = next_bin(bin);
+        bit <<= 1;
+      }
+      
+      else {
+        size = chunksize(victim);
+
+        /*  We know the first chunk in this bin is big enough to use. */
+        assert((unsigned long)(size) >= (unsigned long)(nb));
+
+        remainder_size = size - nb;
+        
+        /* unlink */
+        bck = victim->bk;
+        bin->bk = bck;
+        bck->fd = bin;
+        
+        /* Exhaust */
+        if (remainder_size < MINSIZE) {
+          set_inuse_bit_at_offset(victim, size);
+          check_malloced_chunk(victim, nb);
+          RETURN(chunk2mem(victim));
+        }
+        
+        /* Split */
+        else {
+          remainder = chunk_at_offset(victim, nb);
+          
+          unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+          remainder->bk = remainder->fd = unsorted_chunks(av);
+          /* advertise as last remainder */
+          if (in_smallbin_range(nb)) 
+            av->last_remainder = remainder; 
+          
+          set_head(victim, nb | PREV_INUSE);
+          set_head(remainder, remainder_size | PREV_INUSE);
+          set_foot(remainder, remainder_size);
+          check_malloced_chunk(victim, nb);
+          RETURN(chunk2mem(victim));
+        }
+      }
+    }
+
+  use_top:    
+    /*
+      If large enough, split off the chunk bordering the end of memory
+      (held in av->top). Note that this is in accord with the best-fit
+      search rule.  In effect, av->top is treated as larger (and thus
+      less well fitting) than any other available chunk since it can
+      be extended to be as large as necessary (up to system
+      limitations).
+
+      We require that av->top always exists (i.e., has size >=
+      MINSIZE) after initialization, so if it would otherwise be
+      exhuasted by current request, it is replenished. (The main
+      reason for ensuring it exists is that we may need MINSIZE space
+      to put in fenceposts in sysmalloc.)
+    */
+
+    victim = av->top;
+    size = chunksize(victim);
+   
+    if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) {
+      remainder_size = size - nb;
+      remainder = chunk_at_offset(victim, nb);
+      av->top = remainder;
+      set_head(victim, nb | PREV_INUSE);
+      set_head(remainder, remainder_size | PREV_INUSE);
+
+      check_malloced_chunk(victim, nb);
+      RETURN(chunk2mem(victim));
+    }
+
+    /*
+      If there is space available in fastbins, consolidate and retry,
+      to possibly avoid expanding memory. This can occur only if nb is
+      in smallbin range so we didn't consolidate upon entry.
+    */
+
+    else if (have_fastchunks(av)) {
+      assert(in_smallbin_range(nb));
+      malloc_consolidate(av);
+      idx = smallbin_index(nb); /* restore original bin index */
+    }
+
+    /* 
+       Otherwise, relay to handle system-dependent cases
+    */
+    else {
+      Void_t *ret = sYSMALLOc(nb, av);
+
+      // As pointed out by Jonathon Jamison, the following code is wrong
+      // because if sYSMALLOc used mmap to get the memory, and the address
+      // happened to be below the sbrk() regions retrieved so far, then
+      // 'firstChunk' would get updated to point at the mmap region, which
+      // is bad.  Therefore this code has been moved inside sYSMALLOc, to
+      // a point where it doesn't get to see mmap returns.
+      #if 0
+      mchunkptr retchunk = mem2chunk(ret);
+      if (!av->firstChunk ||
+          retchunk < av->firstChunk) {
+        /* new 'first' */
+        av->firstChunk = retchunk;
+      }                                                   
+      #endif /* 0 */
+
+      RETURN(ret);
+    }
+  }
+}
+
+/*
+  ------------------------------ free ------------------------------
+*/
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+  mstate av = get_malloc_state();
+
+  mchunkptr       p;           /* chunk corresponding to mem */
+  INTERNAL_SIZE_T size;        /* its size */
+  mfastbinptr*    fb;          /* associated fastbin */
+  mchunkptr       nextchunk;   /* next contiguous chunk */
+  INTERNAL_SIZE_T nextsize;    /* its size */
+  int             nextinuse;   /* true if nextchunk is used */
+  INTERNAL_SIZE_T prevsize;    /* size of previous contiguous chunk */
+  mchunkptr       bck;         /* misc temp for linking */
+  mchunkptr       fwd;         /* misc temp for linking */
+
+  /* sm: my stuff */
+  #ifdef TRACE_MALLOC_CALLS
+  fprintf(stderr, "free(%p)\n", mem);
+  #endif
+  av->numFreeCalls++;
+
+
+  /* free(0) has no effect */
+  if (mem != 0) {
+    p = mem2chunk(mem);
+    size = chunksize(p);
+
+    check_inuse_chunk(p);
+
+    /*
+      If eligible, place chunk on a fastbin so it can be found
+      and used quickly in malloc.
+    */
+
+    if ((unsigned long)(size) <= (unsigned long)(av->max_fast)
+
+#if TRIM_FASTBINS
+        /* 
+           If TRIM_FASTBINS set, don't place chunks
+           bordering top into fastbins
+        */
+        && (chunk_at_offset(p, size) != av->top)
+#endif
+        ) {
+
+      set_fastchunks(av);
+      fb = &(av->fastbins[fastbin_index(size)]);
+      p->fd = *fb;
+      *fb = p;
+    }
+
+    /*
+       Consolidate other non-mmapped chunks as they arrive.
+    */
+
+    else if (!chunk_is_mmapped(p)) {
+      nextchunk = chunk_at_offset(p, size);
+      nextsize = chunksize(nextchunk);
+
+      /* consolidate backward */
+      if (!prev_inuse(p)) {
+        prevsize = p->prev_size;
+        size += prevsize;
+        p = chunk_at_offset(p, -((long) prevsize));
+        unlink(p, bck, fwd);
+      }
+
+      if (nextchunk != av->top) {
+        /* get and clear inuse bit */
+        nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+        set_head(nextchunk, nextsize);
+
+        /* consolidate forward */
+        if (!nextinuse) {
+          unlink(nextchunk, bck, fwd);
+          size += nextsize;
+        }
+
+        /*
+          Place the chunk in unsorted chunk list. Chunks are
+          not placed into regular bins until after they have
+          been given one chance to be used in malloc.
+        */
+
+        bck = unsorted_chunks(av);
+        fwd = bck->fd;
+        p->bk = bck;
+        p->fd = fwd;
+        bck->fd = p;
+        fwd->bk = p;
+
+        set_head(p, size | PREV_INUSE);
+        set_foot(p, size);
+        
+        check_free_chunk(p);
+      }
+
+      /*
+         If the chunk borders the current high end of memory,
+         consolidate into top
+      */
+
+      else {
+        size += nextsize;
+        set_head(p, size | PREV_INUSE);
+        av->top = p;
+        check_chunk(p);
+      }
+
+      /*
+        If freeing a large space, consolidate possibly-surrounding
+        chunks. Then, if the total unused topmost memory exceeds trim
+        threshold, ask malloc_trim to reduce top.
+
+        Unless max_fast is 0, we don't know if there are fastbins
+        bordering top, so we cannot tell for sure whether threshold
+        has been reached unless fastbins are consolidated.  But we
+        don't want to consolidate on each free.  As a compromise,
+        consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD
+        is reached.
+      */
+
+      if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) { 
+        if (have_fastchunks(av)) 
+          malloc_consolidate(av);
+
+#ifndef MORECORE_CANNOT_TRIM        
+        if ((unsigned long)(chunksize(av->top)) >= 
+            (unsigned long)(av->trim_threshold)) 
+          sYSTRIm(av->top_pad, av);
+#endif
+      }
+
+    }
+    /*
+      If the chunk was allocated via mmap, release via munmap()
+      Note that if HAVE_MMAP is false but chunk_is_mmapped is
+      true, then user must have overwritten memory. There's nothing
+      we can do to catch this error unless DEBUG is set, in which case
+      check_inuse_chunk (above) will have triggered error.
+    */
+
+    else {
+#if HAVE_MMAP
+      int ret;
+      INTERNAL_SIZE_T offset = p->prev_size;
+
+      /* sm: update my array */
+      {
+        /* find which slot the mmap'd chunk was using */
+        int i;
+        for (i=0; i < av->n_mmaps; i++) {
+          if (av->mmapPtrs[i] == p) {
+            break;    /* found it */
+          }
+        }
+        assert(i < av->n_mmaps);    /* otherwise it's not in the array! */
+
+        /* copy the last ptr into the slot occupied by this one,
+         * thereby maintaining contiguity */
+        av->mmapPtrs[i] = av->mmapPtrs[av->n_mmaps-1];
+      }
+
+      av->n_mmaps--;
+      av->mmapped_mem -= (size + offset);
+      ret = munmap((char*)p - offset, size + offset);
+      /* munmap returns non-zero on failure */
+      assert(ret == 0);
+#endif
+    }
+  }
+}
+
+/*
+  ------------------------- malloc_consolidate -------------------------
+
+  malloc_consolidate is a specialized version of free() that tears
+  down chunks held in fastbins.  Free itself cannot be used for this
+  purpose since, among other things, it might place chunks back onto
+  fastbins.  So, instead, we need to use a minor variant of the same
+  code.
+  
+  Also, because this routine needs to be called the first time through
+  malloc anyway, it turns out to be the perfect place to trigger
+  initialization code.
+*/
+
+#if __STD_C
+static void malloc_consolidate(mstate av)
+#else
+static void malloc_consolidate(av) mstate av;
+#endif
+{
+  mfastbinptr*    fb;                 /* current fastbin being consolidated */
+  mfastbinptr*    maxfb;              /* last fastbin (for loop control) */
+  mchunkptr       p;                  /* current chunk being consolidated */
+  mchunkptr       nextp;              /* next chunk to consolidate */
+  mchunkptr       unsorted_bin;       /* bin header */
+  mchunkptr       first_unsorted;     /* chunk to link to */
+
+  /* These have same use as in free() */
+  mchunkptr       nextchunk;
+  INTERNAL_SIZE_T size;
+  INTERNAL_SIZE_T nextsize;
+  INTERNAL_SIZE_T prevsize;
+  int             nextinuse;
+  mchunkptr       bck;
+  mchunkptr       fwd;
+
+  /*
+    If max_fast is 0, we know that av hasn't
+    yet been initialized, in which case do so below
+  */
+
+  if (av->max_fast != 0) {
+    clear_fastchunks(av);
+
+    unsorted_bin = unsorted_chunks(av);
+
+    /*
+      Remove each chunk from fast bin and consolidate it, placing it
+      then in unsorted bin. Among other reasons for doing this,
+      placing in unsorted bin avoids needing to calculate actual bins
+      until malloc is sure that chunks aren't immediately going to be
+      reused anyway.
+    */
+    
+    maxfb = &(av->fastbins[fastbin_index(av->max_fast)]);
+    fb = &(av->fastbins[0]);
+    do {
+      if ( (p = *fb) != 0) {
+        *fb = 0;
+        
+        do {
+          check_inuse_chunk(p);
+          nextp = p->fd;
+          
+          /* Slightly streamlined version of consolidation code in free() */
+          size = p->size & ~PREV_INUSE;
+          nextchunk = chunk_at_offset(p, size);
+          nextsize = chunksize(nextchunk);
+          
+          if (!prev_inuse(p)) {
+            prevsize = p->prev_size;
+            size += prevsize;
+            p = chunk_at_offset(p, -((long) prevsize));
+            unlink(p, bck, fwd);
+          }
+          
+          if (nextchunk != av->top) {
+            nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+            set_head(nextchunk, nextsize);
+            
+            if (!nextinuse) {
+              size += nextsize;
+              unlink(nextchunk, bck, fwd);
+            }
+            
+            first_unsorted = unsorted_bin->fd;
+            unsorted_bin->fd = p;
+            first_unsorted->bk = p;
+            
+            set_head(p, size | PREV_INUSE);
+            p->bk = unsorted_bin;
+            p->fd = first_unsorted;
+            set_foot(p, size);
+          }
+          
+          else {
+            size += nextsize;
+            set_head(p, size | PREV_INUSE);
+            av->top = p;
+          }
+          
+        } while ( (p = nextp) != 0);
+        
+      }
+    } while (fb++ != maxfb);
+  }
+  else {
+    malloc_init_state(av);
+    check_malloc_state();
+  }
+}
+
+/*
+  ------------------------------ realloc ------------------------------
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+  mstate av = get_malloc_state();
+
+  INTERNAL_SIZE_T  nb;              /* padded request size */
+
+  mchunkptr        oldp;            /* chunk corresponding to oldmem */
+  INTERNAL_SIZE_T  oldsize;         /* its size */
+
+  mchunkptr        newp;            /* chunk to return */
+  INTERNAL_SIZE_T  newsize;         /* its size */
+  Void_t*          newmem;          /* corresponding user mem */
+
+  mchunkptr        next;            /* next contiguous chunk after oldp */
+
+  mchunkptr        remainder;       /* extra space at end of newp */
+  unsigned long    remainder_size;  /* its size */
+
+  mchunkptr        bck;             /* misc temp for linking */
+  mchunkptr        fwd;             /* misc temp for linking */
+
+  unsigned long    copysize;        /* bytes to copy */
+  unsigned int     ncopies;         /* INTERNAL_SIZE_T words to copy */
+  INTERNAL_SIZE_T* s;               /* copy source */ 
+  INTERNAL_SIZE_T* d;               /* copy destination */
+
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) {
+    fREe(oldmem);
+    return 0;
+  }
+#endif
+
+  /* realloc of null is supposed to be same as malloc */
+  if (oldmem == 0) return mALLOc(bytes);
+
+  checked_request2size(bytes, nb);
+
+  oldp    = mem2chunk(oldmem);
+  oldsize = chunksize(oldp);
+
+  check_inuse_chunk(oldp);
+
+  if (!chunk_is_mmapped(oldp)) {
+
+    if ((unsigned long)(oldsize) >= (unsigned long)(nb)) {
+      /* already big enough; split below */
+      newp = oldp;
+      newsize = oldsize;
+    }
+
+    else {
+      next = chunk_at_offset(oldp, oldsize);
+
+      /* Try to expand forward into top */
+      if (next == av->top &&
+          (unsigned long)(newsize = oldsize + chunksize(next)) >=
+          (unsigned long)(nb + MINSIZE)) {
+        set_head_size(oldp, nb);
+        av->top = chunk_at_offset(oldp, nb);
+        set_head(av->top, (newsize - nb) | PREV_INUSE);
+        return chunk2mem(oldp);
+      }
+      
+      /* Try to expand forward into next chunk;  split off remainder below */
+      else if (next != av->top && 
+               !inuse(next) &&
+               (unsigned long)(newsize = oldsize + chunksize(next)) >=
+               (unsigned long)(nb)) {
+        newp = oldp;
+        unlink(next, bck, fwd);
+      }
+
+      /* allocate, copy, free */
+      else {
+        newmem = mALLOc(nb - MALLOC_ALIGN_MASK);
+        if (newmem == 0)
+          return 0; /* propagate failure */
+      
+        newp = mem2chunk(newmem);
+        newsize = chunksize(newp);
+        
+        /*
+          Avoid copy if newp is next chunk after oldp.
+        */
+        if (newp == next) {
+          newsize += oldsize;
+          newp = oldp;
+        }
+        else {
+          /*
+            Unroll copy of <= 36 bytes (72 if 8byte sizes)
+            We know that contents have an odd number of
+            INTERNAL_SIZE_T-sized words; minimally 3.
+          */
+          
+          copysize = oldsize - SIZE_SZ;
+          s = (INTERNAL_SIZE_T*)(oldmem);
+          d = (INTERNAL_SIZE_T*)(newmem);
+          ncopies = copysize / sizeof(INTERNAL_SIZE_T);
+          assert(ncopies >= 3);
+          
+          if (ncopies > 9)
+            MALLOC_COPY(d, s, copysize);
+          
+          else {
+            *(d+0) = *(s+0);
+            *(d+1) = *(s+1);
+            *(d+2) = *(s+2);
+            if (ncopies > 4) {
+              *(d+3) = *(s+3);
+              *(d+4) = *(s+4);
+              if (ncopies > 6) {
+                *(d+5) = *(s+5);
+                *(d+6) = *(s+6);
+                if (ncopies > 8) {
+                  *(d+7) = *(s+7);
+                  *(d+8) = *(s+8);
+                }
+              }
+            }
+          }
+          
+          fREe(oldmem);
+          check_inuse_chunk(newp);
+          return chunk2mem(newp);
+        }
+      }
+    }
+
+    /* If possible, free extra space in old or extended chunk */
+
+    assert((unsigned long)(newsize) >= (unsigned long)(nb));
+
+    remainder_size = newsize - nb;
+
+    if (remainder_size < MINSIZE) { /* not enough extra to split off */
+      set_head_size(newp, newsize);
+      set_inuse_bit_at_offset(newp, newsize);
+    }
+    else { /* split remainder */
+      remainder = chunk_at_offset(newp, nb);
+      set_head_size(newp, nb);
+      set_head(remainder, remainder_size | PREV_INUSE);
+      /* Mark remainder as inuse so free() won't complain */
+      set_inuse_bit_at_offset(remainder, remainder_size);
+      fREe(chunk2mem(remainder)); 
+    }
+
+    check_inuse_chunk(newp);
+    return chunk2mem(newp);
+  }
+
+  /*
+    Handle mmap cases
+  */
+
+  else {
+#if HAVE_MMAP
+
+#if HAVE_MREMAP
+    INTERNAL_SIZE_T offset = oldp->prev_size;
+    size_t pagemask = av->pagesize - 1;
+    char *cp;
+    unsigned long sum;
+    
+    /* Note the extra SIZE_SZ overhead */
+    newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask;
+
+    /* don't need to remap if still within same page */
+    if (oldsize == newsize - offset) 
+      return oldmem;
+
+    cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1);
+    
+    if (cp != (char*)MORECORE_FAILURE) {
+
+      newp = (mchunkptr)(cp + offset);
+      set_head(newp, (newsize - offset)|IS_MMAPPED);
+      
+      assert(aligned_OK(chunk2mem(newp)));
+      assert((newp->prev_size == offset));
+      
+      /* update statistics */
+      sum = av->mmapped_mem += newsize - oldsize;
+      if (sum > (unsigned long)(av->max_mmapped_mem)) 
+        av->max_mmapped_mem = sum;
+      sum += av->sbrked_mem;
+      if (sum > (unsigned long)(av->max_total_mem)) 
+        av->max_total_mem = sum;
+      
+      return chunk2mem(newp);
+    }
+#endif
+
+    /* Note the extra SIZE_SZ overhead. */
+    if ((unsigned long)(oldsize) >= (unsigned long)(nb + SIZE_SZ)) 
+      newmem = oldmem; /* do nothing */
+    else {
+      /* Must alloc, copy, free. */
+      newmem = mALLOc(nb - MALLOC_ALIGN_MASK);
+      if (newmem != 0) {
+        MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+        fREe(oldmem);
+      }
+    }
+    return newmem;
+
+#else 
+    /* If !HAVE_MMAP, but chunk_is_mmapped, user must have overwritten mem */
+    check_malloc_state();
+    MALLOC_FAILURE_ACTION;
+    return 0;
+#endif
+  }
+}
+
+/*
+  ------------------------------ memalign ------------------------------
+*/
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T nb;             /* padded  request size */
+  char*           m;              /* memory returned by malloc call */
+  mchunkptr       p;              /* corresponding chunk */
+  char*           brk;            /* alignment point within p */
+  mchunkptr       newp;           /* chunk to return */
+  INTERNAL_SIZE_T newsize;        /* its size */
+  INTERNAL_SIZE_T leadsize;       /* leading space before alignment point */
+  mchunkptr       remainder;      /* spare room at end to split off */
+  unsigned long   remainder_size; /* its size */
+  INTERNAL_SIZE_T size;
+
+  /* If need less alignment than we give anyway, just relay to malloc */
+
+  if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+  /* Otherwise, ensure that it is at least a minimum chunk size */
+
+  if (alignment <  MINSIZE) alignment = MINSIZE;
+
+  /* Make sure alignment is power of 2 (in case MINSIZE is not).  */
+  if ((alignment & (alignment - 1)) != 0) {
+    size_t a = MALLOC_ALIGNMENT * 2;
+    while ((unsigned long)a < (unsigned long)alignment) a <<= 1;
+    alignment = a;
+  }
+
+  checked_request2size(bytes, nb);
+
+  /*
+    Strategy: find a spot within that chunk that meets the alignment
+    request, and then possibly free the leading and trailing space.
+  */
+
+
+  /* Call malloc with worst case padding to hit alignment. */
+
+  m  = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+  if (m == 0) return 0; /* propagate failure */
+
+  p = mem2chunk(m);
+
+  if ((((unsigned long)(m)) % alignment) != 0) { /* misaligned */
+
+    /*
+      Find an aligned spot inside chunk.  Since we need to give back
+      leading space in a chunk of at least MINSIZE, if the first
+      calculation places us at a spot with less than MINSIZE leader,
+      we can move to the next aligned spot -- we've allocated enough
+      total room so that this is always possible.
+    */
+
+    brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) &
+                           -((signed long) alignment));
+    if ((unsigned long)(brk - (char*)(p)) < MINSIZE)
+      brk += alignment;
+
+    newp = (mchunkptr)brk;
+    leadsize = brk - (char*)(p);
+    newsize = chunksize(p) - leadsize;
+
+    /* For mmapped chunks, just adjust offset */
+    if (chunk_is_mmapped(p)) {
+      newp->prev_size = p->prev_size + leadsize;
+      set_head(newp, newsize|IS_MMAPPED);
+      return chunk2mem(newp);
+    }
+
+    /* Otherwise, give back leader, use the rest */
+    set_head(newp, newsize | PREV_INUSE);
+    set_inuse_bit_at_offset(newp, newsize);
+    set_head_size(p, leadsize);
+    fREe(chunk2mem(p));
+    p = newp;
+
+    assert (newsize >= nb &&
+            (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+  }
+
+  /* Also give back spare room at the end */
+  if (!chunk_is_mmapped(p)) {
+    size = chunksize(p);
+    if ((unsigned long)(size) > (unsigned long)(nb + MINSIZE)) {
+      remainder_size = size - nb;
+      remainder = chunk_at_offset(p, nb);
+      set_head(remainder, remainder_size | PREV_INUSE);
+      set_head_size(p, nb);
+      fREe(chunk2mem(remainder));
+    }
+  }
+
+  check_inuse_chunk(p);
+  return chunk2mem(p);
+}
+
+/*
+  ------------------------------ calloc ------------------------------
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n_elements, size_t elem_size)
+#else
+Void_t* cALLOc(n_elements, elem_size) size_t n_elements; size_t elem_size;
+#endif
+{
+  mchunkptr p;
+  unsigned long clearsize;
+  unsigned long nclears;
+  INTERNAL_SIZE_T* d;
+
+  #ifdef DEBUG_HEAP
+    Void_t* mem = public_mALLOc(n_elements * elem_size);
+    memset(mem, 0, n_elements * elem_size);
+    return mem;
+  #else
+    Void_t* mem = mALLOc(n_elements * elem_size);
+  #endif
+
+  if (mem != 0) {
+    p = mem2chunk(mem);
+
+#if MMAP_CLEARS
+    if (!chunk_is_mmapped(p)) /* don't need to clear mmapped space */
+#endif
+    {  
+      /*
+        Unroll clear of <= 36 bytes (72 if 8byte sizes)
+        We know that contents have an odd number of
+        INTERNAL_SIZE_T-sized words; minimally 3.
+      */
+
+      d = (INTERNAL_SIZE_T*)mem;
+      clearsize = chunksize(p) - SIZE_SZ;
+      nclears = clearsize / sizeof(INTERNAL_SIZE_T);
+      assert(nclears >= 3);
+
+      if (nclears > 9)
+        MALLOC_ZERO(d, clearsize);
+
+      else {
+        *(d+0) = 0;
+        *(d+1) = 0;
+        *(d+2) = 0;
+        if (nclears > 4) {
+          *(d+3) = 0;
+          *(d+4) = 0;
+          if (nclears > 6) {
+            *(d+5) = 0;
+            *(d+6) = 0;
+            if (nclears > 8) {
+              *(d+7) = 0;
+              *(d+8) = 0;
+            }
+          }
+        }
+      }
+    }
+  }
+  return mem;
+}
+
+/*
+  ------------------------------ cfree ------------------------------
+*/
+
+#if __STD_C
+void cFREe(Void_t *mem)
+#else
+void cFREe(mem) Void_t *mem;
+#endif
+{
+  fREe(mem);
+}
+
+/*
+  ------------------------- independent_calloc -------------------------
+*/
+
+#if __STD_C
+Void_t** iCALLOc(size_t n_elements, size_t elem_size, Void_t* chunks[])
+#else
+Void_t** iCALLOc(n_elements, elem_size, chunks) size_t n_elements; size_t elem_size; Void_t* chunks[];
+#endif
+{
+  size_t sz = elem_size; /* serves as 1-element array */
+  /* opts arg of 3 means all elements are same size, and should be cleared */
+  return iALLOc(n_elements, &sz, 3, chunks);
+}
+
+/*
+  ------------------------- independent_comalloc -------------------------
+*/
+
+#if __STD_C
+Void_t** iCOMALLOc(size_t n_elements, size_t sizes[], Void_t* chunks[])
+#else
+Void_t** iCOMALLOc(n_elements, sizes, chunks) size_t n_elements; size_t sizes[]; Void_t* chunks[];
+#endif
+{
+  return iALLOc(n_elements, sizes, 0, chunks);
+}
+
+
+/*
+  ------------------------------ ialloc ------------------------------
+  ialloc provides common support for independent_X routines, handling all of
+  the combinations that can result.
+
+  The opts arg has:
+    bit 0 set if all elements are same size (using sizes[0])
+    bit 1 set if elements should be zeroed
+*/
+
+
+#if __STD_C
+static Void_t** iALLOc(size_t n_elements, 
+                       size_t* sizes,  
+                       int opts,
+                       Void_t* chunks[])
+#else
+static Void_t** iALLOc(n_elements, sizes, opts, chunks) size_t n_elements; size_t* sizes; int opts; Void_t* chunks[];
+#endif
+{
+  mstate av = get_malloc_state();
+  INTERNAL_SIZE_T element_size;   /* chunksize of each element, if all same */
+  INTERNAL_SIZE_T contents_size;  /* total size of elements */
+  INTERNAL_SIZE_T array_size;     /* request size of pointer array */
+  Void_t*         mem;            /* malloced aggregate space */
+  mchunkptr       p;              /* corresponding chunk */
+  INTERNAL_SIZE_T remainder_size; /* remaining bytes while splitting */
+  Void_t**        marray;         /* either "chunks" or malloced ptr array */
+  mchunkptr       array_chunk;    /* chunk for malloced ptr array */
+  int             mmx;            /* to disable mmap */
+  INTERNAL_SIZE_T size;           
+  size_t          i;
+
+  /* Ensure initialization/consolidation */
+  if (have_fastchunks(av)) malloc_consolidate(av);
+
+  /* compute array length, if needed */
+  if (chunks != 0) {
+    if (n_elements == 0)
+      return chunks; /* nothing to do */
+    marray = chunks;
+    array_size = 0;
+  }
+  else {
+    /* if empty req, must still return chunk representing empty array */
+    if (n_elements == 0) 
+      return (Void_t**) mALLOc(0);
+    marray = 0;
+    array_size = request2size(n_elements * (sizeof(Void_t*)));
+  }
+
+  /* compute total element size */
+  if (opts & 0x1) { /* all-same-size */
+    element_size = request2size(*sizes);
+    contents_size = n_elements * element_size;
+  }
+  else { /* add up all the sizes */
+    element_size = 0;
+    contents_size = 0;
+    for (i = 0; i != n_elements; ++i) 
+      contents_size += request2size(sizes[i]);     
+  }
+
+  /* subtract out alignment bytes from total to minimize overallocation */
+  size = contents_size + array_size - MALLOC_ALIGN_MASK;
+  
+  /* 
+     Allocate the aggregate chunk.
+     But first disable mmap so malloc won't use it, since
+     we would not be able to later free/realloc space internal
+     to a segregated mmap region.
+ */
+  mmx = av->n_mmaps_max;   /* disable mmap */
+  av->n_mmaps_max = 0;
+  mem = mALLOc(size);
+  av->n_mmaps_max = mmx;   /* reset mmap */
+  if (mem == 0) 
+    return 0;
+
+  p = mem2chunk(mem);
+  assert(!chunk_is_mmapped(p)); 
+  remainder_size = chunksize(p);
+
+  if (opts & 0x2) {       /* optionally clear the elements */
+    MALLOC_ZERO(mem, remainder_size - SIZE_SZ - array_size);
+  }
+
+  /* If not provided, allocate the pointer array as final part of chunk */
+  if (marray == 0) {
+    array_chunk = chunk_at_offset(p, contents_size);
+    marray = (Void_t**) (chunk2mem(array_chunk));
+    set_head(array_chunk, (remainder_size - contents_size) | PREV_INUSE);
+    remainder_size = contents_size;
+  }
+
+  /* split out elements */
+  for (i = 0; ; ++i) {
+    marray[i] = chunk2mem(p);
+    if (i != n_elements-1) {
+      if (element_size != 0) 
+        size = element_size;
+      else
+        size = request2size(sizes[i]);          
+      remainder_size -= size;
+      set_head(p, size | PREV_INUSE);
+      p = chunk_at_offset(p, size);
+    }
+    else { /* the final element absorbs any overallocation slop */
+      set_head(p, remainder_size | PREV_INUSE);
+      break;
+    }
+  }
+
+#if DEBUG
+  if (marray != chunks) {
+    /* final element must have exactly exhausted chunk */
+    if (element_size != 0) 
+      assert(remainder_size == element_size);
+    else
+      assert(remainder_size == request2size(sizes[i]));
+    check_inuse_chunk(mem2chunk(marray));
+  }
+
+  for (i = 0; i != n_elements; ++i)
+    check_inuse_chunk(mem2chunk(marray[i]));
+#endif
+
+  return marray;
+}
+
+
+/*
+  ------------------------------ valloc ------------------------------
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+  /* Ensure initialization/consolidation */
+  mstate av = get_malloc_state();
+  if (have_fastchunks(av)) malloc_consolidate(av);
+  return mEMALIGn(av->pagesize, bytes);
+}
+
+/*
+  ------------------------------ pvalloc ------------------------------
+*/
+
+
+#if __STD_C
+Void_t* pVALLOc(size_t bytes)
+#else
+Void_t* pVALLOc(bytes) size_t bytes;
+#endif
+{
+  mstate av = get_malloc_state();
+  size_t pagesz;
+
+  /* Ensure initialization/consolidation */
+  if (have_fastchunks(av)) malloc_consolidate(av);
+  pagesz = av->pagesize;
+  return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1));
+}
+   
+
+/*
+  ------------------------------ malloc_trim ------------------------------
+*/
+
+#if __STD_C
+int mTRIm(size_t pad)
+#else
+int mTRIm(pad) size_t pad;
+#endif
+{
+  mstate av = get_malloc_state();
+  /* Ensure initialization/consolidation */
+  malloc_consolidate(av);
+
+#ifndef MORECORE_CANNOT_TRIM        
+  return sYSTRIm(pad, av);
+#else
+  return 0;
+#endif
+}
+
+
+/*
+  ------------------------- malloc_usable_size -------------------------
+*/
+
+#if __STD_C
+size_t mUSABLe(Void_t* mem)
+#else
+size_t mUSABLe(mem) Void_t* mem;
+#endif
+{
+  mchunkptr p;
+  if (mem != 0) {
+    p = mem2chunk(mem);
+    if (chunk_is_mmapped(p))
+      return chunksize(p) - 2*SIZE_SZ;
+    else if (inuse(p))
+      return chunksize(p) - SIZE_SZ;
+  }
+  return 0;
+}
+
+/*
+  ------------------------------ mallinfo ------------------------------
+*/
+
+struct mallinfo mALLINFo()
+{
+  mstate av = get_malloc_state();
+  struct mallinfo mi;
+  int i;
+  mbinptr b;
+  mchunkptr p;
+  INTERNAL_SIZE_T avail;
+  INTERNAL_SIZE_T fastavail;
+  int nblocks;
+  int nfastblocks;
+
+  /* Ensure initialization */
+  if (av->top == 0)  malloc_consolidate(av);
+
+  check_malloc_state();
+
+  /* Account for top */
+  avail = chunksize(av->top);
+  nblocks = 1;  /* top always exists */
+
+  /* traverse fastbins */
+  nfastblocks = 0;
+  fastavail = 0;
+
+  for (i = 0; i < NFASTBINS; ++i) {
+    for (p = av->fastbins[i]; p != 0; p = p->fd) {
+      ++nfastblocks;
+      fastavail += chunksize(p);
+    }
+  }
+
+  avail += fastavail;
+
+  /* traverse regular bins */
+  for (i = 1; i < NBINS; ++i) {
+    b = bin_at(av, i);
+    for (p = last(b); p != b; p = p->bk) {
+      ++nblocks;
+      avail += chunksize(p);
+    }
+  }
+
+  mi.smblks = nfastblocks;
+  mi.ordblks = nblocks;
+  mi.fordblks = avail;
+  mi.uordblks = av->sbrked_mem - avail;
+  mi.arena = av->sbrked_mem;
+  mi.hblks = av->n_mmaps;
+  mi.hblkhd = av->mmapped_mem;
+  mi.fsmblks = fastavail;
+  mi.keepcost = chunksize(av->top);
+  mi.usmblks = av->max_total_mem;
+  return mi;
+}
+
+/*
+  ------------------------------ malloc_stats ------------------------------
+*/
+
+void mSTATs()
+{
+  struct mallinfo mi = mALLINFo();
+
+#ifdef WIN32
+  {
+    unsigned long free, reserved, committed;
+    vminfo (&free, &reserved, &committed);
+    fprintf(stderr, "free bytes       = %10lu\n",
+            free);
+    fprintf(stderr, "reserved bytes   = %10lu\n", 
+            reserved);
+    fprintf(stderr, "committed bytes  = %10lu\n", 
+            committed);
+  }
+#endif
+
+
+  fprintf(stderr, "max system bytes = %10lu\n",
+          (unsigned long)(mi.usmblks));
+  fprintf(stderr, "system bytes     = %10lu\n",
+          (unsigned long)(mi.arena + mi.hblkhd));
+  fprintf(stderr, "in use bytes     = %10lu\n",
+          (unsigned long)(mi.uordblks + mi.hblkhd));
+
+  /* sm: my stats */
+  {
+    mstate av = get_malloc_state();
+    fprintf(stderr, "total malloc calls = %u\n", av->numMallocCalls);
+    #ifdef DEBUG_HEAP
+      fprintf(stderr, "(free is never called because of DEBUG_HEAP)\n");
+    #else
+      fprintf(stderr, "total free calls = %u\n", av->numFreeCalls);
+    #endif
+  }
+
+
+#ifdef WIN32
+  {
+    unsigned long kernel, user;
+    if (cpuinfo (TRUE, &kernel, &user)) {
+      fprintf(stderr, "kernel ms        = %10lu\n",
+              kernel);
+      fprintf(stderr, "user ms          = %10lu\n",
+              user);
+    }
+  }
+#endif
+}
+
+
+unsigned numMallocCalls()
+{
+  mstate av = get_malloc_state();
+  return av->numMallocCalls;
+}
+
+unsigned numFreeCalls()
+{
+  mstate av = get_malloc_state();
+  return av->numFreeCalls;
+}
+
+
+/*
+  ------------------------------ mallopt ------------------------------
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+  mstate av = get_malloc_state();
+  /* Ensure initialization/consolidation */
+  malloc_consolidate(av);
+
+  switch(param_number) {
+  case M_MXFAST:
+    if (value >= 0 && value <= MAX_FAST_SIZE) {
+      set_max_fast(av, value);
+      return 1;
+    }
+    else
+      return 0;
+
+  case M_TRIM_THRESHOLD:
+    av->trim_threshold = value;
+    return 1;
+
+  case M_TOP_PAD:
+    av->top_pad = value;
+    return 1;
+
+  case M_MMAP_THRESHOLD:
+    av->mmap_threshold = value;
+    return 1;
+
+  case M_MMAP_MAX:
+#if !HAVE_MMAP
+    if (value != 0)
+      return 0;
+#endif
+    av->n_mmaps_max = value;
+    return 1;
+
+  default:
+    return 0;
+  }
+}
+
+
+/* 
+  -------------------- Alternative MORECORE functions --------------------
+*/
+
+
+/*
+  General Requirements for MORECORE.
+
+  The MORECORE function must have the following properties:
+
+  If MORECORE_CONTIGUOUS is false:
+
+    * MORECORE must allocate in multiples of pagesize. It will
+      only be called with arguments that are multiples of pagesize.
+
+    * MORECORE(0) must return an address that is at least 
+      MALLOC_ALIGNMENT aligned. (Page-aligning always suffices.)
+
+  else (i.e. If MORECORE_CONTIGUOUS is true):
+
+    * Consecutive calls to MORECORE with positive arguments
+      return increasing addresses, indicating that space has been
+      contiguously extended.
+
+    * MORECORE need not allocate in multiples of pagesize.
+      Calls to MORECORE need not have args of multiples of pagesize.
+
+    * MORECORE need not page-align.
+
+  In either case:
+
+    * MORECORE may allocate more memory than requested. (Or even less,
+      but this will generally result in a malloc failure.)
+
+    * MORECORE must not allocate memory when given argument zero, but
+      instead return one past the end address of memory from previous
+      nonzero call. This malloc does NOT call MORECORE(0)
+      until at least one call with positive arguments is made, so
+      the initial value returned is not important.
+
+    * Even though consecutive calls to MORECORE need not return contiguous
+      addresses, it must be OK for malloc'ed chunks to span multiple
+      regions in those cases where they do happen to be contiguous.
+
+    * MORECORE need not handle negative arguments -- it may instead
+      just return MORECORE_FAILURE when given negative arguments.
+      Negative arguments are always multiples of pagesize. MORECORE
+      must not misinterpret negative args as large positive unsigned
+      args. You can suppress all such calls from even occurring by defining
+      MORECORE_CANNOT_TRIM,
+
+  There is some variation across systems about the type of the
+  argument to sbrk/MORECORE. If size_t is unsigned, then it cannot
+  actually be size_t, because sbrk supports negative args, so it is
+  normally the signed type of the same width as size_t (sometimes
+  declared as "intptr_t", and sometimes "ptrdiff_t").  It doesn't much
+  matter though. Internally, we use "long" as arguments, which should
+  work across all reasonable possibilities.
+
+  Additionally, if MORECORE ever returns failure for a positive
+  request, and HAVE_MMAP is true, then mmap is used as a noncontiguous
+  system allocator. This is a useful backup strategy for systems with
+  holes in address spaces -- in this case sbrk cannot contiguously
+  expand the heap, but mmap may be able to map noncontiguous space.
+
+  If you'd like mmap to ALWAYS be used, you can define MORECORE to be
+  a function that always returns MORECORE_FAILURE.
+
+  If you are using this malloc with something other than sbrk (or its
+  emulation) to supply memory regions, you probably want to set
+  MORECORE_CONTIGUOUS as false.  As an example, here is a custom
+  allocator kindly contributed for pre-OSX macOS.  It uses virtually
+  but not necessarily physically contiguous non-paged memory (locked
+  in, present and won't get swapped out).  You can use it by
+  uncommenting this section, adding some #includes, and setting up the
+  appropriate defines above:
+
+      #define MORECORE osMoreCore
+      #define MORECORE_CONTIGUOUS 0
+
+  There is also a shutdown routine that should somehow be called for
+  cleanup upon program exit.
+
+  #define MAX_POOL_ENTRIES 100
+  #define MINIMUM_MORECORE_SIZE  (64 * 1024)
+  static int next_os_pool;
+  void *our_os_pools[MAX_POOL_ENTRIES];
+
+  void *osMoreCore(int size)
+  {
+    void *ptr = 0;
+    static void *sbrk_top = 0;
+
+    if (size > 0)
+    {
+      if (size < MINIMUM_MORECORE_SIZE)
+         size = MINIMUM_MORECORE_SIZE;
+      if (CurrentExecutionLevel() == kTaskLevel)
+         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+      if (ptr == 0)
+      {
+        return (void *) MORECORE_FAILURE;
+      }
+      // save ptrs so they can be freed during cleanup
+      our_os_pools[next_os_pool] = ptr;
+      next_os_pool++;
+      ptr = (void *) ((((unsigned long) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+      sbrk_top = (char *) ptr + size;
+      return ptr;
+    }
+    else if (size < 0)
+    {
+      // we don't currently support shrink behavior
+      return (void *) MORECORE_FAILURE;
+    }
+    else
+    {
+      return sbrk_top;
+    }
+  }
+
+  // cleanup any allocated memory pools
+  // called as last thing before shutting down driver
+
+  void osCleanupMem(void)
+  {
+    void **ptr;
+
+    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+      if (*ptr)
+      {
+         PoolDeallocate(*ptr);
+         *ptr = 0;
+      }
+  }
+
+*/
+
+
+/* 
+  -------------------------------------------------------------- 
+
+  Emulation of sbrk for win32. 
+  Donated by J. Walter <Walter at GeNeSys-e.de>.
+  For additional information about this code, and malloc on Win32, see 
+     http://www.genesys-e.de/jwalter/
+*/
+
+
+#ifdef WIN32
+
+#ifdef _DEBUG
+/* #define TRACE */
+#endif
+
+/* Support for USE_MALLOC_LOCK */
+#ifdef USE_MALLOC_LOCK
+
+/* Wait for spin lock */
+static int slwait (int *sl) {
+    while (InterlockedCompareExchange ((void **) sl, (void *) 1, (void *) 0) != 0) 
+	    Sleep (0);
+    return 0;
+}
+
+/* Release spin lock */
+static int slrelease (int *sl) {
+    InterlockedExchange (sl, 0);
+    return 0;
+}
+
+#ifdef NEEDED
+/* Spin lock for emulation code */
+static int g_sl;
+#endif
+
+#endif /* USE_MALLOC_LOCK */
+
+/* getpagesize for windows */
+static long getpagesize (void) {
+    static long g_pagesize = 0;
+    if (! g_pagesize) {
+        SYSTEM_INFO system_info;
+        GetSystemInfo (&system_info);
+        g_pagesize = system_info.dwPageSize;
+    }
+    return g_pagesize;
+}
+static long getregionsize (void) {
+    static long g_regionsize = 0;
+    if (! g_regionsize) {
+        SYSTEM_INFO system_info;
+        GetSystemInfo (&system_info);
+        g_regionsize = system_info.dwAllocationGranularity;
+    }
+    return g_regionsize;
+}
+
+/* A region list entry */
+typedef struct _region_list_entry {
+    void *top_allocated;
+    void *top_committed;
+    void *top_reserved;
+    long reserve_size;
+    struct _region_list_entry *previous;
+} region_list_entry;
+
+/* Allocate and link a region entry in the region list */
+static int region_list_append (region_list_entry **last, void *base_reserved, long reserve_size) {
+    region_list_entry *next = HeapAlloc (GetProcessHeap (), 0, sizeof (region_list_entry));
+    if (! next)
+        return FALSE;
+    next->top_allocated = (char *) base_reserved;
+    next->top_committed = (char *) base_reserved;
+    next->top_reserved = (char *) base_reserved + reserve_size;
+    next->reserve_size = reserve_size;
+    next->previous = *last;
+    *last = next;
+    return TRUE;
+}
+/* Free and unlink the last region entry from the region list */
+static int region_list_remove (region_list_entry **last) {
+    region_list_entry *previous = (*last)->previous;
+    if (! HeapFree (GetProcessHeap (), sizeof (region_list_entry), *last))
+        return FALSE;
+    *last = previous;
+    return TRUE;
+}
+
+#define CEIL(size,to)	(((size)+(to)-1)&~((to)-1))
+#define FLOOR(size,to)	((size)&~((to)-1))
+
+#define SBRK_SCALE  0
+/* #define SBRK_SCALE  1 */
+/* #define SBRK_SCALE  2 */
+/* #define SBRK_SCALE  4  */
+
+/* sbrk for windows */
+static void *sbrk (long size) {
+    static long g_pagesize, g_my_pagesize;
+    static long g_regionsize, g_my_regionsize;
+    static region_list_entry *g_last;
+    void *result = (void *) MORECORE_FAILURE;
+#ifdef TRACE
+    printf ("sbrk %d\n", size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+    /* Wait for spin lock */
+    slwait (&g_sl);
+#endif
+    /* First time initialization */
+    if (! g_pagesize) {
+        g_pagesize = getpagesize ();
+        g_my_pagesize = g_pagesize << SBRK_SCALE;
+    }
+    if (! g_regionsize) {
+        g_regionsize = getregionsize ();
+        g_my_regionsize = g_regionsize << SBRK_SCALE;
+    }
+    if (! g_last) {
+        if (! region_list_append (&g_last, 0, 0)) 
+           goto sbrk_exit;
+    }
+    /* Assert invariants */
+    assert (g_last);
+    assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated &&
+            g_last->top_allocated <= g_last->top_committed);
+    assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed &&
+            g_last->top_committed <= g_last->top_reserved &&
+            (unsigned) g_last->top_committed % g_pagesize == 0);
+    assert ((unsigned) g_last->top_reserved % g_regionsize == 0);
+    assert ((unsigned) g_last->reserve_size % g_regionsize == 0);
+    /* Allocation requested? */
+    if (size >= 0) {
+        /* Allocation size is the requested size */
+        long allocate_size = size;
+        /* Compute the size to commit */
+        long to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+        /* Do we reach the commit limit? */
+        if (to_commit > 0) {
+            /* Round size to commit */
+            long commit_size = CEIL (to_commit, g_my_pagesize);
+            /* Compute the size to reserve */
+            long to_reserve = (char *) g_last->top_committed + commit_size - (char *) g_last->top_reserved;
+            /* Do we reach the reserve limit? */
+            if (to_reserve > 0) {
+                /* Compute the remaining size to commit in the current region */
+                long remaining_commit_size = (char *) g_last->top_reserved - (char *) g_last->top_committed;
+                if (remaining_commit_size > 0) {
+                    /* Assert preconditions */
+                    assert ((unsigned) g_last->top_committed % g_pagesize == 0);
+                    assert (0 < remaining_commit_size && remaining_commit_size % g_pagesize == 0); {
+                        /* Commit this */
+                        void *base_committed = VirtualAlloc (g_last->top_committed, remaining_commit_size,
+							                                 MEM_COMMIT, PAGE_READWRITE);
+                        /* Check returned pointer for consistency */
+                        if (base_committed != g_last->top_committed)
+                            goto sbrk_exit;
+                        /* Assert postconditions */
+                        assert ((unsigned) base_committed % g_pagesize == 0);
+#ifdef TRACE
+                        printf ("Commit %p %d\n", base_committed, remaining_commit_size);
+#endif
+                        /* Adjust the regions commit top */
+                        g_last->top_committed = (char *) base_committed + remaining_commit_size;
+                    }
+                } {
+                    /* Now we are going to search and reserve. */
+                    int contiguous = -1;
+                    int found = FALSE;
+                    MEMORY_BASIC_INFORMATION memory_info;
+                    void *base_reserved;
+                    long reserve_size;
+                    do {
+                        /* Assume contiguous memory */
+                        contiguous = TRUE;
+                        /* Round size to reserve */
+                        reserve_size = CEIL (to_reserve, g_my_regionsize);
+                        /* Start with the current region's top */
+                        memory_info.BaseAddress = g_last->top_reserved;
+                        /* Assert preconditions */
+                        assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+                        assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+                        while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) {
+                            /* Assert postconditions */
+                            assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+#ifdef TRACE
+                            printf ("Query %p %d %s\n", memory_info.BaseAddress, memory_info.RegionSize, 
+                                    memory_info.State == MEM_FREE ? "FREE": 
+                                    (memory_info.State == MEM_RESERVE ? "RESERVED":
+                                     (memory_info.State == MEM_COMMIT ? "COMMITTED": "?")));
+#endif
+                            /* Region is free, well aligned and big enough: we are done */
+                            if (memory_info.State == MEM_FREE &&
+                                (unsigned) memory_info.BaseAddress % g_regionsize == 0 &&
+                                memory_info.RegionSize >= (unsigned) reserve_size) {
+                                found = TRUE;
+                                break;
+                            }
+                            /* From now on we can't get contiguous memory! */
+                            contiguous = FALSE;
+                            /* Recompute size to reserve */
+                            reserve_size = CEIL (allocate_size, g_my_regionsize);
+                            memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize;
+                            /* Assert preconditions */
+                            assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+                            assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+                        }
+                        /* Search failed? */
+                        if (! found) 
+                            goto sbrk_exit;
+                        /* Assert preconditions */
+                        assert ((unsigned) memory_info.BaseAddress % g_regionsize == 0);
+                        assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+                        /* Try to reserve this */
+                        base_reserved = VirtualAlloc (memory_info.BaseAddress, reserve_size, 
+					                                  MEM_RESERVE, PAGE_NOACCESS);
+                        if (! base_reserved) {
+                            int rc = GetLastError ();
+                            if (rc != ERROR_INVALID_ADDRESS) 
+                                goto sbrk_exit;
+                        }
+                        /* A null pointer signals (hopefully) a race condition with another thread. */
+                        /* In this case, we try again. */
+                    } while (! base_reserved);
+                    /* Check returned pointer for consistency */
+                    if (memory_info.BaseAddress && base_reserved != memory_info.BaseAddress)
+                        goto sbrk_exit;
+                    /* Assert postconditions */
+                    assert ((unsigned) base_reserved % g_regionsize == 0);
+#ifdef TRACE
+                    printf ("Reserve %p %d\n", base_reserved, reserve_size);
+#endif
+                    /* Did we get contiguous memory? */
+                    if (contiguous) {
+                        long start_size = (char *) g_last->top_committed - (char *) g_last->top_allocated;
+                        /* Adjust allocation size */
+                        allocate_size -= start_size;
+                        /* Adjust the regions allocation top */
+                        g_last->top_allocated = g_last->top_committed;
+                        /* Recompute the size to commit */
+                        to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+                        /* Round size to commit */
+                        commit_size = CEIL (to_commit, g_my_pagesize);
+                    } 
+                    /* Append the new region to the list */
+                    if (! region_list_append (&g_last, base_reserved, reserve_size))
+                        goto sbrk_exit;
+                    /* Didn't we get contiguous memory? */
+                    if (! contiguous) {
+                        /* Recompute the size to commit */
+                        to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+                        /* Round size to commit */
+                        commit_size = CEIL (to_commit, g_my_pagesize);
+                    }
+                }
+            } 
+            /* Assert preconditions */
+            assert ((unsigned) g_last->top_committed % g_pagesize == 0);
+            assert (0 < commit_size && commit_size % g_pagesize == 0); {
+                /* Commit this */
+                void *base_committed = VirtualAlloc (g_last->top_committed, commit_size, 
+				    			                     MEM_COMMIT, PAGE_READWRITE);
+                /* Check returned pointer for consistency */
+                if (base_committed != g_last->top_committed)
+                    goto sbrk_exit;
+                /* Assert postconditions */
+                assert ((unsigned) base_committed % g_pagesize == 0);
+#ifdef TRACE
+                printf ("Commit %p %d\n", base_committed, commit_size);
+#endif
+                /* Adjust the regions commit top */
+                g_last->top_committed = (char *) base_committed + commit_size;
+            }
+        } 
+        /* Adjust the regions allocation top */
+        g_last->top_allocated = (char *) g_last->top_allocated + allocate_size;
+        result = (char *) g_last->top_allocated - size;
+    /* Deallocation requested? */
+    } else if (size < 0) {
+        long deallocate_size = - size;
+        /* As long as we have a region to release */
+        while ((char *) g_last->top_allocated - deallocate_size < (char *) g_last->top_reserved - g_last->reserve_size) {
+            /* Get the size to release */
+            long release_size = g_last->reserve_size;
+            /* Get the base address */
+            void *base_reserved = (char *) g_last->top_reserved - release_size;
+            /* Assert preconditions */
+            assert ((unsigned) base_reserved % g_regionsize == 0); 
+            assert (0 < release_size && release_size % g_regionsize == 0); {
+                /* Release this */
+                int rc = VirtualFree (base_reserved, 0, 
+                                      MEM_RELEASE);
+                /* Check returned code for consistency */
+                if (! rc)
+                    goto sbrk_exit;
+#ifdef TRACE
+                printf ("Release %p %d\n", base_reserved, release_size);
+#endif
+            }
+            /* Adjust deallocation size */
+            deallocate_size -= (char *) g_last->top_allocated - (char *) base_reserved;
+            /* Remove the old region from the list */
+            if (! region_list_remove (&g_last))
+                goto sbrk_exit;
+        } {
+            /* Compute the size to decommit */
+            long to_decommit = (char *) g_last->top_committed - ((char *) g_last->top_allocated - deallocate_size);
+            if (to_decommit >= g_my_pagesize) {
+                /* Compute the size to decommit */
+                long decommit_size = FLOOR (to_decommit, g_my_pagesize);
+                /*  Compute the base address */
+                void *base_committed = (char *) g_last->top_committed - decommit_size;
+                /* Assert preconditions */
+                assert ((unsigned) base_committed % g_pagesize == 0);
+                assert (0 < decommit_size && decommit_size % g_pagesize == 0); {
+                    /* Decommit this */
+                    int rc = VirtualFree ((char *) base_committed, decommit_size, 
+                                          MEM_DECOMMIT);
+                    /* Check returned code for consistency */
+                    if (! rc)
+                        goto sbrk_exit;
+#ifdef TRACE
+                    printf ("Decommit %p %d\n", base_committed, decommit_size);
+#endif
+                }
+                /* Adjust deallocation size and regions commit and allocate top */
+                deallocate_size -= (char *) g_last->top_allocated - (char *) base_committed;
+                g_last->top_committed = base_committed;
+                g_last->top_allocated = base_committed;
+            }
+        }
+        /* Adjust regions allocate top */
+        g_last->top_allocated = (char *) g_last->top_allocated - deallocate_size;
+        /* Check for underflow */
+        if ((char *) g_last->top_reserved - g_last->reserve_size > (char *) g_last->top_allocated ||
+            g_last->top_allocated > g_last->top_committed) {
+            /* Adjust regions allocate top */
+            g_last->top_allocated = (char *) g_last->top_reserved - g_last->reserve_size;
+            goto sbrk_exit;
+        }
+        result = g_last->top_allocated;
+    }
+    /* Assert invariants */
+    assert (g_last);
+    assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated &&
+            g_last->top_allocated <= g_last->top_committed);
+    assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed &&
+            g_last->top_committed <= g_last->top_reserved &&
+            (unsigned) g_last->top_committed % g_pagesize == 0);
+    assert ((unsigned) g_last->top_reserved % g_regionsize == 0);
+    assert ((unsigned) g_last->reserve_size % g_regionsize == 0);
+
+sbrk_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+    /* Release spin lock */
+    slrelease (&g_sl);
+#endif
+    return result;
+}
+
+/* mmap for windows */
+static void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) {
+    static long g_pagesize;
+    static long g_regionsize;
+#ifdef TRACE
+    printf ("mmap %d\n", size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+    /* Wait for spin lock */
+    slwait (&g_sl);
+#endif
+    /* First time initialization */
+    if (! g_pagesize) 
+        g_pagesize = getpagesize ();
+    if (! g_regionsize) 
+        g_regionsize = getregionsize ();
+    /* Assert preconditions */
+    assert ((unsigned) ptr % g_regionsize == 0);
+    assert (size % g_pagesize == 0);
+    /* Allocate this */
+    ptr = VirtualAlloc (ptr, size,
+					    MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
+    if (! ptr) {
+        ptr = (void *) MORECORE_FAILURE;
+        goto mmap_exit;
+    }
+    /* Assert postconditions */
+    assert ((unsigned) ptr % g_regionsize == 0);
+#ifdef TRACE
+    printf ("Commit %p %d\n", ptr, size);
+#endif
+mmap_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+    /* Release spin lock */
+    slrelease (&g_sl);
+#endif
+    return ptr;
+}
+
+/* munmap for windows */
+static long munmap (void *ptr, long size) {
+    static long g_pagesize;
+    static long g_regionsize;
+    int rc = MUNMAP_FAILURE;
+#ifdef TRACE
+    printf ("munmap %p %d\n", ptr, size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+    /* Wait for spin lock */
+    slwait (&g_sl);
+#endif
+    /* First time initialization */
+    if (! g_pagesize) 
+        g_pagesize = getpagesize ();
+    if (! g_regionsize) 
+        g_regionsize = getregionsize ();
+    /* Assert preconditions */
+    assert ((unsigned) ptr % g_regionsize == 0);
+    assert (size % g_pagesize == 0);
+    /* Free this */
+    if (! VirtualFree (ptr, 0, 
+                       MEM_RELEASE))
+        goto munmap_exit;
+    rc = 0;
+#ifdef TRACE
+    printf ("Release %p %d\n", ptr, size);
+#endif
+munmap_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+    /* Release spin lock */
+    slrelease (&g_sl);
+#endif
+    return rc;
+}
+
+static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed) {
+    MEMORY_BASIC_INFORMATION memory_info;
+    memory_info.BaseAddress = 0;
+    *free = *reserved = *committed = 0;
+    while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) {
+        switch (memory_info.State) {
+        case MEM_FREE:
+            *free += memory_info.RegionSize;
+            break;
+        case MEM_RESERVE:
+            *reserved += memory_info.RegionSize;
+            break;
+        case MEM_COMMIT:
+            *committed += memory_info.RegionSize;
+            break;
+        }
+        memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize;
+    }
+}
+
+static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user) {
+    if (whole) {
+        __int64 creation64, exit64, kernel64, user64;
+        int rc = GetProcessTimes (GetCurrentProcess (), 
+                                  (FILETIME *) &creation64,  
+                                  (FILETIME *) &exit64, 
+                                  (FILETIME *) &kernel64, 
+                                  (FILETIME *) &user64);
+        if (! rc) {
+            *kernel = 0;
+            *user = 0;
+            return FALSE;
+        } 
+        *kernel = (unsigned long) (kernel64 / 10000);
+        *user = (unsigned long) (user64 / 10000);
+        return TRUE;
+    } else {
+        __int64 creation64, exit64, kernel64, user64;
+        int rc = GetThreadTimes (GetCurrentThread (), 
+                                 (FILETIME *) &creation64,
+                                 (FILETIME *) &exit64,
+                                 (FILETIME *) &kernel64,
+                                 (FILETIME *) &user64);
+        if (! rc) {
+            *kernel = 0;
+            *user = 0;
+            return FALSE;
+        }
+        *kernel = (unsigned long) (kernel64 / 10000);
+        *user = (unsigned long) (user64 / 10000);
+        return TRUE;
+    }
+}
+
+#endif /* WIN32 */
+
+
+/* sm: my stuff */
+#include "ckheap.h"     // declarations for this code
+
+static enum HeapWalkOpts checkHeapWalker(void *block, int size)
+{
+  #ifdef DEBUG_HEAP
+    int i;
+
+    // get pointer to true block start
+    unsigned char *p =
+      (unsigned char*)block - sizeof(size_t) - ZONE_SIZE;
+
+    // get size from the memory block
+    int bytes = *((int*)p);
+
+    // this isn't always true, I'm not sure why..
+    //assert(size + sizeof(size_t) + ZONE_SIZE*2 == bytes);
+
+    if (p[sizeof(size_t)] == 0xAA) {
+      // check the zone integrities
+      checkZones(p, bytes);
+    }
+    else if (p[sizeof(size_t)] == 0xBB) {
+      // entire thing should be 0xBB
+      for (i=sizeof(size_t); i<bytes; i++) {
+        if (p[i] != 0xBB) {
+          assert(!"freed zone trashed");
+        }
+      }
+    }
+    else {
+      assert(!"first byte of zone isn't 0xAA or 0xBB");
+    }
+  #endif // DEBUG_HEAP
+
+  return HW_GO;
+}
+
+
+void checkHeap()
+{
+  /* 2.6.6: malloc_update_mallinfo(); */
+  check_malloc_state();
+
+  walkMallocHeap(checkHeapWalker);
+
+}
+
+void checkHeapNode(void *node)
+{
+  mchunkptr p;         /* chunk corresponding to node */
+
+  assert(node != 0);
+
+  #ifdef DEBUG_HEAP
+    // get pointer to true block start
+    node = (void*)( (unsigned char*)node - sizeof(size_t) - ZONE_SIZE );
+  #endif
+
+  p = mem2chunk(node);
+  check_inuse_chunk(p);
+}
+
+
+// sm: print information about all in-use blocks
+void walkMallocHeap(HeapWalkFn func)
+{
+  mstate av = get_malloc_state();
+  mchunkptr p;
+  int i;
+
+  // rather than go hunting through the fastbins
+  // on small blocks, let's empty the fastbins now
+  malloc_consolidate(av);
+
+  // start from the first chunk and just walk...
+  // (this could be null if we've only done mmaps so far)
+  p = av->firstChunk;
+
+  // iterate over all chunks, in physical order
+  if (p) while (p != av->top) {
+    int size = chunksize(p);
+
+    // guess where we're going next; this might get changed below
+    // if the client asks to free this block
+    mchunkptr next = next_chunk(p);
+
+    if (inuse(p)) {
+      // call user-supplied function; I have to subtract
+      // sizeof(size_t) because the size is actually malloc's
+      // total size
+      #ifndef DEBUG_HEAP
+        enum HeapWalkOpts opts = func(chunk2mem(p), size - sizeof(size_t));
+      #else
+        // skip the left zone
+        enum HeapWalkOpts opts =
+          func(chunk2mem(p) + sizeof(size_t) + ZONE_SIZE,
+               size - sizeof(size_t)*2 - ZONE_SIZE*2);
+      #endif
+
+      // what did the user want to do?
+      if (opts & HW_FREE) {
+        // what makes this tricky is that 'free' might consolidate
+        // the chunk; we must predict how 'free' is going to behave
+        // (which obviously makes this dependent on its implementation)
+
+        // is the next the top chunk?  then we're done iterating anyway
+        if (next == av->top) {
+          // just do the free
+          fREe(chunk2mem(p));
+
+          // and bail out of this loop
+          break;
+        }
+
+        else {
+          // next is not top, so there's definitely a next next
+          mchunkptr nextNext = next_chunk(next);
+
+          // will it put it into a fastbin?
+          // (this conditional is a copy of what's in 'free')
+          if ((unsigned long)(size) <= (unsigned long)(av->max_fast)
+              #if TRIM_FASTBINS
+                && (chunk_at_offset(p, size) != av->top)
+              #endif
+              ) {
+            // it will go into a fastbin, so 'next' is accurate
+          }
+
+          // will it consolidate with next chunk?  only if
+          // the next chunk is not in use
+          else if (!prev_inuse(nextNext)) {
+            // it will consolidate with next
+            next = nextNext;
+          }
+
+          // do the 'free'
+          fREe(chunk2mem(p));
+
+          // conceptually, the one thing not accounted for is the
+          // possibility that the heap was trimmed; but as I understand
+          // the code, that can only happen when next==top
+        }
+      }
+
+      if (opts & HW_STOP) {
+        return;
+      }
+    }
+
+    else { // not in use
+      //printf("  Free chunk at %p, size %d\n", p, size);
+    }
+
+    // go to next chunk
+    assert(p < next);         // prevent inf loops
+    p = next;
+  }
+
+  // check the mmap regions
+  for (i=0; i < av->n_mmaps; i++) {
+    enum HeapWalkOpts opts;
+
+    p = av->mmapPtrs[i];
+    //printf("  Block (mmap) at %p, size %d\n", p, chunksize(p));
+
+    opts = func(chunk2mem(p), chunksize(p));
+
+    if (opts & HW_FREE) {
+      // my array-management code fills the ith slot with
+      // another valid block; so we just cause this value
+      // of 'i' to be used again on the next iteration
+      i--;
+    }
+
+    if (opts & HW_STOP) {
+      return;
+    }
+  }
+}
+
+
+/* ------------------------------------------------------------
+History:
+
+    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)
+      * Introduce independent_comalloc and independent_calloc.
+        Thanks to Michael Pachos for motivation and help.
+      * Make optional .h file available
+      * Allow > 2GB requests on 32bit systems.
+      * new WIN32 sbrk, mmap, munmap, lock code from <Walter at GeNeSys-e.de>.
+        Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
+        and Anonymous.
+      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for 
+        helping test this.)
+      * memalign: check alignment arg
+      * realloc: don't try to shift chunks backwards, since this
+        leads to  more fragmentation in some programs and doesn't
+        seem to help in any others.
+      * Collect all cases in malloc requiring system memory into sYSMALLOc
+      * Use mmap as backup to sbrk
+      * Place all internal state in malloc_state
+      * Introduce fastbins (although similar to 2.5.1)
+      * Many minor tunings and cosmetic improvements
+      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK 
+      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
+        Thanks to Tony E. Bennett <tbennett at nvidia.com> and others.
+      * Include errno.h to support default failure action.
+
+    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
+      * return null for negative arguments
+      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
+         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+          (e.g. WIN32 platforms)
+         * Cleanup header file inclusion for WIN32 platforms
+         * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+           memory allocation routines
+         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+           usage of 'assert' in non-WIN32 code
+         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+           avoid infinite loop
+      * Always call 'fREe()' rather than 'free()'
+
+    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
+      * Fixed ordering problem with boundary-stamping
+
+    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
+      * Added pvalloc, as recommended by H.J. Liu
+      * Added 64bit pointer support mainly from Wolfram Gloger
+      * Added anonymously donated WIN32 sbrk emulation
+      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+      * malloc_extend_top: fix mask error that caused wastage after
+        foreign sbrks
+      * Add linux mremap support code from HJ Liu
+
+    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
+      * Integrated most documentation with the code.
+      * Add support for mmap, with help from
+        Wolfram Gloger (Gloger at lrz.uni-muenchen.de).
+      * Use last_remainder in more cases.
+      * Pack bins using idea from  colin at nyx10.cs.du.edu
+      * Use ordered bins instead of best-fit threshhold
+      * Eliminate block-local decls to simplify tracing and debugging.
+      * Support another case of realloc via move into top
+      * Fix error occuring when initial sbrk_base not word-aligned.
+      * Rely on page size for units instead of SBRK_UNIT to
+        avoid surprises about sbrk alignment conventions.
+      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+        (raymond at es.ele.tue.nl) for the suggestion.
+      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+      * More precautions for cases where other routines call sbrk,
+        courtesy of Wolfram Gloger (Gloger at lrz.uni-muenchen.de).
+      * Added macros etc., allowing use in linux libc from
+        H.J. Lu (hjl at gnu.ai.mit.edu)
+      * Inverted this history list
+
+    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
+      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+      * Removed all preallocation code since under current scheme
+        the work required to undo bad preallocations exceeds
+        the work saved in good cases for most test programs.
+      * No longer use return list or unconsolidated bins since
+        no scheme using them consistently outperforms those that don't
+        given above changes.
+      * Use best fit for very large chunks to prevent some worst-cases.
+      * Added some support for debugging
+
+    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
+      * Removed footers when chunks are in use. Thanks to
+        Paul Wilson (wilson at cs.texas.edu) for the suggestion.
+
+    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
+      * Added malloc_trim, with help from Wolfram Gloger
+        (wmglo at Dent.MED.Uni-Muenchen.DE).
+
+    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
+
+    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
+      * realloc: try to expand in both directions
+      * malloc: swap order of clean-bin strategy;
+      * realloc: only conditionally expand backwards
+      * Try not to scavenge used bins
+      * Use bin counts as a guide to preallocation
+      * Occasionally bin return list chunks in first scan
+      * Add a few optimizations from colin at nyx10.cs.du.edu
+
+    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
+      * faster bin computation & slightly different binning
+      * merged all consolidations to one part of malloc proper
+         (eliminating old malloc_find_space & malloc_clean_bin)
+      * Scan 2 returns chunks (not just 1)
+      * Propagate failure in realloc if malloc returns 0
+      * Add stuff to allow compilation on non-ANSI compilers
+          from kpv at research.att.com
+
+    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
+      * removed potential for odd address access in prev_chunk
+      * removed dependency on getpagesize.h
+      * misc cosmetics and a bit more internal documentation
+      * anticosmetics: mangled names in macros to evade debugger strangeness
+      * tested on sparc, hp-700, dec-mips, rs6000
+          with gcc & native cc (hp, dec only) allowing
+          Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
+      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+         structure of old version,  but most details differ.)
+
+*/

Added: vendor/elsa/current/smbase/malloc_stub.c
===================================================================
--- vendor/elsa/current/smbase/malloc_stub.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/malloc_stub.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,17 @@
+// malloc_stub.h            see license.txt for copyright and terms of use
+// no-op implementation of ckheap.h
+
+#include "ckheap.h"     // interface to implement
+
+void checkHeap() {}
+
+unsigned numMallocCalls() { return 0; }
+unsigned numFreeCalls() { return 0; }
+
+#ifndef __WIN32__
+void malloc_stats() {}
+void checkHeapNode(void *node) {}
+void walkMallocHeap(HeapWalkFn func) {}
+#endif
+
+// EOF


Property changes on: vendor/elsa/current/smbase/malloc_stub.c
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/missing.cpp
===================================================================
--- vendor/elsa/current/smbase/missing.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/missing.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,25 @@
+// missing.cc            see license.txt for copyright and terms of use
+// code for missing.h
+// Scott McPeak, 1998  This file is public domain.
+
+#include "missing.h"     // this module
+
+#include <ctype.h>       // tolower
+
+int missing_stricmp(char const *s1, char const *s2)
+{
+  while (*s1 && *s2) {
+    // the choice between tolower and toupper affects lexicographic
+    // comparisons between letters and the symbols between Z and a;
+    // I don't know which is the "correct" way.
+    int d = tolower(*s1) - tolower(*s2);
+    if (d != 0) {
+      return d;
+    }
+    s1++;
+    s2++;
+  }
+
+  // one or both are at the null terminator
+  return *s1 - *s2;
+}

Added: vendor/elsa/current/smbase/missing.h
===================================================================
--- vendor/elsa/current/smbase/missing.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/missing.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// missing.h            see license.txt for copyright and terms of use
+// routines that I implemented because they aren't available on all platforms
+// Scott McPeak, 1998  This file is public domain.
+
+#ifndef __MISSING_H
+#define __MISSING_H
+
+// stricmp
+int missing_stricmp(char const *s1, char const *s2);
+
+#endif // __MISSING_H

Added: vendor/elsa/current/smbase/mypopen.c
===================================================================
--- vendor/elsa/current/smbase/mypopen.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/mypopen.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,288 @@
+// mypopen.c            see license.txt for copyright and terms of use
+// code for myopen.h
+// this module's implementation is in C, and not dependent on anything
+// else in smbase, so it can be extracted and used independently
+
+#include "mypopen.h"    // this module
+
+#include <stdlib.h>     // exit, perror
+#include <stdio.h>      // printf
+#include <unistd.h>     // pipe, read, etc.
+#include <string.h>     // strlen
+#include <sys/types.h>  // pid_t
+#include <sys/wait.h>   // wait
+
+#define STDIN 0
+#define STDOUT 1
+#define STDERR 2
+
+#ifndef max
+  #define max(a,b) ((a)>(b)?(a):(b))
+#endif
+
+// -------------------- helpers ----------------------
+static void die(char const *fn)
+{
+  perror(fn);
+  exit(2);
+}
+
+
+void makePipe(int *readEnd, int *writeEnd)
+{
+  int pipes[2];
+  if (pipe(pipes) < 0) {
+    die("pipe");
+  }
+
+  *readEnd = pipes[0];
+  *writeEnd = pipes[1];
+}
+
+
+// ------------------- execvp -------------------
+struct ExecvArgs {
+  char const *file;
+  char const * const *argv;
+};
+
+static void call_execvp(void *_args)
+{
+  char *msg;
+  struct ExecvArgs *args = (struct ExecvArgs*)_args;
+
+  // I think execvp is declared incorrectly; I cast to circumvent
+  execvp(args->file, (char * const *)(args->argv));
+
+  // execvp only returns if there was an error; if this happens,
+  // the error message will be printed to the stderr pipe if
+  // it was redirected
+  msg = (char*)malloc(strlen(args->file) + 6 + 2 + 1);
+  sprintf(msg, "execvp: %s", args->file);
+  die(msg);
+}
+
+int popen_execvp(int *parentWritesChild, int *parentReadsChild,
+                 int *childStderr,
+                 char const *file, char const * const *argv)
+{
+  struct ExecvArgs args;
+  args.file = file;
+  args.argv = argv;
+
+  return popen_pipes(parentWritesChild, parentReadsChild, childStderr,
+                     call_execvp, &args);
+}
+
+
+// ------------------ primary function ------------------
+int popen_pipes(int *parentWritesChild, int *parentReadsChild,
+                int *readChildStderr,
+                execFunction func, void *extraArgs)
+{
+  int childReadsParent;
+  int childWritesParent;
+  int childWritesStderr;
+  int childPid;
+  int stderrToStdout = 0;
+
+  // create pipes
+  makePipe(&childReadsParent, parentWritesChild);
+  makePipe(parentReadsChild, &childWritesParent);
+  if (parentReadsChild == readChildStderr) {
+    // caller wants child stdout and stderr going to same place
+    stderrToStdout = 1;
+    *readChildStderr = *parentReadsChild;
+    readChildStderr = NULL;     // most of the code behaves as if stderr isn't being changed
+  }
+  else if (readChildStderr) {
+    makePipe(readChildStderr, &childWritesStderr);
+  }
+
+  // fork a child
+  childPid = fork();
+  if (childPid < 0) {
+    die("fork");
+  }
+
+  if (childPid != 0) {      // parent
+    // close the pipe ends I'm not going to use
+    if (close(childReadsParent) < -1   ||
+        close(childWritesParent) < -1  ||
+        (readChildStderr && close(childWritesStderr) < -1)) {
+      die("close");
+    }
+
+    return childPid;
+  }
+
+  else {                    // child
+    // rearrange file descriptors so stdin and stdout of the
+    // program we're about to exec will talk to parent
+
+    // sleep so debugger can attach
+    //sleep(10);
+
+    // close the pipe ends I'm not going to use
+    if (close(*parentReadsChild) < -1   ||
+        close(*parentWritesChild) < -1  ||
+        (readChildStderr && close(*readChildStderr) < -1)) {
+      die("close");
+    }
+
+    // first, close parent's stdin/stdout
+    if (close(STDIN) < -1   ||
+        close(STDOUT) < -1  ||
+        (readChildStderr && close(STDERR) < -1)) {
+      die("close");
+    }
+
+    // now, duplicate the pipe fds to stdin/stdout
+    if (dup2(childReadsParent, STDIN) < -1                         ||
+        dup2(childWritesParent, STDOUT)	< -1                       ||
+        (readChildStderr && dup2(childWritesStderr, STDERR) < -1)  ||
+        (stderrToStdout && dup2(childWritesParent, STDERR) < -1)   ) {
+      die("dup2");
+    }
+
+    // finally, close the original pipe fds
+    if (close(childReadsParent) < -1   ||
+        close(childWritesParent) < -1  ||
+        (readChildStderr && close(childWritesStderr) < -1)) {
+      die("close");
+    }
+
+    // ok, fds are in order.  let's exec the child program
+    func(extraArgs);
+
+    // not reached; silence warning
+    return -1;
+  }
+}
+
+
+// ------------------ test code ----------------------
+#ifdef TEST_MYPOPEN
+
+int main()
+{
+  char buf[80];
+  int stat;
+
+  // try cat
+  {
+    int in, out;
+    char const *argv[] = { "cat", NULL };
+    int pid = popen_execvp(&in, &out, NULL, argv[0], argv);
+    printf("child pid is %d\n", pid);
+
+    if (write(in, "foo\n", 4) != 4) {
+      die("write");
+    }
+    if (read(out, buf, 4) != 4) {
+      die("read");
+    }
+
+    if (0==memcmp(buf, "foo\n", 4)) {
+      printf("cat worked for foo\n");
+    }
+    else {
+      printf("cat FAILED\n");
+      return 2;
+    }
+
+    if (write(in, "bar\n", 4) != 4) {
+      die("write");
+    }
+    if (read(out, buf, 4) != 4) {
+      die("read");
+    }
+
+    if (0==memcmp(buf, "bar\n", 4)) {
+      printf("cat worked for bar\n");
+    }
+    else {
+      printf("cat FAILED\n");
+      return 2;
+    }
+
+    close(in);
+    close(out);
+
+    printf("waiting for cat to exit..\n");
+    if (wait(&stat) < 1) {
+      perror("wait");
+    }
+    else {
+      printf("cat exited with status %d\n", stat);
+    }
+  }
+
+  // try something which fails
+  {
+    int in, out, err;
+    int len;
+    char const *argv[] = { "does_not_exist", NULL };
+    int pid = popen_execvp(&in, &out, &err, argv[0], argv);
+    printf("child pid is %d\n", pid);
+
+    printf("waiting for error message...\n");
+    len = read(err, buf, 78);
+    if (len < 0) {
+      die("read");
+    }
+    if (buf[len-1] != '\n') {
+      buf[len++] = '\n';
+    }
+    buf[len] = 0;
+    printf("error string: %s", buf);   // should include newline from perror
+
+    close(in);
+    close(out);
+    close(err);
+
+    printf("waiting for child to exit..\n");
+    if (wait(&stat) < 1) {
+      perror("wait");
+    }
+    else {
+      printf("child exited with status %d\n", stat);
+    }
+  }
+
+  // also fails, but with stdout and stderr going to same pipe
+  {
+    int in, out;
+    int len;
+    char const *argv[] = { "does_not_exist", NULL };
+    int pid = popen_execvp(&in, &out, &out, argv[0], argv);
+    printf("out==err: child pid is %d\n", pid);
+
+    printf("waiting for error message...\n");
+    len = read(out, buf, 78);
+    if (len < 0) {
+      die("read");
+    }
+    if (buf[len-1] != '\n') {
+      buf[len++] = '\n';
+    }
+    buf[len] = 0;
+    printf("error string: %s", buf);   // should include newline from perror
+
+    close(in);
+    close(out);
+
+    printf("waiting for child to exit..\n");
+    if (wait(&stat) < 1) {
+      perror("wait");
+    }
+    else {
+      printf("child exited with status %d\n", stat);
+    }
+  }
+  
+  printf("mypopen worked!\n");
+  return 0;
+}
+
+#endif // TEST_POPEN

Added: vendor/elsa/current/smbase/mypopen.h
===================================================================
--- vendor/elsa/current/smbase/mypopen.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/mypopen.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,37 @@
+// mypopen.h            see license.txt for copyright and terms of use
+// open a process and yield pipes to its stdin/stdout/stderr
+
+#ifndef MYPOPEN_H
+#define MYPOPEN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// create a pipe and retrieve the read and write file descriptors
+void makePipe(int *readEnd, int *writeEnd);
+
+// function to exec something, given some args to say how; it must
+// *not* return
+typedef void (*execFunction)(void *extraArgs);
+
+// generic popen with generic exec function; the first two int* must
+// not be NULL, but the third can be NULL (in which case stderr will
+// not be redirected); alternatively, if 'childStderr' ==
+// 'parentReadsChild', then the child's stderr will be directed to the
+// same pipe as its stdout
+int popen_pipes(int *parentWritesChild, int *parentReadsChild,
+                int *childStderr,
+                execFunction func, void *extraArgs);
+
+// version that calls execvp internally
+int popen_execvp(int *parentWritesChild, int *parentReadsChild,
+                 int *childStderr,
+                 char const *file, char const * const *argv);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MYPOPEN_H

Added: vendor/elsa/current/smbase/mysig.cc
===================================================================
--- vendor/elsa/current/smbase/mysig.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/mysig.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,214 @@
+// mysig.cc            see license.txt for copyright and terms of use
+// code for mysig.h
+
+#include "mysig.h"      // this module
+
+#include <string.h>     // strsignal
+#include <stdlib.h>     // exit
+#include <unistd.h>     // sleep
+#include <stdio.h>      // printf
+
+// needed on Solaris; is __sun__ a good way to detect that?
+#ifdef __sun__
+  #include <siginfo.h>
+#endif
+
+#ifndef __CYGWIN__      // everything here is for *not* cygwin
+
+void setHandler(int signum, SignalHandler handler)
+{
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));       // clear any "extra" fields
+  sa.sa_handler = handler;          // handler function
+  sigemptyset(&sa.sa_mask);         // don't block other signals
+  sa.sa_flags = SA_RESTART;         // automatically restart syscalls
+
+  // install the handler
+  if (0 > sigaction(signum, &sa, NULL)) {
+    perror("sigaction");
+    exit(2);
+  }
+}
+
+
+// simple handler that just prints and re-raises
+void printHandler(int signum)
+{
+  fprintf(stderr, "printHandler: I caught signal %d\n", signum);
+  psignal(signum, "psignal message");
+
+  //fprintf(stderr, "I'm just going to wait a while...\n");
+  //sleep(60);
+
+  // block the signal -- doesn't work for internally-generated
+  // signals (i.e. raise)
+  //sigset_t mask;
+  //sigemptyset(&mask);
+  //sigaddset(&mask, SIGINT);
+
+  // reset the signal handler to its default handler
+  setHandler(signum, SIG_DFL);
+
+  // re-raise, which doesn't come back to this handler because
+  // the signal is blocked while we're in here -- wrong; it
+  // is blocked from external signals, but not from signals
+  // generated internally...
+  fprintf(stderr, "re-raising...\n");
+  raise(signum);
+}
+
+
+jmp_buf sane_state;
+
+// handler to do a longjmp
+void jmpHandler(int signum)
+{
+  //fprintf(stderr, "jmpHandler: I caught signal %d\n", signum);
+  psignal(signum, "jmpHandler: caught signal");
+
+  // reset the signal handler to its default handler
+  setHandler(signum, SIG_DFL);
+
+  // do it
+  //fprintf(stderr, "calling longjmp...\n");
+  longjmp(sane_state, 1);
+}
+
+
+void printAddrHandler(int signum, siginfo_t *info, void *)
+{
+  fprintf(stderr, "faulting address: %p\n", info->si_addr);
+
+  // reset handler and re-raise
+  setHandler(signum, SIG_DFL);
+  raise(signum);
+}
+   
+
+// unfortunately, linux 2.4.18 seems to have some bugs w.r.t.
+// sigalstack... anytime MYSZ is as small as 4096, the test program
+// hangs repeatedly segfaulting once I get the first.. (but note that
+// MINSIGSTKSZ is 2048, so I should be well beyond the acknowledged
+// minimum); and with 8192 it works only some of the time, depending on
+// how things get laid out.  so I'm going to disable the alt stack
+// altogether, and rely on noticing that no "faulting address" is
+// printed if I get a stack overflow...
+
+//#define MYSZ 4096
+//char mysigstack[MYSZ];
+
+void printSegfaultAddrs()
+{
+  // allocate the alternate signal stack; I do this because I want
+  // the handler to work even for SEGVs caused by stack-overflow
+  //if (!mysigstack) {
+  //  mysigstack = (char*)malloc(MINSIGSTKSZ);    // "minimum signal stack size"
+  //}
+
+  #if 0
+  // tell the library about it
+  struct sigaltstack sas;
+  sas.ss_sp = mysigstack;
+  sas.ss_size = MYSZ;
+  sas.ss_flags = SS_ONSTACK;
+
+  if (0 > sigaltstack(&sas, NULL)) {
+    perror("sigaltstack");
+    exit(2);
+  }    
+  #endif // 0
+
+
+  // NOTE: I have no idea how portable this stuff is, especially the
+  // 'sigaltstack' call.  It's only here as a debugging aid.  Feel
+  // free to #ifdef-out the entire section if necessary, but tell me
+  // (smcpeak at acm.org) about it so I can add detection logic.
+
+
+  // construct the handler information struct
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_sigaction = printAddrHandler;
+  sigemptyset(&sa.sa_mask);         // don't block other signals
+  sa.sa_flags = SA_SIGINFO; // | SA_STACK;
+
+  // install the handler
+  if (0 > sigaction(SIGSEGV, &sa, NULL)) {
+    perror("sigaction");
+    exit(2);
+  }
+}
+
+
+// ------------------ test code ------------------
+#ifdef TEST_MYSIG
+
+static void infiniteRecursion()
+{
+  char buf[1024];
+  buf[0] = 4;
+  buf[1] = buf[0];     // silence an icc warning
+  buf[1023] = 6;
+  infiniteRecursion();
+}
+
+int main(int argc, char **argv)
+{
+  if (argc >= 2) {
+    // segfault at a given addr
+    printSegfaultAddrs();
+
+    if (0==strcmp(argv[1], "inf")) {
+      // die by stack overflow.. interesting, I can't catch it..
+      printf("going into infinite recursion...\n");
+      infiniteRecursion();
+    }
+
+    long addr = strtoul(argv[1], NULL /*endp*/, 0 /*radix*/);
+    printf("about to access 0x%lX ...\n", addr);
+    *((int*)addr) = 0;
+    return 0;     // won't be reached for most values of 'addr'
+  }
+
+  if (setjmp(sane_state) == 0) {   // normal flow
+    setHandler(SIGINT, printHandler);
+    setHandler(SIGTERM, printHandler);
+    setHandler(SIGUSR1, jmpHandler);
+    setHandler(SIGSEGV, jmpHandler);
+    setHandler(SIGBUS, jmpHandler);   // osx gives SIBGUS instead of SIGSEGV
+
+    //printf("I'm pid %d waiting to be killed...\n", getpid());
+    //sleep(10);
+    printf("about to deliberately cause a segfault ...\n");
+    *((int*)0) = 0;    // segfault!
+
+    printf("didn't segfault??\n");
+    return 2;
+  }
+
+  else {         // from longjmp
+    printf("came back from a longjmp!\n");
+    printf("\nmysig works\n");
+    return 0;
+  }
+}
+
+#endif // TEST_MYSIG
+
+
+#else   // cygwin -- just stubs so it compiles
+void setHandler(int, SignalHandler) {}
+void printHandler(int) {}
+jmp_buf sane_state;
+void jmpHandler(int) {}
+void printSegfaultAddrs() {}
+
+#ifdef TEST_MYSIG
+int main()
+{
+  printf("mysig on cygwin: nop\n");
+  return 0;
+}
+#endif // TEST_MYSIG
+
+#endif     // cygwin

Added: vendor/elsa/current/smbase/mysig.h
===================================================================
--- vendor/elsa/current/smbase/mysig.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/mysig.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,50 @@
+// mysig.h            see license.txt for copyright and terms of use
+// some simple Unix signal-handling stuff
+
+#ifndef MYSIG_H
+#define MYSIG_H
+
+#include <signal.h>     // signal stuff
+#include <setjmp.h>     // jmp_buf
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// type of a signal handler function; generally, there are
+// three options for a signal handler:
+//   - return, in which case the default action for the
+//     signal is taken
+//   - longjmp to a state where computation can resume
+//   - abort(2) or exit(2)
+// it's somewhat dangerous to do other system calls, but people
+// do it anyway
+typedef void (*SignalHandler)(int signum);
+
+
+// install the given handler on the given signal
+void setHandler(int signum, SignalHandler handler);
+
+
+// simple handler that just prints and re-raises
+void printHandler(int signum);
+
+
+// to use jmpHandler, call setjmp(sane_state) before
+// installing the handler
+extern jmp_buf sane_state;
+
+// handler to do a longjmp to sane_state
+void jmpHandler(int signum);
+
+
+// install a segfault handler that will print the address that
+// caused the fault; this is very useful for debugging
+void printSegfaultAddrs();
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // MYSIG_H

Added: vendor/elsa/current/smbase/nonport.cpp
===================================================================
--- vendor/elsa/current/smbase/nonport.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/nonport.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,860 @@
+// nonport.cpp            see license.txt for copyright and terms of use
+// code for nonport.h
+// Scott McPeak and Dan Bonachea, 1998-1999  This file is public domain.
+
+#include <stdio.h>       // printf
+#include <stdlib.h>      // abort, exit
+#include <string.h>      // strncpy
+
+#ifdef __WIN32__
+#  ifdef USE_MINWIN_H
+#    include "minwin.h"   // api
+#  else
+#    include <windows.h>  // api
+#  endif
+
+#  include <conio.h>      // getch or _getch
+#  include <dos.h>        // sleep
+#  include <io.h>         // chmod
+#  ifdef __BORLANDC__
+#    include <dir.h>      // mkdir, chdir
+#    pragma warn -par     // warning: parameter not used
+#  else    // MSVC
+#    include <errno.h> // ENOENT
+#    include <direct.h>   // _mkdir, _chdir
+#    define getch _getch
+#    define mkdir _mkdir    // why must VC be such an oddball?
+#    define chdir _chdir
+#    define chmod _chmod
+     void sleep(unsigned sec) {
+       Sleep(sec * 1000);
+       return;
+       }
+#  endif
+#  define DIRSLASH '\\'
+#  define DIRSLASHES "\\/"
+
+#else   // unix
+#  include <sys/time.h>   // struct timeval, gettimeofday
+#  include <sys/types.h>  // mkdir constants, DIR, struct dirent
+#  include <fcntl.h>      // mkdir constants
+#  include <unistd.h>     // mkdir, sleep, chdir, geteuid
+#  include <errno.h>      // errno
+#  include <pwd.h>        // getpwuid, struct passwd
+#  define DIRSLASH '/'
+#  define DIRSLASHES "/"
+
+#endif
+
+#include <sys/stat.h>     // chmod, mode macros
+#include <time.h>         // tzset, localtime, time
+#include <iostream.h>     // cout
+
+#if !defined(__WIN32__) || defined(__BORLANDC__)
+  #include <dirent.h>       // opendir
+#endif
+
+#include "nonport.h"      // this module
+
+
+NonportFailFunc nonportFail = defaultNonportFail;
+
+void defaultNonportFail(char const *, char const *)
+{}
+
+// convenience
+inline void fail(char const *call, char const *ctx=NULL)
+{
+  nonportFail(call, ctx);
+}
+
+
+void setRawMode(bool raw)
+{
+# ifdef __WIN32__
+    // nothing necessary; getConsoleChar handles it
+
+# else
+    int res;
+    if (raw) {
+      // turn off UNIX term output, put in raw mode
+      res = system("stty -echo raw");
+    }
+    else {
+      // back to normal mode
+      res = system("stty echo -raw");
+    }
+
+    if (res != 0) {
+      //fail("system", "setRawMode");
+    }
+# endif
+}
+
+
+// get the next character typed, without any intervening interpretation
+// or buffering
+char getConsoleChar()
+{
+# ifdef __WIN32__
+    // this function always bypasses 'cooked' console mode
+    return (char)getch();
+
+# else
+    // relies on raw mode for console
+    int ch = getchar();
+    if (ch == EOF) {
+      fail("getchar", "getConsoleChar");
+    }
+    return ch;
+# endif
+}
+
+
+// return the # of milliseconds since some unspecified, but
+// constant for the life of the program, event
+long getMilliseconds()
+{
+# ifdef __WIN32__
+    // # of milliseconds since program started
+    return GetTickCount();
+
+# else
+    // some unspecified millisecond count (unspecified
+    // because tv.tv_sec * 1000 will overflow a 32-bit
+    // long, for typical values)
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+      // according to HPUX man page, this always returns 0 and does
+      // not have any errors defined
+
+    //printf("tv.tv_sec = %d, tv.tv_usec = %d\n",
+    //       tv.tv_sec, tv.tv_usec);
+    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+# endif
+}
+
+
+bool limitFileAccess(char const *fname)
+{
+  // read/write for user, nothing for group or others
+  if (chmod(fname, 0600) != 0) {
+    fail("chmod", fname);
+    return false;
+  }
+  else {
+    return true;
+  }
+}
+
+
+bool createDirectory(char const *dirname)
+{
+  int res;
+# ifdef __WIN32__
+    // no 'mode' argument
+    res = mkdir(dirname);
+# else   // unix
+    // read/write/execute permission for user, no one else
+    res = mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR);
+# endif
+
+  if (res != 0) {
+    fail("mkdir", dirname);
+    return false;
+  }
+  else {
+    return true;
+  }
+}
+
+
+bool changeDirectory(char const *dirname)
+{
+  if (0!=chdir(dirname)) {
+    fail("chdir", dirname);
+    return false;
+  }
+  else {
+    return true;
+  }
+}
+
+
+bool getCurrentDirectory(char *dirname, int len)
+{
+  bool ok = getcwd(dirname, len) != NULL;
+  if (!ok) {
+    fail("getcwd");
+  }
+  return ok;
+}
+
+
+bool removeFile(char const *fname)
+{
+  bool ok = unlink(fname) == 0;
+  if (!ok) {
+    fail("unlink", fname);
+  }
+  return ok;
+}
+
+
+// this may in fact use a portable subset of the standard
+// C library.. but I'm not holding my breath, so that's why
+// this routine is in the 'nonport' module
+void getCurrentDate(int &month, int &day, int &year)
+{
+  // tzset is apparently required (recommended?) before
+  // calling localtime()
+  #if !defined(__CYGWIN__)
+  tzset();
+  #endif
+
+  // retrieve standard UNIX time
+  time_t unixTime;
+  time(&unixTime);
+
+  // convert to month/day/year
+  struct tm *t = localtime(&unixTime);
+
+  // write into return variables
+  month = t->tm_mon + 1;
+  day = t->tm_mday;
+  year = t->tm_year + 1900;    // this is not a y2k bug!
+}
+
+
+void portableSleep(unsigned seconds)
+{
+  // with proper headers included (above), "sleep" works
+  sleep(seconds);
+}
+
+
+void getCurrentUsername(char *buf, int buflen)
+{
+  #ifdef __WIN32__
+    DWORD len = buflen;
+    if (!GetUserName(buf, &len)) {
+      fail("GetUserName");
+      strncpy(buf, "(unknown)", buflen);
+    }
+
+  #else    // unix (SunOS only?  we'll see..)
+    #if 0     // old.. linux man page insists 'cuserid' is a bad fn to call
+      char temp[L_cuserid];
+      cuserid(temp);         // fail return?
+    #endif // 0
+
+    char const *temp;
+    struct passwd *pw = getpwuid(geteuid());
+    if (!pw) {
+      fail("getpwuid(geteuid())");
+      temp = "(unknown)";
+    }
+    else {
+      temp = pw->pw_name;
+    }
+
+    strncpy(buf, temp, buflen);
+  #endif
+}
+
+
+// loop reading characters, return when finished
+static void nonechoLoop(char *buf, int len)
+{
+  int cursor = 0;
+  for(;;) {
+    char ch = getConsoleChar();
+    switch (ch) {
+      case '\r':    // carriage return
+        buf[cursor] = 0;
+        return;
+
+      case '\b':    // backspace
+        if (cursor > 0) {
+          cursor--;
+        }
+        break;
+
+      default:
+        buf[cursor++] = ch;
+        if (cursor >= len-1) {
+          // end of buffer
+          buf[len-1] = 0;
+          return;
+        }
+        break;
+    }
+  }
+}
+
+
+void readNonechoString(char *buf, int len, char const *prompt)
+{
+  cout << prompt;
+  cout.flush();
+
+  setRawMode(true);
+
+  try {
+    nonechoLoop(buf, len);
+  }
+  catch (...) {
+    setRawMode(false);    // make sure it gets reset
+    throw;
+  }
+
+  setRawMode(false);
+
+  cout << "\n";
+  cout.flush();
+}
+
+
+void applyToCwdContents(PerFileFunc func, void *extra)
+{
+  applyToDirContents(".", func, extra);
+}
+
+
+void applyToDirContents(char const *dirName,
+                        PerFileFunc func, void *extra)
+{
+  // SM: we had find{first,next} code here for win32, but
+  //     my Borland has opendir & friends, so let's see if
+  //     that works everywhere.. (old code is below, in
+  //     trash section)
+  // DOB: VC doesn't have opendir-
+  //  I think this is the only way to do it in the Win32 API
+  #if defined(__WIN32__) && !defined(__BORLANDC__)
+    struct _finddata_t fb;
+    char* buf = new char[strlen(dirName)+5];
+    strcpy(buf, dirName);
+    if (buf[strlen(buf)-1] != '\\') strcat(buf, "\\");
+    strcat(buf, "*");
+    long handle = _findfirst(buf, &fb);
+    delete buf;
+    int done = (handle == -1);
+    if (handle == -1 && errno != ENOENT) // ENOENT = no matching entries
+      fail("_findfirst", dirName);
+    while (!done) {
+      if (!func(fb.name, extra)) {
+	break;
+	}
+      done = _findnext(handle, &fb);
+      }
+    if (handle != -1) {
+      if (_findclose(handle)) fail("_findclose", dirName);
+      }
+
+  #else     // unix and borland
+    DIR *dir = opendir(dirName);
+    if (!dir) {
+      fail("opendir", dirName);
+      return;
+    }
+
+    for(;;) {
+      // grab next directory entry
+      struct dirent *ent = readdir(dir);
+      if (!ent) {
+	break;     // end of listing
+      }
+
+      if (!func(ent->d_name, extra)) {
+	break;     // user wants to stop listing
+      }
+    }
+
+    if (closedir(dir) != 0) {
+      fail("closedir", dirName);
+    }
+  #endif
+}
+
+
+bool isDirectory(char const *path)
+{
+  struct stat st;
+  if (0!=stat(path, &st)) {
+    fail("stat", path);
+    return false;
+  }
+  #if defined(__WIN32__) && !defined(__BORLANDC__)
+    return !!(st.st_mode & _S_IFDIR); // this is how it works for VC
+  #else
+    return S_ISDIR(st.st_mode);
+  #endif
+}
+
+
+bool fileOrDirectoryExists(char const *path)
+{
+  struct stat st;
+  if (0!=stat(path, &st)) {
+    return false;     // assume error is because of nonexistence
+  }
+  else {
+    return true;
+  }
+}
+
+
+// adapted from Dan's keyutils.cpp (and indentation style
+// ruthlessly changed! :) )
+bool ensurePath(char const *filename, bool isDirectory)
+{
+  // make a temporary buffer so we can modify it safely
+  int len = strlen(filename);
+  char *temp = new char[len+1];
+  strcpy(temp, filename);
+
+  if (isDirectory) {
+    len++;    // also consider final '\0' (strchr returns ptr to it)
+  }
+
+  // start at 1 (and not 0) because if the path starts with a slash,
+  // then starting at 0 will cause us to try mkdir("")
+  for (int i=1; i < len; i++) {
+    if (strchr(DIRSLASHES, temp[i])) {
+      // wherever there is a slash (or '\0'), truncate and test
+      temp[i] = '\0';
+      if (!fileOrDirectoryExists(temp)) {
+        // make directory if necessary; automatically limits file access
+        if (!createDirectory(temp)) {
+          delete[] temp;
+          return false;
+        }
+      }
+      temp[i] = DIRSLASH;      // may kill final '\0', doesn't matter
+    }
+  }
+
+  // was leaking this.. found the leak with the feudal-C instrumentor!
+  delete[] temp;
+  return true;
+}
+
+ 
+// underlying test
+bool hsrcHelper()
+{
+  #if !defined(__WIN32__)     // unix
+    // see if /dev/random exists and is readable
+    int fd = open("/dev/random", O_RDONLY);
+    if (fd < 0) {
+      return false;
+    }
+
+    // looks ok!
+    if (close(fd) < 0) {
+      perror("close");
+      return false;      // seems unlikely, but..
+    }
+
+    return true;
+
+  #else    // windows
+    return false;
+  #endif
+}
+
+bool hasSystemCryptoRandom()
+{
+  static bool cached = false;
+  static bool cachedAnswer;
+
+  if (!cached) {
+    cachedAnswer = hsrcHelper();
+    cached = true;
+  }
+  
+  return cachedAnswer;
+}
+
+
+// assume we are only called if the above fn returned true;
+// for this fn, any failure is considered fatal because we
+// don't have a way to communicate it, and the possibility of
+// returning nonrandom values is not tolerable (if something
+// I haven't thought of is causing failure, add it to the list
+// of things hasSystemCryptoRandom checks)
+unsigned getSystemCryptoRandom()
+{
+  #if !defined(__WIN32__)     // unix
+    // open /dev/random
+    int fd = open("/dev/random", O_RDONLY);
+    if (!fd) {
+      perror("open");
+      exit(2);
+    }
+
+    // grab 4 bytes
+    union {
+      unsigned ret;
+      char c[4];
+    };
+    int got = 0;
+
+    while (got < 4) {
+      int ct = read(fd, c+got, 4-got);
+      if (ct < 0) {
+       	perror("read");
+       	exit(2);
+      }
+      if (ct == 0) {
+        fprintf(stderr, "got 0 bytes from /dev/random.. it's supposed to block!!\n");
+        exit(2);
+      }
+      got += ct;
+    }
+
+    if (close(fd) < 0) {
+      perror("close");
+      exit(2);
+    }
+
+    return ret;
+
+  #else     // windows
+    fprintf(stderr, "no system crypto random function available!\n");
+    exit(2);
+    return 0;    // silence warning
+  #endif
+}
+
+
+int getProcessId()
+{
+  #ifdef __WIN32__
+    return GetCurrentProcessId();
+
+  #else  // unix
+    return getpid();
+
+  #endif
+}
+
+
+// do we have access to C99 vsnprintf?
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+  #if __GLIBC__ >= 3 || (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)
+    // glibc-2.1 or later: yes (glibc-2.0.6 has a function called
+    // vsnprintf, but the interface is wrong)
+    #define HAS_C99_VSNPRINTF
+  #endif
+#endif
+
+// note to reader: if your system has C99 VSNPRINTF, feel free to add
+// appropriate detection code
+
+#ifndef HAS_C99_VSNPRINTF
+  // no vsnprintf, will use gprintf (which is slow, and overestimates sometimes)
+  #include "gprintf.h"        // general_vprintf
+  
+  static int counting_output_function(void *extra, int ch)
+  {
+    // 'extra' is a pointer to the count
+    int *ct = (int*)extra;
+    (*ct)++;
+    return 0;    // no failure
+  }
+#endif // !HAS_C99_VSNPRINTF
+
+int vnprintf(char const *format, va_list args)
+{
+  #ifdef HAS_C99_VSNPRINTF
+    // can use this directly
+    return vsnprintf(NULL, 0, format, args);
+
+  #else
+    // conservatively interpret the format string using gprintf
+    int count = 0;
+    general_vprintf(counting_output_function, &count, format, args);
+    return count;
+  #endif
+}
+
+
+int nprintf(char const *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  int ret = vnprintf(format, args);
+  va_end(args);
+  return ret;
+}
+
+
+// ----------------- test code --------------------
+#ifdef TEST_NONPORT
+
+#include <stdio.h>       // printf
+
+
+// helper for testing applyToCwdFiles
+bool printFirst10(char const *name, void *extra)
+{
+  int &count = *((int*)extra);
+  count++;
+  if (count <= 10) {
+    printf("  %s\n", name);
+    return true;    // continue
+  }
+  else {
+    return false;   // stop
+  }
+}
+
+
+bool printIt(char const *name, void*)
+{
+  printf("%s\n", name);
+  return true;    // continue
+}
+
+
+void testingFail(char const *call, char const *ctx)
+{
+  printf("FAIL: call=%s, ctx=%s, errno=%d\n",
+         call, (ctx? ctx : "(null)"), errno);
+}
+
+
+void nprintfVector(char const *format, ...)
+{
+  va_list args;
+
+  // run vnprintf to obtain estimate
+  va_start(args, format);
+  int est = vnprintf(format, args);
+  va_end(args);
+
+  // make that much space
+  char *buf = new char[est+1 + 50 /*safety margin*/];
+
+  // run the real vsprintf
+  va_start(args, format);
+  int len = vsprintf(buf, format, args);
+  va_end(args);
+  
+  if (len > est) {
+    printf("nprintf failed to conservatively estimate!\n");
+    printf("    format: %s\n", format);
+    printf("  estimate: %d\n", est);
+    printf("    actual: %d\n", len);
+    exit(2);
+  }
+
+  if (len != est) {
+    // print the overestimates; they shouldn't be much noise in the
+    // common case, but might hint at a problem earlier than I'd
+    // otherwise notice
+    printf("nprintf overestimate:\n");
+    printf("    format: %s\n", format);
+    printf("  estimate: %d\n", est);
+    printf("    actual: %d\n", len);
+  }
+
+  delete[] buf;
+}
+
+
+int main(int argc, char **argv)
+{
+  nonportFail = testingFail;
+
+  char s[4];
+  s[0] = '-';
+  s[1] = 'l';
+  s[2] = 's';
+  s[3] = 0;
+  if (0!=strcmp(s, "-ls")) {
+    printf("strcmp failed!\n");
+    return 4;
+  }
+
+  // process arguments
+  bool interactive = false;
+  for (int i=1; i<argc; i++) {
+    if (0==strcmp("-ls", argv[i])) {
+      // do an ls, and bail
+      applyToCwdContents(printIt);
+      return 0;
+    }
+    else if (0==strcmp("-noninteractive", argv[i])) {
+      // don't do the interactive stuff
+      interactive = false;
+    }
+    else {
+      printf("unknown option: %s\n", argv[i]);
+      return 2;
+    }
+  }
+
+  // trying to figure out why backspace sometimes gives ^? crap
+  // (turns out Konsole sometimes sends ^? in response to BS,
+  // even when the option looks unchecked)
+  //char buf[80];
+  //printf("type stuff and try backspace: ");
+  //gets(buf);
+  //printf("%s (%d chars)\n", buf, strlen(buf));
+  //return 0;
+
+  long startTime = getMilliseconds();
+
+  if (interactive) {
+    printf("Type some characters; you should see each\n"
+	   "character echoed once as you type it (q to stop):\n");
+    setRawMode(true);
+    char ch;
+    do {
+      ch = getConsoleChar();
+      printf("%c", ch);
+    } while (ch != 'q');
+
+    setRawMode(false);
+
+    printf("\n\nYou typed for %ld milliseconds\n",
+	   getMilliseconds() - startTime);
+  }
+
+  limitFileAccess("chmod.test");
+
+  printf("if the current dir contains a file called "
+         "chmod.test, I just attempted to limit\n"
+         "its access to just the owner\n");
+
+  createDirectory("test.dir");
+
+  // test chdir, which also implicitly tests mkdir
+  bool didFirst=false;
+  if (!changeDirectory("test.dir") || (didFirst=true, false) ||
+      !changeDirectory("..")) {
+    printf("failed while trying to chdir to %s\n",
+           (didFirst? ".." : "test.dir"));
+  }
+
+  // more straightforward
+  if (!fileOrDirectoryExists("test.dir")) {
+    printf("test.dir didn't get created?\n");
+  }
+
+  printf("what's more, I just tried to mkdir & chdir test.dir\n");
+
+  // test ensurePath
+  if (!ensurePath("test.dir/a/b/c/d", false /*isDirectory*/)) {
+    printf("ensurePath test.dir/a/b/c/d failed\n");
+  }
+
+  // try to list partial directory contents
+  printf("listing of first 10 files in this directory:\n");
+  {
+    int count = 0;
+    applyToCwdContents(printFirst10, &count);
+  }
+
+  // test date function
+  {
+    int m, d, y;
+    getCurrentDate(m, d, y);
+
+    printf("I think the date is (m/d/yyyy): %d/%d/%d\n",
+           m, d, y);
+  }
+
+  // test sleep (mostly just to make sure it doesn't segfault)
+  printf("sleeping for 1 second...\n");
+  portableSleep(1);
+
+  // test user name
+  char buf[80];
+  getCurrentUsername(buf, 80);
+  printf("current user name is: %s\n", buf);
+
+  if (interactive) {
+    // test nonecho reading
+    printf("Type something and press Enter; it won't be echoed (yet):\n");
+    readNonechoString(buf, 80, "  > ");
+    printf("You typed: %s\n", buf);
+  }
+
+  // test random stuff
+  printf("hasSystemCryptoRandom: ");
+  if (!hasSystemCryptoRandom()) {
+    printf("no\n");
+  }
+  else {
+    printf("yes\n");
+    
+    printf("three random numbers: %u %u %u\n",
+           getSystemCryptoRandom(),
+           getSystemCryptoRandom(),
+           getSystemCryptoRandom());
+  }
+
+  printf("testing nprintf...\n");
+  nprintfVector("simple");
+  nprintfVector("a %s more", "little");
+  nprintfVector("some %4d more %s complicated %c stuff",
+                33, "yikes", 'f');
+  nprintfVector("%f", 3.4);
+
+  printf("nonport works\n");
+  return 0;
+}
+
+#endif // TEST_NONPORT
+
+
+// -------------- trash ----------------
+#if 0
+void limitFileAccess(char const *fname)
+{
+  // we'll decide whether this is possible by whether
+  // or not the necessary macros are defined
+#ifndef S_IRGRP     // assume rest are if this is
+    // probably can't do anything
+    return;
+#else
+
+  // modify file permissions (to simplify things,
+  // we'll just set permissions, rather than
+  // read-modify-write); don't bother testing for
+  // error condition since there isn't much we
+  // can do about it anyway
+  chmod(fname, S_IRUSR | S_IWUSR);
+# endif
+}
+
+# ifdef __WIN32__     // findfirst, findnext
+#   ifdef __BORLANDC__
+      struct ffblk fb;
+      int done = findfirst("*", &fb, 0);
+      while (!done) {
+        if (!func(fb.ff_name, extra)) {
+          break;
+        }
+        done = findnext(&fb);
+      }
+#   else  // DOB: VC has a totally diff interface for this
+      struct _finddata_t fb;
+      long handle = _findfirst("*", &fb);
+      int done = (handle == -1);
+      while (!done) {
+        if (!func(fb.name, extra)) {
+          break;
+        }
+        done = _findnext(handle, &fb);
+      }
+      if (handle != -1) _findclose(handle);
+#   endif
+# else    // unix     // {open,read,close}dir, stat
+# endif
+
+#endif // 0    (trash)
+

Added: vendor/elsa/current/smbase/nonport.h
===================================================================
--- vendor/elsa/current/smbase/nonport.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/nonport.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,141 @@
+// nonport.h            see license.txt for copyright and terms of use
+// collection of nonportable routines (the interfaces
+//   are portable, but the implementations are not)
+// Scott McPeak, Dan Bonachea 1998-1999  This file is public domain.
+
+#ifndef __NONPORT_H
+#define __NONPORT_H
+
+#include "typ.h"     // bool
+#include <stdarg.h>  // va_list
+
+
+// I'm attempting to improve error handling in this module; this fn will be
+// called when a syscall fails, *in addition* to whatever error behavior
+// is documented here (e.g., a fn might call this, and then return false).
+// The default behavior is to do nothing.  In sftpc and sftpd, I plan to
+// point this at xSysError::xsyserror (see syserr.h).
+typedef void (*NonportFailFunc)(char const *syscallName, char const *context);
+  // syscallName  - name of failing system call
+  // context      - current activity (maybe just calling fn's name) or NULL
+extern NonportFailFunc nonportFail;
+
+// this is default handler
+void defaultNonportFail(char const *syscallName, char const *context);
+
+
+
+// put terminal into 'raw' or 'cooked' mode
+void setRawMode(bool raw);
+
+// get the next character typed without buffering or echoing; needs the
+// console to be in 'raw' mode
+char getConsoleChar();
+
+
+// get a millisecond count, where 0 is an unspecified event
+long getMilliseconds();
+
+
+// remove all priviledges to a file, except for read/write
+// access by the file's owner; returns false on error
+bool limitFileAccess(char const *fname);
+
+
+// get process id; meaning is somewhat system-dependent, but the goal
+// is to return something that can be used to correlate log output
+// from (say) sftpd with log output from some other source (syslog,
+// or NT event viewer, etc.)
+int getProcessId();
+
+
+// create a new directory; returns false on error;
+// precise naming semantics, such as use
+// of 'current working directory', etc., are specified by the
+// underlying OS's mkdir (or equivalent) command (it is hoped
+// this underspecification will not be a problem in practice)
+bool createDirectory(char const *dirname);
+
+// change to a directory; returns false on failure
+// again, current-directory semantics are unspecified
+bool changeDirectory(char const *dirname);
+
+// retrieve the name of the current working directory
+// (more best effort crap, I guess)
+bool getCurrentDirectory(char *dirname, int dirnameLen);
+
+
+// get and process the names of files *and directories* in the current directory
+typedef bool (*PerFileFunc)(char const *name, void *extra);
+  // name   - file/dir being processed (contains no slashes)
+  // extra  - 2nd parameter to applyToCwdContents
+  // return - true to continue, false to stop iterating
+void applyToCwdContents(PerFileFunc func, void *extra=NULL);
+
+// same as above, but in an explicitly named directory
+void applyToDirContents(char const *dirName,
+                        PerFileFunc func, void *extra=NULL);
+
+
+// return true if the given string names a directory
+bool isDirectory(char const *path);
+
+
+// delete a file; returns false on failure
+bool removeFile(char const *fname);
+
+
+// retrieve the current date
+void getCurrentDate(int &month, int &day, int &year);
+  // month:    1 = January ... 12 = December
+  // day:      1 = first day of month, ...
+  // year:     1999 is when this being coded
+  // e.g., February 8, 1999  is  month=2, day=8, year=1999
+
+
+// sleep for a bit (low resolution)
+void portableSleep(unsigned seconds);
+
+
+// determine usable name of current user, and write it into 'buffer'
+void getCurrentUsername(char *buffer, int buflen);
+
+
+// read a string from the console, with no echo
+void readNonechoString(char *buffer, int buflen, char const *prompt);
+
+
+// return true if a file or directory exists
+bool fileOrDirectoryExists(char const *name);
+
+
+// ensure that the pathname part of a file name exists;
+// it creates missing directories as necessary, with only
+// user rwx permission; if 'isDirectory' is true, the whole
+// name is also verified as a directory; returns false on
+// error
+bool ensurePath(char const *filename, bool isDirectory);
+
+
+// returns true if the system has a cryptographically-
+// secure random number generator
+bool hasSystemCryptoRandom();
+
+// if the above fn returns true, this will retrieve a
+// random 32-bit integer; may block until the bits
+// become available
+unsigned getSystemCryptoRandom();
+
+
+// determine how many characters, *not* including the final NUL, would
+// be written by vsprintf; this is allowed to overestimate
+int vnprintf(char const *format, va_list args);
+
+// this is implemented in terms of vnprintf, so not technically
+// a function with "nonportable implementation", but it belongs
+// here anyway
+int nprintf(char const *format, ...);
+
+
+#endif // __NONPORT_H
+

Added: vendor/elsa/current/smbase/objlist.h
===================================================================
--- vendor/elsa/current/smbase/objlist.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/objlist.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,322 @@
+// objlist.h
+// owner list of arbitrary dynamically-allocated objects
+// NOTE: automatically generated from xobjlist.h -- do not edit directly
+
+// Author: Scott McPeak, 2000
+
+#ifndef OBJLIST_H
+#define OBJLIST_H
+
+#include "voidlist.h"    // VoidList
+
+
+// forward declarations of template classes, so we can befriend them in ObjList
+// (not required by Borland C++ 4.5, but GNU wants it...)
+template <class T> class ObjListIter;
+template <class T> class ObjListMutator;
+template <class T> class ObjListIterNC;
+
+
+// the list is considered to own all of the items; it is an error to insert
+// an item into more than one such list, or to insert an item more than once
+// into any such list
+template <class T>
+class ObjList {
+private:
+  friend class ObjListIter<T>;
+  friend class ObjListMutator<T>;
+  friend class ObjListIterNC<T>;
+
+protected:
+  VoidList list;                        // list itself
+
+private:
+  // this is an owner list; these are not allowed
+  ObjList(ObjList const &obj);
+  ObjList& operator= (ObjList const &src);
+
+public:
+  ObjList()                            : list() {}
+  ~ObjList()                           { deleteAll(); }
+
+  // The difference function should return <0 if left should come before
+  // right, 0 if they are equivalent, and >0 if right should come before
+  // left.  For example, if we are sorting numbers into ascending order,
+  // then 'diff' would simply be subtraction.
+  typedef int (*Diff)(T const *left, T const *right, void *extra);
+
+  // selectors
+  int count() const                     { return list.count(); }
+  bool isEmpty() const                  { return list.isEmpty(); }
+  bool isNotEmpty() const               { return list.isNotEmpty(); }
+  T *&nthRef(int which)                 { return (T*&)list.nthRef(which); }
+  T *nth(int which)                     { return (T*)list.nth(which); }
+  T const *nthC(int which) const        { return (T const*)list.nth(which); }
+  T *first()                            { return (T*)list.first(); }
+  T const *firstC() const               { return (T const*)list.first(); }
+  T *last()                             { return (T*)list.last(); }
+  T const *lastC() const                { return (T const*)list.last(); }
+
+  // insertion
+  void prepend(T *newitem)              { list.prepend((void*)newitem); }
+  void append(T *newitem)               { list.append((void*)newitem); }
+  void insertAt(T *newitem, int index)  { list.insertAt((void*)newitem, index); }
+  void insertSorted(T *newitem, Diff diff, void *extra=NULL)
+    { list.insertSorted((void*)newitem, (VoidDiff)diff, extra); }
+
+  // removal
+  T *removeAt(int index)                { return (T*)list.removeAt(index); }
+  T *removeFirst()                      { return (T*)list.removeFirst(); }
+  void deleteAt(int index)              { delete (T*)list.removeAt(index); }
+  void deleteAll();
+
+  // list-as-set: selectors
+  int indexOf(T const *item) const      { return list.indexOf((void*)item); }
+  int indexOfF(T const *item) const     { return list.indexOfF((void*)item); }
+  bool contains(T const *item) const    { return list.contains((void*)item); }
+
+  // list-as-set: mutators
+  bool prependUnique(T *newitem)        { return list.prependUnique((void*)newitem); }
+  bool appendUnique(T *newitem)         { return list.appendUnique((void*)newitem); }
+  void removeItem(T const *item)        { list.removeItem((void*)item); }    // whether the arg should be const is debatable..
+  bool removeIfPresent(T const *item)   { return list.removeIfPresent((void*)item); }
+
+  // complex modifiers
+  void reverse()                                    { list.reverse(); }
+  void insertionSort(Diff diff, void *extra=NULL)   { list.insertionSort((VoidDiff)diff, extra); }
+  void mergeSort(Diff diff, void *extra=NULL)       { list.mergeSort((VoidDiff)diff, extra); }
+
+  // and a related test
+  bool isSorted(Diff diff, void *extra=NULL) const  { return list.isSorted((VoidDiff)diff, extra); }
+
+  // multiple lists
+  void concat(ObjList &tail)                       { list.concat(tail.list); }
+  // (we do *not* have appendAll, since these are supposed to be owner lists)
+
+  // steal
+  void stealTailAt(int index, ObjList &tail)       { list.stealTailAt(index, tail.list); }
+
+  // equal items in equal positions
+  bool equalAsLists(ObjList const &otherList, Diff diff, void *extra=NULL) const
+    { return list.equalAsLists(otherList.list, (VoidDiff)diff, extra); }
+  int compareAsLists(ObjList const &otherList, Diff diff, void *extra=NULL) const
+    { return list.compareAsLists(otherList.list, (VoidDiff)diff, extra); }
+
+  // last-as-set: comparisons (NOT efficient)
+  bool equalAsSets(ObjList const &otherList, Diff diff, void *extra=NULL) const
+    { return list.equalAsSets(otherList.list, (VoidDiff)diff, extra); }
+  bool isSubsetOf(ObjList const &otherList, Diff diff, void *extra=NULL) const
+    { return list.isSubsetOf(otherList.list, (VoidDiff)diff, extra); }
+  bool containsByDiff(T const *item, Diff diff, void *extra=NULL) const
+    { return list.containsByDiff((void*)item, (VoidDiff)diff, extra); }
+
+  // treating the pointer values themselves as the basis for comparison
+  bool equalAsPointerLists(ObjList const &otherList) const
+    { return list.equalAsPointerLists(otherList.list); }
+  bool equalAsPointerSets(ObjList const &otherList) const
+    { return list.equalAsPointerSets(otherList.list); }
+
+  // debugging: two additional invariants
+  void selfCheck() const { 
+    list.selfCheck();
+    list.checkHeapDataPtrs();
+    list.checkUniqueDataPtrs();
+  }
+};
+
+
+template <class T>
+void ObjList<T>::deleteAll()
+{
+  while (!list.isEmpty()) {
+    deleteAt(0);
+  }
+}
+
+
+// for traversing the list and modifying it (nodes and/or structure)
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists, and only one such iterator should exist for
+//       any given list
+template <class T>
+class ObjListMutator {
+  friend class ObjListIter<T>;
+
+protected:
+  VoidListMutator mut;       // underlying mutator
+
+public:
+  ObjListMutator(ObjList<T> &lst)     : mut(lst.list) { reset(); }
+  ~ObjListMutator()                    {}
+
+  void reset()                          { mut.reset(); }
+
+  // iterator copying; safe *only* until one of the mutators modifies
+  // the list structure (by inserting or removing), at which time all
+  // other iterators might be in limbo
+  ObjListMutator(ObjListMutator const &obj)             : mut(obj.mut) {}
+  ObjListMutator& operator=(ObjListMutator const &obj)  { mut = obj.mut;  return *this; }
+    // requires that 'this' and 'obj' already refer to the same 'list'
+
+  // iterator actions
+  bool isDone() const                   { return mut.isDone(); }
+  void adv()                            { mut.adv(); }
+  T *data()                             { return (T*)mut.data(); }
+  T *&dataRef()                         { return (T*&)mut.dataRef(); }
+
+  // insertion
+  void insertBefore(T *item)            { mut.insertBefore((void*)item); }
+    // 'item' becomes the new 'current', and the current 'current' is
+    // pushed forward (so the next adv() will make it current again)
+
+  void insertAfter(T *item)             { mut.insertAfter((void*)item); }
+    // 'item' becomes what we reach with the next adv();
+    // isDone() must be false
+
+  void append(T *item)                  { mut.append((void*)item); }
+    // only valid while isDone() is true, it inserts 'item' at the end of
+    // the list, and advances such that isDone() remains true; equivalent
+    // to { xassert(isDone()); insertBefore(item); adv(); }
+
+  // removal
+  T *remove()                           { return (T*)mut.remove(); }
+    // 'current' is removed from the list and returned, and whatever was
+    // next becomes the new 'current'
+
+  void deleteIt()                       { delete (T*)mut.remove(); }
+    // same as remove(), except item is deleted also
+
+  // debugging
+  void selfCheck() const                { mut.selfCheck(); }
+};
+
+#define MUTATE_EACH_OBJLIST(T, list, iter) \
+  for(ObjListMutator< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// for traversing the list without modifying it (neither nodes nor structure)
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists
+template <class T>
+class ObjListIter {
+protected:
+  VoidListIter iter;      // underlying iterator
+
+public:
+  ObjListIter(ObjList<T> const &list) : iter(list.list) {}
+  ObjListIter(ObjList<T> const &list, int pos) : iter(list.list, pos) {}
+  ~ObjListIter()                       {}
+
+  void reset(ObjList<T> const &list)   { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  ObjListIter(ObjListIter const &obj)             : iter(obj.iter) {}
+  ObjListIter& operator=(ObjListIter const &obj)  { iter = obj.iter;  return *this; }
+
+  // but copying from a mutator is less safe; see above
+  ObjListIter(ObjListMutator<T> &obj)             : iter(obj.mut) {}
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T const *data() const                 { return (T const*)iter.data(); }
+};
+
+#define FOREACH_OBJLIST(T, list, iter) \
+  for(ObjListIter< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// intermediate to the above two, this allows modification of the
+// objects stored on the list, but not the identity or order of
+// the objects in the list
+template <class T>
+class ObjListIterNC {
+protected:
+  VoidListIter iter;      // underlying iterator
+
+public:
+  ObjListIterNC(ObjList<T> &list) : iter(list.list) {}
+  ObjListIterNC(ObjList<T> &list, int pos) : iter(list.list, pos) {}
+  ~ObjListIterNC()                     {}
+
+  void reset(ObjList<T> &list)         { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  ObjListIterNC(ObjListIterNC const &obj)             : iter(obj.iter) {}
+  ObjListIterNC& operator=(ObjListIterNC const &obj)  { iter = obj.iter;  return *this; }
+
+  // but copying from a mutator is less safe; see above
+  ObjListIterNC(ObjListMutator<T> &obj)               : iter(obj.mut) {}
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T *data() const                       { return (T*)iter.data(); }
+};
+
+#define FOREACH_OBJLIST_NC(T, list, iter) \
+  for(ObjListIterNC< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// iterate over the combined elements of two or more lists
+template <class T>
+class ObjListMultiIter {
+private:
+  // all the lists
+  ObjList<T> **lists;                // serf array of serf list pointers
+  int numLists;                      // length of this array
+
+  // current element
+  int curList;                       // which list we're working on
+  ObjListIter<T> iter;               // current element of that list
+
+  // invariant:
+  //   either curList==numLists, or
+  //   iter is not 'done'
+
+public:
+  ObjListMultiIter(ObjList<T> **L, int n)
+    : lists(L),
+      numLists(n),
+      curList(0),
+      iter(*(lists[0]))
+  {
+    xassert(n > 0);
+    normalize();
+  }
+
+  // advance the iterator to the next element of the next non-empty list;
+  // establishes invariant above
+  void normalize();
+
+  bool isDone() const {
+    return curList == numLists;
+  }
+
+  T const *data() const {
+    return iter.data();
+  }
+
+  void adv() {
+    iter.adv();
+    normalize();
+  }
+};
+
+// this was originally inline, but that was causing some strange
+// problems (compiler bug?)
+template <class T>
+void ObjListMultiIter<T>::normalize()
+{
+  while (iter.isDone() && curList < numLists) {
+    curList++;
+    if (curList < numLists) {
+      iter.reset(*(lists[curList]));
+    }
+  }
+}
+
+
+// (tweak to ensure objlist.h and sobjlist.h both change)
+
+#endif // OBJLIST_H

Added: vendor/elsa/current/smbase/objmap.h
===================================================================
--- vendor/elsa/current/smbase/objmap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/objmap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,124 @@
+// objmap.h            see license.txt for copyright and terms of use
+// variant of ptrmap.h where the values are owned
+
+// for const purposes, as the values are owned, in a const table
+// the values cannot be modified
+
+#ifndef OBJMAP_H
+#define OBJMAP_H
+
+#include "ptrmap.h"           // PtrMap
+#include "xassert.h"          // xassert
+
+template <class KEY, class VALUE>
+class ObjMap {
+private:    // data
+  PtrMap<KEY,VALUE> map;
+
+public:     // funcs
+  ObjMap() {}
+  ObjMap(ObjMap const &src) { *this = src; }
+  ~ObjMap() { empty(); }
+
+  // query # of mapped entries
+  int getNumEntries() const               { return map.getNumEntries(); }
+  bool isEmpty() const                    { return map.isEmpty(); }
+  bool isNotEmpty() const                 { return map.isNotEmpty(); }
+
+  // if this key has a mapping, return it; otherwise, return NULL
+  VALUE const *getC(KEY *key) const       { return map.get(key); }
+  VALUE *get(KEY *key)                    { return map.get(key); }
+
+  // add a mapping from 'key' to 'value'; must not be mapped already
+  void add(KEY *key, VALUE *value)        { xassert(!map.get(key)); map.add(key, value); }
+  
+  // add with replacement
+  void addReplace(KEY *key, VALUE *value)
+  {
+    VALUE *oldValue = map.get(key);
+    if (oldValue) {
+      delete oldValue;
+    }
+    map.add(key, value);
+  }
+
+  // remove all mappings, and deallocate all VALUEs
+  void empty();
+  
+  // copy the whole map, including making copies of the VALUEs
+  ObjMap& operator=(ObjMap const &src);
+
+
+public:      // iterators
+  class IterC {
+  private:     // data
+    // underlying iterator state
+    typename PtrMap<KEY,VALUE>::Iter iter;
+
+  public:      // fucs
+    IterC(ObjMap<KEY,VALUE> const &map)   : iter(map.map) {}
+    ~IterC()                              {}
+
+    bool isDone() const                   { return iter.isDone(); }
+    void adv()                            { return iter.adv(); }
+
+    // return information about the currently-referenced table entry
+    KEY *key() const                      { return iter.key(); }
+    VALUE const *value() const            { return iter.value(); }
+  };
+  friend class IterC;
+
+  class Iter {
+  private:     // data
+    // underlying iterator state
+    typename PtrMap<KEY,VALUE>::Iter iter;
+
+  public:      // fucs
+    Iter(ObjMap<KEY,VALUE> &map)          : iter(map.map) {}
+    ~Iter()                               {}
+
+    bool isDone() const                   { return iter.isDone(); }
+    void adv()                            { return iter.adv(); }
+
+    // return information about the currently-referenced table entry
+    KEY *key() const                      { return iter.key(); }
+    VALUE *value() const                  { return iter.value(); }
+  };
+  friend class Iter;
+};
+
+
+template <class KEY, class VALUE>
+void ObjMap<KEY,VALUE>::empty()
+{
+  // delete the values; enclose in {} so the iterator goes
+  // away before the table is modified
+  {
+    typename PtrMap<KEY,VALUE>::Iter iter(map);
+    for (; !iter.isDone(); iter.adv()) {
+      delete iter.value();
+    }
+  }
+
+  map.empty();
+}
+
+
+template <class KEY, class VALUE>
+ObjMap<KEY,VALUE>& ObjMap<KEY,VALUE>::operator=(ObjMap const &src)
+{
+  if (this != &src) {
+    empty();
+    
+    // insert copies
+    IterC iter(src);
+    for (; !iter.isDone(); iter.adv()) {
+      add(iter.key(), new VALUE(*iter.value()));
+    }
+  }
+
+  return *this;
+}
+
+
+#endif // OBJMAP_H

Added: vendor/elsa/current/smbase/objpool.h
===================================================================
--- vendor/elsa/current/smbase/objpool.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/objpool.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,164 @@
+// objpool.h            see license.txt for copyright and terms of use
+// custom allocator: array of objects meant to be
+// re-used frequently, with high locality
+
+#ifndef OBJPOOL_H
+#define OBJPOOL_H
+
+#include "array.h"     // GrowArray
+
+// the class T should have:
+//   // a link in the free list; it is ok for T to re-use this
+//   // member while the object is not free in the pool
+//   T *nextInFreeList;
+//
+//   // object is done being used for now
+//   void deinit();
+//
+//   // needed so we can make arrays
+//   T::T();
+
+template <class T>
+class ObjectPool {
+private:     // data
+  // when the pool needs to expand, it expands by allocating an
+  // additional 'rackSize' objects; I use a linear (instead of
+  // exponential) expansion strategy because these are supposed
+  // to be used for small sets of rapidly-reused objects, not
+  // things allocated for long-term storage
+  int rackSize;
+
+  // growable array of pointers to arrays of 'rackSize' T objects
+  ArrayStack<T*> racks;
+
+  // head of the free list; NULL when empty
+  T *head;
+
+private:     // funcs
+  void expandPool();
+
+public:      // funcs
+  ObjectPool(int rackSize);
+  ~ObjectPool();
+
+  // yields a pointer to an object ready to be used; typically,
+  // T should have some kind of init method to play the role a
+  // constructor ordinarily does; this might cause the pool to
+  // expand (but previously allocated objects do *not* move)
+  inline T *alloc();
+
+  // return an object to the pool of objects; dealloc internally
+  // calls obj->deinit()
+  inline void dealloc(T *obj);
+
+  // same as 'dealloc', but without the call to 'deinit'
+  inline void deallocNoDeinit(T *obj);
+
+  // available for diagnostic purposes
+  int freeObjectsInPool() const;
+  
+  // low-level access for heavily-optimized client code; clients that
+  // use these functions accept the burden of possibly needing to
+  // change if internals of ObjectPool change
+  T *private_getHead() { return head; }
+  void private_setHead(T *h) { head = h; }
+};
+
+
+template <class T>
+ObjectPool<T>::ObjectPool(int rs)
+  : rackSize(rs),
+    racks(5),
+    head(NULL)
+{}
+
+template <class T>
+ObjectPool<T>::~ObjectPool()
+{
+  // deallocate all the objects in the racks
+  for (int i=0; i < racks.length(); i++) {
+    delete[] racks[i];
+  }
+}
+
+
+template <class T>
+inline T *ObjectPool<T>::alloc()
+{
+  if (!head) {
+    // need to expand the pool
+    expandPool();
+  }
+
+  T *ret = head;                     // prepare to return this one
+  head = ret->nextInFreeList;        // move to next free node
+
+  #ifndef NDEBUG
+    ret->nextInFreeList = NULL;        // paranoia
+  #endif
+
+  return ret;
+}
+
+
+// this is pulled out of 'alloc' so alloc can be inlined
+// without causing excessive object code bloat
+template <class T>
+void ObjectPool<T>::expandPool()
+{
+  T *rack = new T[rackSize];
+  racks.push(rack);
+
+  // thread new nodes into a free list
+  for (int i=rackSize-1; i>=0; i--) {
+    rack[i].nextInFreeList = head;
+    head = &(rack[i]);
+  }
+}
+
+
+// usually I want the convenience of dealloc calling deinit; however,
+// in the inner loop of a performance-critical section of code, I
+// want finer control
+template <class T>
+inline void ObjectPool<T>::deallocNoDeinit(T *obj)
+{
+  // I don't check that nextInFreeList == NULL, despite having set it
+  // that way in alloc(), because I want to allow for users to make
+  // nextInFreeList share storage (e.g. with a union) with some other
+  // field that gets used while the node is allocated
+
+  // prepend the object to the free list; will be next yielded
+  obj->nextInFreeList = head;
+  head = obj;
+}
+
+
+template <class T>
+inline void ObjectPool<T>::dealloc(T *obj)
+{
+  // call obj's pseudo-dtor (the decision to have dealloc do this is
+  // motivated by not wanting to have to remember to call deinit
+  // before dealloc)
+  obj->deinit();
+
+  deallocNoDeinit(obj);
+}
+
+
+template <class T>
+int ObjectPool<T>::freeObjectsInPool() const
+{
+  T *p = head;
+  int ct = 0;
+
+  while (p) {
+    ct++;
+    p = p->nextInFreeList;
+  }
+
+  return ct;
+}
+
+
+#endif // OBJPOOL_H

Added: vendor/elsa/current/smbase/objstack.h
===================================================================
--- vendor/elsa/current/smbase/objstack.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/objstack.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,34 @@
+// objstack.h            see license.txt for copyright and terms of use
+// stack of objects, owned by the stack
+
+#ifndef OBJSTACK_H
+#define OBJSTACK_H
+
+#include "objlist.h"    // ObjList
+
+template <class T>
+class ObjStack {
+private:      // data
+  // will implement the stack as a list, with prepend and removeAt(0)
+  ObjList<T> list;
+
+public:       // funcs
+  ObjStack()                            : list() {}
+  ~ObjStack()                           {}
+
+  int count() const                     { return list.count(); }
+  bool isEmpty() const                  { return list.isEmpty(); }
+  bool isNotEmpty() const               { return list.isNotEmpty(); }
+
+  T const *topC() const                 { return list.firstC(); }
+  T * /*serf*/ top()                    { return list.first(); }
+
+  T * /*owner*/ pop()                   { return list.removeAt(0); }
+  void delPop()                         { list.deleteAt(0); }
+  void push(T *item)                    { list.prepend(item); }
+  void clear()                          { list.deleteAll(); }
+
+  bool contains(T const *item) const    { return list.contains((void*)item); }
+};
+
+#endif // OBJSTACK_H

Added: vendor/elsa/current/smbase/ofstreamts.cc
===================================================================
--- vendor/elsa/current/smbase/ofstreamts.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/ofstreamts.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,89 @@
+// ofstreamts.cc
+
+// quarl 2006-05-25 initial version, factored from 2006-05-16 astgen.cc
+
+#include "ofstreamts.h"
+#include "exc.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+size_t getFileSize(istream &i)
+{
+  // use 'streampos' instead of 'istream::pos_type' for gcc-2.95
+  // compatibility.
+  if (!i) return 0;
+  streampos save_pos = i.tellg();
+  i.seekg(0, ios::beg);
+  streampos begin_pos = i.tellg();
+  i.seekg(0, ios::end);
+  streampos end_pos = i.tellg();
+  size_t size = end_pos - begin_pos;
+  i.seekg(save_pos);
+  return size;
+}
+
+bool filesIdentical(const char *f1, const char *f2)
+{
+  ifstream i1(f1);
+  if (!i1) return false;
+
+  ifstream i2(f2);
+  if (!i2) {
+    xfatal(stringc << "I thought I just wrote " << f2 << ", but it doesn't exist");
+    return false;
+  }
+
+  if (getFileSize(i1) != getFileSize(i2))
+    return false;
+
+  while (true) {
+    if (i1.bad() || i2.bad()) {
+      return false;
+    }
+
+    if (i1.eof() && i2.eof()) {
+      // reached EOF and no problem.
+      return true;
+    }
+
+    if (!i1 || !i2) {
+      // Other error? or for some reason we reached EOF in one file but not
+      // another even though file sizes are the same
+      return false;
+    }
+
+    if (i1.get() != i2.get()) {
+      // unidentical character
+      return false;
+    }
+  }
+}
+
+const char *ofstreamTS::init_fname(string const &destFname0)
+{
+  destFname = destFname0;
+  tmpFname = destFname0 & ".tmp";
+  return tmpFname.c_str();
+}
+
+void ofstreamTS::save() {
+  close();
+  if (filesIdentical(destFname.c_str(), tmpFname.c_str())) {
+    cout << "  file " << destFname << " unchanged, so not overwriting it.\n";
+    if (unlink(tmpFname.c_str())) {
+      cerr << "  unlink " << tmpFname << " failed\n";
+    }
+    return;
+  }
+  if (rename(tmpFname.c_str(), destFname.c_str())) {
+    xfatal(stringc << "Rename " << tmpFname << " to " << destFname << " failed");
+  }
+}
+
+void ofstreamTS::deleteTmp() {
+  close();
+  if (unlink(tmpFname.c_str())) {
+    cerr << "  unlink " << tmpFname << " failed\n";
+  }
+}

Added: vendor/elsa/current/smbase/ofstreamts.h
===================================================================
--- vendor/elsa/current/smbase/ofstreamts.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/ofstreamts.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,59 @@
+// ofstreamts.h
+
+// quarl 2006-05-25 initial version, factored from 2006-05-16 astgen.cc
+
+#ifndef OFSTREAMTS_H
+#define OFSTREAMTS_H
+
+#include <fstream.h>
+#include "str.h"
+
+// An ofstream which is timestamp-conscious.  It first writes to a temporary
+// file, and on success renames it to the target destination.  However, it
+// doesn't do this if the file hasn't changed.  This way we avoid messing with
+// the timestamp, which is annoying since 'make' will think we have to rebuild
+// everything.
+//
+// Another advantage of writing to a temporary file then renaming is we get
+// atomic output.
+//
+// Call 'dontsave()' to avoid saving, e.g. if an error occurred.
+class ofstreamTS : public ofstream {
+  // The name of the file where the data is eventually saved
+  string destFname;
+
+  // The name of a temporary file where we write until we rename.
+  //
+  // This is currently "filename.tmp".  Since it is 'rename'd to destFname, it
+  // must be in the same file system as destFname (i.e. generally not in
+  // /tmp)
+  string tmpFname;
+
+  // Flag indicating whether the destructor should save.  See dontsave().
+  bool dosave;
+
+  // Initialize the member filenames; used internally by constructor
+  const char *init_fname(string const &destFname0);
+
+  // Open the temporary file
+  void openTmp() { open(tmpFname.c_str()); }
+
+  // Close the temporary file and rename to the destination file
+  void save();
+
+  // Close the temporary file and delete it without saving.
+  void deleteTmp();
+
+public:
+  ofstreamTS(string const &destFname0) : dosave(true)
+  { init_fname(destFname0); openTmp(); }
+  ~ofstreamTS() { if (dosave) save(); }
+
+  // Indicate that the output shouldn't be saved, e.g. due to an error.
+  void dontsave() { dosave = false; }
+
+  // Abort output: delete temporary file, and don't save.
+  void abort() { deleteTmp(); dontsave(); }
+};
+
+#endif

Added: vendor/elsa/current/smbase/ohashtbl.h
===================================================================
--- vendor/elsa/current/smbase/ohashtbl.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/ohashtbl.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+// ohashtbl.h            see license.txt for copyright and terms of use
+// hash table that owns the values; uses void* keys
+// see hashtbl.h for more detail on the semantics of the member fns
+
+#ifndef OHASHTBL_H
+#define OHASHTBL_H
+
+#include "hashtbl.h"       // HashTable
+
+template <class T> class OwnerHashTableIter;
+
+template <class T>
+class OwnerHashTable {
+public:     // types
+  friend class OwnerHashTableIter<T>;
+
+  // see hashtbl.h
+  typedef void const* (*GetKeyFn)(T *data);
+  typedef unsigned (*HashFn)(void const *key);
+  typedef bool (*EqualKeyFn)(void const *key1, void const *key2);
+
+private:    // data
+  // inner table that does the hash mapping
+  HashTable table;
+
+public:     // funcs
+  OwnerHashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek,
+                 int initSize = HashTable::defaultSize)
+    : table((HashTable::GetKeyFn)gk, hf, ek, initSize) {}
+  ~OwnerHashTable() { empty(1); }
+
+  int getNumEntries() const               { return table.getNumEntries(); }
+  T *get(void const *key) const           { return (T*)table.get(key); }
+  void add(void const *key, T *value)     { table.add(key, value); }
+  T *remove(void const *key)              { return (T*)table.remove(key); }
+  void empty(int initSize = HashTable::defaultSize);
+  void setEnableShrink(bool en)           { table.setEnableShrink(en); }
+  void selfCheck() const                  { table.selfCheck(); }
+
+  // this simply drops all the entries without deleting them; it is
+  // useful when the objects have been taken out via iteration
+  void disownAndForgetAll(int initSize = HashTable::defaultSize)
+                                          { table.empty(initSize); }
+};
+
+template <class T>
+void OwnerHashTable<T>::empty(int initSize)
+{
+  HashTableIter iter(table);
+  for (; !iter.isDone(); iter.adv()) {
+    delete (T*)iter.data();
+  }
+  table.empty(initSize);
+}
+
+
+template <class T>
+class OwnerHashTableIter {
+private:      // data
+  HashTableIter iter;      // internal iterator
+
+public:       // funcs
+  OwnerHashTableIter(OwnerHashTable<T> &table)
+    : iter(table.table) {}
+
+  bool isDone() const      { return iter.isDone(); }
+  void adv()               { iter.adv(); }
+  T *data()                { return (T*)iter.data(); }
+};
+
+#endif // OHASHTBL_H

Added: vendor/elsa/current/smbase/okhasharr.h
===================================================================
--- vendor/elsa/current/smbase/okhasharr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/okhasharr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,63 @@
+// okhasharr.h            see license.txt for copyright and terms of use
+// combination of an owner hash table and an array/stack
+//
+// in its present form, it's ideal for a worklist, but not
+// for a 'finished' list, due to inability to randomly remove
+
+#ifndef OKHASHARR_H
+#define OKHASHARR_H
+
+#include "array.h"      // ArrayStack
+#include "okhashtbl.h"  // OwnerKHashTable
+
+// T is value, K is key
+template <class T, class K>
+class OwnerKHashArray {
+private:    // data
+  OwnerKHashTable<T,K> hash;
+  ArrayStack<T*> stack;
+
+public:     // funcs
+  OwnerKHashArray(typename OwnerKHashTable<T,K>::GetKeyFn gk,
+                  typename OwnerKHashTable<T,K>::HashFn hf,
+                  typename OwnerKHashTable<T,K>::EqualKeyFn ek,
+                  int initSize = HashTable::defaultSize)
+    : hash(gk, hf, ek, initSize),
+      stack(initSize)
+  {
+    hash.setEnableShrink(false);
+  }
+  ~OwnerKHashArray();
+
+  // # elts in the structure
+  int count() const                  { return stack.length(); }
+  bool isEmpty() const               { return stack.isEmpty(); }
+  bool isNotEmpty() const            { return !isEmpty(); }
+
+  // access as a hashtable
+  T *lookup(K const *key) const      { return hash.get(key); }
+  K const *callGetKeyFn(T *data)     { return hash.callGetKeyFn(data); }
+
+  // TODO: make a new base-level implementation so I can support
+  // removal of arbitrary objects efficiently
+
+  // access as a stack
+  void push(K const *key, T *value) {
+    hash.add(key, value);
+    stack.push(value);
+  }
+
+  T *pop() {
+    T *ret = stack.pop();
+    hash.remove(hash.callGetKeyFn(ret));
+    return ret;
+  }
+};
+
+
+template <class T, class K>
+OwnerKHashArray<T,K>::~OwnerKHashArray()
+{}
+
+
+#endif // OKHASHARR_H

Added: vendor/elsa/current/smbase/okhashtbl.h
===================================================================
--- vendor/elsa/current/smbase/okhashtbl.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/okhashtbl.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,75 @@
+// okhashtbl.h            see license.txt for copyright and terms of use
+// version of ohasharr.h with type-safe keys ("k" for keys)
+
+#ifndef OKHASHTBL_H
+#define OKHASHTBL_H
+
+#include "hashtbl.h"       // HashTable
+
+template <class T, class K> class OwnerKHashTableIter;
+
+// T is the value type, K is the key type
+template <class T, class K>
+class OwnerKHashTable {
+public:     // types
+  friend class OwnerKHashTableIter<T,K>;
+
+  // see hashtbl.h
+  typedef K const* (*GetKeyFn)(T *data);
+  typedef unsigned (*HashFn)(K const *key);
+  typedef bool (*EqualKeyFn)(K const *key1, K const *key2);
+
+private:    // data
+  // inner table that does the hash mapping
+  HashTable table;
+
+public:     // funcs
+  OwnerKHashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek,
+                  int initSize = HashTable::defaultSize)
+    : table((HashTable::GetKeyFn)gk, 
+            (HashTable::HashFn)hf, 
+            (HashTable::EqualKeyFn)ek, 
+            initSize) {}
+  ~OwnerKHashTable() { empty(1); }
+
+  int getNumEntries() const               { return table.getNumEntries(); }
+  T *get(K const *key) const              { return (T*)table.get(key); }
+  void add(K const *key, T *value)        { table.add(key, value); }
+  T *remove(K const *key)                 { return (T*)table.remove(key); }
+  void empty(int initSize = HashTable::defaultSize);
+  void setEnableShrink(bool en)           { table.setEnableShrink(en); }
+  K const *callGetKeyFn(T *data)          { return (K const*)table.callGetKeyFn(data); }
+  void selfCheck() const                  { table.selfCheck(); }
+
+  // this simply drops all the entries without deleting them; it is
+  // useful when the objects have been taken out via iteration
+  void disownAndForgetAll(int initSize = HashTable::defaultSize)
+                                          { table.empty(initSize); }
+};
+
+template <class T, class K>
+void OwnerKHashTable<T,K>::empty(int initSize)
+{
+  HashTableIter iter(table);
+  for (; !iter.isDone(); iter.adv()) {
+    delete (T*)iter.data();
+  }
+  table.empty(initSize);
+}
+
+
+template <class T, class K>
+class OwnerKHashTableIter {
+private:      // data
+  HashTableIter iter;      // internal iterator
+
+public:       // funcs
+  OwnerKHashTableIter(OwnerKHashTable<T,K> &table)
+    : iter(table.table) {}
+
+  bool isDone() const      { return iter.isDone(); }
+  void adv()               { iter.adv(); }
+  T *data()                { return (T*)iter.data(); }
+};
+
+#endif // OKHASHTBL_H

Added: vendor/elsa/current/smbase/oobjmap.h
===================================================================
--- vendor/elsa/current/smbase/oobjmap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/oobjmap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+// oobjmap.h            see license.txt for copyright and terms of use
+// owner object map, implemented with a hash table
+// maps pointer-to-key-object to pointer-to-value-object, and owns
+// all instances of value-object (they are deallocated when the
+// map itself goes away)
+                        
+// I had envisioned an interface which didn't require the function
+// that maps values back to keys.. given that OwnerHashTable requires
+// this, I'll suspend this line of work for now and keep using
+// OwnerHashTable directly
+#error This does not work quite right
+
+#ifndef OOBJMAP_H
+#define OOBJMAP_H
+
+#include "ohashtbl.h"      // OwnerHashTable
+
+template <class Key, class Value> class OObjMapIter;
+
+template <class Key, class Value>
+class OObjMap {
+public:     // types
+  friend class OObjMapIter<Key, Value>;
+
+private:    // data 
+  OwnerHashTable<Value> table;            // implementation
+
+public:     // funcs
+  OObjMap() {}
+  ~OObjMap() {}                           // deallocates Value objects
+
+  int getNumEntries() const               { return table.getNumEntries(); }
+  Value *get(Key const *key) const        { return table.get(key); }
+  void add(Key const *key, Value *value)  { table.add(key, value); }
+  Value *remove(Key const *key)           { return table.remove(key); }
+  void empty()                            { table.empty(); }
+  void selfCheck() const                  { table.selfCheck(); }
+};
+
+
+template <class Key, class Value>
+class OObjMapIter {
+private:    // data
+  OwnerHashTableIter<Value> iter;         // implementation
+
+public:
+  OObjMapIter(OObjMap<Key,Value> &map)    : iter(map.table) {}
+
+  bool isDone() const                     { return iter.isDone(); }
+  void adv()                              { iter.adv(); }
+  Value *data()                           { return iter.data(); }
+};
+
+
+#endif // OOBJMAP_H

Added: vendor/elsa/current/smbase/owner.h
===================================================================
--- vendor/elsa/current/smbase/owner.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/owner.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,98 @@
+// owner.h            see license.txt for copyright and terms of use
+// a stab at an owner ptr abstraction
+
+#ifndef OWNER_H
+#define OWNER_H
+
+#include "typ.h"      // NULL
+
+// I'm tossing these in here so they are somewhere in smbase, even
+// though they don't have much to do with the Owner class.
+#define owner /*nothing*/
+#define serf /*nothing*/
+#define nullable /*nothing*/
+
+#ifdef DEBUG_OWNER
+  #include <stdio.h>    // printf, temporary
+  #define DBG(fn) printf("%s(%p)\n", fn, ptr)
+#else
+  #define DBG(fn)
+#endif
+
+template <class T>
+class Owner {
+private:    // data
+  T *ptr;                // the real pointer
+
+private:    // funcs
+  Owner(Owner&);         // not allowed
+
+public:     // funcs
+  Owner(T *p = NULL) : ptr(p) { DBG("ctor"); }
+  ~Owner() { DBG("dtor"); del(); }
+
+  // take ownership (no transitive = here)
+  void operator= (T *p) { DBG("op=ptr"); del(); ptr=p; }
+  void operator= (Owner<T> &obj) { DBG("op=obj"); del(); ptr=obj.ptr; obj.ptr=NULL; }
+
+  // release ownership
+  T *xfr() { DBG("xfr"); T *temp = ptr; ptr = NULL; return temp; }
+
+  // free
+  void del() { DBG("del"); delete ptr; ptr = NULL; }    // relies on delete(NULL) being ok
+
+  // some operators that make Owner behave more or less like
+  // a native C++ pointer.. note that some compilers to really
+  // bad handling the "ambiguity", so the non-const versions
+  // can be disabled at compile time
+  operator T const* () const { DBG("opcT*"); return ptr; }
+  T const & operator* () const { DBG("opc*"); return *ptr; }
+  T const * operator-> () const { DBG("opc->"); return ptr; }
+
+  // according to http://www.google.com/search?q=cache:zCRFFDMZvVUC:people.we.mediaone.net/stanlipp/converops.htm+conversion+sequence+for+the+argument+is+better&hl=en&ie=ISO-8859-1,
+  // a solution to the gcc "conversion sequence is better" complaint
+  // is to define this version
+  operator T const* () { DBG("opcT*_nc"); return ptr; }
+
+  #ifndef NO_OWNER_NONCONST
+  operator T* () { DBG("opT*"); return ptr; }
+  T& operator* () { DBG("op*"); return *ptr; }
+  T* operator-> () { DBG("op->"); return ptr; }
+  #endif
+
+  // escape hatch for when operators flake out on us
+  T *get() { DBG("get"); return ptr; }
+  T const *getC() const { DBG("getC"); return ptr; }
+
+  // even more dangerous escape; only use where the caller
+  // agrees to restore the owner invariant!
+  T *&getRef() { DBG("getRed"); return ptr; }
+
+  // swaps are interesting because they don't require checking
+  void swapWith(Owner<T> &obj) {
+    T *tmp = ptr;
+    ptr = obj.ptr;
+    obj.ptr = tmp;
+  }
+};
+   
+
+template <class T>
+void swap(Owner<T> &obj1, Owner<T> &obj2)
+{
+  obj1.swapWith(obj2);
+}
+
+
+// not used with Owner objects, but rather with
+// simple pointers (Foo*) that are used as owners
+template <class T>
+T *xfr(T *&ptr)
+{
+  T *ret = ptr;
+  ptr = NULL;
+  return ret;
+}
+
+
+#endif // OWNER_H

Added: vendor/elsa/current/smbase/pair.h
===================================================================
--- vendor/elsa/current/smbase/pair.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/pair.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,59 @@
+// pair.h            see license.txt for copyright and terms of use
+// approximately standard-conforming (20.2.2) definition of pair<>
+
+// It is intended that a user who wants to use STL can simply arrange
+// to #include <utility> (and say 'using std::pair;') at this point
+// instead of using the definitions contained in this file.  That is,
+// this file provides a subset of <utility>.
+
+#ifndef PAIR_H
+#define PAIR_H
+
+template <class T1, class T2>
+struct pair {
+  typedef T1 first_type;
+  typedef T2 second_type;
+
+  T1 first;
+  T2 second;
+
+  pair() {}
+  pair(T1 const &x, T2 const &y) : first(x), second(y) {}
+
+  // I don't plan to use the templatized ctor, so will omit it
+
+  // operator= is defined by the compiler
+
+  // the header synopsis in 20.2 puts all the operators into
+  // the namespace, but I like them in the class and it should
+  // not make a difference
+  
+  // equality
+  bool operator==(pair<T1,T2> const &obj)
+    { return first == obj.first && second == obj.second; }
+  bool operator!=(pair<T1,T2> const &obj)
+    { return !operator==(obj); }
+             
+  // inequalities; note that this is the lexicographic order
+  // with 'first' dominating
+  bool operator <(pair<T1,T2> const &obj)
+    { return first < obj.first ||
+             (!(obj.first < first) && second < obj.second); }
+  bool operator >(pair<T1,T2> const &obj)
+    { return obj.operator<(*this); }
+  bool operator<=(pair<T1,T2> const &obj)
+    { return operator<(obj) || operator==(obj); }
+  bool operator>=(pair<T1,T2> const &obj)
+    { return operator>(obj) || operator==(obj); }
+};
+  
+
+// I do not know why the standard uses 'T1' instead of 'T1 const &' here.
+template <class T1, class T2>
+inline pair<T1,T2> make_pair(T1 const &x, T2 const &y)
+{
+  return pair<T1,T2>(x,y);
+}
+
+
+#endif // PAIR_H

Added: vendor/elsa/current/smbase/point.cc
===================================================================
--- vendor/elsa/current/smbase/point.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/point.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,15 @@
+// point.cc            see license.txt for copyright and terms of use
+// code for point.h
+
+#include "point.h"      // this module
+#include "str.h"        // stringBuilder
+
+stringBuilder& operator<< (stringBuilder &sb, point const &pt)
+{
+  return sb << "(" << pt.x << ", " << pt.y << ")";
+}
+
+stringBuilder& operator<< (stringBuilder &sb, fpoint const &pt)
+{
+  return sb << "(" << pt.x << ", " << pt.y << ")";
+}

Added: vendor/elsa/current/smbase/point.h
===================================================================
--- vendor/elsa/current/smbase/point.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/point.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,110 @@
+// point.h            see license.txt for copyright and terms of use
+// 2-dimensional point
+// derived from Melee's prmtvs2.hpp
+
+#ifndef __POINT_H
+#define __POINT_H
+
+#include "typ.h"          // bool, min, max
+
+// point defined over arbitrary underlying types
+template <class num>
+class TPoint {
+public:
+  num x, y;
+
+public:
+  TPoint() {}
+  TPoint(num nx, num ny) { set(nx,ny); }
+  TPoint(TPoint<num> const &obj) : x(obj.x), y(obj.y) {}
+
+  TPoint const& operator = (TPoint<num> const &obj)
+    { x=obj.x; y=obj.y; return *this; }
+
+  void set(num nx, num ny) { x=nx; y=ny; }
+  void get(num *gx, num *gy) const { *gx=x; *gy=y; }
+  bool zero() const { return x==0 && y==0; }
+  bool gtez() const { return x>=0 && y>=0; }
+
+  TPoint<num> operator - () const
+    { return TPoint<num>(-x, -y); }
+  TPoint<num> absval() const
+    { return TPoint<num>(x<0? -x : x, y<0? -y : y); }
+      // don't call abs() because that requires stdlib.h
+      // also, don't call the function "abs" because abs() is usually
+      //   implemented as a macro
+
+  TPoint<num> operator + (TPoint<num> const &obj) const
+    { return TPoint<num>(x+obj.x, y+obj.y); }
+  TPoint<num> operator - (TPoint<num> const &obj) const
+    { return TPoint<num>(x-obj.x, y-obj.y); }
+  num dotprod(TPoint<num> const &obj) const
+    { return x*obj.x + y*obj.y; }
+
+  // for the arithmetic functions of the form point <op> num, <op> num is
+  // applied to x and y independently
+
+  TPoint<num> operator * (num factor) const
+    { return TPoint<num>(x*factor, y*factor); }
+  TPoint<num> operator / (num factor) const
+    { return TPoint<num>(x/factor, y/factor); }
+
+  TPoint<num> operator * (TPoint<num> const &factor) const
+    { return TPoint<num>(x*factor.x, y*factor.y); }
+  TPoint<num> operator / (TPoint<num> const &factor) const
+    { return TPoint<num>(x/factor.x, y/factor.y); }
+
+  TPoint<num> operator += (TPoint<num> const &obj)
+    { x+=obj.x; y+=obj.y; return *this; }
+  TPoint<num> operator -= (TPoint<num> const &obj)
+    { x-=obj.x; y-=obj.y; return *this; }
+  TPoint<num> operator *= (num factor)
+    { x*=factor; y*=factor; return *this; }
+  TPoint<num> operator /= (num factor)
+    { x/=factor; y/=factor; return *this; }
+
+  bool operator == (TPoint<num> const &obj) const
+    { return x==obj.x && y==obj.y; }
+  bool operator != (TPoint<num> const &obj) const
+    { return ! operator==(obj); }
+
+  // use with care; note that each relation requires the relation to hold for
+  // *both* x and y for it to be true (this is different than, for example, the
+  // way STL does relations between pairs)
+  bool operator > (TPoint<num> const &obj) const
+    { return x>obj.x && y>obj.y; }
+  bool operator >= (TPoint<num> const &obj) const
+    { return x>=obj.x && y>=obj.y; }
+  bool operator < (TPoint<num> const &obj) const
+    { return x<obj.x && y<obj.y; }
+  bool operator <= (TPoint<num> const &obj) const
+    { return x<=obj.x && y<=obj.y; }
+};
+
+
+// common incarnations
+typedef TPoint<int> point;
+typedef TPoint<double> fpoint;
+
+
+// and we can then define stringBuilder output ops for them
+class stringBuilder;
+stringBuilder& operator<< (stringBuilder &sb, point const &pt);
+stringBuilder& operator<< (stringBuilder &sb, fpoint const &pt);
+
+
+// iterate: 0,0    1,0    2,0    ... x-1,0    and then
+//          0,1    1,1    2,1    ... x-1,1    and then
+//           .                          .
+//           .                          .     (each line in succession)
+//           .                          .
+//          0,y-1  1,y-1  2,y-1	 ... x-1,y-1  done
+// can 'break' out of the loop at any time
+
+#define FOREACH_point(size, var)   \
+  if ((size).x > 0)                \
+    for(point var(0,0); var.y < (size).y; ++var.x == (size).x && (var.x=0,var.y++))
+
+
+#endif // ___POINT_H
+

Added: vendor/elsa/current/smbase/pprint.cc
===================================================================
--- vendor/elsa/current/smbase/pprint.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/pprint.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,363 @@
+// pprint.cc
+// code for pprint.h
+
+#include "pprint.h"      // this module
+#include "breaker.h"     // breaker
+#include <stdio.h>       // sprintf
+#include <string.h>      // memcpy
+
+
+// ---------------------- PPrintOut ----------------------
+void PPrintStringOut::write(char const *text)
+{
+  sb << text;
+}
+
+void PPrintOstreamOut::write(char const *text)
+{
+  os << text;
+}
+
+
+// ------------------------ PPrint ----------------------
+bool PPrint::warnWhenUnbalanced = true;
+
+PPrint::PPrint(PPrintOut &o)
+  : line(),
+    lineIndent(0),
+    margin(72),
+    altIndent(2),
+    startText(NULL),
+    out(o)
+{}
+
+PPrint::~PPrint()
+{
+  if (line.length() > 0) {
+    // hit a breakpoint if we're in the debugger, since this
+    // is unexpected
+    breaker();
+
+    // add a final newline to get all the output out
+    print("\n");
+  }
+}
+
+
+struct BreakInfo {
+  int p;        // index in the 'line' array of the '\r'
+  int pCol;     // column of emitted text where the newline would go
+  int pInd;     // indent for the next line
+
+  BreakInfo(int pp, int pc, int pi)
+    : p(pp), pCol(pc), pInd(pi) {}
+  BreakInfo() {}      // for use in arrays
+    
+  // when choosing breaks, we maximize this sum: the # of chars
+  // that will be on this line, and the # of chars available to
+  // fill on the next line
+  int sum(/*int margin*/) const {
+    // except, since all the margins play the same role and will
+    // all cancel, we don't need to consider it
+    return pCol +                 // this line
+           (/*margin*/ - pInd);   // next line
+  }
+
+  // decision between two breaks
+  bool betterThan(BreakInfo const &obj /*, int margin*/) { 
+    if (sum(/*margin*/) > obj.sum(/*margin*/)) 
+      { return true; }
+      
+    // tiebreaker: prefer more space on the next line, since that's
+    // likely to become the space available on the line after that,
+    // etc.
+    if (sum(/*margin*/) == obj.sum(/*margin*/) &&
+        pInd < obj.pInd)
+      { return true; }
+
+    return false;
+  }
+};
+
+
+void PPrint::Setter::indent(int amt)
+{
+  for (int i=0; i<amt; i++) {
+    curLine << ' ';
+  }
+}
+
+
+void PPrint::Setter::set()
+{
+  // initialize the indentation stack with the line-start indentation
+  indentGroups.push(pprint.lineIndent);
+    
+  // loop over the actual emitted lines
+  while (lineIndex < pprint.line.length()) {
+    // indent the line by the amount at the top of the stack
+    curLineInd = indentGroups.top();
+    indent(curLineInd);
+
+    // find all of the line breaks that would make the current line end
+    // before the 'margin' column
+    ArrayStack<BreakInfo> breaks;      // TODO: move up to avoid allocation
+
+    // this will scan forward to find optional line breaks
+    int p = lineIndex;
+
+    // column at which the line would break, if we broke at 'p'
+    int pCol = curLine.length();
+
+    // the topmost entry of this stack says how far we'd indent
+    // at the beginning of the next line, if we broke at 'p'
+    ArrayStack<int> pInd;              // TODO: move up to avoid allocation
+
+    // initialize 'pInd' with 'indentGroups', because what happens next
+    // is we speculatively emit, as if doing it for real and consequently
+    // updating 'indentGroups'
+    {
+      pInd.ensureAtLeast(indentGroups.length());
+      for (int i=0; i < indentGroups.length(); i++) {
+        pInd[i] = indentGroups[i];
+      }
+      pInd.setLength(indentGroups.length());
+    }
+
+    while (p < pprint.line.length()-1 && pCol < pprint.margin) {
+      switch (pprint.line[p]) {
+        case '\r':   // optional line break
+          breaks.push(BreakInfo(p, pCol, pInd.top()));
+          pCol++;    // if *not* taken, it will be a space
+          break;
+
+        case '\b':   // begin break group
+          pInd.push(pCol);
+          break;
+
+        case '\a':   // alternate begin group
+          pInd.push(curLineInd + pprint.altIndent);
+          break;
+
+        case '\f':   // break group end
+          pInd.pop();
+          break;
+
+        default:     // printing character
+          // increases output column
+          pCol++;
+          break;
+      }
+
+      p++;
+    }
+
+    if (pCol < pprint.margin) {
+      // we got to the end of 'line' before hitting margin; emit the
+      // remainder as-is
+      emitTo(p+1 /*include newline*/);
+      flush();
+      return;
+    }
+
+    if (breaks.isEmpty()) {
+      // no line breaks happen soon enough, so just find the first
+      // break and take it
+      while (p < pprint.line.length()-1) {
+        if (pprint.line[p] == '\r') {
+          emitTo(p /*not including '\r'*/);
+          lineIndex++;     // skip '\r'
+          curLine << '\n';
+          flush();
+          break;
+        }
+
+        p++;
+      }
+
+      if (p == pprint.line.length()-1) {
+        // no optional line breaks at all; emit remainder
+        emitTo(p+1 /*include newline*/);
+        flush();
+        return;
+      }
+    }
+
+    else {
+      // choose the best break from among those in 'breaks'
+      int best = 0;
+      for (int i=1; i < breaks.length(); i++) {
+        if (breaks[i].betterThan(breaks[best] /*, pprint.margin*/)) {
+          best = i;
+        }
+      }
+
+      // break the line
+      emitTo(breaks[best].p /*not including '\r'*/);
+      lineIndex++;                  // skip '\r'
+      curLine << '\n';
+      flush();
+    }
+  }
+}
+
+PPrint::Setter::~Setter()
+{
+  if (indentGroups.length() != 1) {
+    // unbalanced groups
+    breaker();          
+    if (warnWhenUnbalanced) {
+      cout << "warning: unbalanced indentation grouping in pprint input\n";
+    }
+  }
+}
+
+
+void PPrint::Setter::emitTo(int p)
+{
+  while (lineIndex < p) {
+    char ch = pprint.line[lineIndex];
+    switch (ch) {
+      case '\r':   // optional line break
+        // not taken, it's a space
+        curLine << ' ';
+        break;
+
+      case '\b':   // begin break group
+        indentGroups.push(curLine.length());
+        break;
+
+      case '\a':   // alternate begin group
+        indentGroups.push(curLineInd + pprint.altIndent);
+        break;
+
+      case '\f':   // break group end
+        indentGroups.pop();
+        break;
+
+      default:     // printing character
+        curLine << ch;
+        break;
+    }
+
+    lineIndex++;
+  }
+}
+
+
+void PPrint::Setter::flush()
+{
+  if (pprint.startText) {
+    pprint.out.write(pprint.startText);
+  }
+  pprint.out.write(curLine);
+  curLine.clear();
+}
+
+
+void PPrint::set()
+{
+  // on entry, 'line' contains exactly one newline, at the end
+  xassert(line[line.length()-1] == '\n');
+
+  Setter s(*this);
+  s.set();
+
+  // clear the line, ready for the next one
+  line.setLength(0);
+}
+
+
+void append(ArrayStack<char> &line, char const *src, int len)
+{
+  line.ensureAtLeast(line.length() + len);
+  memcpy(line.getArrayNC()+line.length(),     // dest
+         src, len);                           // src, len
+  line.setLength(line.length() + len);
+}
+
+void PPrint::print(char const *text)
+{
+  // any newlines?
+  char const *p = text;
+  while (*p != 0) {
+    if (*p == '\n') {
+      // transfer everything up to the newline into the setting buffer
+      int copylen = p-text+1;
+      append(line, text, copylen);
+
+      // advance 'text' so the next batch will begin after what we
+      // just transferred
+      text += copylen;
+
+      // set the now-complete line
+      set();
+    }
+
+    p++;
+  }
+
+  // copy the remainder into the line buffer
+  append(line, text, p-text);
+}
+
+
+PPrint& PPrint::operator<< (int i)
+{
+  char tmp[40];
+  sprintf(tmp, "%d", i);
+  print(tmp);
+  return *this;
+}
+
+PPrint& PPrint::operator<< (char const *s)
+{
+  print(s);
+  return *this;
+}
+
+
+PPrintToString::~PPrintToString()
+{}
+
+
+// --------------------- test code -----------------------
+#ifdef TEST_PPRINT
+
+PPrintToString pp;
+
+int main()
+{
+  pp.margin = 30;
+  pp.startText = "; ";
+
+  cout << "         1    1    2    2    3\n";
+  cout << "1---5----0----5----0----5----0\n";
+
+  pp << "int foo()\n"
+        "{\n"
+        ;
+  pp.ind(+2);
+  pp << "printf(\b\"hello there %d!\\n\",\r123456789\f);\n";
+  pp << "bar(\b1 +\r2 +\r3 +\r4 +\r5 +\r6 +\r7 +\r8 +\r9 +\r10\f);\n";
+  pp << "baz(\b\"a really long line that has no optional breaks at all\"\f);\n";
+  pp << "zoo(\b\"one break is here, but it is very\",\r\"far from the start\"\f);\n";
+  pp << "assert(\bx ==\ry &&\rz ==\rw &&\r"
+               "(\bmoron !=\rfool ||\rtaxes->theRich\f)\f);\n";
+  pp << "\aforall(x, y, z). if {\r"
+          "x == yooey_more;\r"
+          "yowza != fooey;\f\r"
+        "} {\a\r"
+          "z(x,y,z)==3;\r"
+          "ay_caramba;\f\r"
+        "}\n";
+  pp.ind(-2);
+  pp << "}\n";
+  
+  cout << pp.sb;
+  
+  return 0;
+}
+
+
+#endif // TEST_PPRINT

Added: vendor/elsa/current/smbase/pprint.h
===================================================================
--- vendor/elsa/current/smbase/pprint.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/pprint.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,182 @@
+// pprint.h
+// pretty-print code while emitting it
+
+
+
+// NOTE: This module is a little simpler to use, but much less
+// powerful than the 'boxprint' module.  I'm leaving this module
+// here for now, but will probably delete it at some point.
+
+
+
+// inspired by:
+//   CIL's 'pretty' module
+//   http://www.cs.berkeley.edu/~necula/cil/index.html
+// and
+//   Caml pretty-print module (boxes, etc.)
+//   http://caml.inria.fr/FAQ/format-eng.html
+
+// special characters:
+//   '\n' - hard linebreak
+//   '\r' - optional linebreak; is 1 space if the break isn't taken
+//   '\b' - begin a break group (return to <here>)
+//   '\a' - alternate begin group (return to <this_line_ind> + altIndent)
+//   '\f' - finish a break group
+
+#ifndef PPRINT_H
+#define PPRINT_H
+
+#include <iostream.h>      // ostream
+#include "str.h"           // string
+#include "array.h"         // GrowArray
+
+
+// output interface for PPrint.. I'd like to just start using the
+// C++ iostreams interfaces, but reading on the net I get the
+// impression they're still a little too much in flux
+class PPrintOut {
+public:
+  virtual ~PPrintOut() {}
+  virtual void write(char const *text) = 0;
+};
+
+class PPrintStringOut : public PPrintOut {
+  stringBuilder &sb;
+public:
+  PPrintStringOut(stringBuilder &s) : sb(s) {}
+  virtual ~PPrintStringOut() {}
+  virtual void write(char const *text);
+};
+
+class PPrintOstreamOut : public PPrintOut {
+  ostream &os;
+public:
+  PPrintOstreamOut(ostream &o) : os(o) {}
+  virtual ~PPrintOstreamOut() {}
+  virtual void write(char const *text);
+};
+
+
+// pretty printer formatting engine
+class PPrint {
+private:     // types
+  // manages the line-setting algorithm
+  class Setter {
+  private:     // data
+    // inter-line information
+    PPrint &pprint;
+
+    // emitted text in the current line
+    stringBuilder curLine;
+
+    // indentation used for 'curLine'
+    int curLineInd;
+
+    // place in the 'line' buffer; all the chars up to this point
+    // have been sent out
+    int lineIndex;
+
+    // stack of columns at which indent groups opened
+    ArrayStack<int> indentGroups;
+
+  private:     // funcs
+    // add 'amt' spaces to 'curLine'
+    void indent(int amt);
+
+    // copy characters [lineIndex,lineIndex+p-1] from 'line' into
+    // 'curLine', moving 'lineIndex' along so eventually it equals
+    // 'p'; also maintain 'indentGroups'
+    void emitTo(int p);
+
+    // send all of 'curLine' to 'pprint.out', and clear 'curLine'
+    void flush();
+
+  public:      // funcs
+    Setter(PPrint &p)
+      : pprint(p),
+        curLine(),
+        curLineInd(0),
+        lineIndex(0),
+        indentGroups()
+    {}
+    ~Setter();
+
+    void set();
+  };
+  friend class Setter;
+
+private:     // data
+  // the contents of each line, up to a hard linebreak, is accumulated here
+  ArrayStack<char> line;
+
+public:      // data
+  // current indentation level for the beginning of a complete line
+  // (one preceded by a hard linebreak)
+  int lineIndent;
+
+  // desired right margin; we'll try to set text so it doesn't go
+  // beyond that many columns; defaults to 72
+  int margin;
+
+  // incremental indentation for '\a' groups; defaults to 2
+  int altIndent;
+
+  // if not NULL, text to emit at the start of every line; intended
+  // for emitting text into a comment or other embedded context;
+  // defaults to NULL; not counted against the margin
+  char const *startText;
+
+  // where to send output
+  PPrintOut &out;
+
+  // When true, and we find that the grouping is unbalanced at
+  // the end of setting a line, pring a warning.  This defaults
+  // to 'true'.  Note that while too many '\b's will only trigger
+  // this warning, too many '\f's can cause an assertion failure
+  // when the indentation stack underflows.
+  static bool warnWhenUnbalanced;
+
+private:     // funcs
+  // take the current line buffer and break it up into output
+  // lines, sending them to 'out'
+  void set();
+
+public:      // funcs
+  PPrint(PPrintOut &out);
+  ~PPrint();
+
+  // basic printing routine; the text can contain the special
+  // characters listed above; whenever a '\n' is seen, the current
+  // line is set and emitted to 'out'
+  void print(char const *text);
+
+  // convenience
+  PPrint& operator<< (int i);
+  PPrint& operator<< (char const *s);
+
+  // manage the line-start indentation
+  void ind(int amt) { lineIndent += amt; }
+};
+
+
+class PPrintToString : public PPrint {
+public:
+  stringBuilder sb;            // output (set) lines accumulate here
+  PPrintStringOut sbOut;       // helper
+
+public:
+  PPrintToString()
+    : PPrint(sbOut), sb(), sbOut(sb) {}
+  ~PPrintToString();
+};
+
+class PPrintToOstream : public PPrint {
+  PPrintOstreamOut osOut;
+
+public:
+  PPrintToOstream(ostream &os)
+    : PPrint(osOut), osOut(os) {}
+};
+
+
+#endif // PPRINT_H

Added: vendor/elsa/current/smbase/ptrintmap.h
===================================================================
--- vendor/elsa/current/smbase/ptrintmap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/ptrintmap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,68 @@
+// ptrintmap.h            see license.txt for copyright and terms of use
+// map from KEY* to int for arbitrary type KEY
+// (key is not owned by the table)
+
+// dsw: modified from ptrmap.h by replacing 'VALUE*' with 'DATAVALUE'.
+// this is an abuse of VoidPtrMap as it only works with types
+// DATAVALUE that are the same size as a 'void*', such as 'int'; I
+// think VoidPtrMap should be generalized to allow this usage.
+
+// for const purposes, I regard the mapping itself as the only
+// thing that cannot be modified in a "const" map
+
+#ifndef PTRINTMAP_H
+#define PTRINTMAP_H
+
+#include "vptrmap.h"       // VoidPtrMap
+#include "typ.h"           // NULL
+
+
+template <class KEY, class DATAVALUE>
+class PtrIntMap {
+private:     // data
+  // underlying map implementation, around which this class
+  // is a type-safe wrapper
+  VoidPtrMap map;
+
+public:      // funcs
+  PtrIntMap()                         : map() {}
+  ~PtrIntMap()                        {}
+
+  // query # of mapped entries
+  int getNumEntries() const        { return map.getNumEntries(); }
+  bool isEmpty() const             { return getNumEntries() == 0; }
+  bool isNotEmpty() const          { return !isEmpty(); }
+
+  // if this key has a mapping, return it; otherwise, return NULL
+  DATAVALUE get(KEY const *key) const { return reinterpret_cast<DATAVALUE>(map.get((void const*)key)); }
+
+  // add a mapping from 'key' to 'value'; replaces existing
+  // mapping, if any
+  void add(KEY *key, DATAVALUE value) { map.add((void*)key, (void*)value); }
+
+  // remove all mappings
+  void empty()                     { map.empty(); }
+
+
+public:      // iterators
+  class Iter {
+  private:     // data
+    // underlying iterator state
+    VoidPtrMap::Iter iter;
+
+  public:      // fucs
+    Iter(PtrIntMap<KEY,DATAVALUE> const &map)   : iter(map.map) {}
+    ~Iter()                              {}
+
+    bool isDone() const            { return iter.isDone(); }
+    void adv()                     { return iter.adv(); }
+
+    // return information about the currently-referenced table entry
+    KEY *key() const               { return (KEY*)iter.key(); }
+    DATAVALUE value() const        { return reinterpret_cast<DATAVALUE>(iter.value()); }
+  };
+  friend class Iter;
+};
+
+
+#endif // PTRINTMAP_H

Added: vendor/elsa/current/smbase/ptrmap.h
===================================================================
--- vendor/elsa/current/smbase/ptrmap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/ptrmap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,112 @@
+// ptrmap.h            see license.txt for copyright and terms of use
+// map from KEY* to VALUE* for arbitrary types KEY and VALUE
+// (neither are owned by the table)
+
+// for const purposes, I regard the mapping itself as the only
+// thing that cannot be modified in a "const" map; in particular,
+// I allow a non-const VALUE* to be extracted
+
+#ifndef PTRMAP_H
+#define PTRMAP_H
+
+#include "vptrmap.h"       // VoidPtrMap
+#include "typ.h"           // NULL
+
+
+template <class KEY, class VALUE>
+class PtrMap {
+private:     // data
+  // underlying map implementation, around which this class
+  // is a type-safe wrapper
+  VoidPtrMap map;
+
+public:      // funcs
+  PtrMap()                         : map() {}
+  ~PtrMap()                        {}
+
+  // query # of mapped entries
+  int getNumEntries() const        { return map.getNumEntries(); }
+  bool isEmpty() const             { return getNumEntries() == 0; }
+  bool isNotEmpty() const          { return !isEmpty(); }
+
+  // if this key has a mapping, return it; otherwise, return NULL
+  VALUE *get(KEY const *key) const { return (VALUE*)map.get((void const*)key); }
+
+  // add a mapping from 'key' to 'value'; replaces existing
+  // mapping, if any
+  void add(KEY *key, VALUE *value) { map.add((void*)key, (void*)value); }
+
+  // remove all mappings
+  void empty()                     { map.empty(); }
+
+
+public:      // iterators
+  class Iter {
+  private:     // data
+    // underlying iterator state
+    VoidPtrMap::Iter iter;
+
+  public:      // fucs
+    Iter(PtrMap<KEY,VALUE> const &map)   : iter(map.map) {}
+    ~Iter()                              {}
+
+    bool isDone() const            { return iter.isDone(); }
+    void adv()                     { return iter.adv(); }
+
+    // return information about the currently-referenced table entry
+    KEY *key() const               { return (KEY*)iter.key(); }
+    VALUE *value() const           { return (VALUE*)iter.value(); }
+  };
+  friend class Iter;
+};
+
+
+// a set based on PtrMap
+template <class KEY>
+  // dsw: I made the superclass public so I could iterate over it
+  // using the superclass iterator
+// class PtrSet : private PtrMap<KEY, KEY> {
+class PtrSet : public PtrMap<KEY, KEY> {
+  public:
+  PtrSet() {}
+  ~PtrSet() {}
+
+  // query # of mapped entries
+  int getNumEntries() const        { return PtrMap<KEY, KEY>::getNumEntries(); }
+  bool isEmpty() const             { return PtrMap<KEY, KEY>::isEmpty(); }
+  bool isNotEmpty() const          { return PtrMap<KEY, KEY>::isNotEmpty(); }
+
+  // if this key has a mapping, return it; otherwise, return NULL
+  bool contains(KEY const *key) const { return PtrMap<KEY, KEY>::get(key)!=NULL; }
+
+  // add key to the set
+  void add(KEY *key) { PtrMap<KEY, KEY>::add(key, key); }
+
+  // make the set empty; FIX: this would be better named makeEmpty(),
+  // as it could be confused with the meaning of isEmpty(); however I
+  // reflect the naming of PtrMap, where the same criticism applies.
+  void empty()                     { PtrMap<KEY, KEY>::empty(); }
+
+  // dsw: I could not get this to compile; don't know why
+// public:      // iterators
+//   class Iter {
+//   private:     // data
+//     // underlying iterator state
+//     ::PtrMap<KEY, KEY>::Iter iter;
+
+//   public:      // fucs
+//     Iter(PtrSet<KEY> const &set)   : iter(set) {}
+//     ~Iter()                          {}
+
+//     bool isDone() const            { return iter.isDone(); }
+//     void adv()                     { return iter.adv(); }
+
+//     // return information about the currently-referenced table entry
+//     KEY *key() const               { return (KEY*)iter.key(); }
+//     VALUE *value() const           { return (VALUE*)iter.value(); }
+//   };
+//   friend class Iter;
+};
+
+
+#endif // PTRMAP_H

Added: vendor/elsa/current/smbase/run-flex.pl
===================================================================
--- vendor/elsa/current/smbase/run-flex.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/run-flex.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,380 @@
+#!/usr/bin/perl -w
+# wrapper around flex
+
+# The purpose of this script is basically to "fix" flex's output
+# in a number of ways.
+#
+# 1. It changes a forward declaration of istream into a proper
+# #include directive.  In current C++ libraries, istream is not
+# a class but rather a template specialization.
+#
+# 2. Fix the "yyclass" option output so that the resulting module
+# can be linked with other flex-generated lexers:
+#
+#   2a. Wrap all yyFlexLexer methods with
+#         #ifdef WANT_YYFLEXLEXER_METHODS
+#         #endif
+#   so that from the Makefile I can control whether the object file
+#   contains those methods.
+#
+#   2b. Make copies of two yyFlexLexer methods and rename them to
+#   be methods of the derived lexer class, as these methods are
+#   different in each generated lexer.  (This is optional.)
+#
+# 3. Redhat's flex-2.5.4a-29 (actually somewhere between -20 and -23)
+# includes a "fix" so its generated output file includes the line:
+#
+#   using namespace std;
+#
+# This causes a clash for the name 'string'.  Long term, I'd like
+# to have a good, general way to reconcile this clash.  But for the
+# short term, this script replaces that line with these two:
+#
+#   using std::istream;
+#   using std::ostream;
+#
+# and that solves the problem nicely, as Flex does not use any
+# library classes other than those two.
+#
+# 4. Emit proper #line directives for merged extensions.
+
+# Given that I make so many changes, and they are so dependent on
+# the details of the generated file, it might seem easier to just
+# hack my own copy of flex and distribute that.  I may end up
+# doing that, but for now this provides a little portability (I
+# will try to make this work with both 2.5.4 and 2.5.31), and
+# avoids the need for me to repackage things like flex's configure
+# script.
+
+use strict 'subs';
+
+# defaults
+$nobackup = 0;           # if true, require the scanner to be backup-free
+$makeMethodCopies = 0;   # if true, do step 2b above
+$outputFile = "";        # name of eventual output file
+$inputFile = "";         # name if input file
+ at flexArgs = ("flex");    # arguments to pass to flex
+
+if (@ARGV == 0) {
+  print(<<"EOF");
+usage: $0 [-nobackup] [-copies] -o<fname> [flex-options] input.lex
+  -nobackup: fail if the scanner can jam
+  -copies:   make copies of methods that use per-lexer state
+  -o<fname>: specify output file name
+For details on other flex options, consult "man flex".
+EOF
+  exit(0);
+}
+
+# process command-line arguments; the syntax is basically a superset
+# of what flex itself accepts
+for (; @ARGV; shift @ARGV) {
+  # interestingly, both my choices of options are deprecated NOPs
+  # to flex in their single-letter forms (-n and -c), so there is
+  # little chance of confusion
+
+  if ($ARGV[0] eq "-nobackup") {
+    $nobackup = 1;
+    push @flexArgs, ("-b");
+    next;
+  }
+
+  if ($ARGV[0] eq "-copies") {
+    $makeMethodCopies = 1;
+    next;
+  }
+
+  my ($s) = ($ARGV[0] =~ m/^-o(.+)/);
+  if (defined($s)) {
+    diagnostic("saw output file: $s\n");
+    $outputFile = $s;
+  }
+
+  my ($if) = ($ARGV[0] =~ m/([^-].+)/);
+  $inputFile = $if if defined($if);
+
+  push @flexArgs, ($ARGV[0]);
+}
+
+if (!$inputFile) {
+  die("please specify an input file\n");
+}
+
+if (!$outputFile) {
+  die("please specify an output file with -o<file>\n");
+}
+
+# run flex
+print(join(' ', @flexArgs) . "\n");
+if (0!=system(@flexArgs)) {
+  print("flex failed, so removing output file $outputFile\n");
+  system("rm -f $outputFile");
+  exit(2);
+}
+
+# check for backing up
+if ($nobackup) {
+  if (0==system("grep non-accepting lex.backup")) {
+    print("(see lex.backup for details)\n");
+    print("removing output file $outputFile\n");
+    system("rm -f $outputFile");
+    exit(2);
+  }
+  else {
+    unlink("lex.backup");
+  }
+}
+
+# don't want to give the impression that the only thing that was
+# done was running flex, as I echoed that command line
+print("modifying $outputFile\n");
+
+# read the flex-generated output into memory
+open(IN, "<$outputFile") or die("cannot read $outputFile: $!\n");
+ at lines = <IN>;
+close(IN);
+
+# start writing it again
+open(OUT, ">$outputFile") or die("cannot write $outputFile: $!\n");
+
+# keep track of what we've done
+$state = 1;
+
+# name of derived lexer class (if any)
+$derivedClassName = "";
+
+# text (lines) of methods to copy
+ at methodCopies = ();
+
+# additional lines to move past the end of the methodCopies
+ at movedLines = ();
+
+# within extension
+my $extfilename;
+my $extlineno = -1;
+
+# filename as specified by last #line directive (including quotes)
+my $linefile = "\"$outputFile\"";
+my $lineno = 0;       # current line number of processed output
+
+# begin translating the generated file, making the changes outlined above
+for ($i=0; $i < @lines; $i++) {
+  $line = $lines[$i];
+
+  # this is stateless for no good reason
+  my ($s) = ($line =~ m/^\#define YY_DECL int (.*)::yylex/);
+  if (defined($s) && $s ne "yyFlexLexer") {
+    $derivedClassName = $s;
+  }
+
+  # this is stateless because it does not occur in the cygwin
+  # flex output (they have a different fix)
+  if ($line =~ m/class istream;/) {
+    $lineno++;
+    print OUT ("#include <iostream.h>      // class istream\n");
+    next;
+  }
+
+  # also stateless for similar reasons
+  if ($line =~ m/using namespace std;/) {
+    $lineno++;
+    print OUT ("using std::istream;\n");
+    $lineno++;
+    print OUT ("using std::ostream;\n");
+    next;
+  }
+
+  # this 'undef' must be moved to after the copied methods because
+  # those methods refer to 'yytext_ptr', which is just a #define
+  # for 'yytext'
+  if ($makeMethodCopies &&
+      $line =~ m/\#undef yytext_ptr/) {
+    push @movedLines, ($line);
+    next;
+  }
+
+  # this is stateless because I don't understand the state stuff
+  # start of lexical extension
+  if ($line =~ /\/\* start of (?:extension|base) ([^(]*)\((\d+)\) \*\//) {
+    $extfilename = $1;
+    $extlineno = $2;
+    next;
+  }
+
+  # this is stateless because I don't understand the state stuff
+  # adjust #line directives for proper pointing into extensions
+  if ($extlineno != -1 && $line =~ /#line (\d+)\s+("[^"]*"|)/) {
+    $linefile = $2 unless $2 eq "";
+    my $filename = $linefile;
+    my $number = $lineno + 1;
+    if ($filename eq "\"$inputFile\"") {
+      $filename = "\"$extfilename\"";
+      $number = $1 - $extlineno;
+    } elsif ($filename ne "\"$outputFile\"") {
+      # if not output file, consider it preprocessed and leave as is
+      $number = $1;
+    }
+    $line = "#line $number $filename\n";
+  }
+
+  # this is stateless because I don't understand the state stuff
+  # end of lexical extension
+  if ($line =~ /\/\* end of extension (.*) \*\//) {
+    $extlineno = -1;
+    next;
+  }
+
+  if ($state == 1) {
+    if ($lines[$i+1] =~ m/^(static )?void \*(yy_flex_alloc|yyalloc)/) {
+      $state++;
+      $lineno++;
+      print OUT ("#ifndef NO_YYFLEXLEXER_METHODS\n");
+      next;
+    }
+  }
+
+  elsif ($state == 2) {
+    if ($line =~ m/^(static )?void (yy_flex_free|yyfree)/) {
+      $state++;
+      $i++;
+      $lineno++;
+      $lineno++;
+      print OUT ($line .
+                 "#endif // yyflexlexer methods\n");
+      next;
+    }
+  }
+
+  elsif ($state == 3) {
+    if ($line =~ m/^\#include <FlexLexer.h>/) {
+      $state++;
+      $lineno++;
+      print OUT ("#include \"sm_flexlexer.h\"\n");
+      next;
+    }
+  }
+
+  elsif ($state == 4) {
+    if ($line =~ m/^int yyFlexLexer::yylex/) {
+      $state++;
+      $i++;       # skip the '{' line, to keep #line numbers in sync
+      chomp($line);
+      $lineno += 3;
+      print OUT ("#ifndef NO_YYFLEXLEXER_METHODS\n" .
+                 $line . " {\n");
+      next;
+    }
+  }
+
+  elsif ($state == 5) {
+    if ($line =~ m/^\s*\}\s*$/) {
+      $state++;
+      $i++;       # skip subsequent blank line
+      $lineno++;
+      $lineno++;
+      print OUT ($line .
+                 "#endif // yyflexlexer methods\n");
+      next;
+    }
+  }
+
+  elsif ($state == 6) {
+    if ($lines[$i+1] =~ m/^yyFlexLexer::yyFlexLexer/) {
+      $state++;
+      $lineno++;
+      print OUT ("#ifndef NO_YYFLEXLEXER_METHODS\n");
+      next;
+    }
+  }
+
+  elsif ($state == 7) {
+    if ($lines[$i+1] =~ m/yyFlexLexer::yy_get_previous_state/) {
+      $state++;
+    }
+  }
+
+  elsif ($state == 8) {
+    push @methodCopies, ($line);
+    if ($line =~ m/yyFlexLexer::yy_try_NUL_trans/) {
+      $state++;
+
+      # need to see how much this brace is indented, so we can
+      # find the matching one in the next state
+      ($ind) = ($lines[$i+1] =~ m/^(\s*)\{/);
+      if (!defined($ind)) {
+        die("yy_try_NUL_trans not followed by line with left brace\n");
+      }
+    }
+  }
+
+  elsif ($state == 9) {
+    push @methodCopies, ($line);
+    if ($line =~ m/^$ind\}\s*$/) {
+      $state++;
+    }
+  }
+
+  elsif ($state == 10) {
+    if ($line =~ m/^\#line/) {    # #line directive just before section 3
+      $state++;
+
+      # NOTE: This if-endif encloses the redefinition of 'yynext'
+      # that is appropriate for section 3.  I never use yynext in
+      # section 3 (in fact I rarely use section 3 at all), but if
+      # someone does then this will need to be adjusted.
+      $lineno++;
+      print OUT ("#endif // yyflexlexer methods\n");
+
+      if ($makeMethodCopies) {
+        # emit the copied method text again, this time substituting
+        # the name of the derived lexer class
+        if (!$derivedClassName) {
+          die("$0: did not see a derived lexer class name\n");
+        }
+
+        $lineno++;
+        print OUT ("// BEGIN method copies for $derivedClassName\n");
+        foreach $copyLine (@methodCopies) {
+          $copyLine =~ s/yyFlexLexer/$derivedClassName/;
+          $lineno++;
+          print OUT ($copyLine);
+        }
+        $lineno++;
+        print OUT ("// END method copies for $derivedClassName\n");
+
+        $lineno += $#movedLines + 1;
+        print OUT (@movedLines);
+      }
+    }
+  }
+
+  elsif ($state == 11) {
+    # this state prevails until the end of the file; just check
+    # that the yynext breakage isn't being exposed
+    if ($line =~ m/yynext/) {
+      die("$0: unimplemented: 'yynext' used in section 3\n");
+    }
+  }
+
+  $lineno++;
+  print OUT ($line);
+}
+
+$lastState = 11;
+if ($state != $lastState) {
+  $lineno++;
+  print OUT ("#error please rebuild $outputFile\n");    # in case not deleted
+  close(OUT);    # flush
+  die("failed to reach state $lastState; got stuck in state " . $state);
+}
+
+close(OUT);
+exit(0);
+
+
+sub diagnostic {
+  #print(@_);
+}
+
+
+# EOF


Property changes on: vendor/elsa/current/smbase/run-flex.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/scan-depends.pl
===================================================================
--- vendor/elsa/current/smbase/scan-depends.pl	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/scan-depends.pl	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,459 @@
+#!/usr/bin/perl -w
+# scan some C/C++ source files for their module dependencies,
+# output a description in the Dot graph format
+# author: smcpeak at cs.berkeley.edu
+
+# info on Dot: http://www.research.att.com/sw/tools/graphviz/
+
+# this scanner assumes that dependencies are expressed in one
+# of three ways:
+#   1. direct #inclusion, using quotes to delimit the filename
+#      (assuption is that angle brackets are used to refer to
+#      system headers, and we don't want to see those 
+#      dependencies)
+#   2. implicit link dependency of foo.h on foo.{c,cc,cpp},
+#      whichever exists, if any
+#   3. explicit link dependency expressed as a comment of the form
+#      // linkdepend: <filename>
+
+# Any line containing "(r)" is ignored by this script.  The intent
+# is to mark #include lines with this if the file included is
+# actually pulled in by another #include (so it's redundant, hence
+# the "r") but I don't want to remove the #include altogether
+# (because it still provides useful documentation).  By adding the
+# occasional "(r)" here and there one can prune the dependency tree
+# output to get a pleasing output (I wish Dot itself exposed more
+# knobs to tweak...)
+
+# The scanner does *not* run the preprocessor or otherwise use any
+# smarts to decode #ifdefs, #defines, tricky #inclusion sequences,
+# etc.  It also does not analyze anything produced by the compiler,
+# so it can easily miss link-time dependencies if your coding
+# conventions differ from mine.  Caveat emptor.
+
+# The scanner also assumes that file names are unique across all
+# directories under consideration.  My own projects conform to this
+# constraint since it helps avoid confusion, and using this assumption
+# means avoiding the clutter of qualifying names with directories.
+
+# NOTE: throughout, when file names are passed or stored, they
+# are stored *without* path qualification; all files are in
+# either the current directory or one of the directories 
+# specified with -I (and hence in @incdirs)
+
+
+# -------------------- global variables ---------------------
+# list of directories to search for #include files in; the user
+# adds things to this list with -I
+ at incdirs = ();
+
+# hashtable of files to exclude; actually, each entry is a number,
+# and when that number is positive it says how many more incoming
+# links we'll allow; when it is zero then no more links are allowed;
+# user adds to this with -X
+%excluded = ();
+
+# table of files whose outgoing edges should not be explored;
+# the data is always a 1; user adds to this with -S
+%subsystem = ();
+
+# when I print the info for a node, I put a 1 in this hashtable
+%nodes = ();
+
+# when I explore the edges from a node, I put a 1 in this table
+%explored = ();
+$recursive = 0;
+
+# list of files to explore; initially it's whatever is passed on the
+# command line, but as new files are discovered (when $recursive is
+# true) they get added here too
+ at toExplore = ();
+
+# true to print debug messages
+$debug = 0;
+
+# true to suppress warning messages
+$quiet = 0;
+                     
+# list of extensions to try when looking for implicit link dependencies
+ at extensions = (".cc", ".cpp", ".c");
+
+
+# ---------------------- subroutines ----------------------
+sub usage {
+  print(<<"EOF");
+usage: $0 [options] sourcefile [sourcefile ...]
+
+This program reads each of the source files specified on the command
+line, and emits a graph of their interdependencies in the Dot graph
+file format.  The source files should *not* be qualified with a path,
+but instead be inside some directory specified with -I.
+
+Options:
+  -I<dir>     Add <dir> to the list of directories to search when
+              looking for \#included files (files which are included
+              but not found are not printed as dependencies).
+
+  -X<name>    Exclude module <name> from the graph.  If a number is
+  -X<name>=n  specified, at most that many incoming links will be shown.
+
+  -S<name>    Do not process any outgoing edges from module <name>.  This
+              is useful when <name> is the entry point to a subsystem
+              whose dependencies are charted separately.
+
+  -r          Recursively follow dependencies for files encountered.
+  -q          Suppress warnings.
+  -d          Enable debug messages.
+  -h,-help    Print this usage string.
+
+EOF
+  exit(0);
+}
+
+
+# read command-line arguments, looking for options as documented above
+$origArgs = join(' ', @ARGV);
+sub processArguments {
+  while (@ARGV >= 1 &&
+         ($ARGV[0] =~ m/^-/)) {
+    my $option = $ARGV[0];
+    shift @ARGV;
+
+    my ($arg) = ($option =~ m/^-I(.*)$/);
+    if (defined($arg)) {
+      @incdirs = (@incdirs, $arg);
+      next;
+    }
+
+    my $count;
+    ($arg, $count) = ($option =~ m/^-X(.*)=(\d+)$/);
+    if (defined($arg)) {
+      $excluded{$arg} = $count;
+      next;
+    }
+
+    ($arg) = ($option =~ m/^-X(.*)$/);
+    if (defined($arg)) {
+      $excluded{$arg} = 0;    # no count implies 0 incoming links allowed
+      next;
+    }
+
+    ($arg) = ($option =~ m/^-S(.*)$/);
+    if (defined($arg)) {
+      $subsystem{$arg} = 1;
+      next;
+    }
+
+    if ($option eq "-r") {
+      $recursive = 1;
+      next;
+    }
+
+    if ($option eq "-q") {
+      $quiet = 1;
+      next;
+    }
+
+    if ($option eq "-d") {
+      $debug = 1;
+      next;
+    }
+
+    if ($option eq "-h" ||
+        $option eq "-help" ||
+        $option eq "--help") {
+      usage();
+    }
+
+    error("unknown option: $option\n" .
+          "try \"$0 -help\" for usage info");
+  }
+
+  if (@ARGV == 0) {
+    usage();
+  }
+}
+
+
+# error messages
+sub error {
+  print STDERR ("error: ", @_, "\n");
+  exit(2);
+}
+
+# warnings the user might be interested in
+sub warning {
+  if (!$quiet) {
+    print STDERR ("warning: ", @_, "\n");
+  }
+}
+
+# debug messages
+sub diagnostic {
+  if ($debug) {
+    print STDERR ("diagnostic: ", @_, "\n");
+  }
+}
+
+
+# return true if the argument file exists in the current directory
+# or any of the directories in @incdirs; return value is the name
+# under which the file was found, if it was
+sub fileExists {
+  my ($fname) = @_;
+
+  if (-e $fname) {
+    return $fname;
+  }
+
+  foreach $dir (@incdirs) {
+    if (-e "$dir/$fname") {
+      return "$dir/$fname";
+    }
+  }
+
+  diagnostic("didn't find $fname");
+  return "";   # false
+}
+
+
+# true if the filename meets my definition of a 'header', which has
+# two implications:
+#   - headers are printed without a circle around their name
+#   - headers have implicit link-time dependencies on their
+#     correspondingly-named .cc files
+sub isHeader {
+  my ($filename) = @_;
+  return ($filename =~ m/\.h$/);
+}
+
+
+# print the node info for the argument filename, if it
+# hasn't already been printed
+sub addNode {
+  my ($filename) = @_;
+
+  if (!defined($nodes{$filename})) {
+    # print info for this node; note that the default label is the
+    # same as the name of the node, so I normally don't also have
+    # an explicit 'label' attribute
+    $nodes{$filename} = 1;
+    print("  \"$filename\" [\n");
+
+    if (defined($subsystem{$filename})) {
+      # indicate that this module's dependencies weren't explored, hence
+      # the module actually stands for a subgraph of hidden dependencies
+      print("    label = \"$filename\\n(subsystem)\"\n",
+            "    shape = box\n",
+            "    style = dashed\n");
+    }
+
+    elsif (defined($excluded{$filename})) {
+      # indicate some incoming edges were not explored
+      print("    label = \"$filename\\n(ubiquitous)\"\n",
+            "    style = dashed\n");
+    }
+
+    elsif (isHeader($filename)) {
+      # I prefer headers to not have any delimiting shape; since I
+      # don't see a way to turn off the shape altogether, I make
+      # it white so it's effectively invisible
+      print("    color = white\n");
+    }
+
+    print("  ]\n");
+  }
+}
+
+
+# given a file name, strip its path if there is one (this is what
+# /bin/basename does, also)
+sub basename {
+  my ($fname) = @_;
+
+  my ($ret) = ($fname =~ m,/([^/]*)$,);
+  if (defined($ret)) {
+    # there was a slash, and we stripped it and everything before it
+    return $ret;
+  }
+  else {
+    # no slash
+    return $fname;
+  }
+}
+
+
+# given a file name, possibly with path, return the string of
+# characters after the last slash (if any) but before the first dot
+# which follows the last slash (if any)
+sub prefix {
+  my ($fname) = @_;
+  $fname = basename($fname);
+
+  # no slash now; get everything up to first dot
+  ($ret) = ($fname =~ m,^([^.]*),);
+  #diagnostic("prefix($fname) = $ret");
+  return $ret;
+}
+
+
+# add an edge between the two nodes; if the third argument
+# is true, then this is a link-time dependency (which is
+# printed with a dashed line)
+sub addEdge {
+  my ($src, $dest, $isLinkTime) = @_;
+
+  # is the link excluded?
+  my $allowed = $excluded{$dest};
+  if (defined($allowed)) {
+    die if $allowed < 0;
+    if ($allowed == 0) {
+      diagnostic("skipping $dest because it is excluded");
+      return;
+    }                      
+    $allowed--;
+    diagnostic("$allowed more links will be allowed for $dest");
+    $excluded{$dest} = $allowed;
+  }
+
+  if ($recursive) {
+    # arrange to explore this later
+    @toExplore = (@toExplore, $dest);
+  }
+
+  addNode($src);
+  addNode($dest);
+
+  print("  \"$src\" -> \"$dest\" [\n");
+
+  if ($isLinkTime) {
+    print("    style = dashed\n");
+  }
+
+  # if src and dest have the same base name, use a large
+  # weight so they will be close together visually
+  if (prefix($src) eq prefix($dest)) {
+    print("    weight = 10\n");
+  }
+
+  print("  ]\n");
+}
+
+
+# explore the edges emanating from this file; expect a filename
+# without path
+sub exploreFile {
+  my ($filename) = @_;
+  
+  # since we expect a filename without path, qualify it now
+  # so we can open the file
+  my $withPath = fileExists($filename);
+  if (!$withPath) {
+    warning("does not exist: $filename");
+    return;
+  }
+
+  if (defined($explored{$filename})) {
+    return;    # already explored this node
+  }
+  $explored{$filename} = 1;
+
+  # if the file has no outgoing or incoming edges (the user must have
+  # explicitly specified its name on the command line), this will
+  # ensure the node at least shows up (floating off disconnected, of
+  # course)
+  addNode($filename);
+
+  if (defined($subsystem{$filename})) {
+    return;    # don't explore outgoing edges
+  }
+
+  # if it's a header, and the corresponding .cc file exists,
+  # then add a link-time dependency edge
+  if (isHeader($filename)) {
+    foreach my $ext (@extensions) {
+      my $corresp = $filename;
+      $corresp =~ s/\.h$/$ext/;
+      $corresp = basename($corresp);
+      if (fileExists($corresp)) {
+        addEdge($filename, $corresp, 1);
+        last;     # stop looking after first match
+      }
+    }
+  }
+
+  if (!open(IN, "<$withPath")) {
+    warning("cannot read $withPath: $!");
+    next;    # skip it
+  }
+
+  # scan the file for its edges
+  my $line;
+  while (defined($line = <IN>)) {
+    # is this line marked with "(r)", meaning "redundant", and
+    # should therefore be ignored by this script?
+    if ($line =~ m/\(r\)/) {
+      next;
+    }
+
+    # is this an #include line?
+    my ($target) = ($line =~ m/^\s*\#include\s+\"([^\"]*)\"/);
+    if (defined($target)) {
+      $target = basename($target);
+      if (fileExists($target)) {
+        # add a compile-time edge
+        addEdge($filename, $target, 0);
+      }
+    }
+
+    # is this a comment specifying a link-time dependency?
+    ($target) = ($line =~ m/linkdepend: (.*)$/);
+    if (defined($target)) {
+      $target = basename($target);
+
+      # add a link-time edge; do so even if the file can't
+      # be found, because it's clearly important if the
+      # programmer went to the trouble of mentioning it
+      addEdge($filename, $target, 1);
+
+      if (!fileExists($target)) {
+        warning("could not find linkdepend: $target\n");
+      }
+    }
+  }
+
+  close(IN) or die;
+}
+
+
+# ---------------------- main ------------------------
+processArguments();
+
+# graph preamble
+print(<<"EOF");
+// dependency graph automatically produced by
+//   $0 $origArgs
+
+digraph "Dependencies" {
+EOF
+
+# process all the files, in the process adding nodes and edges to the
+# graph
+ at toExplore = @ARGV;
+while (@toExplore != 0) {
+  my $filename = $toExplore[0];
+  shift @toExplore;
+
+  if ($filename =~ m,/,) {
+    warning("should not use paths in arguments: $filename\n");
+    $filename = basename($filename);
+  }
+
+  exploreFile($filename);
+}
+
+# finish the graph
+print("}\n");
+
+exit(0);
+


Property changes on: vendor/elsa/current/smbase/scan-depends.pl
___________________________________________________________________
Name: svn:executable
   + 

Added: vendor/elsa/current/smbase/sm_config.pm
===================================================================
--- vendor/elsa/current/smbase/sm_config.pm	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/sm_config.pm	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,498 @@
+# sm_config.pm
+# Perl module for package configuration
+#
+# For now, the idea is simply to have a common place to put
+# a library of routines that my individual directory configure
+# scripts can use.
+
+# autoflush so progress reports work
+$| = 1;
+
+# smbase config version number; also serves as an
+# initialization routine
+sub get_sm_config_version {
+  $main::CC = getEnvOrDefault("CC", "gcc");
+  $main::CXX = getEnvOrDefault("CXX", "g++");
+  @main::CCFLAGS = ("-g", "-Wall", "-Wno-deprecated", "-D__UNIX__");
+  $main::CC_SYSINC_PATH = "";
+  $main::debug = 0;
+  $main::target = 0;
+  $main::no_dash_g = 0;
+  $main::no_dash_O2 = 0;
+  $main::exe = "";
+
+  return 1.05;
+
+  # 1.01: first version
+  #
+  # 1.02: added the PERLIO=crlf stuff
+  #
+  # 1.03: 2005-04-23: moved a bunch of argument processing into sm_config
+  #
+  # 1.04: 2005-05-04: re-added -no-dash-g and -no-dash-O2
+}
+
+# standard prefix of the usage string
+sub standardUsage {
+  print(<<"EOF");
+usage: ./configure [options]
+
+influential environment variables:
+  CC                 C compiler [$main::CC]
+  CXX                C++ compiler [$main::CXX]
+
+standard (sm_config) options:
+  -h:                print this message
+  -debug[=0/1]:      enable debugging options [$main::debug]
+  -target=<target>:  cross compilation target, e.g., "i386-mingw32msvc"
+  -no-dash-g:        disable -g
+  -no-dash-O2:       disable -O2
+EOF
+
+  if ($main::thisPackage ne "smbase") {
+    print("  -smbase=<dir>:     specify where the smbase library is [$main::SMBASE]\n");
+  }
+  print("\n");
+}
+
+
+# process standard command-line options; the option name is
+# in $main::option, and its argument (if any) in $main::value;
+# this returns true if it handles the argument
+sub handleStandardOption {
+  my $arg = $main::option;
+  my $val = $main::value;
+
+  if ($arg eq "h" ||
+      $arg eq "help") {
+    main::usage();
+    exit(0);
+  }
+
+  elsif ($arg eq "debug") {
+    $main::debug = getBoolArg();
+    return 1;
+  }
+
+  elsif ($arg eq "target") {
+    $main::target = getOptArg();
+    if ($target eq "i386-mingw32msvc") {
+      $main::exe = ".exe";
+      @main::CCFLAGS = grep { $_ ne "-D__UNIX__" } @main::CCFLAGS;
+      push @main::CCFLAGS, "-D__WIN32__";
+      return 1;
+    }
+    else {
+      die("at the moment, only the 'i386-mingw32msvc' cross target is supported\n");
+    }
+  }
+
+  elsif ($arg eq "smbase") {
+    $main::SMBASE = getOptArg();
+  }
+
+  elsif ($arg eq "no-dash-g") {
+    $main::no_dash_g = 1;
+  }
+
+  elsif ($arg eq "no-dash-O2") {
+    $main::no_dash_O2 = 1;
+  }
+
+  else {
+    return 0;
+  }
+}
+
+
+# run after all options have been processed
+sub finishedOptionProcessing {
+  if (!$main::debug) {
+    push @CCFLAGS, ("-O2", "-DNDEBUG");
+  }
+
+  if (!$main::target) {
+    my $os = `uname -s`;
+    chomp($os);
+    if ($os eq "Linux") {
+      push @main::CCFLAGS, "-D__LINUX__";
+    } elsif ($os =~ /CYGWIN/) {
+      push @main::CCFLAGS, "-D__CYGWIN__";
+    }
+  }
+
+  if ($main::no_dash_g) {
+    @main::CCFLAGS = grep { $_ ne "-g" } @main::CCFLAGS;
+  }
+
+  if ($main::no_dash_O2) {
+    @main::CCFLAGS = grep { $_ ne "-O2" } @main::CCFLAGS;
+  }
+}
+
+
+# get a value from the environment, or use a supplied default
+sub getEnvOrDefault {
+  my ($var, $def) = @_;
+
+  my $ret = $ENV{$var};
+  if (!defined($ret)) {
+    $ret = $def;
+  }
+
+  return $ret;
+}
+
+# use smbase's $BASE_FLAGS if I can find them
+sub get_smbase_BASE_FLAGS {
+  my $smbase_flags = `$main::SMBASE/config.summary 2>/dev/null | grep BASE_FLAGS`;
+  if (defined($smbase_flags)) {
+    ($main::BASE_FLAGS = $smbase_flags) =~ s|^.*: *||;
+    chomp($main::BASE_FLAGS);
+  }
+}
+
+
+# get smbase's compile flags, as a starting point
+sub get_smbase_compile_flags {
+  my $cfgsum = "$main::SMBASE/config.summary";
+  if (! -x $cfgsum) {
+    die("$cfgsum is not executable.\n" .
+        "smbase should be configured first.\n");
+  }
+  my @lines = `$main::SMBASE/config.summary 2>/dev/null`;
+  foreach my $line (@lines) {
+    my ($name, $value) = ($line =~ m/^\s*(\S+)\s*:\s*(\S.*)$/);
+                                 #       name    :   value
+    if (!defined($value)) { next; }
+
+    if ($name eq "CC") {
+      $main::CC = $value;
+    }
+    elsif ($name eq "CXX") {
+      $main::CXX = $value;
+    }
+    elsif ($name eq "CCFLAGS") {
+      @main::CCFLAGS = split(' ', $value);
+    }
+    elsif ($name eq "CROSSTARGET") {
+      $main::target = $value;
+    }
+    elsif ($name eq "EXE") {
+      $main::exe = $value;
+    }
+  }
+}
+
+
+# get an argument to an option
+sub getOptArg {
+  if (!$value) {
+    die("option $option requires an argument\n");
+  }
+  return $value;
+}
+
+# for a boolean option:
+#   -foo       -> true
+#   -foo=1     -> true
+#   -foo=0     -> false
+sub getBoolArg {
+  if ($value eq "" || $value eq "1") {
+    return 1;
+  }
+  elsif ($value eq "0") {
+    return 0;
+  }
+  else {
+    die("option $option expects either no argument, or arg 0 or 1\n");
+  }
+}
+
+
+# detect whether we need PERLIO=crlf
+sub getPerlEnvPrefix {
+  # It's important to do this test on a file in the current
+  # directory, since the behavior under cygwin can change
+  # depending on the mount charactersics of the file's location.
+  #
+  # It is also important that the file be opened by the shell
+  # instead of perl; when perl opens the file itself, things
+  # work differently.
+  if (0!=system("perl -e 'print(\"a\\n\")' >tmp.txt")) {
+    die;
+  }
+
+  my $sz1 = getFileSize("tmp.txt");
+  if ($sz1 == 2) {
+    # no LF->CRLF translation done on output, I think we're ok
+    #print("(case 1) ");
+    return "";
+  }
+  if ($sz1 != 3) {
+    die("expected file size of 2 or 3");
+  }
+
+  open(TMP, "<tmp.txt") or die;
+  my $line = <TMP>;
+  close(TMP) or die;
+  unlink("tmp.txt");
+
+  if (length($line) == 2) {
+    # reading did CRLF->LF, so again we're ok
+    #print("(case 2) ");
+    return "";
+  }
+  elsif (length($line) == 3) {
+    # reading was raw, so if we wrote again then we'd have
+    # CRCRLF; this is the condition that "PERLIO=crlf" fixes
+    #print("(case 3) ");
+
+    # make this the default for *this* perl session too;
+    # but it does not work ...
+    #use open OUT => ":crlf";
+
+    return "PERLIO=crlf ";
+  }
+  else {
+    die("expected line length of 2 or 3");
+  }
+}
+
+sub getFileSize {
+  my ($fname) = @_;
+
+  my @details = stat($fname);
+
+  # how do I tell if 'stat' failed?
+
+  return $details[7];
+}
+
+sub get_PERL_variable {
+  print("checking how to run perl... ");
+
+  my $ret = getPerlEnvPrefix() . "perl";
+
+  print($ret . "\n");
+  return $ret;
+}
+
+
+sub run {
+  my $code = system(@_);
+  checkExitCode($code);
+}
+
+sub checkExitCode {
+  my ($code) = @_;
+  if ($code != 0) {
+    # hopefully the command has already printed a message,
+    # I'll just relay the status code
+    if ($code >> 8) {
+      exit($code >> 8);
+    }
+    else {
+      exit($code & 127);
+    }
+  }
+}
+
+sub pretendUsed {
+}
+
+
+sub slurpFile {
+  my ($fname) = @_;
+  open(IN, "<$fname") or die("can't open $fname: $!\n");
+  my @ret = <IN>;
+  close(IN) or die;
+  return @ret;
+}
+
+
+# -------------- does the C++ compiler work? --------------
+sub test_CXX_compiler {
+  my $wd = `pwd`;
+  chomp($wd);
+
+  my $testcout = "testcout" . $main::exe;
+  print("Testing C++ compiler ...\n");
+  my $cmd = "$main::CXX -o $testcout @main::CCFLAGS $main::SMBASE/testcout.cc";
+  if (system($cmd)) {
+    # maybe problem is -Wno-deprecated?
+    printf("Trying without -Wno-deprecated ...\n");
+    @main::CCFLAGS = grep { $_ ne "-Wno-deprecated" } @main::CCFLAGS;
+    $cmd = "$main::CXX -o $testcout @main::CCFLAGS $main::SMBASE/testcout.cc";
+    if (system($cmd)) {
+      print(<<"EOF");
+
+I was unable to compile a really simple C++ program.  I tried:
+  cd $wd
+  $cmd
+
+Please double-check your compiler installation.
+
+Until this is fixed, smbase (and any software that depends on it) will
+certainly not compile either.
+EOF
+      exit(2);
+    }
+  }
+
+  if (!$target) {
+    if (system("./$testcout")) {
+      print(<<"EOF");
+
+I was able to compile testcout.cc, but it did not run.  I tried:
+  cd $wd
+  $cmd
+
+and then
+  ./$testcout      (this one failed)
+
+A frequent cause for this error is a misconfiguration of the language
+runtime libraries.
+
+For example, by default g++ installs libstdc++ into /usr/local/lib,
+but on many systems this directory is not searched by the loader.
+Solutions would include symlinking or copying the files into /usr/lib,
+adding /usr/local/lib to the library search path, or reinstalling g++
+with a different --prefix argument to its configuration script.
+
+Until this is fixed, smbase (and any software that depends on it) will
+certainly not run either.
+EOF
+      exit(2);
+    }
+
+    print("C++ compiler seems to work\n");
+  }
+  else {
+    print("because we are in cross mode, I will not try running '$testcout'\n",
+          "but it might be a good idea to try that yourself\n");
+  }
+
+  # make a variant, CFLAGS, that doesn't include -Wno-deprecated
+  @main::CFLAGS = grep { $_ ne "-Wno-deprecated" } @main::CCFLAGS;
+}
+
+
+# ------------------ config.summary -----------------
+sub getStandardConfigSummary {
+  print("\n");
+
+  my $ret = (<<"EOF");
+#!/bin/sh
+# config.summary
+
+echo "$main::thisPackage configuration summary:"
+echo "  command:     ./configure @main::ARGV"
+echo ""
+echo "Compile flags:"
+echo "  CC:          $main::CC"
+echo "  CXX:         $main::CXX"
+echo "  CCFLAGS:     @main::CCFLAGS"
+EOF
+
+  if ($main::target) {
+    $ret .= "echo \"  CROSSTARGET: $main::target\"\n";
+  }
+  if ($exe) {
+    $ret .= "echo \"  EXE:         $main::exe\"\n";
+  }
+
+  return $ret;
+}
+
+
+sub writeConfigSummary {
+  my ($summary) = @_;
+
+  open (OUT, ">config.summary") or die("cannot write config.summary: $!\n");
+
+  print OUT ($summary);
+  print OUT ("echo \"\"\n");
+
+  close(OUT) or die;
+  chmod 0755, "config.summary";
+}
+
+
+# ------------------- config.status ------------------
+sub writeConfigStatus {
+  my @pairs = @_;
+
+  # create a program which will create the Makefile
+  open(OUT, ">config.status") or die("can't make config.status");
+
+  # preamble
+  print OUT (<<"OUTER_EOF");
+#!/bin/sh
+# config.status
+
+# this file was created by ./configure
+
+if [ "\$1" = "-reconfigure" ]; then
+  # re-issue the ./configure command
+  exec ./configure @main::ARGV
+fi
+
+# report on configuration
+./config.summary
+
+echo "creating Makefile ..."
+
+# overcome my chmod below
+rm -f Makefile
+
+cat >Makefile <<EOF
+# Makefile for smbase
+# NOTE: generated by ./configure, do not edit
+
+EOF
+
+# variable substitution
+sed -e "s|\@CCFLAGS\@|@main::CCFLAGS|g" \\
+    -e "s|\@CFLAGS\@|@main::CFLAGS|g" \\
+    -e "s|\@CC\@|$main::CC|g" \\
+    -e "s|\@CXX\@|$main::CXX|g" \\
+    -e "s|\@CROSSTARGET\@|$main::target|g" \\
+    -e "s|\@EXE\@|$main::exe|g" \\
+    -e "s|\@SMBASE\@|$main::SMBASE|g" \\
+OUTER_EOF
+
+  # package-specific substitution
+  for ($i=0; $i < @pairs; $i += 2) {
+    my $a = $pairs[$i];
+    my $b = $pairs[$i+1];
+    #           -e  "s|@foo@|bar|g" \           (example)
+    print OUT ("-e \"s|\@$a\@|$b|g\" \\\n");
+  }
+
+  # postamble
+  print OUT (<<"EOF");
+  <Makefile.in >>Makefile
+
+# discourage editing ..
+chmod a-w Makefile
+
+
+EOF
+
+  close(OUT) or die;
+  chmod 0755, "config.status";
+}
+
+
+sub test_smbase_presence {
+  if (! -f "$main::SMBASE/nonport.h") {
+    die "I cannot find nonport.h in `$main::SMBASE'.\n" .
+        "The smbase library is required for $thisPackage.\n" .
+        "If it's in a different location, use the -smbase=<dir> option.\n";
+  }
+}
+
+
+1;
+# EOF

Added: vendor/elsa/current/smbase/sm_flexlexer.h
===================================================================
--- vendor/elsa/current/smbase/sm_flexlexer.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/sm_flexlexer.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,28 @@
+// sm_flexlexer.h
+// a layer of indirection to try to work with different
+// installed versions of Flex
+
+
+// Basically, what has happened is the last version of flex created by
+// Vern Paxson et al. is 2.5.4, and a lot of distributions use that.
+// More recently some other people started a project hosted at
+// Sourceforge, and their current (only?) release is flex-2.5.31.
+// Unfortunately, the authors of 2.5.31 do not appear concerned with
+// maintaining compatibility for C++ scanners.
+//
+// See bug "[ 751550 ] c++ derived scanners will not compile",
+// http://sourceforge.net/tracker/index.php?func=detail&aid=751550&group_id=72099&atid=533377
+//
+// So in an attempt to make Elkhound/Elsa work, this file is where
+// I'll put my hacks.
+
+
+// workaround for flex-2.5.31 bug
+#ifdef yyFlexLexer
+  #undef yyFlexLexer
+#endif
+
+// now get the installed FlexLexer.h.. this nominally lives in
+// /usr/include or /usr/local/include, depending on how Flex is
+// installed
+#include <FlexLexer.h>

Added: vendor/elsa/current/smbase/sm_strstream.h
===================================================================
--- vendor/elsa/current/smbase/sm_strstream.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/sm_strstream.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,30 @@
+// sm_strstream.h      see license.txt for copyright and terms of use
+// portable header for c++ strstream
+
+#ifndef SM_STRSTREAM_H
+#define SM_STRSTREAM_H
+
+#if defined(__GNUC__) && (__GNUC__ > 2)
+  // gcc-3 doesn't have istrstream (but it is standard!), so fake it
+#  include <sstream>       // istringstream
+
+#  undef string            // in case the string->mystring definition is active
+#  include <string>        // std::string
+  
+  typedef std::istringstream istrstream;
+  typedef std::ostringstream ostrstream;
+
+  // define fake istrstream-constructor arguments
+#  define wrap_istrstream_args(buf, len) std::string(buf, len)
+  // define wrapper for ostringstream::str
+#  define wrap_ostrstream_str(o) (o).str().c_str();
+#else
+  // should work on any compiler that implements the C++98 standard
+  // (istrstream is deprecated but still standard)
+#  include <strstream.h>   // istrstream
+#  define wrap_istrstream_args(buf, len) buf, len
+#  define wrap_ostrstream_str(o) (o).str();
+#endif
+
+
+#endif // SM_STRSTREAM_H

Added: vendor/elsa/current/smbase/smbase.dsp
===================================================================
--- vendor/elsa/current/smbase/smbase.dsp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/smbase.dsp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,116 @@
+# Microsoft Developer Studio Project File - Name="smbase" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=smbase - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "smbase.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "smbase.mak" CFG="smbase - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "smbase - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "smbase - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "smbase - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "smbase - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "smbase___Win32_Debug"
+# PROP BASE Intermediate_Dir "smbase___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "."
+# PROP Intermediate_Dir "."
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ  /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "__WIN32__" /YX /FD /GZ /TP /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "smbase - Win32 Release"
+# Name "smbase - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\breaker.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\exc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\nonport.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\point.cc
+# End Source File
+# Begin Source File
+
+SOURCE=.\str.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\voidlist.cc
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# End Target
+# End Project

Added: vendor/elsa/current/smbase/smbase.gif
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/smbase/smbase.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/smbase/smregexp.cc
===================================================================
--- vendor/elsa/current/smbase/smregexp.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/smregexp.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,169 @@
+// smregexp.cc
+// code for smregexp.h
+
+#include "smregexp.h"     // this module
+#include "str.h"          // string
+#include "exc.h"          // xbase
+#include "array.h"        // Array
+
+#include <stddef.h>       // size_t
+
+// for now, I implement everything using the libc POSIX regex
+// facilities
+//
+// linux (etc.) has proper declarations in regex.h, but FreeBSD (and
+// other BSDs?) has regex.h contents that do not compile under C++,
+// and apparently gnuregex.h is the substitute that does
+#ifndef __FreeBSD__
+  #include <regex.h>
+#else
+  #include <gnuregex.h>
+#endif
+
+
+// get an error string
+static string regexpErrorString(regex_t const *pat, int code)
+{
+  // find out how long the error string is; this size
+  // includes the final NUL byte
+  int size = regerror(code, pat, NULL, 0);
+
+  // get the string
+  Array<char> buf(size);
+  regerror(code, pat, buf.ptr(), size);
+  buf[size] = 0;     // paranoia
+
+  return string(buf);
+}
+
+// throw an exception
+static void regexpError(regex_t const *pat, int code) NORETURN;
+static void regexpError(regex_t const *pat, int code)
+{
+  xbase(regexpErrorString(pat, code));
+}
+
+
+// -------------------- Regexp --------------------------
+// interpretation of 'impl' field
+#define PAT ((regex_t*&)impl)
+
+Regexp::Regexp(rostring exp, CFlags flags)
+{
+  PAT = new regex_t;
+
+  int f = REG_EXTENDED;    // "extended" language
+  
+  // if the values I chose line up perfectly with the values used by
+  // libc, then I don't have to interpret them (hopefully the
+  // optimizer will discover that the 'if' test is constant
+  // (gcc-2.95.3's optimizer does); I can't do it with the
+  // preprocessor because it can't see the enumerator values)
+  if (REG_ICASE==ICASE && REG_NOSUB==NOSUB) {
+    f |= (int)flags;
+  }
+  else {
+    // interpret my flags
+    if (flags & ICASE) f |= REG_ICASE;
+    if (flags & NOSUB) f |= REG_NOSUB;
+  }
+
+  int code = regcomp(PAT, toCStr(exp), f);
+  if (code) {
+    // deallocate the pattern buffer before throwing the exception
+    string msg = regexpErrorString(PAT, code);
+    delete PAT;
+    xbase(msg);
+  }
+}
+
+Regexp::~Regexp()
+{
+  regfree(PAT);
+  delete PAT;
+}
+
+
+void Regexp::err(int code)
+{
+  regexpError(PAT, code);
+}
+
+
+bool Regexp::match(rostring str, EFlags flags)
+{
+  int f = 0;
+  
+  // same thing as above
+  if (REG_NOTBOL==NOTBOL && REG_NOTEOL==NOTEOL) {
+    f = (int)flags;
+  }
+  else {
+    if (flags & NOTBOL) f |= REG_NOTBOL;
+    if (flags & NOTEOL) f |= REG_NOTEOL;
+  }
+
+  int code = regexec(PAT, toCStr(str), 0, NULL, f);
+  if (code == 0) {
+    return true;
+  }
+  else if (code == REG_NOMATCH) {
+    return false;
+  }
+  else {
+    err(code);
+  }
+}
+
+
+#undef PAT
+
+
+// --------------- convenience functions ---------------
+bool regexpMatch(rostring str, rostring exp)
+{
+  Regexp pat(exp, Regexp::NOSUB);
+  return pat.match(str);
+}
+
+
+// ----------------- test code --------------------
+#ifdef TEST_SMREGEXP
+                         
+#include <stdlib.h>    // exit
+#include <stdio.h>     // printf
+
+
+void matchVector(char const *str, char const *exp, bool expect)
+{
+  bool actual = regexpMatch(str, exp);
+  if (actual != expect) {       
+    printf("regexp failure\n");
+    printf("  str: %s\n", str);
+    printf("  exp: %s\n", exp);
+    printf("  expect: %s\n", (expect? "true" : "false"));
+    printf("  actual: %s\n", (actual? "true" : "false"));
+    exit(2);
+  }
+}
+
+
+int main()
+{
+  matchVector("abc", "a", true);
+  matchVector("abc", "b", true);
+  matchVector("abc", "c", true);
+  matchVector("abc", "d", false);
+
+  matchVector("abc", "^a", true);
+  matchVector("abc", "^b", false);
+  matchVector("abc", "b$", false);
+  matchVector("abc", "c$", true);
+  matchVector("abc", "^d", false);
+
+  printf("regexp works\n");
+  return 0;
+}
+
+
+#endif // TEST_SMREGEXP

Added: vendor/elsa/current/smbase/smregexp.h
===================================================================
--- vendor/elsa/current/smbase/smregexp.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/smregexp.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,81 @@
+// smregexp.h
+// regular expression matching, etc.
+
+// the "sm" prefix in the name is to avoid a name conflict with something
+// in my version of glibc..
+
+// The regular expression language is, for now, the "Extended" regexp
+// language described in the regex(7) man page, itself a description
+// of POSIX 1003.2, section 2.8 (Regular Expression Notation).
+
+// The interface is based on the POSIX regex functions too, but I
+// don't actually include regex.h here since I want to allow a
+// different implementation, if that becomes necessary.
+
+#ifndef REGEXP_H
+#define REGEXP_H
+
+#include "macros.h"      // ENUM_BITWISE_OR, NORETURN
+#include "str.h"         // string
+
+
+// ----------------- Regexp class -------------------
+// This class represents a compiled regexp pattern.  For maximum
+// efficiency, repeated uses of the same pattern should use the
+// same Regexp object each time instead of making a new one.
+class Regexp {
+public:      // types
+  // compilation flags
+  enum CFlags {
+    C_NONE     = 0x00,         // no flags
+    ICASE      = 0x02,         // case insensitive
+    NOSUB      = 0x08,         // substring matches are not needed
+    //NEWLINE                  // still not sure what this really means
+  };
+
+  // execution flags
+  enum EFlags {
+    E_NONE     = 0x00,         // no flags
+    NOTBOL     = 0x01,         // treat 'str' as not including beginning of line
+    NOTEOL     = 0x02,         // ............................ end of line
+  };
+
+private:     // data
+  void *impl;                  // implementation data
+  //int numLParens;              // # of left-parens in the pattern
+
+private:     // funcs
+  // not allowed
+  Regexp(Regexp&);
+  void operator=(Regexp&);
+
+  void err(int code) NORETURN;
+
+public:      // funcs
+  Regexp(rostring exp, CFlags flags = C_NONE);
+  ~Regexp();
+
+  bool match(rostring str, EFlags flags = E_NONE);
+};
+
+// allow '|' to be used on the flags
+ENUM_BITWISE_OR(Regexp::CFlags)
+ENUM_BITWISE_OR(Regexp::EFlags)
+
+
+// TODO: Add support for substring matches by building a class to
+// remember the substring offsets (enable 'numLParens' above)
+// efficiently.  Major question: do I always make an internal copy of
+// the string in which we searched?  Leaning towards yes...
+
+
+
+// --------------- convenience functions ---------------
+// The functions in this section are built on top of the
+// Regexp class in the obvious way.
+
+// return true if 'str' matches 'exp'
+bool regexpMatch(rostring str, rostring exp);
+
+
+#endif // REGEXP_H

Added: vendor/elsa/current/smbase/sobjlist.h
===================================================================
--- vendor/elsa/current/smbase/sobjlist.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/sobjlist.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,315 @@
+// sobjlist.h
+// serf list of arbitrary objects
+// NOTE: automatically generated from xobjlist.h -- do not edit directly
+
+// Author: Scott McPeak, 2000
+
+#ifndef SOBJLIST_H
+#define SOBJLIST_H
+
+#include "voidlist.h"    // VoidList
+
+
+// forward declarations of template classes, so we can befriend them in SObjList
+// (not required by Borland C++ 4.5, but GNU wants it...)
+template <class T> class SObjListIter;
+template <class T> class SObjListMutator;
+template <class T> class SObjListIterNC;
+
+
+// the list is considered to not own any of the items; it's ok to
+// insert items multiple times or into multiple lists
+template <class T>
+class SObjList {
+private:
+  friend class SObjListIter<T>;
+  friend class SObjListMutator<T>;
+  friend class SObjListIterNC<T>;
+
+protected:
+  VoidList list;                        // list itself
+
+public:
+  // make shallow copies
+  SObjList(SObjList const &obj)         : list(obj.list) {}
+  SObjList& operator= (SObjList const &src)         { list = src.list; return *this; }
+
+public:
+  SObjList()                            : list() {}
+  ~SObjList()                           {}    /* all items removed */
+
+  // The difference function should return <0 if left should come before
+  // right, 0 if they are equivalent, and >0 if right should come before
+  // left.  For example, if we are sorting numbers into ascending order,
+  // then 'diff' would simply be subtraction.
+  typedef int (*Diff)(T const *left, T const *right, void *extra);
+
+  // selectors
+  int count() const                     { return list.count(); }
+  bool isEmpty() const                  { return list.isEmpty(); }
+  bool isNotEmpty() const               { return list.isNotEmpty(); }
+  T *&nthRef(int which)                 { return (T*&)list.nthRef(which); }
+  T *nth(int which)                     { return (T*)list.nth(which); }
+  T const *nthC(int which) const        { return (T const*)list.nth(which); }
+  T *first()                            { return (T*)list.first(); }
+  T const *firstC() const               { return (T const*)list.first(); }
+  T *last()                             { return (T*)list.last(); }
+  T const *lastC() const                { return (T const*)list.last(); }
+
+  // insertion
+  void prepend(T *newitem)              { list.prepend((void*)newitem); }
+  void append(T *newitem)               { list.append((void*)newitem); }
+  void insertAt(T *newitem, int index)  { list.insertAt((void*)newitem, index); }
+  void insertSorted(T *newitem, Diff diff, void *extra=NULL)
+    { list.insertSorted((void*)newitem, (VoidDiff)diff, extra); }
+
+  // removal
+  T *removeAt(int index)                { return (T*)list.removeAt(index); }
+  T *removeFirst()                      { return (T*)list.removeFirst(); }
+  void removeAll()                      { list.removeAll(); }
+
+  // list-as-set: selectors
+  int indexOf(T const *item) const      { return list.indexOf((void*)item); }
+  int indexOfF(T const *item) const     { return list.indexOfF((void*)item); }
+  bool contains(T const *item) const    { return list.contains((void*)item); }
+
+  // list-as-set: mutators
+  bool prependUnique(T *newitem)        { return list.prependUnique((void*)newitem); }
+  bool appendUnique(T *newitem)         { return list.appendUnique((void*)newitem); }
+  void removeItem(T const *item)        { list.removeItem((void*)item); }    // whether the arg should be const is debatable..
+  bool removeIfPresent(T const *item)   { return list.removeIfPresent((void*)item); }
+
+  // complex modifiers
+  void reverse()                                    { list.reverse(); }
+  void insertionSort(Diff diff, void *extra=NULL)   { list.insertionSort((VoidDiff)diff, extra); }
+  void mergeSort(Diff diff, void *extra=NULL)       { list.mergeSort((VoidDiff)diff, extra); }
+
+  // and a related test
+  bool isSorted(Diff diff, void *extra=NULL) const  { return list.isSorted((VoidDiff)diff, extra); }
+
+  // multiple lists
+  void concat(SObjList &tail)                       { list.concat(tail.list); }
+  void appendAll(SObjList const &tail)              { list.appendAll(tail.list); }
+  void prependAll(SObjList const &head)             { list.prependAll(head.list); }
+
+  // steal
+  void stealTailAt(int index, SObjList &tail)       { list.stealTailAt(index, tail.list); }
+
+  // equal items in equal positions
+  bool equalAsLists(SObjList const &otherList, Diff diff, void *extra=NULL) const
+    { return list.equalAsLists(otherList.list, (VoidDiff)diff, extra); }
+  int compareAsLists(SObjList const &otherList, Diff diff, void *extra=NULL) const
+    { return list.compareAsLists(otherList.list, (VoidDiff)diff, extra); }
+
+  // last-as-set: comparisons (NOT efficient)
+  bool equalAsSets(SObjList const &otherList, Diff diff, void *extra=NULL) const
+    { return list.equalAsSets(otherList.list, (VoidDiff)diff, extra); }
+  bool isSubsetOf(SObjList const &otherList, Diff diff, void *extra=NULL) const
+    { return list.isSubsetOf(otherList.list, (VoidDiff)diff, extra); }
+  bool containsByDiff(T const *item, Diff diff, void *extra=NULL) const
+    { return list.containsByDiff((void*)item, (VoidDiff)diff, extra); }
+
+  // treating the pointer values themselves as the basis for comparison
+  bool equalAsPointerLists(SObjList const &otherList) const
+    { return list.equalAsPointerLists(otherList.list); }
+  bool equalAsPointerSets(SObjList const &otherList) const
+    { return list.equalAsPointerSets(otherList.list); }
+
+  // removing duplicates
+  void removeDuplicatesAsMultiset(Diff diff, void *extra=NULL)
+    { list.removeDuplicatesAsMultiset((VoidDiff)diff, extra); }
+  void removeDuplicatesAsPointerMultiset()
+    { list.removeDuplicatesAsPointerMultiset(); }
+
+  // debugging: no invariants beyond VoidList
+  void selfCheck() const                { list.selfCheck(); }
+  
+  // but export the additional checks for cases where they apply anyway
+  void checkHeapDataPtrs() const        { list.checkHeapDataPtrs(); }
+  void checkUniqueDataPtrs() const      { list.checkUniqueDataPtrs(); }
+};
+
+
+// for traversing the list and modifying it (nodes and/or structure)
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists, and only one such iterator should exist for
+//       any given list
+template <class T>
+class SObjListMutator {
+  friend class SObjListIter<T>;
+
+protected:
+  VoidListMutator mut;       // underlying mutator
+
+public:
+  SObjListMutator(SObjList<T> &lst)     : mut(lst.list) { reset(); }
+  ~SObjListMutator()                    {}
+
+  void reset()                          { mut.reset(); }
+
+  // iterator copying; safe *only* until one of the mutators modifies
+  // the list structure (by inserting or removing), at which time all
+  // other iterators might be in limbo
+  SObjListMutator(SObjListMutator const &obj)             : mut(obj.mut) {}
+  SObjListMutator& operator=(SObjListMutator const &obj)  { mut = obj.mut;  return *this; }
+    // requires that 'this' and 'obj' already refer to the same 'list'
+
+  // iterator actions
+  bool isDone() const                   { return mut.isDone(); }
+  void adv()                            { mut.adv(); }
+  T *data()                             { return (T*)mut.data(); }
+  T *&dataRef()                         { return (T*&)mut.dataRef(); }
+
+  // insertion
+  void insertBefore(T *item)            { mut.insertBefore((void*)item); }
+    // 'item' becomes the new 'current', and the current 'current' is
+    // pushed forward (so the next adv() will make it current again)
+
+  void insertAfter(T *item)             { mut.insertAfter((void*)item); }
+    // 'item' becomes what we reach with the next adv();
+    // isDone() must be false
+
+  void append(T *item)                  { mut.append((void*)item); }
+    // only valid while isDone() is true, it inserts 'item' at the end of
+    // the list, and advances such that isDone() remains true; equivalent
+    // to { xassert(isDone()); insertBefore(item); adv(); }
+
+  // removal
+  T *remove()                           { return (T*)mut.remove(); }
+    // 'current' is removed from the list and returned, and whatever was
+    // next becomes the new 'current'
+
+  // debugging
+  void selfCheck() const                { mut.selfCheck(); }
+};
+
+#define SMUTATE_EACH_OBJLIST(T, list, iter) \
+  for(SObjListMutator< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// for traversing the list without modifying it (neither nodes nor structure)
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists
+template <class T>
+class SObjListIter {
+protected:
+  VoidListIter iter;      // underlying iterator
+
+public:
+  SObjListIter(SObjList<T> const &list) : iter(list.list) {}
+  SObjListIter(SObjList<T> const &list, int pos) : iter(list.list, pos) {}
+  ~SObjListIter()                       {}
+
+  void reset(SObjList<T> const &list)   { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  SObjListIter(SObjListIter const &obj)             : iter(obj.iter) {}
+  SObjListIter& operator=(SObjListIter const &obj)  { iter = obj.iter;  return *this; }
+
+  // but copying from a mutator is less safe; see above
+  SObjListIter(SObjListMutator<T> &obj)             : iter(obj.mut) {}
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T const *data() const                 { return (T const*)iter.data(); }
+};
+
+#define SFOREACH_OBJLIST(T, list, iter) \
+  for(SObjListIter< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// intermediate to the above two, this allows modification of the
+// objects stored on the list, but not the identity or order of
+// the objects in the list
+template <class T>
+class SObjListIterNC {
+protected:
+  VoidListIter iter;      // underlying iterator
+
+public:
+  SObjListIterNC(SObjList<T> &list) : iter(list.list) {}
+  SObjListIterNC(SObjList<T> &list, int pos) : iter(list.list, pos) {}
+  ~SObjListIterNC()                     {}
+
+  void reset(SObjList<T> &list)         { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  SObjListIterNC(SObjListIterNC const &obj)             : iter(obj.iter) {}
+  SObjListIterNC& operator=(SObjListIterNC const &obj)  { iter = obj.iter;  return *this; }
+
+  // but copying from a mutator is less safe; see above
+  SObjListIterNC(SObjListMutator<T> &obj)               : iter(obj.mut) {}
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T *data() const                       { return (T*)iter.data(); }
+};
+
+#define SFOREACH_OBJLIST_NC(T, list, iter) \
+  for(SObjListIterNC< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// iterate over the combined elements of two or more lists
+template <class T>
+class SObjListMultiIter {
+private:
+  // all the lists
+  SObjList<T> **lists;               // serf array of serf list pointers
+  int numLists;                      // length of this array
+
+  // current element
+  int curList;                       // which list we're working on
+  SObjListIter<T> iter;              // current element of that list
+
+  // invariant:
+  //   either curList==numLists, or
+  //   iter is not 'done'
+
+public:
+  SObjListMultiIter(SObjList<T> **L, int n)
+    : lists(L),
+      numLists(n),
+      curList(0),
+      iter(*(lists[0]))
+  {
+    xassert(n > 0);
+    normalize();
+  }
+
+  // advance the iterator to the next element of the next non-empty list;
+  // establishes invariant above
+  void normalize();
+
+  bool isDone() const {
+    return curList == numLists;
+  }
+
+  T const *data() const {
+    return iter.data();
+  }
+
+  void adv() {
+    iter.adv();
+    normalize();
+  }
+};
+
+// this was originally inline, but that was causing some strange
+// problems (compiler bug?)
+template <class T>
+void SObjListMultiIter<T>::normalize()
+{
+  while (iter.isDone() && curList < numLists) {
+    curList++;
+    if (curList < numLists) {
+      iter.reset(*(lists[curList]));
+    }
+  }
+}
+
+
+// (tweak to ensure objlist.h and sobjlist.h both change)
+
+#endif // SOBJLIST_H

Added: vendor/elsa/current/smbase/sobjset.h
===================================================================
--- vendor/elsa/current/smbase/sobjset.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/sobjset.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,56 @@
+// sobjset.h            see license.txt for copyright and terms of use
+// non-owning set of objects (identified by address),
+// implemented with a hashtable
+
+#ifndef SOBJSET_H
+#define SOBJSET_H
+
+#include "hashtbl.h"    // HashTable
+
+template <class T> class SObjSetIter;
+
+
+// experiment: to try to support const-polymorphism,
+// I expect T to either be Foo* or Foo const *
+
+template <class T>
+class SObjSet : private HashTable {
+  friend class SObjSetIter<T>;
+
+public:
+  SObjSet(int initSize = HashTable::defaultSize)
+    : HashTable(identityKeyFn, lcprngHashFn, pointerEqualKeyFn, initSize) {}
+
+  // # of distinct elements in the set
+  int size() const               { return HashTable::getNumEntries(); }
+
+  // true if 'elt' is in the set
+  bool contains(T elt) const     { return !!HashTable::get((void const*)elt); }
+
+  // add 'elt' to the set; if it is already in, this has no effect
+  void add(T elt)                { if (!contains(elt)) { HashTable::add((void const*)elt, (void*)elt); } }
+
+  // remove 'elt' from the set; if it's not there, this has no effect
+  void remove(T elt)             { if (contains(elt)) { HashTable::remove((void const*)elt); } }
+
+  // remove all elements
+  void empty()                   { HashTable::empty(); }
+
+  // debug check which throws an exception if there's a problem
+  void selfCheck()               { HashTable::selfCheck(); }
+};
+
+
+template <class T>
+class SObjSetIter : private HashTableIter {
+public:
+  SObjSetIter(SObjSet<T> &table)
+    : HashTableIter(table) {}    // I'm a friend, I can see it's a HashTable inside
+
+  bool isDone() const          { return HashTableIter::isDone(); }
+  void adv()                   { return HashTableIter::adv(); }
+  T data() const               { return (T)HashTableIter::data(); }
+};
+
+
+#endif // SOBJSET_H

Added: vendor/elsa/current/smbase/sobjstack.h
===================================================================
--- vendor/elsa/current/smbase/sobjstack.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/sobjstack.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,71 @@
+// sobjstack.h            see license.txt for copyright and terms of use
+// stack of objects, *not* owned by the stack
+
+#ifndef SOBJSTACK_H
+#define SOBJSTACK_H
+
+#include "sobjlist.h"    // SObjList
+
+template <class T>
+class SObjStack {
+public:       // data
+  // will implement the stack as a list, with prepend and removeAt(0)
+  SObjList<T> list;
+
+public:       // funcs
+  SObjStack()                           : list() {}
+  ~SObjStack()                          {}
+
+  int count() const                     { return list.count(); }
+  bool isEmpty() const                  { return list.isEmpty(); }
+  bool isNotEmpty() const               { return list.isNotEmpty(); }
+
+  T const *topC() const                 { return list.firstC(); }
+  T *top()                              { return list.first(); }
+
+  // get nth item (linear time)
+  T *nth(int which)                     { return list.nth(which); }
+  T *&nthRef(int which)                 { return list.nthRef(which); }
+
+  T *pop()                              { return list.removeAt(0); }
+  void push(T *item)                    { list.prepend(item); }
+
+  bool contains(T const *item) const    { return list.contains((void*)item); }
+};
+
+
+// utility class for maintaining a first-class sub-stack of the AST
+// stack isomorphic to the stackframe stack; Note that the fact that
+// nothing happens if 'obj' is NULL is a feature: sometimes you can't
+// map the need to call this class completely onto the control flow,
+// and so some dataflow is involved; since the dtor for this class is
+// used as a kind of finally statement, we can't nest its construction
+// in an 'if' statement!  Instead pass in NULL if you want a no-op
+// effect.
+template<class T>
+class StackMaintainer {
+  SObjStack<T> &s;
+  T *obj;
+
+  StackMaintainer(StackMaintainer&); // forbid copying
+
+public:
+  explicit StackMaintainer(SObjStack<T> &s0, T *obj0)
+    : s(s0)
+    , obj(obj0)
+  {
+    if (obj) {
+      s.push(obj);
+    }
+  }
+
+  ~StackMaintainer() {
+    if (obj) {
+      T *obj0 = s.pop();
+      xassert(obj0 == obj);
+    }
+  }
+};
+
+
+#endif // SOBJSTACK_H

Added: vendor/elsa/current/smbase/srcloc.cc
===================================================================
--- vendor/elsa/current/smbase/srcloc.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/srcloc.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,1264 @@
+// srcloc.cc            see license.txt for copyright and terms of use
+// code for srcloc.h
+
+#include "srcloc.h"     // this module
+#include "autofile.h"   // AutoFILE
+#include "array.h"      // ArrayStack
+#include "syserr.h"     // xsyserror
+#include "trace.h"      // traceProgress
+#include "hashline.h"   // HashLineMap
+
+#include <stdio.h>      // fprintf
+#include <string.h>     // memcpy
+
+
+// this parameter controls the frequency of Markers in
+// the marker index; lower period makes the index
+// faster but use more space
+enum { MARKER_PERIOD = 100 };    // 100 is about a 10% overhead
+
+
+// given an ArrayStack, copy the data into a ptr/len pair
+template <class T>
+void extractArray(T *&array, int &size, ArrayStack<T> const &src)
+{
+  size = src.length();
+  array = new T[size];
+  memcpy(array, src.getArray(), size * sizeof(T));
+}
+
+
+// ------------------------- File -----------------------
+void addLineLength(ArrayStack<unsigned char> &lengths, int len)
+{
+  while (len >= UCHAR_MAX) {
+    // add a long-line marker, which represents UCHAR_MAX chars of input
+    lengths.push(UCHAR_MAX);
+    len -= UCHAR_MAX;
+  }
+
+  // add the short count at the end
+  lengths.push((unsigned char)len);
+}
+
+
+SourceLocManager::File::File(char const *n, SourceLoc aStartLoc)
+  : name(n),
+    startLoc(aStartLoc),     // assigned by SourceLocManager
+    hashLines(NULL),
+
+    // valid marker/col for the first char in the file
+    marker(0, 1, 0),
+    markerCol(1),
+    erroredNumLines(false)
+{
+  // dsw: I want a way to make sure that we never look for a file.
+  xassert(sourceLocManager->mayOpenFiles);
+
+  // open in binary mode since it's too unpredictable whether
+  // the lower level (e.g. cygwin) will do CRLF translation,
+  // and whether that will be done consistently, if text mode
+  // is requested
+  AutoFILE fp(toCStr(name), "rb");
+
+  // the buffering that FILE would do would be wasted, so
+  // make it unbuffered (if this causes a problem on some
+  // system it can be commented-out)
+  setbuf(fp, NULL);
+
+  // These are growable versions of the indexes.  They will be
+  // discarded after the file has been read.  They keep track of their
+  // own 'next index' values.  I chose to use a growable array instead
+  // of making two passes over the file to reduce i/o.
+  ArrayStack<unsigned char> lineLengths;
+  ArrayStack<Marker> index;
+
+  // put a marker at the start for uniformity
+  index.push(Marker(0, 1, 0));
+
+  // how many lines to go before I insert the next marker
+  int indexDelay = MARKER_PERIOD;
+
+  // where I am in the file
+  int charOffset = 0;
+  int lineNum = 1;
+  int lineLen = 0;       // length of current line, so far
+
+  // read the file, computing information about line lengths
+  enum { BUFLEN=8192 };
+  char buf[BUFLEN];
+  for (;;) {
+    // read a buffer of data
+    int len = fread(buf, 1, BUFLEN, fp);
+    if (len < 0) {
+      xsyserror("fread", name);
+    }
+    if (len==0) {
+      break;
+    }
+
+    // the code that follows can be seen as abstracting the data
+    // contained in buf[0] through buf[len-1] and adding that
+    // information to the summary variables above
+    char const *start = buf;      // beginning of unaccounted-for chars
+    char const *p = buf;          // scan pointer
+    char const *end = buf+len;    // end of unaccounted-for chars
+
+    // loop over the lines in 'buf'
+    while (start < end) {
+      // scan to the next newline
+      xassert(start == p);
+      while (p<end && *p!='\n') {
+        p++;
+      }
+      if (p==end) {
+        break;
+      }
+      xassert(*p == '\n');
+
+      // account for [start,p)
+      charOffset += p-start;
+      lineLen += p-start;
+      start = p;
+
+      // account for the newline at '*p'
+      addLineLength(lineLengths, lineLen);
+      charOffset++;
+      lineNum++;
+      lineLen = 0;
+
+      p++;
+      start++;
+
+      if (--indexDelay == 0) {
+        // insert a marker to remember this location
+        index.push(Marker(charOffset, lineNum, lineLengths.length()));
+        indexDelay = MARKER_PERIOD;
+      }
+    }
+
+    // move [start,p) into 'lineLen'
+    charOffset += p-start;
+    lineLen += p-start;
+    start = p;
+    xassert(start == end);
+  }
+
+  // handle the last line; in the usual case, where a newline is
+  // the last character, the final line will have 0 length
+  addLineLength(lineLengths, lineLen);
+
+  // move computed information into 'this'
+  this->numChars = charOffset;
+  this->numLines = lineNum;
+  xassert(numLines >= 1);
+  this->avgCharsPerLine = numChars / numLines;
+
+  extractArray(this->lineLengths, this->lineLengthsSize, lineLengths);
+  extractArray(this->index, this->indexSize, index);
+
+  selfCheck();
+
+  // 'fp' closed by the AutoFILE
+}
+
+SourceLocManager::File::~File()
+{
+  if (hashLines) {
+    delete hashLines;
+  }
+  delete[] lineLengths;
+  delete[] index;
+}
+
+SourceLocManager::File::File(FileData *fileData, SourceLoc aStartLoc)
+  : name(fileData->name),
+    startLoc(aStartLoc),        // assigned by SourceLocManager
+//      hashLines(fileData->hashLines),
+    hashLines(NULL),            // dsw: initialized later
+
+    // valid marker/col for the first char in the file
+    marker(0, 1, 0),
+    markerCol(1),
+    erroredNumLines(false)
+{
+  xassert(fileData->complete());
+
+  numChars = fileData->numChars;
+  numLines = fileData->numLines;
+  xassert(numLines >= 1);
+  avgCharsPerLine = numChars / numLines;
+
+  extractArray(lineLengths, lineLengthsSize, *(fileData->lineLengths));
+
+  // make a Marker every MARKER_PERIOD lines
+  ArrayStack<Marker> index;
+  index.push(Marker(0, 1, 0));
+  int indexDelay = MARKER_PERIOD;
+  int numChars0 = 0;
+  int numLines0 = 1;
+  for(int i=0; i<lineLengthsSize; ++i) {
+    int len0 = lineLengths[i];
+    numChars0 += len0;
+    if (len0 != UCHAR_MAX) {
+      // a new line
+      ++numLines0;
+      // Scott counts newlines as out-of-band, not counted in the line
+      // lenth, so add it back in.
+      ++numChars0;
+      if (--indexDelay == 0 && i+1 < lineLengthsSize) {
+        // insert a marker to remember this location
+        index.push(Marker(numChars0, numLines0, i+1));
+        indexDelay = MARKER_PERIOD;
+      }
+    }
+  }
+  // dsw: These assertions demonstrate that something is wrong with
+  // Scott's other File ctor that counts the characters by reading in
+  // the file.  If you use a file that had no newlines in it and read
+  // it in and print it out again, the numChars serialized in the XML
+  // will be twice the length of the file.
+  //
+  // last newline doesn't count or something??
+//    --numChars0;
+//    --numLines0;
+//    xassert(numChars0 == numChars);
+//    xassert(numLines0 == numLines);
+
+  extractArray(this->index, this->indexSize, index);
+
+  selfCheck();
+}
+
+
+int SourceLocManager::File::lineLengthSum() const
+{
+  int sum = 0;
+  for (int i=0; i<lineLengthsSize; i++) {
+    sum += lineLengths[i];
+  }
+  return sum;
+}
+
+void SourceLocManager::File::selfCheck() const
+{
+  xassert(lineLengthSum() + numLines-1 == numChars);
+
+  // check the markers
+  int charOffset = 0;   // current character offset
+  int lineNum = 1;      // current line number
+  int m = 1;            // current marker to validate
+  bool foundMovableMarker = false;
+  for (int i=0; i<lineLengthsSize; i++) {
+    if (m < indexSize) {
+      if (index[m].charOffset <= charOffset) {
+        // if we just reached or exceeded the offset of marker
+        // 'm', check its stats
+        xassert(index[m].charOffset == charOffset &&
+                index[m].lineOffset == lineNum &&
+                index[m].arrayOffset == i);
+
+        // ready to check next marker
+        m++;
+      }
+    }
+
+    // I'm only about 90% sure this is the right invariant...
+    if (marker.charOffset-(markerCol-1) == charOffset) {
+      foundMovableMarker = true;
+      xassert(marker.lineOffset == lineNum &&
+              marker.arrayOffset == i);
+    }
+
+    charOffset += lineLengths[i];
+    if (lineLengths[i] < UCHAR_MAX) {
+      // account for the newline character
+      charOffset++;
+      lineNum++;
+    }
+  }
+  xassert(foundMovableMarker);
+  xassert(m == indexSize);
+
+  // marker offsets should be in increasing order
+  for (m=0; m<(indexSize-1); m++) {
+    xassert(index[m].charOffset < index[m+1].charOffset);
+  }
+}
+
+
+void SourceLocManager::File::resetMarker()
+{
+  marker.charOffset = 0;
+  marker.lineOffset = 1;
+  marker.arrayOffset = 0;
+  markerCol = 1;
+}
+
+
+// it's conceivable gcc is smart enough to recognize
+// the induction variable, if I inline this..
+inline void SourceLocManager::File::advanceMarker()
+{
+  int len = (int)lineLengths[marker.arrayOffset];
+  if (len < UCHAR_MAX) {
+    // normal length line
+    marker.charOffset += len+1;     // +1 for newline
+    marker.lineOffset++;
+    marker.arrayOffset++;
+    markerCol = 1;
+  }
+  else {
+    // fragment of a long line, representing UCHAR_MAX characters
+    marker.charOffset += UCHAR_MAX;
+    marker.arrayOffset++;
+    markerCol += UCHAR_MAX;
+  }
+}
+
+
+int SourceLocManager::File::lineToChar(int lineNum)
+{
+  xassert(1 <= lineNum);
+  // xassert(lineNum <= numLines);
+
+  // If we encounter an invalid line number, don't abort fatally, just say
+  // line numbers will be wrong.  This happens often when a cpp'ed file is
+  // modified.
+  if (erroredNumLines) {
+    return 0;
+  }
+
+  if (lineNum > numLines) {
+    fprintf(stderr,
+            "Error: invalid line number %s:%d (only %d lines exist).\n"
+            "       Line numbers will be incorrect.\n",
+            name.c_str(), lineNum, numLines);
+    if (tolerateHashlineErrors) {
+      erroredNumLines = true;
+      return 0;
+    } else {
+      throw xBase("Invalid hashline numbers found (use '-tr tolerateHashlineErrors' to ignore).");
+    }
+  }
+
+  // check to see if the marker is already close
+  if (marker.lineOffset <= lineNum &&
+                           lineNum < marker.lineOffset + MARKER_PERIOD) {
+    // use the marker as-is
+  }
+  else {
+    // do a binary search on the index to find the marker whose
+    // lineOffset is closest to 'lineNum' without going over
+    int low = 0;              // lowest index under consideration
+    int high = indexSize-1;   // highest index under consideration
+    while (low < high) {
+      // check the midpoint (round up to ensure progress when low+1 == high)
+      int mid = (low+high+1)/2;
+      if (index[mid].lineOffset > lineNum) {
+        // too high
+        high = mid-1;
+      }
+      else {
+        // too low or just right
+        low = mid;
+      }
+    }
+
+    // copy this index marker into our primary marker
+    marker = index[low];
+    markerCol = 1;            // all index markers implicitly have column 1
+  }
+
+  xassert(marker.lineOffset <= lineNum);
+
+  // move the marker down the array until it arrives at
+  // the desired line
+  while (marker.lineOffset < lineNum) {
+    advanceMarker();
+  }
+
+  // make sure we never go beyond the end of the array
+  xassert(marker.arrayOffset < lineLengthsSize);
+
+  // if we didn't move the marker, we might not be in column 1
+  return marker.charOffset - (markerCol-1);
+}
+
+
+int SourceLocManager::File::lineColToChar(int lineNum, int col)
+{
+  // use the above function first
+  int offset = lineToChar(lineNum);
+
+  // now, we use an property established by the previous function:
+  // the marker points at the line of interest, possibly offset from
+  // the line start by 'markerCol-1' places
+  if (col <= markerCol) {
+    // the column we want is not even beyond the marker's column,
+    // so it's surely not beyond the end of the line, so do the
+    // obvious thing
+    return offset + (col-1);
+  }
+
+  // we're at least as far as the marker; move the offset up to
+  // this far, and subtract from 'col' so it now represents the
+  // number of chars yet to traverse on this line
+  offset = marker.charOffset;
+  col -= markerCol;       // 'col' is now 0-based
+
+  // march to the end of the line, looking for either the end or a
+  // line length component which goes beyond 'col'; I don't move the
+  // marker itself out of concern for preserving the locality of
+  // future accesses
+  int index = marker.arrayOffset;
+  for (;;) {
+    int len = (int)lineLengths[index];
+    if (col <= len) {
+      // 'col' doesn't go beyond this component, we're done
+      // (even if len==UCHAR_MAX it still works)
+      return offset + col;
+    }
+    if (len < UCHAR_MAX) {
+      // the line ends here, truncate and we're done
+      SourceLocManager::shortLineCount++;
+      return offset + len;
+    }
+
+    // the line continues
+    xassertdb(len == UCHAR_MAX);
+
+    col -= UCHAR_MAX;
+    offset += UCHAR_MAX;
+    xassertdb(col > 0);
+
+    index++;
+    xassert(index < lineLengthsSize);
+  }
+}
+
+
+void SourceLocManager::File::charToLineCol(int offset, int &line, int &col)
+{
+  xassert(0 <= offset && offset <= numChars);
+
+  // check if the marker is close enough
+  if (marker.charOffset <= offset &&
+                           offset < marker.charOffset + MARKER_PERIOD*avgCharsPerLine) {
+    // use as-is
+  }
+  else {
+    // binary search, like above
+    int low = 0;
+    int high = indexSize-1;
+    while (low < high) {
+      // check midpoint
+      int mid = (low+high+1)/2;
+      if (index[mid].charOffset > offset) {
+        high = mid-1;
+      }
+      else {
+        low = mid;
+      }
+    }
+
+    // copy this marker
+    marker = index[low];
+    markerCol = 1;
+  }
+
+  xassert(marker.charOffset <= offset);
+
+  // move the marker until it's within one spot of moving
+  // beyond the offset
+  while (marker.charOffset + lineLengths[marker.arrayOffset] < offset) {
+    advanceMarker();
+  }
+
+  // make sure we never go beyond the end of the array
+  xassert(marker.arrayOffset < lineLengthsSize);
+
+  // read off line/col
+  line = marker.lineOffset;
+  col = markerCol + (offset - marker.charOffset);
+}
+
+
+void SourceLocManager::File::addHashLine
+  (int ppLine, int origLine, char const *origFname)
+{
+  if (!hashLines) {
+    hashLines = new HashLineMap(name);
+  }
+  hashLines->addHashLine(ppLine, origLine, origFname);
+}
+
+void SourceLocManager::File::doneAdding()
+{
+  if (hashLines) {
+    hashLines->doneAdding();
+  }
+  else {
+    // nothing to consolidate, the NULL pointer is valid and
+    // will cause the map to be ignored, so do nothing
+  }
+}
+
+
+// ----------------------- StaticLoc -------------------
+SourceLocManager::StaticLoc::~StaticLoc()
+{}
+
+
+// ----------------------- SourceLocManager -------------------
+int SourceLocManager::shortLineCount = 0;
+bool SourceLocManager::tolerateHashlineErrors = false;
+
+SourceLocManager *sourceLocManager = NULL;
+
+
+SourceLocManager::SourceLocManager()
+  : files(),
+    recent(NULL),
+    statics(),
+    nextLoc(toLoc(1)),
+    nextStaticLoc(toLoc(0)),
+    mayOpenFiles(true),
+    maxStaticLocs(100),
+    useHashLines(true),
+    useOriginalOffset(true)
+{
+  if (!sourceLocManager) {
+    sourceLocManager = this;
+  }
+
+  makeFirstStatics();
+}
+
+SourceLocManager::~SourceLocManager()
+{
+  if (sourceLocManager == this) {
+    sourceLocManager = NULL;
+  }
+}
+
+
+void SourceLocManager::reset()
+{
+  files.deleteAll();
+  recent = NULL;
+  statics.deleteAll();
+  nextLoc = toLoc(1);
+  nextStaticLoc = toLoc(0);
+  makeFirstStatics();
+}
+
+void SourceLocManager::makeFirstStatics()
+{
+  // slightly clever: treat SL_UNKNOWN as a static
+  SourceLoc u = encodeStatic(StaticLoc("<noloc>", 0,1,1));
+  xassert(u == SL_UNKNOWN);
+  PRETEND_USED(u);     // silence warning in case xasserts are turned off
+
+  // similarly for SL_INIT
+  u = encodeStatic(StaticLoc("<init>", 0,1,1));
+  xassert(u == SL_INIT);
+  PRETEND_USED(u);
+}
+
+
+// find it, or return NULL
+SourceLocManager::File *SourceLocManager::findFile(char const *name)
+{
+  if (!this) {
+    // it's quite common to forget to do this, and this function is
+    // almost always the one which segfaults in that case, so I'll
+    // make the error message a bit nicer to save a trip through
+    // the debugger
+    xfailure("you have to create a SourceLocManager in your main() function");
+  }
+
+  if (recent && recent->name.equals(name)) {
+    return recent;
+  }
+
+  FOREACH_OBJARRAYSTACK_NC(File, files, iter) {
+    if (iter.data()->name.equals(name)) {
+      return recent = iter.data();
+    }
+  }
+
+  return NULL;
+}
+
+// find it or make it
+SourceLocManager::File *SourceLocManager::getFile(char const *name)
+{
+  File *f = findFile(name);
+  if (!f) {
+    // read the file
+    f = new File(name, nextLoc);
+    files.append(f);
+
+    // bump 'nextLoc' according to how long that file was,
+    // plus 1 so it can own the position equal to its length
+    nextLoc = toLoc(f->startLoc + f->numChars + 1);
+  }
+
+  return recent = f;
+}
+
+
+// load a file from a FileData object
+void SourceLocManager::loadFile(FileData *fileData)
+{
+  xassert(fileData);
+  // we should be loading a new file; dsw: I think this should remain
+  // an assertion failure instead of being a user error because the
+  // client code can check this before calling into the
+  // SourceLocManager and provide a better error message there
+  xassert(!findFile(fileData->name.c_str()));
+
+  // finish off the fileData->hashLines object; FIX: there is probably
+  // a better place for this, but I'm not sure where
+//    if (fileData->hashLines) {
+//      FOREACH_ARRAYSTACK_NC(HashLineMap::HashLine, fileData->hashLines->directives, iter) {
+//        HashLineMap::HashLine *line = iter.data();
+//        char const * const origFname = line->origFname;
+//        StringObjDict<string> &filenames = fileData->hashLines->serializationOnly_get_filenames();
+//        // load the 'filenames' dictionary with the origFnames of the FileDatas.
+//        string *canon = filenames.queryif(origFname);
+//        if (!canon) {
+//          canon = new string(origFname);
+//          filenames.add(origFname, canon);
+//        }
+//        line->origFname = canon->c_str();
+//      }
+//    }
+
+  // convert the FileData object to a File
+  File *f = new File(fileData, nextLoc);
+  files.append(f);
+  if (fileData->hashLines) {
+    FOREACH_ARRAYSTACK_NC(HashLineMap::HashLine, fileData->hashLines->directives, iter) {
+      HashLineMap::HashLine *line = iter.data();
+      f->addHashLine(line->ppLine, line->origLine, line->origFname);
+    }
+    f->doneAdding();
+  }
+
+  // bump 'nextLoc' according to how long that file was,
+  // plus 1 so it can own the position equal to its length
+  nextLoc = toLoc(f->startLoc + f->numChars + 1);
+}
+
+
+SourceLoc SourceLocManager::encodeOffset(
+  char const *filename, int charOffset)
+{
+  xassert(charOffset >= 0);
+
+  File *f = getFile(filename);
+  xassert(charOffset <= f->numChars);
+  return toLoc(f->startLoc + charOffset);
+}
+
+
+SourceLoc SourceLocManager::encodeLineCol(
+  char const *filename, int line, int col)
+{
+  xassert(line >= 1);
+  xassert(col >= 1);
+
+  File *f = getFile(filename);
+
+  // map from a line number to a char offset
+  int charOffset = f->lineColToChar(line, col);
+  return toLoc(toInt(f->startLoc) + charOffset);
+}
+
+
+SourceLoc SourceLocManager::encodeStatic(StaticLoc const &obj)
+{
+  if (-toInt(nextStaticLoc) == maxStaticLocs) {
+    // Each distinct static location should correspond to a single
+    // place in the source code.  If one place in the source is creating
+    // a given static location over and over, that's bad because it
+    // quickly leads to poor performance when storing and decoding them.
+    // Instead, make one and re-use it.
+    //
+    // If this message is being printed because the program is just
+    // really big and has lots of distinct static locations, then you
+    // can increase maxStaticLocs manually.
+    fprintf(stderr,
+      "Warning: You've created %d static locations, which is symptomatic\n"
+      "of a bug.  See %s, line %d.\n",
+      maxStaticLocs, __FILE__, __LINE__);
+  }
+
+  // save this location
+  statics.append(new StaticLoc(obj));
+
+  // return current index, yield next
+  SourceLoc ret = nextStaticLoc;
+  nextStaticLoc = toLoc(toInt(ret) - 1);
+  return ret;
+}
+
+
+SourceLocManager::File *SourceLocManager::findFileWithLoc(SourceLoc loc)
+{
+  static int count1 = 0;
+  ++count1;
+
+  // check cache
+//    if (recent && recent->hasLoc(loc)) {
+//      return recent;
+//    }
+
+  // quarl 2006-05-21
+  //    Used to use a linear search through a linked list; now we do a O(log
+  //    N) binary search through an array.
+
+  // // iterative walk
+  // FOREACH_OBJARRAYSTACK_NC(File, files, iter) {
+  //   if (iter.data()->hasLoc(loc)) {
+  //     return recent = iter.data();
+  //   }
+  // }
+
+  // binary search
+  int left  = 0;                  // inclusive lower bound
+  int right = files.length() - 1; // inclusive upper bound
+
+  while (left <= right) {
+    int mid = int((right-left)/2) + left;
+    File *file = files[mid];
+    int cmp = file->cmpLoc(loc);
+
+    if (cmp == 0) {
+      // xassert(file->hasLoc(loc));
+      return file;
+    } else if (cmp > 0) {
+      right = mid - 1;
+    } else if (cmp < 0) {
+      left = mid + 1;
+    }
+  }
+
+  // the user gave me a value that I never made!
+  xfailure("invalid source location");
+  return NULL;    // silence warning
+}
+
+
+SourceLocManager::StaticLoc const *SourceLocManager::getStatic(SourceLoc loc)
+{
+  int index = -toInt(loc);
+  return statics.nthC(index);
+}
+
+
+void SourceLocManager::decodeOffset(
+  SourceLoc loc, char const *&filename, int &charOffset)
+{
+  decodeOffset_explicitHL(loc, filename, charOffset, this->useHashLines);
+}
+
+void SourceLocManager::decodeOffset_explicitHL(
+  SourceLoc loc, char const *&filename, int &charOffset,
+  bool localUseHashLines)
+{
+  // check for static
+  if (isStatic(loc)) {
+    StaticLoc const *s = getStatic(loc);
+    filename = s->name.c_str();
+    charOffset = s->offset;
+    return;
+  }
+
+  File *f = findFileWithLoc(loc);
+  filename = f->name.c_str();
+  charOffset = toInt(loc) - toInt(f->startLoc);
+
+  if (localUseHashLines && f->hashLines) {
+    // we can't pass charOffsets directly through the #line map, so we
+    // must first map to line/col and then back to charOffset after
+    // going through the map
+
+    // map to a pp line/col
+    int ppLine, ppCol;
+    f->charToLineCol(charOffset, ppLine, ppCol);
+
+    // map to original line/file
+    int origLine;
+    char const *origFname;
+    f->hashLines->map(ppLine, origLine, origFname);
+
+    // dsw: we want to avoid looking for the original file if we just
+    // need *some* offset, not *the* original offset; thanks to Matt
+    // Harren for pointing out this subtle trick
+    if (this->useOriginalOffset) {
+      // get a File for the original file; this opens that file
+      // and scans it for line boundaries
+      File *orig = getFile(origFname);
+
+      // use that map to get an offset, truncating columns that are
+      // beyond the true line ending (happens due to macro expansion)
+      charOffset = orig->lineColToChar(origLine, ppCol);
+    }
+
+    // filename is whatever #line said
+    filename = origFname;
+  }
+}
+
+
+void SourceLocManager::decodeLineCol(
+  SourceLoc loc, char const *&filename, int &line, int &col)
+{
+  decodeLineCol_explicitHL(loc, filename, line, col, this->useHashLines);
+}
+
+void SourceLocManager::decodeLineCol_explicitHL(
+  SourceLoc loc, char const *&filename, int &line, int &col,
+  bool localUseHashLines)
+{
+  if (!this) {
+    // didn't initialize a loc manager.. but maybe we can survive?
+    if (loc == SL_UNKNOWN) {
+      filename = "<noloc>";
+      line = 1;
+      col = 1;
+      return;
+    }
+    else {
+      xfailure("you have to create a SourceLocManager in your main() function");
+    }
+  }
+
+  // check for static
+  if (isStatic(loc)) {
+    StaticLoc const *s = getStatic(loc);
+    filename = s->name.c_str();
+    line = s->line;
+    col = s->col;
+    return;
+  }
+
+  File *f = findFileWithLoc(loc);
+  filename = f->name.c_str();
+  int charOffset = toInt(loc) - toInt(f->startLoc);
+
+  f->charToLineCol(charOffset, line, col);
+
+  if (localUseHashLines && f->hashLines) {
+    // use the #line map to determine a new file/line pair; simply
+    // assume that the column information is still correct, though of
+    // course in C, due to macro expansion, it isn't always
+    f->hashLines->map(line, line, filename);
+  }
+}
+
+
+char const *SourceLocManager::getFile(SourceLoc loc, bool localUseHashLines)
+{
+  char const *name;
+  int ofs;
+  decodeOffset_explicitHL(loc, name, ofs, localUseHashLines);
+  return name;
+}
+
+
+int SourceLocManager::getOffset(SourceLoc loc)
+{
+  char const *name;
+  int ofs;
+  decodeOffset(loc, name, ofs);
+  return ofs;
+}
+
+int SourceLocManager::getOffset_nohashline(SourceLoc loc)
+{
+  char const *name;
+  int ofs;
+  decodeOffset_explicitHL(loc, name, ofs, false);
+  return ofs;
+}
+
+int SourceLocManager::getLine(SourceLoc loc)
+{
+  char const *name;
+  int line, col;
+  decodeLineCol(loc, name, line, col);
+  return line;
+}
+
+
+int SourceLocManager::getCol(SourceLoc loc)
+{
+  char const *name;
+  int line, col;
+  decodeLineCol(loc, name, line, col);
+  return col;
+}
+
+
+string SourceLocManager::getString(SourceLoc loc)
+{
+  return getString_explicitHL(loc, this->useHashLines);
+}
+
+string SourceLocManager::getString_explicitHL(SourceLoc loc, bool localUseHashLines)
+{
+  char const *name;
+  int line, col;
+  decodeLineCol_explicitHL(loc, name, line, col, localUseHashLines);
+
+  return stringc << name << ":" << line << ":" << col;
+}
+
+string SourceLocManager::getLCString(SourceLoc loc)
+{
+  char const *name;
+  int line, col;
+  decodeLineCol(loc, name, line, col);
+
+  return stringc << line << ":" << col;
+}
+
+
+string locToStr(SourceLoc sl)
+{
+  return sourceLocManager->getString(sl);
+}
+
+
+// -------------------------- test code ----------------------
+#ifdef TEST_SRCLOC
+
+#include "test.h"        // USUAL_MAIN
+#include "strtokp.h"     // StrtokParse
+
+#include <stdlib.h>      // rand, exit, system
+
+SourceLocManager mgr;
+int longestLen=0;
+
+// given a location, decode it into line/col and then re-encode,
+// and check that the new encoding matches the old
+void testRoundTrip(SourceLoc loc)
+{
+  char const *fname;
+  int line, col;
+  mgr.decodeLineCol(loc, fname, line, col);
+
+  if (col > longestLen) {
+    longestLen = col;
+  }
+
+  SourceLoc loc2 = mgr.encodeLineCol(fname, line, col);
+
+  xassert(loc == loc2);
+}
+
+
+// location in SourceLoc and line/col
+class BiLoc {
+public:
+  int line, col;
+  SourceLoc loc;
+};
+
+
+// given a file, compute SourceLocs throughout it and verify
+// that round-trip encoding works
+void testFile(char const *fname)
+{
+  // dsw: I want a way to make sure that we never look for a file.
+  xassert(sourceLocManager->mayOpenFiles);
+
+  // find the file's length
+  int len;
+  {
+    AutoFILE fp(fname, "rb");
+
+    fseek(fp, 0, SEEK_END);
+    len = (int)ftell(fp);
+    cout << "length of " << fname << ": " << len << endl;
+  }
+
+  // get locations for the start and end
+  SourceLoc start = mgr.encodeOffset(fname, 0);
+  SourceLoc end = mgr.encodeOffset(fname, len);
+
+  // check expectations for start
+  xassert(mgr.getLine(start) == 1);
+  xassert(mgr.getCol(start) == 1);
+
+  // test them
+  testRoundTrip(start);
+  testRoundTrip(end);
+
+  // temporary
+  //testRoundTrip((SourceLoc)11649);
+
+  BiLoc *bi = new BiLoc[len+1];
+  char const *dummy;
+
+  // test all positions, forward sequential; also build the
+  // map for the random test; note that 'len' is considered
+  // a valid source location even though it corresponds to
+  // the char just beyond the end
+  int i;
+  for (i=0; i<=len; i++) {
+    SourceLoc loc = mgr.encodeOffset(fname, i);
+    testRoundTrip(loc);
+
+    bi[i].loc = loc;
+    mgr.decodeLineCol(loc, dummy, bi[i].line, bi[i].col);
+  }
+
+  // backward sequential
+  for (i=len; i>0; i--) {
+    SourceLoc loc = mgr.encodeOffset(fname, i);
+    testRoundTrip(loc);
+  }
+
+  // random access, both mapping directions
+  for (i=0; i<=len; i++) {
+    int j = rand()%(len+1);
+    int dir = rand()%2;
+
+    if (dir==0) {
+      // test loc -> line/col map
+      int line, col;
+      mgr.decodeLineCol(bi[j].loc, dummy, line, col);
+      xassert(line == bi[j].line);
+      xassert(col == bi[j].col);
+    }
+    else {
+      // test line/col -> loc map
+      SourceLoc loc = mgr.encodeLineCol(fname, bi[j].line, bi[j].col);
+      xassert(loc == bi[j].loc);
+    }
+  }
+
+  delete[] bi;
+}
+
+
+// write a file with the given contents, and call 'testFile' on it
+void testFileString(char const *contents)
+{
+  {
+    AutoFILE fp("srcloc.tmp", "w");
+    int written = fwrite(contents, 1, strlen(contents), fp);
+    xassert(written == (int)strlen(contents));
+  }
+
+  testFile("srcloc.tmp");
+
+  // since I keep using "srcloc.tmp" over and over, I need to reset
+  // the manager between attempts since otherwise it thinks it already
+  // knows the line lengths
+  mgr.reset();
+}
+
+
+// decode with given expectation, complain if it doesn't match
+void expect(SourceLoc loc, char const *expFname, int expLine, int expCol)
+{
+  char const *fname;
+  int line, col;
+  mgr.decodeLineCol(loc, fname, line, col);
+
+  if (0!=strcmp(fname, expFname) ||
+      line != expLine ||
+      col != expCol) {
+    printf("expected %s:%d:%d, but got %s:%d:%d\n",
+           expFname, expLine, expCol,
+           fname, line, col);
+    exit(2);
+  }
+}
+
+
+// should this be exported?
+string locString(char const *fname, int line, int col)
+{
+  return stringc << fname << ":" << line << ":" << col;
+}
+
+
+void buildHashMap(SourceLocManager::File *pp, char const *fname, int &expanderLine)
+{
+  expanderLine = 0;
+
+  // dsw: I want a way to make sure that we never look for a file.
+  xassert(sourceLocManager->mayOpenFiles);
+
+  AutoFILE fp(fname, "rb");
+
+  enum { SZ=256 };
+  char buf[SZ];
+  int ppLine=0;
+  while (fgets(buf, SZ, fp)) {
+    if (buf[strlen(buf)-1] == '\n') {
+      ppLine++;
+    }
+
+    if (0==memcmp(buf, "int blah_de_blah", 16)) {
+      expanderLine = ppLine;
+    }
+
+    if (buf[0]!='#') continue;
+
+    // break into tokens at whitespace (this isn't exactly
+    // right, because the file names can have quoted spaces,
+    // but it will do for testing purposes)
+    StrtokParse tok(buf, " \r\n");
+    if (tok < 3) continue;
+
+    int origLine = atoi(tok[1]);
+    char const *tok2 = tok[2];
+    string origFname = substring(tok2+1, strlen(tok2)-2);  // remove quotes
+    pp->addHashLine(ppLine, origLine, origFname.c_str());
+  }
+  pp->doneAdding();
+}
+
+
+void testHashMap()
+{
+  // run the preprocessor
+  if (0!=system("cpp -DTEST_SRCLOC srcloc.test.cc >srcloc.tmp 2>/dev/null")) {
+    xbase("failed to preprocess srcloc.test.cc; the command that failed was:\n"
+          "  cpp -DTEST_SRCLOC srcloc.test.cc >srcloc.tmp");
+  }
+
+  SourceLocManager::File *pp = mgr.getInternalFile("srcloc.tmp");
+  SourceLocManager::File *orig = mgr.getInternalFile("srcloc.test.cc");
+
+  // read srcloc.tmp and install the hash maps
+  int expanderLine=0;
+  buildHashMap(pp, "srcloc.tmp", expanderLine);
+
+  // the 2nd line in the pp source should correspond to the
+  // first line in the orig src
+  // update: this doesn't work with all preprocessors, and I'm
+  // confident in the implementation now, so I'll turn this off
+  //SourceLoc lineTwo = mgr.encodeLineCol("srcloc.tmp", 2, 1);
+  //expect(lineTwo, "srcloc.cc", 1,1);
+
+  // print decodes of first several lines (including those that
+  // are technically undefined because they occur on #line lines)
+  int ppLine;
+  for (ppLine = 1; ppLine < 10; ppLine++) {
+    SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", ppLine, 1);
+    cout << "ppLine " << ppLine << ": " << toString(loc) << endl;
+  }
+
+  // similar for last few lines
+  for (ppLine = pp->numLines - 4; ppLine <= pp->numLines; ppLine++) {
+    SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", ppLine, 1);
+    cout << "ppLine " << ppLine << ": " << toString(loc) << endl;
+  }
+
+  // see how the expander line behaves
+  if (!expanderLine) {
+    cout << "didn't find expander line!\n";
+    exit(2);
+  }
+  else {
+    SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", expanderLine, 1);
+    cout << "expander column 1: " << toString(loc) << endl;
+
+    // in the pp file, I can advance the expander horizontally a long ways;
+    // this should truncate to column 9
+    loc = advCol(loc, 20);
+
+    char const *fname;
+    int offset;
+    mgr.decodeOffset(loc, fname, offset);
+    cout << "expander column 21: " << fname << ", offset " << offset << endl;
+    xassert(0==strcmp(fname, "srcloc.test.cc"));
+
+    // map that to line/col, which should show the truncation
+    int line, col;
+    orig->charToLineCol(offset, line, col);
+    cout << "expander column 21: " << locString(fname, line, col) << endl;
+    if (col != 9 && col != 10) {
+      // 9 is for LF line endings, 10 for CRLF
+      cout << "expected column 9 or 10!\n";
+      exit(2);
+    }
+  }
+}
+
+
+void testHashMap2()
+{
+  SourceLocManager::File *pp = mgr.getInternalFile("srcloc.test2.cc");
+
+  int expanderLine=0;
+  buildHashMap(pp, "srcloc.test2.cc", expanderLine);
+
+  for (int ppLine = 1; ppLine <= pp->numLines; ppLine++) {
+    SourceLoc loc = mgr.encodeLineCol("srcloc.test2.cc", ppLine, 1);
+    cout << "ppLine " << ppLine << ": " << toString(loc) << endl;
+  }
+}
+
+
+void entry(int argc, char ** /*argv*/)
+{
+  xBase::logExceptions = false;
+  traceAddSys("progress");
+  traceProgress() << "begin" << endl;
+
+  if (argc >= 2) {
+    // set maxStaticLocs low to test the warning
+    mgr.maxStaticLocs = 1;
+  }
+
+  // test with some special files
+  testFileString("first\nsecond\nthird\n");      // ordinary
+  testFileString("first\nsecond\nthird no nl");  // no final newline
+  testFileString("");                            // empty
+  testFileString("x");                           // one char
+  testFileString("\n");                          // one newline
+
+  // test my source code
+  testFile("srcloc.cc");
+  testFile("srcloc.h");
+
+  // do it again, so at least one won't be the just-added file;
+  // in fact do it many times so I can see results in a profiler
+  for (int i=0; i<1; i++) {
+    testFile("srcloc.cc");
+    testFile("srcloc.h");
+  }
+
+  traceProgress() << "end" << endl;
+
+  // protect against degeneracy by printing the length of
+  // the longest line
+  cout << "\n";
+  cout << "long line len: " << longestLen << endl;
+
+  // test the statics
+  cout << "invalid: " << toString(SL_UNKNOWN) << endl;
+  cout << "here: " << toString(HERE_SOURCELOC) << endl;
+
+  cout << "\n";
+  testHashMap();
+  testHashMap2();
+
+  cout << "srcloc is ok\n";
+}
+
+ARGS_MAIN
+
+
+#endif // TEST_SRCLOC

Added: vendor/elsa/current/smbase/srcloc.h
===================================================================
--- vendor/elsa/current/smbase/srcloc.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/srcloc.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,450 @@
+// srcloc.h            see license.txt for copyright and terms of use
+// source location information, efficiently represented as one word
+
+// The fundamental assumption in this module is that source location
+// information is frequently created, stored and passed around, but
+// infrequently decoded into human-readable form.  Therefore the
+// module uses a single word to store the information, and appeals
+// to several index structures when decoding is necessary.
+//
+// Since decoding, when it happens, also usually has high locality,
+// the data structures include caches to make accesses to nearby
+// locations fast.
+//
+// No attempt is made to fold creation of SourceLocs into other
+// file-processing activities, such as traditional lexical analysis.
+// The complexity of doing that would be substantial, with little gain
+// in efficiency, due to the large buffer caches in modern OSes.  The
+// main drawback is the inability to work with non-seekable inputs
+// (like pipes) because we consume the whole input when its line
+// counts are computed.
+
+// This module mostly uses 'char const *' for filenames instead of
+// 'rostring' because performance is important here; the lexer is
+// often calling into this module with its raw buffer pointers, and I
+// don't want any allocation happening then.
+
+#ifndef SRCLOC_H
+#define SRCLOC_H
+
+#include <limits.h>   // UCHAR_MAX
+
+#include "str.h"      // string
+#include "objlist.h"  // ObjList
+#include "array.h"    // ArrayStack, ObjArrayStack
+
+class HashLineMap;    // hashline.h
+
+
+// This is a source location.  It's interpreted as an integer
+// specifying the byte offset within a hypothetical file created by
+// concatenating all the sources together.  Its type is 'enum' so I
+// can overload functions to accept SourceLoc without confusion.
+// I assume the compiler will use a machine word for this (and check
+// that assumption in the .cc file).
+//
+// I would love to be able to annotate this so that the C++ compiler
+// would not allow variables of this type to be created
+// uninitialized.. that's the one drawback of calling this an 'enum'
+// instead of a 'class': I don't get to write a constructor.
+enum SourceLoc {
+  // entity is defined within the translator's initialization code
+  SL_INIT=-1,
+
+  // location is unknown for some reason
+  SL_UNKNOWN=0
+};
+
+
+// This class manages all the data associated with creating and
+// interpreting SourceLocs.  It's expected to be a singleton in the
+// program, though within this module that assumption is confined to
+// the 'toString' function at the end.
+class SourceLocManager {
+private:     // types
+  // a triple that identifies a line boundary in a file (it's
+  // implicit which file it is)
+  class Marker {
+  public:
+    // character offset, starting with 0
+    int charOffset;
+
+    // line offset, starting with 1
+    int lineOffset;
+
+    // offset into the 'lineLengths' array; this is not simply
+    // lineOffset-1 because of the possible presence of lines with
+    // length longer than UCHAR_MAX-1 chars
+    int arrayOffset;
+
+  public:
+    Marker() {}      // for creation in arrays
+    Marker(int c, int L, int a)
+      : charOffset(c), lineOffset(L), arrayOffset(a) {}
+    Marker(Marker const &obj)
+      : DMEMB(charOffset), DMEMB(lineOffset), DMEMB(arrayOffset) {}
+  };
+
+public:      // types
+
+  // Holds basic data about files for use in initializing the
+  // SourceLocManager when de-serializing it from XML.
+  class FileData {
+    public:
+    string name;
+    int numChars;
+    int numLines;
+    ArrayStack<unsigned char> *lineLengths;
+    HashLineMap *hashLines;
+
+    FileData()
+      : numChars(-1)
+      , numLines(-1)
+      , lineLengths(NULL)
+      , hashLines(NULL)
+    {}
+    // FIX: recursively delete the members here
+
+    bool complete() {
+      // NOTE: hashLines is nullable, so says Scott, so it is not on
+      // the list of things that have to be there for the object to be
+      // complete
+      return !name.empty() && numChars>=0 && numLines>=0 && lineLengths;
+    }
+  };
+
+  // describes a file we know about
+  class File {
+  public:    // data
+    // file name; we consider two files to be the same if and only
+    // if their names are equal, i.e. there is no checking done to
+    // see if their names happen to be aliases in the filesystem
+    string name;
+
+    // start offset in the SourceLoc space
+    SourceLoc startLoc;
+
+    // number of chars in the file (i.e., if you say stat(2), you get
+    // this number)
+    int numChars;
+
+    // number of lines in the file; for this purpose we say that a
+    // file is a sequence of lines *separated* (not terminated) by
+    // newline characters; so this value is exactly one greater than
+    // the number of '\n' characters in the file
+    int numLines;
+
+    // average number of chars per line; this is used for estimating
+    // whether the index should be consulted for some lookups (and
+    // it's stored instead of computed to save a division)
+    int avgCharsPerLine;
+
+    // known #line directives for this file; NULL if none are known
+    HashLineMap *hashLines;          // (nullable owner)
+
+  private:   // data
+    // an array of line lengths; to handle lines longer than UCHAR_MAX
+    // chars, we use runs of UCHAR_MAX chars to (in unary) encode
+    // multiples of UCHAR_MAX chars, plus the final short count (in
+    // [0,UCHAR_MAX-1]) to give the total length; "line length" does
+    // not include newline characters, but it *does* include carriage
+    // return characters if the file (as raw bytes) contains them
+    unsigned char *lineLengths;      // (owner)
+
+    // # of elements in 'lineLengths'
+    int lineLengthsSize;
+
+    // invariant: lineLengthSum() + numLines-1 == numChars
+
+    // this marker and offset can name an arbitrary point in the
+    // array, including those that are not at the start of a line; we
+    // move this around when searching within the array
+    Marker marker;
+    int markerCol;      // 1-based column; it's usually 1
+
+    // an index built on top of 'lineLengths' for faster random access
+    Marker *index;                   // (owner)
+
+    // # of elements in 'index'
+    int indexSize;
+
+    // whether there have been any hashline errors already in this input file.
+    bool erroredNumLines;
+
+  private:   // funcs
+    File(File&);                     // disallowed
+    void resetMarker();
+    void advanceMarker();
+
+    // decode and sum the lengths of all lines
+    int lineLengthSum() const;
+
+  public:    // funcs
+    // this builds both the array and the index
+    File(char const *name, SourceLoc startLoc);
+    // used when de-serializing from xml
+    File(FileData *fileData, SourceLoc aStartLoc);
+    ~File();
+
+    // line number to character offset
+    int lineToChar(int lineNum);
+
+    // line/col to offset, with truncation if col exceeds line length
+    int lineColToChar(int lineNum, int col);
+
+    // char offset to line/col
+    void charToLineCol(int offset, int &line, int &col);
+
+    // true if this file contains the specified location
+    bool hasLoc(SourceLoc sl) const
+      { return toInt(startLoc) <= sl &&
+                                  sl <= toInt(startLoc) + numChars; }
+
+    // returns -1 if the range of 'this' is less than sl, 0 if this contains
+    // sl (i.e. hasLoc), and +1 if this is greater than sl.
+    int cmpLoc(SourceLoc sl) const
+    {
+      if (toInt(startLoc) > sl) return +1;
+      if (toInt(startLoc) + numChars < sl) return -1;
+      return 0;
+    }
+
+    // call this time each time a #line directive is encountered;
+    // same semantics as HashLineMap::addHashLine
+    void addHashLine(int ppLine, int origLine, char const *origFname);
+    void doneAdding();
+
+    // check internal invariants
+    void selfCheck() const;
+
+    // dsw: the xml serialization code needs access to these two
+    // fields; the idea is that the method names suggest that people
+    // not use them
+    unsigned char *serializationOnly_get_lineLengths() {return lineLengths;}
+    int serializationOnly_get_lineLengthsSize() {return lineLengthsSize;}
+  };
+
+  // this is used for SourceLocs where the file isn't reliably
+  // available, yet we'd like to be able to store some location
+  // information anyway; the queries below just return the static
+  // information stored, and incremental update is impossible
+  class StaticLoc {
+  public:
+    string name;      // file name
+    int offset;       // char offset
+    int line, col;    // line,col
+
+  public:
+    StaticLoc(char const *n, int o, int L, int c)
+      : name(n), offset(o), line(L), col(c) {}
+    StaticLoc(StaticLoc const &obj)
+      : DMEMB(name), DMEMB(offset), DMEMB(line), DMEMB(col) {}
+    ~StaticLoc();
+  };
+
+public:
+  // type of SourceLocManager::files, so that we don't have to update
+  // everything when the type of this changes.
+  typedef ObjArrayStack<File> FileList;
+
+private:     // data
+  // list of files; implemented using an array for fast binary search lookup
+  // (used to be a linked list).
+  FileList files;
+
+  // most-recently accessed File; this is a cache
+  File *recent;                      // (nullable serf)
+
+  // list of StaticLocs; any SourceLoc less than 0 is interpreted
+  // as an index into this list
+  ObjList<StaticLoc> statics;
+
+  // next source location to assign
+  SourceLoc nextLoc;
+
+  // next static (negative) location
+  SourceLoc nextStaticLoc;
+
+public:      // data
+  // when true, the SourceLocManager may go to the file system and
+  // open a file in order to find out something about it.  dsw: I want
+  // to turn this off when de-serializing XML for example; whatever
+  // the SourceLocManager wants to kno about a file should be in the
+  // XML.
+  bool mayOpenFiles;
+
+  // number of static locations at which we print a warning message;
+  // defaults to 100
+  int maxStaticLocs;
+
+  // when true, we automatically consult the #line maps when decoding;
+  // defaults to true; NOTE: when this is true, encode and decode are
+  // not necessarily inverses of each other
+  bool useHashLines;
+
+  // when true, open the original file and scan it so that we can
+  // report true character offset counts; otherwise, just use what is
+  // in the preprocessed file
+  bool useOriginalOffset;
+
+  // count the # of times we had to truncate a char offset because
+  // the #line map pointed at a line shorter than the column number
+  // we expected to use; this is initially 0; calling code can use
+  // this to tell if the offset information across a given call or
+  // sequence of calls is perfect or truncated
+  static int shortLineCount;
+
+  // whether to tolerate problems with line numbers (from hashlines) being
+  // higher than the number of actual lines in files.  true means print at
+  // most 1 warning (per file); false means die.
+  static bool tolerateHashlineErrors;
+
+private:     // funcs
+  // let File know about these functions
+  friend class SourceLocManager::File;
+
+  static SourceLoc toLoc(int L) {
+    SourceLoc ret = (SourceLoc)L;
+
+    // in debug mode, we verify that SourceLoc is wide enough
+    // to encode this integer
+    xassertdb(toInt(ret) == L);
+
+    return ret;
+  }
+  static int toInt(SourceLoc loc) { return (int)loc; }
+
+  void makeFirstStatics();
+
+  File *findFile(char const *name);
+  File *getFile(char const *name);
+
+  File *findFileWithLoc(SourceLoc loc);
+  StaticLoc const *getStatic(SourceLoc loc);
+
+public:      // funcs
+  SourceLocManager();
+  ~SourceLocManager();
+
+  // return to state where no files are known
+  void reset();
+
+  // origins:
+  //   character offsets start at 0
+  //   lines start at 1
+  //   columns start at 1
+
+  // Note that the legal source locations go from the first byte
+  // in the file through to the last+1 byte.  So, if the file has
+  // 5 characters, then offsets 0,1,2,3,4,5 are legal.
+
+  // encode from scratch
+  SourceLoc encodeOffset(char const *filename, int charOffset);
+  SourceLoc encodeBegin(char const *filename)
+    { return encodeOffset(filename, 0 /*offset*/); }
+  SourceLoc encodeLineCol(char const *filename, int line, int col);
+
+  // some care is required with 'encodeStatic', since each call makes
+  // a new location with a new entry in the static array to back it
+  // up, so the caller should ensure a given static location is not
+  // encoded more than once, if possible
+  SourceLoc encodeStatic(StaticLoc const &obj);
+  SourceLoc encodeStatic(char const *fname, int offset, int line, int col)
+    { return encodeStatic(StaticLoc(fname, offset, line, col)); }
+  static bool isStatic(SourceLoc loc) { return toInt(loc) <= 0; }
+
+  // encode incremental; these are the methods we expect are called
+  // the most frequently; this interface is supposed to allow an
+  // implementation which uses explicit line/col, even though that
+  // is not what is used here
+  static SourceLoc advCol(SourceLoc base, int colOffset)
+    { xassert(!isStatic(base)); return toLoc(toInt(base) + colOffset); }
+  static SourceLoc advLine(SourceLoc base)     // from end of line to beginning of next
+    { xassert(!isStatic(base)); return toLoc(toInt(base) + 1); }
+  static SourceLoc advText(SourceLoc base, char const * /*text*/, int textLen)
+    { xassert(!isStatic(base)); return toLoc(toInt(base) + textLen); }
+
+  // decode
+  void decodeOffset(SourceLoc loc, char const *&filename, int &charOffset);
+  void decodeLineCol(SourceLoc loc, char const *&filename, int &line, int &col);
+
+  // more specialized decode
+  char const *getFile(SourceLoc loc) { return getFile(loc, this->useHashLines); }
+  char const *getFile(SourceLoc loc, bool localUseHashLines);
+  int getOffset(SourceLoc loc);
+  int getOffset_nohashline(SourceLoc loc);
+  int getLine(SourceLoc loc);
+  int getCol(SourceLoc loc);
+
+  // get access to the File itself, for adding #line directives
+  File *getInternalFile(char const *fname)
+    { return getFile(fname); }
+
+  // render as string in "file:line:col" format
+  string getString(SourceLoc loc);
+
+  // versions of the decode routine that either use or do not use the
+  // hashline map (when available) depending on an explicit flag,
+  // rather than using this->useHashLines
+  void decodeOffset_explicitHL(SourceLoc loc, char const *&filename, int &charOffset, bool localUseHashLines);
+  void decodeOffset_nohashline(SourceLoc loc, char const *&filename, int &charOffset)
+    { decodeOffset_explicitHL(loc, filename, charOffset, false); }
+  void decodeLineCol_explicitHL(SourceLoc loc, char const *&filename, int &line, int &col, bool localUseHashLines);
+  void decodeLineCol_nohashline(SourceLoc loc, char const *&filename, int &line, int &col)
+    { decodeLineCol_explicitHL(loc, filename, line, col, false); }
+  string getString_explicitHL(SourceLoc loc, bool localUseHashLines);
+  string getString_nohashline(SourceLoc loc)
+    { return getString_explicitHL(loc, false); }
+
+  // "line:col" format
+  string getLCString(SourceLoc loc);
+
+  // dsw: the xml serialization code needs access to this field; the
+  // idea is that the method name suggests that people not use it
+  FileList &serializationOnly_get_files() {return files;}
+  // for de-serializing from xml a single File and loading it into the SourceLocManager
+  void loadFile(FileData *fileData);
+  // has this file been loaded?
+  bool isLoaded(char const *name) { return findFile(name); }
+};
+
+
+// singleton pointer, set automatically by the constructor
+extern SourceLocManager *sourceLocManager;
+
+// dsw: So that gdb can find it please DO NOT inline this; also the
+// unique public name is intentional: I don't want gdb doing
+// overloading and sometimes getting it wrong, which it does
+string locToStr(SourceLoc sl);
+
+inline string toString(SourceLoc sl)
+  { return locToStr(sl); }
+
+inline stringBuilder& operator<< (stringBuilder &sb, SourceLoc sl)
+  { return sb << toString(sl); }
+
+inline string toLCString(SourceLoc sl)
+  { return sourceLocManager->getLCString(sl); }
+
+
+// macro for obtaining a source location that points at the
+// point in the source code where this macro is invoked
+#define HERE_SOURCELOC \
+  (sourceLocManager->encodeStatic(__FILE__, 0, __LINE__, 1))
+
+
+// it's silly to demand mention of 'SourceLocManager' just to update
+// the locations, esp. since SourceLoc is its own type and therefore
+// overloading will avoid any possible collisions
+inline SourceLoc advCol(SourceLoc base, int colOffset)
+  { return SourceLocManager::advCol(base, colOffset); }
+inline SourceLoc advLine(SourceLoc base)
+  { return SourceLocManager::advLine(base); }
+inline SourceLoc advText(SourceLoc base, char const *text, int textLen)
+  { return SourceLocManager::advText(base, text, textLen); }
+
+//  string toXml(SourceLoc index);
+//  void fromXml(SourceLoc &out, string str);
+
+
+#endif // SRCLOC_H

Added: vendor/elsa/current/smbase/srcloc.test.cc
===================================================================
--- vendor/elsa/current/smbase/srcloc.test.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/srcloc.test.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,992 @@
+// srcloc.test.cc            see license.txt for copyright and terms of use
+// test input
+
+#include <stdio.h>      // fprintf
+#include <string.h>     // memcpy
+
+// This is not a real source file, it is simply some test input for
+// the srcloc module to consume.  Originally, srcloc.cc simply used
+// its own source code for this purpose, but it turns out that some
+// preprocessors do not by default search the C++ include file
+// directories, so consequently invoking "cpp" is not sufficient to
+// preprocess srcloc.cc.
+//
+// So, the solution was to simply create this test input file, with
+// most of the #includes simply commented-out or replaced with ones
+// that should be portable.
+
+
+// this parameter controls the frequency of Markers in 
+// the marker index; lower period makes the index
+// faster but use more space
+enum { MARKER_PERIOD = 100 };    // 100 is about a 10% overhead
+
+
+// ------------------------- File -----------------------
+void addLineLength(ArrayStack<unsigned char> &lengths, int len)
+{
+  while (len >= 255) {
+    // add a long-line marker, which represents 254 chars of input
+    lengths.push(255);
+    len -= 254;
+  }
+
+  // add the short count at the end
+  lengths.push((unsigned char)len);
+}
+
+
+SourceLocManager::File::File(char const *n, SourceLoc aStartLoc)
+  : name(n),
+    startLoc(aStartLoc),     // assigned by SourceLocManager
+    hashLines(NULL),
+
+    // valid marker/col for the first char in the file
+    marker(0, 1, 0),
+    markerCol(1)
+{
+  // open in binary mode since it's too unpredictable whether
+  // the lower level (e.g. cygwin) will do CRLF translation,
+  // and whether that will be done consistently, if text mode
+  // is requested
+  AutoFILE fp(toCStr(name), "rb");
+
+  // the buffering that FILE would do would be wasted, so
+  // make it unbuffered (if this causes a problem on some
+  // system it can be commented-out)
+  setbuf(fp, NULL);
+
+  // These are growable versions of the indexes.  They will be
+  // discarded after the file has been read.  They keep track of their
+  // own 'next index' values.  I chose to use a growable array instead
+  // of making two passes over the file to reduce i/o.
+  ArrayStack<unsigned char> lineLengths;
+  ArrayStack<Marker> index;
+
+  // put a marker at the start for uniformity
+  index.push(Marker(0, 1, 0));
+
+  // how many lines to go before I insert the next marker
+  int indexDelay = MARKER_PERIOD;
+
+  // where I am in the file
+  int charOffset = 0;
+  int lineNum = 1;
+  int lineLen = 0;       // length of current line, so far
+
+  // read the file, computing information about line lengths
+  enum { BUFLEN=8192 };
+  char buf[BUFLEN];
+  for (;;) {
+    // read a buffer of data
+    int len = fread(buf, 1, BUFLEN, fp);
+    if (len < 0) {
+      xsyserror("fread", name);
+    }
+    if (len==0) {
+      break;
+    }
+
+    // the code that follows can be seen as abstracting the data
+    // contained in buf[start] through buf[end-1] and adding that
+    // information to the summary variables above
+    char const *start = buf;      // beginning of unaccounted-for chars
+    char const *p = buf;          // scan pointer
+    char const *end = buf+len;    // end of unaccounted-for chars
+
+    // loop over the lines in 'buf'
+    while (start < end) {
+      // scan to the next newline
+      while (p<end && *p!='\n') {
+        p++;
+      }
+      if (p==end) {
+        break;
+      }
+      xassert(*p == '\n');
+
+      // account for [start,p)
+      charOffset += p-start;
+      lineLen += p-start;
+      start = p;
+
+      // account for the newline at '*p'
+      addLineLength(lineLengths, lineLen);
+      charOffset++;
+      lineNum++;
+      lineLen = 0;
+
+      p++;
+      start++;
+
+      if (--indexDelay == 0) {
+        // insert a marker to remember this location
+        index.push(Marker(charOffset, lineNum, lineLengths.length()));
+        indexDelay = MARKER_PERIOD;
+      }
+    }
+
+    // move [start,p) into 'lineLen'
+    charOffset += p-start;
+    lineLen += p-start;
+    start = p;
+    xassert(start == end);
+  }
+
+  // handle the last line; in the usual case, where a newline is
+  // the last character, the final line will have 0 length, but
+  // we encode that anyway since it helps the decode phase below
+  addLineLength(lineLengths, lineLen);
+  charOffset += lineLen;
+
+  // move computed information into 'this'
+  this->numChars = charOffset;
+  this->numLines = lineNum-1;
+  if (numLines == 0) {
+    // a file with no newlines
+    this->avgCharsPerLine = numChars;
+  }
+  else {
+    this->avgCharsPerLine = numChars / numLines;
+  }
+
+  this->lineLengthsSize = lineLengths.length();
+  this->lineLengths = new unsigned char[lineLengthsSize];
+  memcpy(this->lineLengths, lineLengths.getArray(),
+         lineLengthsSize * sizeof(this->lineLengths[0]));
+
+  this->indexSize = index.length();
+  this->index = new Marker[indexSize];
+  memcpy(this->index, index.getArray(),
+         indexSize * sizeof(this->index[0]));
+         
+  // 'fp' closed by the AutoFILE
+}
+
+
+SourceLocManager::File::~File()
+{
+  if (hashLines) { 
+    delete hashLines;
+  }
+  delete[] lineLengths;
+}
+
+
+void SourceLocManager::File::resetMarker()
+{
+  marker.charOffset = 0;
+  marker.lineOffset = 1;
+  marker.arrayOffset = 0;
+  markerCol = 1;
+}
+
+
+// it's conceivable gcc is smart enough to recognize
+// the induction variable, if I inline this..
+inline void SourceLocManager::File::advanceMarker()
+{
+  int len = (int)lineLengths[marker.arrayOffset];
+  if (len < 255) {
+    // normal length line
+    marker.charOffset += len+1;     // +1 for newline
+    marker.lineOffset++;
+    marker.arrayOffset++;
+    markerCol = 1;
+  }
+  else {
+    // fragment of a long line, representing 254 characters
+    marker.charOffset += 254;
+    marker.arrayOffset++;
+    markerCol += 254;
+  }
+}
+
+
+int SourceLocManager::File::lineToChar(int lineNum)
+{
+  if (lineNum == numLines+1) {
+    // end of file location
+    return numChars;
+  }
+
+  xassert(1 <= lineNum && lineNum <= numLines);
+
+  // check to see if the marker is already close
+  if (marker.lineOffset <= lineNum &&
+                           lineNum < marker.lineOffset + MARKER_PERIOD) {
+    // use the marker as-is
+  }
+  else {
+    // do a binary search on the index to find the marker whose
+    // lineOffset is closest to 'lineNum' without going over
+    int low = 0;              // lowest index under consideration
+    int high = indexSize-1;   // highest index under consideration
+    while (low < high) {
+      // check the midpoint (round up to ensure progress when low+1 == high)
+      int mid = (low+high+1)/2;
+      if (index[mid].lineOffset > lineNum) {
+        // too high
+        high = mid-1;
+      }
+      else {
+        // too low or just right
+        low = mid;
+      }
+    }
+
+    // copy this index marker into our primary marker
+    marker = index[low];
+    markerCol = 1;            // all index markers implicitly have column 1
+  }
+
+  xassert(marker.lineOffset <= lineNum);
+
+  // move the marker down the array until it arrives at
+  // the desired line
+  while (marker.lineOffset < lineNum) {
+    advanceMarker();
+  }
+
+  // make sure we never go beyond the end of the array
+  xassert(marker.arrayOffset < lineLengthsSize);
+
+  // if we didn't move the marker, we might not be in column 1
+  return marker.charOffset - (markerCol-1);
+}
+
+
+int SourceLocManager::File::lineColToChar(int lineNum, int col)
+{
+  // use the above function first
+  int offset = lineToChar(lineNum);
+
+  // now, we use an property established by the previous function:
+  // the marker points at the line of interest, possibly offset from
+  // the line start by 'markerCol-1' places
+  if (col <= markerCol) {
+    // the column we want is not even beyond the marker's column,
+    // so it's surely not beyond the end of the line, so do the
+    // obvious thing
+    return offset + (col-1);
+  }
+
+  // we're at least as far as the marker; move the offset up to
+  // this far, and subtract from 'col' so it now represents the
+  // number of chars yet to traverse on this line
+  offset = marker.charOffset;
+  col -= markerCol;       // 'col' is now 0-based
+
+  // march to the end of the line, looking for either the end or a
+  // line length component which goes beyond 'col'; I don't move the
+  // marker itself out of concern for preserving the locality of
+  // future accesses
+  int index = marker.arrayOffset;
+  for (;;) {
+    int len = (int)lineLengths[index];
+    if (col <= len) {
+      // 'col' doesn't go beyond this component, we're done
+      // (even if len==255 it still works)
+      return offset + col;
+    }
+    if (len < 255) {
+      // the line ends here, truncate and we're done
+      SourceLocManager::shortLineCount++;
+      return offset + len;
+    }
+
+    // the line continues
+    xassertdb(len == 255);
+
+    col -= 254;
+    offset += 254;
+    xassertdb(col > 0);
+
+    index++;
+    xassert(index < lineLengthsSize);
+  }
+}
+
+
+void SourceLocManager::File::charToLineCol(int offset, int &line, int &col)
+{
+  if (offset == numChars) {
+    // end of file location
+    line = numLines+1;
+    col = 1;
+    return;
+  }
+
+  xassert(0 <= offset && offset < numChars);
+
+  // check if the marker is close enough
+  if (marker.charOffset <= offset &&
+                           offset < marker.charOffset + MARKER_PERIOD*avgCharsPerLine) {
+    // use as-is
+  }
+  else {
+    // binary search, like above
+    int low = 0;
+    int high = indexSize-1;
+    while (low < high) {
+      // check midpoint
+      int mid = (low+high+1)/2;
+      if (index[mid].charOffset > offset) {
+        high = mid-1;
+      }
+      else {
+        low = mid;
+      }
+    }
+
+    // copy this marker
+    marker = index[low];
+    markerCol = 1;
+  }
+
+  xassert(marker.charOffset <= offset);
+
+  // move the marker until it's within one spot of moving
+  // beyond the offset
+  while (marker.charOffset + lineLengths[marker.arrayOffset] < offset) {
+    advanceMarker();
+  }
+
+  // make sure we never go beyond the end of the array
+  xassert(marker.arrayOffset < lineLengthsSize);
+
+  // read off line/col
+  line = marker.lineOffset;
+  col = markerCol + (offset - marker.charOffset);
+}
+
+
+void SourceLocManager::File::addHashLine
+  (int ppLine, int origLine, char const *origFname)
+{
+  if (!hashLines) {
+    hashLines = new HashLineMap(name);
+  }
+  hashLines->addHashLine(ppLine, origLine, origFname);
+}
+
+void SourceLocManager::File::doneAdding()
+{ 
+  if (hashLines) {
+    hashLines->doneAdding();
+  }
+  else {
+    // nothing to consolidate, the NULL pointer is valid and
+    // will cause the map to be ignored, so do nothing
+  }
+}
+
+
+// ----------------------- StaticLoc -------------------
+SourceLocManager::StaticLoc::~StaticLoc()
+{}
+
+
+// ----------------------- SourceLocManager -------------------
+int SourceLocManager::shortLineCount = 0;
+
+SourceLocManager *sourceLocManager = NULL;
+
+
+SourceLocManager::SourceLocManager()
+  : files(),
+    recent(NULL),
+    statics(),
+    nextLoc(toLoc(1)),
+    nextStaticLoc(toLoc(0)),
+    maxStaticLocs(100),
+    useHashLines(true),
+    useOriginalOffset(true)
+{
+  if (!sourceLocManager) {
+    sourceLocManager = this;
+  }
+
+  // slightly clever: treat SL_UNKNOWN as a static
+  SourceLoc u = encodeStatic(StaticLoc("<noloc>", 0,1,1));
+  xassert(u == SL_UNKNOWN);
+  PRETEND_USED(u);     // silence warning in case xasserts are turned off
+
+  // similarly for SL_INIT
+  u = encodeStatic(StaticLoc("<init>", 0,1,1));
+  xassert(u == SL_INIT);
+  PRETEND_USED(u);
+}
+
+SourceLocManager::~SourceLocManager()
+{
+  if (sourceLocManager == this) {
+    sourceLocManager = NULL;
+  }
+}
+
+
+// find it, or return NULL
+SourceLocManager::File *SourceLocManager::findFile(char const *name)
+{
+  if (!this) {
+    // it's quite common to forget to do this, and this function is 
+    // almost always the one which segfaults in that case, so I'll
+    // make the error message a bit nicer to save a trip through
+    // the debugger
+    xfailure("you have to create a SourceLocManager in your main() function");
+  }
+
+  if (recent && recent->name.equals(name)) {
+    return recent;
+  }
+
+  FOREACH_OBJLIST_NC(File, files, iter) {
+    if (iter.data()->name.equals(name)) {
+      return recent = iter.data();
+    }
+  }
+
+  return NULL;
+}
+
+// find it or make it
+SourceLocManager::File *SourceLocManager::getFile(char const *name)
+{
+  File *f = findFile(name);
+  if (!f) {
+    // read the file
+    f = new File(name, nextLoc);
+    files.append(f);
+
+    // bump 'nextLoc' according to how long that file was,
+    // plus 1 so it can own the position equal to its length
+    nextLoc = toLoc(f->startLoc + f->numChars + 1);
+  }
+
+  return recent = f;
+}
+
+
+SourceLoc SourceLocManager::encodeOffset(
+  char const *filename, int charOffset)
+{
+  xassert(charOffset >= 0);
+
+  File *f = getFile(filename);
+  xassert(charOffset <= f->numChars);
+  return toLoc(f->startLoc + charOffset);
+}
+
+
+SourceLoc SourceLocManager::encodeLineCol(
+  char const *filename, int line, int col)
+{
+  xassert(line >= 1);
+  xassert(col >= 1);
+
+  File *f = getFile(filename);
+
+  // map from a line number to a char offset
+  #if 1  // new
+    int charOffset = f->lineColToChar(line, col);
+    return toLoc(toInt(f->startLoc) + charOffset);
+  #else  // old
+    int charOffset = f->lineToChar(line);
+    return toLoc(toInt(f->startLoc) + charOffset + (col-1));
+  #endif
+}
+
+
+SourceLoc SourceLocManager::encodeStatic(StaticLoc const &obj)
+{
+  if (-toInt(nextStaticLoc) == maxStaticLocs) {
+    // Each distinct static location should correspond to a single
+    // place in the source code.  If one place in the source is creating
+    // a given static location over and over, that's bad because it
+    // quickly leads to poor performance when storing and decoding them.
+    // Instead, make one and re-use it.
+    //
+    // If this message is being printed because the program is just
+    // really big and has lots of distinct static locations, then you
+    // can increase maxStaticLocs manually.
+    fprintf(stderr,
+      "Warning: You've created %d static locations, which is symptomatic\n"
+      "of a bug.  See %s, line %d.\n",
+      maxStaticLocs, __FILE__, __LINE__);
+  }
+
+  // save this location
+  statics.append(new StaticLoc(obj));
+
+  // return current index, yield next
+  SourceLoc ret = nextStaticLoc;
+  nextStaticLoc = toLoc(toInt(ret) - 1);
+  return ret;
+}
+
+
+SourceLocManager::File *SourceLocManager::findFileWithLoc(SourceLoc loc)
+{
+  // check cache
+  if (recent && recent->hasLoc(loc)) {
+    return recent;
+  }
+
+  // iterative walk
+  FOREACH_OBJLIST_NC(File, files, iter) {
+    if (iter.data()->hasLoc(loc)) {
+      return recent = iter.data();
+    }
+  }
+
+  // the user gave me a value that I never made!
+  xfailure("invalid source location");
+  return NULL;    // silence warning
+}
+
+
+SourceLocManager::StaticLoc const *SourceLocManager::getStatic(SourceLoc loc)
+{
+  int index = -toInt(loc);
+  return statics.nthC(index);
+}
+
+
+void SourceLocManager::decodeOffset(
+  SourceLoc loc, char const *&filename, int &charOffset)
+{
+  // check for static
+  if (isStatic(loc)) {
+    StaticLoc const *s = getStatic(loc);
+    filename = s->name.c_str();
+    charOffset = s->offset;
+    return;
+  }
+
+  File *f = findFileWithLoc(loc);
+  filename = f->name.c_str();
+  charOffset = toInt(loc) - toInt(f->startLoc);
+  
+  if (useHashLines && f->hashLines) {
+    // we can't pass charOffsets directly through the #line map, so we
+    // must first map to line/col and then back to charOffset after
+    // going through the map
+
+    // map to a pp line/col
+    int ppLine, ppCol;
+    f->charToLineCol(charOffset, ppLine, ppCol);
+
+    // map to original line/file
+    int origLine;
+    char const *origFname;
+    f->hashLines->map(ppLine, origLine, origFname);
+
+    // get a File for the original file; this opens that file
+    // and scans it for line boundaries
+    File *orig = getFile(origFname);
+
+    // use that map to get an offset, truncating columns that are
+    // beyond the true line ending (happens due to macro expansion)
+    charOffset = orig->lineColToChar(origLine, ppCol);
+    
+    // filename is whatever #line said
+    filename = origFname;             
+  }
+}
+
+
+void SourceLocManager::decodeLineCol(
+  SourceLoc loc, char const *&filename, int &line, int &col)
+{ 
+  if (!this) {
+    // didn't initialize a loc manager.. but maybe we can survive?
+    if (loc == SL_UNKNOWN) {
+      filename = "<noloc>";
+      line = 1;
+      col = 1;
+      return;
+    }
+    else {
+      xfailure("you have to create a SourceLocManager in your main() function");
+    }
+  }
+
+  // check for static
+  if (isStatic(loc)) {
+    StaticLoc const *s = getStatic(loc);
+    filename = s->name.c_str();
+    line = s->line;
+    col = s->col;
+    return;
+  }
+
+  File *f = findFileWithLoc(loc);
+  filename = f->name.c_str();
+  int charOffset = toInt(loc) - toInt(f->startLoc);
+  
+  f->charToLineCol(charOffset, line, col);
+  
+  if (useHashLines && f->hashLines) {       
+    // use the #line map to determine a new file/line pair; simply
+    // assume that the column information is still correct, though of
+    // course in C, due to macro expansion, it isn't always
+    f->hashLines->map(line, line, filename);
+  }
+}
+
+
+char const *SourceLocManager::getFile(SourceLoc loc)
+{
+  char const *name;
+  int ofs;
+  decodeOffset(loc, name, ofs);
+  return name;
+}
+
+
+int SourceLocManager::getOffset(SourceLoc loc)
+{
+  char const *name;
+  int ofs;
+  decodeOffset(loc, name, ofs);
+  return ofs;
+}
+
+
+int SourceLocManager::getLine(SourceLoc loc)
+{
+  char const *name;
+  int line, col;
+  decodeLineCol(loc, name, line, col);
+  return line;
+}
+
+
+int SourceLocManager::getCol(SourceLoc loc)
+{
+  char const *name;
+  int line, col;
+  decodeLineCol(loc, name, line, col);
+  return col;
+}
+
+
+string SourceLocManager::getString(SourceLoc loc)
+{
+  char const *name;
+  int line, col;
+  decodeLineCol(loc, name, line, col);
+
+  return stringc << name << ":" << line << ":" << col;
+}
+
+string SourceLocManager::getLCString(SourceLoc loc)
+{
+  char const *name;
+  int line, col;
+  decodeLineCol(loc, name, line, col);
+
+  return stringc << line << ":" << col;
+}
+
+
+string locToStr(SourceLoc sl)
+{
+  return sourceLocManager->getString(sl);
+}
+
+
+// -------------------------- test code ----------------------
+#ifdef TEST_SRCLOC
+
+//#include "test.h"        // USUAL_MAIN
+//#include "strtokp.h"     // StrtokParse
+
+#include <stdlib.h>      // rand, exit, system
+
+SourceLocManager mgr;
+int longestLen=0;
+
+// given a location, decode it into line/col and then re-encode,
+// and check that the new encoding matches the old
+void testRoundTrip(SourceLoc loc)
+{
+  char const *fname;
+  int line, col;
+  mgr.decodeLineCol(loc, fname, line, col);
+
+  if (col > longestLen) {
+    longestLen = col;
+  }
+
+  SourceLoc loc2 = mgr.encodeLineCol(fname, line, col);
+  
+  xassert(loc == loc2);
+}
+
+
+// these are some long lines to test their handling
+// 109: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+// 209: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+// 309: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+// 509: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+// 609: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+// 1210: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+// 2410: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+// 4810: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+// 9610: 1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------1---------2---------3---------4---------5---------6---------7---------8---------9---------10--------
+
+
+           
+// location in SourceLoc and line/col
+class BiLoc {
+public:
+  int line, col;
+  SourceLoc loc;
+};
+
+
+// given a file, compute SourceLocs throughout it and verify
+// that round-trip encoding works
+void testFile(char const *fname)
+{
+  // find the file's length
+  int len;
+  {
+    AutoFILE fp(fname, "rb");
+
+    fseek(fp, 0, SEEK_END);
+    len = (int)ftell(fp);
+    cout << "length of " << fname << ": " << len << endl;
+  }
+
+  // get locations for the start and end
+  SourceLoc start = mgr.encodeOffset(fname, 0);
+  SourceLoc end = mgr.encodeOffset(fname, len-1);
+
+  // check expectations for start
+  xassert(mgr.getLine(start) == 1);
+  xassert(mgr.getCol(start) == 1);
+
+  // test them
+  testRoundTrip(start);
+  testRoundTrip(end);
+
+  // temporary
+  //testRoundTrip((SourceLoc)11649);
+
+  BiLoc *bi = new BiLoc[len+1];
+  char const *dummy;
+
+  // test all positions, forward sequential; also build the
+  // map for the random test; note that 'len' is considered
+  // a valid source location even though it corresponds to
+  // the char just beyond the end
+  int i;
+  for (i=0; i<=len; i++) {
+    SourceLoc loc = mgr.encodeOffset(fname, i);
+    testRoundTrip(loc);
+
+    bi[i].loc = loc;
+    mgr.decodeLineCol(loc, dummy, bi[i].line, bi[i].col);
+  }
+
+  // backward sequential
+  for (i=len; i>0; i--) {
+    SourceLoc loc = mgr.encodeOffset(fname, i);
+    testRoundTrip(loc);
+  }
+
+  // random access, both mapping directions
+  for (i=0; i<=len; i++) {
+    int j = rand()%(len+1);
+    int dir = rand()%2;
+
+    if (dir==0) {
+      // test loc -> line/col map
+      int line, col;
+      mgr.decodeLineCol(bi[j].loc, dummy, line, col);
+      xassert(line == bi[j].line);
+      xassert(col == bi[j].col);
+    }
+    else {
+      // test line/col -> loc map
+      SourceLoc loc = mgr.encodeLineCol(fname, bi[j].line, bi[j].col);
+      xassert(loc == bi[j].loc);
+    }
+  }
+  
+  delete[] bi;
+}
+
+
+// decode with given expectation, complain if it doesn't match
+void expect(SourceLoc loc, char const *expFname, int expLine, int expCol)
+{
+  char const *fname;
+  int line, col;
+  mgr.decodeLineCol(loc, fname, line, col);
+  
+  if (0!=strcmp(fname, expFname) ||
+      line != expLine ||
+      col != expCol) {
+    printf("expected %s:%d:%d, but got %s:%d:%d\n",
+           expFname, expLine, expCol,
+           fname, line, col);
+    exit(2);
+  }
+}
+
+
+// this is a macro that will expand to more text than the call site,
+// to test column truncation
+#define EXPANDER int blah_de_blah_de_frickin_blah;
+EXPANDER
+
+
+// should this be exported?
+string locString(char const *fname, int line, int col)
+{
+  return stringc << fname << ":" << line << ":" << col;
+}
+
+
+void testHashMap()
+{
+  // run the preprocessor
+  if (0!=system("cpp -DTEST_SRCLOC srcloc.cc >srcloc.tmp 2>/dev/null")) {
+    xbase("failed to preprocess srcloc.cc");
+  }
+
+  SourceLocManager::File *pp = mgr.getInternalFile("srcloc.tmp");
+  SourceLocManager::File *orig = mgr.getInternalFile("srcloc.cc");
+
+  // read srcloc.tmp and install the hash maps
+  int expanderLine=0;
+  {
+    AutoFILE fp("srcloc.tmp", "rb");
+
+    enum { SZ=256 };
+    char buf[SZ];
+    int ppLine=0;
+    while (fgets(buf, SZ, fp)) {
+      if (buf[strlen(buf)-1] == '\n') {
+        ppLine++;
+      }
+
+      if (0==memcmp(buf, "int blah_de_blah", 16)) {
+        expanderLine = ppLine;
+      }
+
+      if (buf[0]!='#') continue;
+                                       
+      // break into tokens at whitespace (this isn't exactly
+      // right, because the file names can have quoted spaces,
+      // but it will do for testing purposes)
+      StrtokParse tok(buf, " \r\n");
+      if (tok < 3) continue;
+
+      int origLine = atoi(tok[1]);
+      char const *tok2 = tok[2];
+      string origFname = substring(tok2+1, strlen(tok2)-2);  // remove quotes
+      pp->addHashLine(ppLine, origLine, origFname.c_str());
+    }
+    pp->doneAdding();
+  }
+
+  // the 2nd line in the pp source should correspond to the
+  // first line in the orig src
+  // update: this doesn't work with all preprocessors, and I'm
+  // confident in the implementation now, so I'll turn this off
+  //SourceLoc lineTwo = mgr.encodeLineCol("srcloc.tmp", 2, 1);
+  //expect(lineTwo, "srcloc.cc", 1,1);
+
+  // print decodes of first several lines (including those that
+  // are technically undefined because they occur on #line lines)
+  int ppLine;
+  for (ppLine = 1; ppLine < 10; ppLine++) {
+    SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", ppLine, 1);
+    cout << "ppLine " << ppLine << ": " << toString(loc) << endl;
+  }
+
+  // similar for last few lines
+  for (ppLine = pp->numLines - 4; ppLine <= pp->numLines; ppLine++) {
+    SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", ppLine, 1);
+    cout << "ppLine " << ppLine << ": " << toString(loc) << endl;
+  }
+
+  // see how the expander line behaves
+  if (!expanderLine) {
+    cout << "didn't find expander line!\n";
+    exit(2);
+  }
+  else {
+    SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", expanderLine, 1);
+    cout << "expander column 1: " << toString(loc) << endl;
+
+    // in the pp file, I can advance the expander horizontally a long ways;
+    // this should truncate to column 9
+    loc = advCol(loc, 20);
+
+    char const *fname;
+    int offset;
+    mgr.decodeOffset(loc, fname, offset);
+    cout << "expander column 21: " << fname << ", offset " << offset << endl;
+    xassert(0==strcmp(fname, "srcloc.cc"));
+
+    // map that to line/col, which should show the truncation
+    int line, col;
+    orig->charToLineCol(offset, line, col);
+    cout << "expander column 21: " << locString(fname, line, col) << endl;
+    if (col != 9 && col != 10) {
+      // 9 is for LF line endings, 10 for CRLF
+      cout << "expected column 9 or 10!\n";
+      exit(2);
+    }
+  }
+}
+
+
+void entry(int argc, char ** /*argv*/)
+{
+  traceAddSys("progress");
+  traceProgress() << "begin" << endl;
+
+  if (argc >= 2) {
+    // set maxStaticLocs low to test the warning
+    mgr.maxStaticLocs = 1;
+  }
+
+  // test my source code
+  testFile("srcloc.cc");
+  testFile("srcloc.h");
+
+  // do it again, so at least one won't be the just-added file;
+  // in fact do it many times so I can see results in a profiler
+  for (int i=0; i<1; i++) {
+    testFile("srcloc.cc");
+    testFile("srcloc.h");
+  }
+
+  traceProgress() << "end" << endl;
+
+  // protect against degeneracy by printing the length of
+  // the longest line
+  cout << "\n";
+  cout << "long line len: " << longestLen << endl;
+
+  // test the statics
+  cout << "invalid: " << toString(SL_UNKNOWN) << endl;
+  cout << "here: " << toString(HERE_SOURCELOC) << endl;
+  
+  cout << "\n";
+  testHashMap();
+
+  cout << "srcloc is ok\n";
+}
+
+ARGS_MAIN
+
+
+#endif // TEST_SRCLOC

Added: vendor/elsa/current/smbase/srcloc.test2.cc
===================================================================
--- vendor/elsa/current/smbase/srcloc.test2.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/srcloc.test2.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,11 @@
+// srcloc.test2.cc
+// already-preprocessed test input for the 'srcloc' module
+
+# 5 "srcloc.h"
+hello
+
+# 15 "nonexist.h"
+this comes from a file that does not exist
+
+# 11 "srcloc.test2.cc"
+back to the original file

Added: vendor/elsa/current/smbase/str.cpp
===================================================================
--- vendor/elsa/current/smbase/str.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/str.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,508 @@
+// str.cpp            see license.txt for copyright and terms of use
+// code for str.h
+// Scott McPeak, 1995-2000  This file is public domain.
+
+#include "str.h"            // this module
+
+#include <stdlib.h>         // atoi
+#include <stdio.h>          // sprintf
+#include <ctype.h>          // isspace
+#include <string.h>         // strcmp
+#include <iostream.h>       // ostream << char*
+#include <assert.h>         // assert
+#include <unistd.h>         // write
+
+#include "xassert.h"        // xassert
+#include "ckheap.h"         // checkHeapNode
+#include "flatten.h"        // Flatten
+#include "nonport.h"        // vnprintf
+#include "array.h"          // Array
+
+
+// ----------------------- string ---------------------
+
+// put the empty string itself in read-only memory
+char const nul_byte = 0;
+
+// deliberately cast away the constness; I cannot declare
+// 'emptyString' to be const because it gets assigned to 's', but it
+// is nevertheless the intent that I never modify 'nul_byte'
+char * const string::emptyString = const_cast<char*>(&nul_byte);
+
+
+string::string(char const *src, int length, SmbaseStringFunc)
+{
+  s=emptyString;
+  setlength(length);       // setlength already has the +1; sets final NUL
+  memcpy(s, src, length);
+}
+
+
+void string::dup(char const *src)
+{
+  // std::string does not accept NULL pointers
+  xassert(src != NULL);
+
+  if (src[0]==0) {
+    s = emptyString;
+  }
+  else {
+    s = new char[ strlen(src) + 1 ];
+    xassert(s);
+    strcpy(s, src);
+  }
+}
+
+void string::kill()
+{
+  if (s != emptyString) {
+    delete[] s;         // found by Coverity Prevent
+  }
+}
+
+
+string::string(Flatten&)
+  : s(emptyString)
+{}
+
+void string::xfer(Flatten &flat)
+{
+  flat.xferCharString(s);
+}
+
+
+int string::length() const
+{
+  xassert(s);
+  return strlen(s);
+}
+
+bool string::contains(char c) const
+{
+  xassert(s);
+  return !!strchr(s, c);
+}
+
+
+string string::substring(int startIndex, int len) const
+{
+  xassert(startIndex >= 0 &&
+          len >= 0 &&
+          startIndex + len <= length());
+
+  return ::substring(s+startIndex, len);
+}
+
+
+string &string::setlength(int length)
+{
+  kill();
+  if (length > 0) {
+    s = new char[ length+1 ];
+    xassert(s);
+    s[length] = 0;      // final NUL in expectation of 'length' chars
+    s[0] = 0;           // in case we just wanted to set allocated length
+  }
+  else {
+    xassert(length == 0);     // negative wouldn't make sense
+    s = emptyString;
+  }
+  return *this;
+}
+
+
+int string::compareTo(string const &src) const
+{
+  return compareTo(src.s);
+}
+
+int string::compareTo(char const *src) const
+{
+  if (src == NULL) {
+    src = emptyString;
+  }
+  return strcmp(s, src);
+}
+
+
+string string::operator&(string const &tail) const
+{
+  string dest(length() + tail.length(), SMBASE_STRING_FUNC);
+  strcpy(dest.s, s);
+  strcat(dest.s, tail.s);
+  return dest;
+}
+
+string& string::operator&=(string const &tail)
+{
+  return *this = *this & tail;
+}
+
+
+void string::readdelim(istream &is, char const *delim)
+{
+  stringBuilder sb;
+  sb.readdelim(is, delim);
+  operator= (sb);
+}
+
+
+void string::write(ostream &os) const
+{
+  os << s;     // standard char* writing routine
+}
+
+
+void string::selfCheck() const
+{
+  if (s != emptyString) {
+    checkHeapNode(s);
+  }
+}
+
+
+// ----------------------- rostring ---------------------
+int strcmp(rostring s1, rostring s2)
+  { return strcmp(s1.c_str(), s2.c_str()); }
+int strcmp(rostring s1, char const *s2)
+  { return strcmp(s1.c_str(), s2); }
+int strcmp(char const *s1, rostring s2)
+  { return strcmp(s1, s2.c_str()); }
+
+
+char const *strstr(rostring haystack, char const *needle)
+{
+  return strstr(haystack.c_str(), needle);
+}
+
+
+int atoi(rostring s)
+{
+  return atoi(toCStr(s));
+}
+
+string substring(char const *p, int n)
+{
+  return string(p, n, SMBASE_STRING_FUNC);
+}
+
+
+// --------------------- stringBuilder ------------------
+stringBuilder::stringBuilder(int len)
+{
+  init(len);
+}
+
+void stringBuilder::init(int initSize)
+{
+  size = initSize + EXTRA_SPACE + 1;     // +1 to be like string::setlength
+  s = new char[size];
+  end = s;
+  end[initSize] = 0;
+}
+
+
+void stringBuilder::dup(char const *str)
+{
+  int len = strlen(str);
+  init(len);
+  strcpy(s, str);
+  end += len;
+}
+
+
+stringBuilder::stringBuilder(char const *str)
+{
+  dup(str);
+}
+
+
+stringBuilder::stringBuilder(char const *str, int len)
+{
+  init(len);
+  memcpy(s, str, len);
+  end += len;
+}
+
+
+stringBuilder& stringBuilder::operator=(char const *src)
+{
+#if 1
+  // quarl 2006-06-01
+  //    This implementation avoids re-allocation unless necessary.
+  if (s != src) {
+    int srclen = strlen(src)+1;
+    if (srclen > size) { // need to re-allocate?
+      delete s;
+      s = new char[ srclen ];
+    }
+    xassert(s);
+    memcpy(s, src, srclen); // copy string including NULL
+    end = s + srclen - 1; // point to NULL
+  }
+  return *this;
+#else
+  if (s != src) {
+    kill();
+    dup(src);
+  }
+  return *this;
+#endif
+}
+
+
+stringBuilder& stringBuilder::setlength(int newlen)
+{
+  kill();
+  init(newlen);
+  return *this;
+}
+
+
+void stringBuilder::adjustend(char* newend)
+{
+  xassert(s <= newend  &&  newend < s + size);
+
+  end = newend;
+  *end = 0;        // sm 9/29/00: maintain invariant
+}
+
+
+void stringBuilder::truncate(int newLength)
+{
+  xassert(0 <= newLength && newLength <= length());
+  adjustend(s + newLength);
+}
+
+
+stringBuilder& stringBuilder::operator&= (char const *tail)
+{
+  append(tail, strlen(tail));
+  return *this;
+}
+
+void stringBuilder::append(char const *tail, int len)
+{
+  ensure(length() + len);
+
+  memcpy(end, tail, len);
+  end += len;
+  *end = 0;
+}
+
+
+stringBuilder& stringBuilder::indent(int amt)
+{
+  xassert(amt >= 0);
+  ensure(length() + amt);
+
+  memset(end, ' ', amt);
+  end += amt;
+  *end = 0;
+
+  return *this;
+}
+
+
+void stringBuilder::grow(int newMinLength)
+{
+  // I want at least EXTRA_SPACE extra
+  int newMinSize = newMinLength + EXTRA_SPACE + 1;         // compute resulting allocated size
+
+  // I want to grow at the rate of at least 50% each time
+  int suggest = size * 3 / 2;
+
+  // see which is bigger
+  newMinSize = max(newMinSize, suggest);
+
+  // remember old length..
+  int len = length();
+
+  // realloc s to be newMinSize bytes
+  char *temp = new char[newMinSize];
+  xassert(len+1 <= newMinSize);    // prevent overrun
+  memcpy(temp, s, len+1);          // copy null too
+  delete[] s;
+  s = temp;
+
+  // adjust other variables
+  end = s + len;
+  size = newMinSize;
+}
+
+
+stringBuilder& stringBuilder::operator<< (char c)
+{
+  ensure(length() + 1);
+  *(end++) = c;
+  *end = 0;
+  return *this;
+}
+
+
+#define MAKE_LSHIFT(Argtype, fmt)                        \
+  stringBuilder& stringBuilder::operator<< (Argtype arg) \
+  {                                                      \
+    char buf[60];      /* big enough for all types */    \
+    int len = sprintf(buf, fmt, arg);                    \
+    if (len >= 60) {					 \
+      abort();    /* too big */                          \
+    }                                                    \
+    return *this << buf;                                 \
+  }
+
+MAKE_LSHIFT(long, "%ld")
+MAKE_LSHIFT(unsigned long, "%lu")
+MAKE_LSHIFT(double, "%g")
+MAKE_LSHIFT(void*, "%p")
+
+#undef MAKE_LSHIFT
+
+
+stringBuilder& stringBuilder::operator<< (
+  stringBuilder::Hex const &h)
+{
+  char buf[32];        // should only need 19 for 64-bit word..
+  int len = sprintf(buf, "0x%lX", h.value);
+  if (len >= 20) {
+    abort();
+  }
+  return *this << buf;
+
+  // the length check above isn't perfect because we only find out there is
+  // a problem *after* trashing the environment.  it is for this reason I
+  // use 'assert' instead of 'xassert' -- the former calls abort(), while the
+  // latter throws an exception in anticipation of recoverability
+}
+
+
+stringBuilder& stringBuilder::operator<< (Manipulator manip)
+{
+  return manip(*this);
+}
+
+
+// slow but reliable
+void stringBuilder::readdelim(istream &is, char const *delim)
+{
+  char c;
+  is.get(c);
+  while (!is.eof() &&
+         (!delim || !strchr(delim, c))) {
+    *this << c;
+    is.get(c);
+  }
+}
+
+
+// ---------------------- toString ---------------------
+#define TOSTRING(type)        \
+  string toString(type val)   \
+  {                           \
+    return stringc << val;    \
+  }
+
+TOSTRING(int)
+TOSTRING(unsigned)
+TOSTRING(char)
+TOSTRING(long)
+TOSTRING(float)
+
+#undef TOSTRING
+
+// this one is more liberal than 'stringc << null' because it gets
+// used by the PRINT_GENERIC macro in my astgen tool
+string toString(char const *str)
+{
+  if (!str) {
+    return string("(null)");
+  }
+  else {
+    return string(str);
+  }
+}
+
+
+// ------------------- stringf -----------------
+string stringf(char const *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  string ret = vstringf(format, args);
+  va_end(args);
+  return ret;
+}
+
+
+// this should eventually be put someplace more general...
+#ifndef va_copy
+  #ifdef __va_copy
+    #define va_copy(a,b) __va_copy(a,b)
+  #else
+    #define va_copy(a,b) (a)=(b)
+  #endif
+#endif
+
+
+string vstringf(char const *format, va_list args)
+{
+  // estimate string length
+  va_list args2;
+  va_copy(args2, args);
+  int est = vnprintf(format, args2);
+  va_end(args2);
+
+  // allocate space
+  Array<char> buf(est+1);
+
+  // render the string
+  int len = vsprintf(buf, format, args);
+
+  // check the estimate, and fail *hard* if it was low, to avoid any
+  // possibility that this might become exploitable in some context
+  // (do *not* turn this check off in an NDEGUG build)
+  if (len > est) {
+    // don't go through fprintf, etc., because the state of memory
+    // makes that risky
+    static char const msg[] =
+      "fatal error: vnprintf failed to provide a conservative estimate,\n"
+      "memory is most likely corrupted\n";
+    write(2 /*stderr*/, msg, strlen(msg));
+    abort();
+  }
+
+  // happy
+  return string(buf);
+}
+
+
+// ------------------ test code --------------------
+#ifdef TEST_STR
+
+#include <iostream.h>    // cout
+
+void test(unsigned long val)
+{
+  //cout << stringb(val << " in hex: 0x" << stringBuilder::Hex(val)) << endl;
+
+  cout << stringb(val << " in hex: " << SBHex(val)) << endl;
+}
+
+int main()
+{
+  // for the moment I just want to test the hex formatting
+  test(64);
+  test(0xFFFFFFFF);
+  test(0);
+  test((unsigned long)(-1));
+  test(1);
+
+  cout << "stringf: " << stringf("int=%d hex=%X str=%s char=%c float=%f",
+                                 5, 0xAA, "hi", 'f', 3.4) << endl;
+
+  cout << "tests passed\n";
+
+  return 0;
+}
+
+#endif // TEST_STR

Added: vendor/elsa/current/smbase/str.h
===================================================================
--- vendor/elsa/current/smbase/str.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/str.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,359 @@
+// str.h            see license.txt for copyright and terms of use
+// a string class
+// the representation uses just one char*, so that a smart compiler
+//   can pass the entire object as a single word
+// Scott McPeak, 1995-2000  This file is public domain.
+
+// 2005-03-01: See string.txt.  The plan is to evolve the class
+// towards compatibility with std::string, such that eventually
+// they will be interchangeable.  So far I have converted only
+// the most problematic constructs, those involving construction,
+// conversion, and internal pointers.
+
+#ifndef STR_H
+#define STR_H
+
+#include "typ.h"         // bool
+#include <iostream.h>	 // istream, ostream
+#include <stdarg.h>      // va_list
+#include <string.h>      // strcmp, etc.
+
+class Flatten;           // flatten.h
+
+// certain unfortunate implementation decisions by some compilers
+// necessitate avoiding the name 'string'
+//
+// 9/19/04: I originally made this definition to work around a problem
+// with Borland C++ 4.5.  It causes a problem when using the new
+// standard library, since the name clashes with std::string.  A
+// simple solution is to remove the #definition and let namespaces do
+// their job.  Since Intel's headers are the only ones that provoke
+// the problem I'll confine it to that case for now.  Eventually I
+// will do the same for gcc.
+//
+// 2005-02-28: Let's try getting rid of this.
+//
+// 2005-03-15: There were some problems on Redhat due to flex-2.5.4a-29.
+//             I have solved them differently, but it is worth noting
+//             that re-enabling this #define also fixed the problem.
+#if 0   //!defined(__INTEL_COMPILER)
+  #define string mystring
+#endif
+
+
+// ------------------------- string ---------------------
+// This is used when I want to call a function in smbase::string
+// that does not exist or has different semantics in std::string.
+// That way for now I can keep using the function, but it is
+// marked as incompatible.
+enum SmbaseStringFunc { SMBASE_STRING_FUNC };
+
+class string {
+public:
+  typedef int size_type;
+protected:     // data
+  // 10/12/00: switching to never letting s be NULL
+  char *s;     	       	       	       // string contents; never NULL
+  static char * const emptyString;     // a global ""; should never be modified
+
+protected:     // funcs
+  void dup(char const *source);        // copies, doesn't dealloc first
+  void kill();                         // dealloc if str != 0
+
+public:	       // funcs
+  string(string const &src) { dup(src.s); }
+  string(char const *src) { dup(src); }
+  string() { s=emptyString; }
+  ~string() { kill(); }
+
+  // for this one, use ::substring instead
+  string(char const *src, int length, SmbaseStringFunc);
+
+  // for this one, there are two alternatives:
+  //   - stringBuilder has nearly the same constructor interface
+  //     as string had, but cannot export a char* for writing
+  //     (for the same reason string can't anymore); operator[] must
+  //     be used
+  //   - Array<char> is very flexible, but remember to add 1 to
+  //     the length passed to its constructor!
+  string(int length, SmbaseStringFunc) { s=emptyString; setlength(length); }
+
+  string(Flatten&);
+  void xfer(Flatten &flat);
+
+  // simple queries
+  int length() const;  	       	// returns number of non-null chars in the string; length of "" is 0
+  bool isempty() const { return s[0]==0; }
+  bool contains(char c) const;
+
+  // std::string has this instead; I will begin using slowly
+  bool empty() const { return isempty(); }
+
+  // array-like access
+  char& operator[] (int i) { return s[i]; }
+  char operator[] (int i) const { return s[i]; }
+
+  // substring
+  string substring(int startIndex, int length) const;
+
+  // conversions
+  #if 0    // removing these for more standard compliace
+    //operator char* () { return s; }      // ambiguities...
+    operator char const* () const { return s; }
+    char *pchar() { return s; }
+    char const *pcharc() const { return s; }
+  #else
+    char const *c_str() const { return s; }
+  #endif
+
+  // assignment
+  string& operator=(string const &src)
+    { if (&src != this) { kill(); dup(src.s); } return *this; }
+  string& operator=(char const *src)
+    { if (src != s) { kill(); dup(src); } return *this; }
+
+  // allocate 'newlen' + 1 bytes (for null); initial contents is ""
+  string& setlength(int newlen);
+
+  // comparison; return value has same meaning as strcmp's return value:
+  //   <0   if   *this < src
+  //   0    if   *this == src
+  //   >0   if   *this > src
+  int compareTo(string const &src) const;
+  int compareTo(char const *src) const;
+  bool equals(char const *src) const { return compareTo(src) == 0; }
+  bool equals(string const &src) const { return compareTo(src) == 0; }
+
+  #define MAKEOP(op)							       	 \
+    bool operator op (string const &src) const { return compareTo(src) op 0; }	 \
+    /*bool operator op (const char *src) const { return compareTo(src) op 0; }*/ \
+    /* killed stuff with char* because compilers are too flaky; use compareTo */
+  MAKEOP(==)  MAKEOP(!=)
+  MAKEOP(>=)  MAKEOP(>)
+  MAKEOP(<=)  MAKEOP(<)
+  #undef MAKEOP
+
+  // concatenation (properly handles string growth)
+  // uses '&' instead of '+' to avoid char* coercion problems
+  string operator& (string const &tail) const;
+  string& operator&= (string const &tail);
+
+  // input/output
+  friend istream& operator>> (istream &is, string &obj)
+    { obj.readline(is); return is; }
+  friend ostream& operator<< (ostream &os, string const &obj)
+    { obj.write(os); return os; }
+
+  // note: the read* functions are currently implemented in a fairly
+  // inefficient manner (one char at a time)
+
+  void readdelim(istream &is, char const *delim);
+    // read from is until any character in delim is encountered; consumes that
+    // character, but does not put it into the string; if delim is null or
+    // empty, reads until EOF
+
+  void readall(istream &is) { readdelim(is, NULL); }
+    // read all remaining chars of is into this
+
+  void readline(istream &is) { readdelim(is, "\n"); }
+    // read a line from input stream; consumes the \n, but doesn't put it into
+    // the string
+
+  void write(ostream &os) const;
+    // writes all stored characters (but not '\0')
+
+  // debugging
+  void selfCheck() const;
+    // fail an assertion if there is a problem
+};
+
+// ------------------------ rostring ----------------------
+// My plan is to use this in places I currently use 'char const *'.
+typedef string const &rostring;
+
+// I have the modest hope that the transition to 'rostring' might be
+// reversible, so this function converts to 'char const *' but with a
+// syntax that could just as easily apply to 'char const *' itself
+// (and in that case would be the identity function).
+inline char const *toCStr(rostring s) { return s.c_str(); }
+
+// at the moment, if I do this it is a mistake, so catch it; this
+// function is not implemented anywhere
+void/*unusable*/ toCStr(char const *s);
+
+// I need some compatibility functions
+inline int strlen(rostring s) { return s.length(); }
+
+inline istream &getline(istream &in, string &line) { line.readline(in); return in; }
+
+int strcmp(rostring s1, rostring s2);
+int strcmp(rostring s1, char const *s2);
+int strcmp(char const *s1, rostring s2);
+// string.h, above, provides:
+// int strcmp(char const *s1, char const *s2);
+
+// dsw: this is what we are asking most of the time so let's special
+// case it
+inline bool streq(rostring s1, rostring s2)       {return strcmp(s1, s2) == 0;}
+inline bool streq(rostring s1, char const *s2)    {return strcmp(s1, s2) == 0;}
+inline bool streq(char const *s1, rostring s2)    {return strcmp(s1, s2) == 0;}
+inline bool streq(char const *s1, char const *s2) {return strcmp(s1, s2) == 0;}
+
+char const *strstr(rostring haystack, char const *needle);
+
+// there is no wrapper for 'strchr'; use string::contains
+
+int atoi(rostring s);
+
+// construct a string out of characters from 'p' up to 'p+n-1',
+// inclusive; resulting string length is 'n'
+string substring(char const *p, int n);
+inline string substring(rostring p, int n)
+  { return substring(p.c_str(), n); }
+
+
+// --------------------- stringBuilder --------------------
+// this class is specifically for appending lots of things
+class stringBuilder : public string {
+protected:
+  enum { EXTRA_SPACE = 30 };    // extra space allocated in some situations
+  char *end;          // current end of the string (points to the NUL character)
+  int size;           // amount of space (in bytes) allocated starting at 's'
+
+protected:
+  void init(int initSize);
+  void dup(char const *src);
+
+public:
+  stringBuilder(int length=0);    // creates an empty string
+  stringBuilder(char const *str);
+  stringBuilder(char const *str, int length);
+  stringBuilder(string const &str) { dup(str.c_str()); }
+  stringBuilder(stringBuilder const &obj) { dup(obj.c_str()); }
+  ~stringBuilder() {}
+
+  stringBuilder& operator= (char const *src);
+  stringBuilder& operator= (string const &s) { return operator= (s.c_str()); }
+  stringBuilder& operator= (stringBuilder const &s) { return operator= (s.c_str()); }
+
+  int length() const { return end-s; }
+  bool isempty() const { return length()==0; }
+
+  // unlike 'string' above, I will allow stringBuilder to convert to
+  // char const * so I can continue to use 'stringc' to build strings
+  // for functions that accept char const *; this should not conflict
+  // with std::string, since I am explicitly using a different class
+  // (namely stringBuilder) when I use this functionality
+  operator char const * () const { return c_str(); }
+
+  stringBuilder& setlength(int newlen);    // change length, forget current data
+
+  // make sure we can store 'someLength' non-null chars; grow if necessary
+  void ensure(int someLength) { if (someLength >= size) { grow(someLength); } }
+
+  // std::string compatibility name for ensure()
+  void reserve(int someLength) { ensure(someLength); }
+
+  // grow the string's length (retaining data); make sure it can hold at least
+  // 'newMinLength' non-null chars
+  void grow(int newMinLength);
+
+  // this can be useful if you modify the string contents directly..
+  // it's not really the intent of this class, though
+  void adjustend(char* newend);
+
+  // remove characters from the end of the string; 'newLength' must
+  // be at least 0, and less than or equal to current length
+  void truncate(int newLength);
+
+  // make the string be the empty string, but don't change the
+  // allocated space
+  void clear() { adjustend(s); }
+
+  // concatenation, which is the purpose of this class
+  stringBuilder& operator&= (char const *tail);
+
+  // useful for appending substrings or strings with NUL in them
+  void append(char const *tail, int length);
+
+  // append a given number of spaces; meant for contexts where we're
+  // building a multi-line string; returns '*this'
+  stringBuilder& indent(int amt);
+
+  // sort of a mixture of Java compositing and C++ i/o strstream
+  stringBuilder& operator << (rostring text) { return operator&=(text.c_str()); }
+  stringBuilder& operator << (char const *text) { return operator&=(text); }
+  stringBuilder& operator << (char c);
+  stringBuilder& operator << (unsigned char c) { return operator<<((char)c); }
+  stringBuilder& operator << (long i);
+  stringBuilder& operator << (unsigned long i);
+  stringBuilder& operator << (int i) { return operator<<((long)i); }
+  stringBuilder& operator << (unsigned i) { return operator<<((unsigned long)i); }
+  stringBuilder& operator << (short i) { return operator<<((long)i); }
+  stringBuilder& operator << (unsigned short i) { return operator<<((long)i); }
+  stringBuilder& operator << (double d);
+  stringBuilder& operator << (void *ptr);     // inserts address in hex
+  #ifndef LACKS_BOOL
+    stringBuilder& operator << (bool b) { return operator<<((long)b); }
+  #endif // LACKS_BOOL
+
+  // useful in places where long << expressions make it hard to
+  // know when arguments will be evaluated, but order does matter
+  typedef stringBuilder& (*Manipulator)(stringBuilder &sb);
+  stringBuilder& operator<< (Manipulator manip);
+
+  // work around problems invoking non-const non-member funcs
+  // on temporaries
+  stringBuilder &myself() { return *this; }
+
+  // stream readers
+  friend istream& operator>> (istream &is, stringBuilder &sb)
+    { sb.readline(is); return is; }
+  void readall(istream &is) { readdelim(is, NULL); }
+  void readline(istream &is) { readdelim(is, "\n"); }
+
+  void readdelim(istream &is, char const *delim);
+
+  // an experiment: hex formatting (something I've sometimes done by resorting
+  // to sprintf in the past)
+  class Hex {
+  public:
+    unsigned long value;
+
+    Hex(unsigned long v) : value(v) {}
+    Hex(Hex const &obj) : value(obj.value) {}
+  };
+  stringBuilder& operator<< (Hex const &h);
+  #define SBHex stringBuilder::Hex
+};
+
+
+// ---------------------- misc utils ------------------------
+// the real strength of this entire module: construct strings in-place
+// using the same syntax as C++ iostreams.  e.g.:
+//   puts(stringb("x=" << x << ", y=" << y));
+#define stringb(expr) (stringBuilder().myself() << expr)
+
+// experimenting with dropping the () in favor of <<
+// (the "c" can be interpreted as "constructor", or maybe just
+// the successor to "b" above)
+#define stringc (stringBuilder().myself())
+
+
+// experimenting with using toString as a general method for datatypes
+string toString(int i);
+string toString(unsigned i);
+string toString(char c);
+string toString(long i);
+string toString(char const *str);
+string toString(float f);
+
+
+// printf-like construction of a string; often very convenient, since
+// you can use any of the formatting characters (like %X) that your
+// libc's sprintf knows about
+string stringf(char const *format, ...);
+string vstringf(char const *format, va_list args);
+
+
+#endif // STR_H

Added: vendor/elsa/current/smbase/strdict.cc
===================================================================
--- vendor/elsa/current/smbase/strdict.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strdict.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,483 @@
+// strdict.cc            see license.txt for copyright and terms of use
+// code for strdict.h
+
+#include "strdict.h"        // this module
+#include <string.h>         // strcmp
+
+
+#define FOREACH_NODE(itervar) \
+  for(Node *itervar = top; itervar != NULL; itervar = itervar->next)
+
+#define FOREACH_ITER(dict, itervar) \
+  for(Iter itervar = (dict).getIter(); !itervar.isDone(); itervar.next())
+
+#define FOREACH_ITERC(dict, itervar) \
+  for(IterC itervar = (dict).getIterC(); !itervar.isDone(); itervar.next())
+
+#define MUTABLE_SORT(obj) (const_cast<StringDict&>(obj)).sort()
+
+
+StringDict::StringDict()
+  : top(NULL)
+{}
+
+
+StringDict::StringDict(StringDict const &obj)
+  : top(NULL)
+{
+  *this = obj;
+}
+
+
+StringDict::~StringDict()
+{
+  SELFCHECK();
+  empty();
+}
+
+
+StringDict& StringDict::operator= (StringDict const &obj)
+{
+  if (this == &obj) {
+    return *this;
+  }
+
+  empty();
+
+  Node *end = top;
+  FOREACH_ITERC(obj, src) {
+    Node *newnode = new Node(src.key().c_str(), src.value().c_str());
+    if (!end) {
+      // first element of list
+      end = top = newnode;
+    }
+    else {
+      // adding to end of nonempty list
+      end = end->next = newnode;
+    }
+  }
+
+  SELFCHECK();
+  return *this;
+}
+
+
+bool StringDict::operator== (StringDict const &obj) const
+{
+  // sort both lists
+  MUTABLE_SORT(*this);
+  MUTABLE_SORT(obj);
+
+  IterC ths(*this), other(obj);
+  while (!ths.isDone() && !other.isDone()) {
+    if (0!=strcmp(ths.key(), other.key()) ||
+        0!=strcmp(ths.value(), other.value())) {
+      return false;
+    }
+    ths.next();
+    other.next();
+  }
+
+  if (!ths.isDone() || !other.isDone()) {
+    // one finished first, so they can't be equal
+    return false;
+  }
+
+  return true;
+}
+
+
+bool StringDict::isEmpty() const
+{
+  return top == NULL;
+}
+
+
+int StringDict::size() const
+{
+  int ret=0;
+  FOREACH_ITERC(*this, entry) {
+    ret++;
+  }
+  return ret;
+}
+
+
+bool StringDict::query(char const *key, string &value) const
+{
+  FOREACH_ITERC(*this, entry) {
+    if (0==strcmp(entry.key(), key)) {
+      value = entry.value();
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+string StringDict::queryf(char const *key) const
+{
+  string ret;
+  bool ok = query(key, ret);
+  xassert(ok);
+  return ret;
+}
+
+
+bool StringDict::isMapped(char const *key) const
+{
+  string dummy;
+  return query(key, dummy);
+}
+
+
+void StringDict::add(char const *key, char const *value)
+{
+  xassert(!isMapped(key));
+
+  // just prepend; we'll sort later (when an iterator is retrieved)
+  top = new Node(key, value, top);
+
+  SELFCHECK();
+}
+
+
+void StringDict::modify(char const *key, char const *newValue)
+{
+  Iter entry = find(key);
+  xassert(!entry.isDone());
+
+  entry.value() = newValue;
+
+  SELFCHECK();
+}
+
+
+void StringDict::addOrModify(char const *key, char const *newValue)
+{
+  if (!isMapped(key)) {
+    add(key, newValue);
+  }
+  else {
+    modify(key, newValue);
+  }
+}
+
+
+StringDict::Iter StringDict::find(char const *key)
+{
+  FOREACH_ITER(*this, entry) {
+    if (0==strcmp(entry.key(), key)) {
+      return entry;
+    }
+  }
+  return Iter(NULL);
+}
+
+
+void StringDict::remove(char const *key)
+{
+  xassert(top);
+
+  // check for removal of top element
+  if (0==strcmp(top->key, key)) {
+    Node *temp = top;
+    top = top->next;
+    delete temp;
+  }
+
+  // find node to remove in tail of list
+  else {
+    Node *p = top;
+    while (p->next && 0!=strcmp(p->next->key, key)) {
+      p = p->next;
+    }
+
+    if (!p->next) {
+      // reached the end of the list without finding the key
+      xfailure("failed to find key");
+    }
+
+    // remove p->next from the list
+    Node *temp = p->next;
+    p->next = p->next->next;
+    delete temp;
+  }
+
+  SELFCHECK();
+}
+
+
+void StringDict::empty()
+{
+  while (top) {
+    Node *temp = top;
+    top = top->next;
+    delete temp;
+  }
+
+  SELFCHECK();
+}
+
+
+StringDict::Iter StringDict::getIter()
+{
+  sort();        // must return items in sorted order
+  return Iter(top);
+}
+
+
+StringDict::IterC StringDict::getIterC() const
+{
+  //sort();
+  const_cast<StringDict*>(this)->sort();    // mutable
+  return IterC(top);
+}
+
+
+// use simple insertion sort for now
+/*mutable*/ void StringDict::sort()
+{
+  if (!top) {
+    return;
+  }
+
+  // invariant: sequence of nodes from 'top' to 'walker', inclusive,
+  //            is always sorted
+  Node *walker = top;
+  while (walker->next != NULL) {
+    // see if walker->next is out of order
+    if (0 <= strcmp(walker->key, walker->next->key)) {
+      // it's in order
+      walker = walker->next;
+      continue;
+    }
+
+    // remove walker->next from where it is (note that this has
+    // the effect of advancing walker, so below here we won't
+    // have another movement of walker)
+    Node *mover = walker->next;
+    walker->next = walker->next->next;
+    mover->next = NULL;       // (redundant because of (**) lines)
+
+    // insert at head?
+    if (0 < strcmp(mover->key, top->key)) {
+      mover->next = top;            // (**)
+      top = mover;
+      continue;
+    }
+
+    // must find correct place to insert mover (will find the place
+    // where we can insert mover just before searcher->next)
+    Node *searcher = top;
+    while (0 < strcmp(searcher->next->key, mover->key)) {
+      searcher = searcher->next;
+      xassert(searcher != walker);
+        // otherwise how could mover have been out of order to begin with?
+    }
+
+    // insert mover before searcher->next
+    mover->next = searcher->next;   // (**)
+    searcher->next = mover;
+  }
+
+  SELFCHECK();
+
+  #ifndef NDEBUG
+    verifySorted();
+  #endif
+}
+
+
+void StringDict::verifySorted() const
+{
+  if (!top) {
+    return;
+  }
+
+  Node *p = top;
+  while (p->next) {
+    xassert(0 <= strcmp(p->key, p->next->key));
+    p = p->next;
+  }
+}
+
+
+// verify that the list is well structured
+void StringDict::selfCheck() const
+{
+  Node *fast = top, *slow = top;
+  while (fast && fast->next) {
+    fast = fast->next->next;
+    slow = slow->next;
+
+    xassert(fast != slow);
+      // if these become equal, the list is circular
+  }
+}
+
+
+void StringDict::insertOstream(ostream &os) const
+{
+  FOREACH_ITERC(*this, entry) {
+    os << entry.key() << " = " << entry.value() << endl;
+  }
+}
+
+
+string StringDict::toString() const
+{
+  stringBuilder sb;
+  sb << "{";
+  int count=0;
+  FOREACH_ITERC(*this, entry) {
+    if (count++ > 0) {
+      sb << ",";
+    }
+    sb << " " << entry.key() << "=\"" << entry.value() << "\"";
+  }
+  sb << " }";
+  return sb;
+}
+
+
+// -------------------- test code ------------------------
+#ifdef TEST_STRDICT
+
+#include "test.h"      // USUAL_MAIN
+#include <stdlib.h>    // rand
+
+#define myrandom(n) (rand()%(n))
+
+char randChar()
+{
+  return (char)(myrandom(127-32+1)+32);
+}
+
+string randString(int len)
+{
+  stringBuilder str;
+  loopj(len) {
+    str << randChar();
+  }
+  return str;
+}
+
+string randStringRandLen(int maxlen)
+{
+  return randString(myrandom(maxlen)+1);
+}
+
+string randKey(StringDict const &dict)
+{
+  int size = dict.size();
+  xassert(size > 0);
+
+  int nth = myrandom(size);
+  StringDict::IterC entry(dict);
+  for (; nth > 0; entry.next(), nth--)
+    {}
+
+  return entry.key();
+}
+
+
+void entry()
+{
+  StringDict dict;
+  int size=0, collisions=0;
+
+  int iters = 1000;
+  loopi(iters) {
+    switch (myrandom(6)) {
+      case 0: {
+        // insert a random element
+        string key = randStringRandLen(10);
+        string value = randStringRandLen(30);
+
+        if (!dict.isMapped(key.c_str())) {
+          dict.add(key.c_str(), value.c_str());
+          size++;
+        }
+        else {
+          collisions++;
+        }
+        break;
+      }
+
+      case 1: {
+        // remove a random element
+        if (dict.isEmpty()) {
+          break;
+        }
+
+        string key = randKey(dict);
+        dict.remove(key.c_str());
+        size--;
+        break;
+      }
+
+      case 2: {
+        // check a random element that should not be there
+        string key = randStringRandLen(10);
+        if (dict.isMapped(key.c_str())) {
+          collisions++;
+        }
+        break;
+      }
+
+      case 3: {
+        // verify that computed length is right
+        xassert(size == dict.size());
+        break;
+      }
+
+      case 4: {
+        // test == and =
+        StringDict dict2(dict);
+        xassert(dict2 == dict);
+        xassert(dict2.size() == dict.size());
+
+        // modify it, then verify inequality
+        if (!dict2.isEmpty()) {
+          string key = randKey(dict2);
+          string value = dict2.queryf(key.c_str());
+
+          if (myrandom(2) == 0) {
+            dict2.remove(key.c_str());
+          }
+          else {
+            dict2.modify(key.c_str(), stringc << value << "x");
+          }
+          xassert(dict2 != dict);
+        }
+
+        break;
+      }
+
+      case 5: {
+        // random modification
+        if (!dict.isEmpty()) {
+          string key = randKey(dict);
+          dict.modify(key.c_str(), randStringRandLen(30).c_str());
+        }
+        break;
+      }
+
+      default:
+        xfailure("huh?");
+        break;
+    }
+  }
+
+  cout << "final size: " << size
+       << "\ncollisions: " << collisions
+       << "\n";
+
+  cout << "all tests passed\n";
+}
+
+USUAL_MAIN
+
+#endif // TEST_STRDICT

Added: vendor/elsa/current/smbase/strdict.h
===================================================================
--- vendor/elsa/current/smbase/strdict.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strdict.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,148 @@
+// strdict.h            see license.txt for copyright and terms of use
+// string dictionary
+// (c) Scott McPeak, 2000
+
+// entire module is case sensitive
+
+#ifndef __STRDICT_H
+#define __STRDICT_H
+
+#include <iostream.h>   // ostream
+#include "str.h"        // string
+#include "macros.h"     // DMEMB
+#include "xassert.h"    // xassert
+#include "typ.h"        // MUTABLE
+
+class StringDict {
+private:    // types
+  class Node {
+  public:
+    Node *next;
+    string key, value;
+
+  public:
+    Node(char const *k, char const *v, Node *n = NULL)
+      : next(n), key(k), value(v) {}
+    ~Node() {}
+  };
+
+public:     // types
+  // Note: some care must be taken when dealing with Iters, because
+  //       they can be invalidated when held across modifications to
+  //       structure of the underlying dictionary
+  class Iter {
+  private:
+    Node *current;
+
+  public:
+    Iter(Node *n) : current(n) {}
+    Iter(StringDict &dict) { operator=(dict.getIter()); }
+    Iter(Iter const &obj) : DMEMB(current) {}
+    Iter& operator= (Iter const &obj) { CMEMB(current); return *this; }
+
+    bool isDone() const { return current == NULL; }
+    Iter& next() { xassert(current); current = current->next; return *this; }
+      // 'next' returns a value primarily to allow use in for-loop comma exprs
+
+    string& key() const { return current->key; }
+    string& value() const { return current->value; }
+  };
+  friend class Iter;
+
+  // iterator that can't modify the dictionary entries
+  class IterC : protected Iter {
+  public:
+    IterC(Node const *n) : Iter(const_cast<Node*>(n)) {}
+    IterC(StringDict const &dict) : Iter(const_cast<StringDict&>(dict)) {}
+    IterC(IterC const &obj) : Iter(obj) {}
+    IterC& operator= (IterC const &obj) { Iter::operator=(obj); return *this; }
+
+    // some operations can be made available unchanged
+    Iter::isDone;
+    Iter::next;
+
+    // others must be const-ified
+    string const &key() const { return Iter::key(); }
+    string const &value() const { return Iter::value(); }
+  };
+
+private:    // data
+  Node *top;             // first list node (possibly NULL)
+
+protected:  // funcs
+  void selfCheck() const;      // throw exception if invariants violated
+
+  void verifySorted() const;   // throw exception if list isn't sorted
+
+  void /*mutable*/ sort();     // arrange nodes in alphabetically sorted order
+    // (mutable because this isn't supposed to be visible from the outside)
+
+  // invariants:
+  //   list is well-formed structurally
+
+public:
+  StringDict();          // initializes to empty dictionary
+  StringDict(StringDict const &obj);
+  ~StringDict();
+
+  StringDict& operator= (StringDict const &obj);
+
+  bool operator== (StringDict const &obj) const;
+  NOTEQUAL_OPERATOR(StringDict)
+
+  // ------- selectors ---------
+  int size() const;
+    // retrieve # of mappings
+
+  bool isEmpty() const;
+    // returns true if size() is 0
+
+  bool isNotEmpty() const
+    { return !isEmpty(); }
+
+  bool query(char const *key, string &value) const;
+    // if 'key' is mapped to a value, put it into 'value' and return true;
+    // otherwise, return false
+
+  string queryf(char const *key) const;
+    // return the value corresponding to 'key', or throw an exception of it's
+    // not mapped
+
+  bool isMapped(char const *key) const;
+    // return true if 'key' is mapped to a value
+
+  // -------- mutators -----------
+  void add(char const *key, char const *value);
+    // add a mapping from 'key' to 'value'; 'key' must initially be unmapped
+
+  void modify(char const *key, char const *newValue);
+    // change the existing value for 'key', which must exist, to 'newValue'
+    
+  void addOrModify(char const *key, char const *value);
+    // map 'key' to 'value'; works regardless of any current mapping
+
+  void remove(char const *key);
+    // remove the mapping from 'key', which must exist
+
+  void empty();
+    // remove all mappings
+
+  // --------- iters -------------
+  Iter getIter();
+    // retrieve an iterator (the iterator remains valid only as long as
+    // the structure of the dictionary does not get modified);
+    // values will be iterated in *alphabetical* order
+
+  IterC getIterC() const;
+    // retrieve a const iterator
+
+  Iter find(char const *key);
+    // return an iterator pointing to 'key', or an iterator
+    // that isDone() if 'key' isn't mapped
+
+  // ------------ misc --------------
+  INSERT_OSTREAM(StringDict)
+  string toString() const;
+};
+
+#endif // __STRDICT_H

Added: vendor/elsa/current/smbase/strhash.cc
===================================================================
--- vendor/elsa/current/smbase/strhash.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strhash.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,587 @@
+// strhash.cc            see license.txt for copyright and terms of use
+// code for strhash.h
+
+#include "strhash.h"     // this module
+#include "xassert.h"     // xassert
+
+#include <string.h>      // strcmp
+
+// notes on string hash functions ****************
+
+// We need to test the various hash functions versus each other for
+// randomness.  Scott suggests simply hashing the same data and
+// modding it down as a hashtable would and seeing which gives more
+// collisions.
+
+// Note that both hash functions could be improved if they were aware
+// of how many of their low order bits were really going to be
+// preserved and then taking the high order bits that would otherwise
+// be discarded and xoring or adding them to the low order bits.
+
+// Hash function 2:
+
+// 1) Does not work on architectures other than 32 bit.
+
+// 2) Will not work well or at all if the strings do not start on
+// 32-bit aligned boundaries.
+
+// 3) Could be made to work faster if the strings start AND end on
+// 32-bit aligned boundaries and are padded out with NUL-s.  Actually,
+// if we do this trick, then the code becomes portable with no
+// #ifdef-s !  All you do is cast the array to an array of ints and
+// then test for termination by masking off all but the last 8 bits.
+// Everything else is just operations on ints.  You might want to pick
+// 64-bit primes, but they will work in 32-bit mode as long as the
+// compiler just truncates their high bits off.
+
+// ****************
+
+
+StringHash::StringHash(GetKeyFn gk)
+  : HashTable((HashTable::GetKeyFn)gk,
+              (HashTable::HashFn)coreHash,
+              (HashTable::EqualKeyFn)keyCompare)
+{}
+
+StringHash::~StringHash()
+{}
+
+
+STATICDEF unsigned StringHash::coreHash(char const *key)
+{
+  // dsw: not sure if this is the best place for it, but an assertion
+  // failure is better than a segfault
+  //
+  // sm: I don't agree; segfaults arising from NULL derefs are
+  // quite friendly (deref'ing random address is another story).
+  // Anyway, this is fine, but I'd like it to go away in NDEBUG
+  // mode so I'm changing it to use 'xassertdb'.
+  xassertdb(key);
+
+  // some more references:
+
+  // http://www.cs.yorku.ca/~oz/hash.html
+  //
+  // Describes three well-known hashes: djb2, sdbm, and K&R ed. 1.
+
+  // http://burtleburtle.net/bob/hash/doobs.html
+  //
+  // Describes a particular hash function (called simply "My Hash")
+  // and provides justifications for preferring it to several others,
+  // including MD4.
+
+  // http://www.isthe.com/chongo/tech/comp/fnv/
+  //
+  // Glen Fowler, Landon Curt Noll, and Phong Vo's hash function.
+
+  // http://mail.python.org/pipermail/python-dev/2004-April/044235.html
+  //
+  // Start of a discussion thread about changing the string hash
+  // in Python.
+
+
+
+
+
+
+  #if 0
+  // I pulled this out of my ass.. it's supposed to mimic
+  // a linear congruential random number generator
+  unsigned val = 0x42e9d115;    // arbitrary
+  while (*key != 0) {
+    val *= (unsigned)(*key);
+    val += 1;
+    key++;
+  }
+  return val;
+  #endif // 0
+
+  // pick a default STRHASH_ALG
+  #ifndef STRHASH_ALG
+    #define STRHASH_ALG 1
+  #endif // STRHASH_ALG
+
+
+  #if STRHASH_ALG == 1
+  #ifdef SAY_STRHASH_ALG
+    #warning hash function 1: Nelson
+  #endif // SAY_STRHASH_ALG
+  // this one is supposed to be better
+  /* An excellent string hashing function.
+     Adapted from glib's g_str_hash().
+     Investigation by Karl Nelson <kenelson at ece.ucdavis.edu>.
+     Do a web search for "g_str_hash X31_HASH" if you want to know more. */
+  /* update: this is the same function as that described in Kernighan and Pike,
+     "The Practice of Programming", section 2.9 */
+  unsigned h = 0;
+  for (; *key != '\0'; key += 1) {
+    // original X31_HASH
+    h = ( h << 5 ) - h + *key;       // h*31 + *key
+
+    // dsw: this one is better because it does the multiply last;
+    // otherwise the last byte has no hope of modifying the high order
+    // bits
+    //
+    // sm: I'm not convinced it's better.  For short strings, say less
+    // than 6 characters, the arithmetic won't overflow a 32-bit
+    // register.  In that case, by multiplying last, the hash value is
+    // always a multiple of 31 and hence will suffer many more
+    // collisions.  I would like more justification in the form of
+    // experimental measurements before making a change.
+    //h += *key;
+    //h = ( h << 5 ) - h;         // h *= 31
+  }
+  return h;
+
+
+  #elif STRHASH_ALG == 2
+  #ifdef SAY_STRHASH_ALG
+    #warning hash function 2: word-rotate/final-mix
+  #endif // SAY_STRHASH_ALG
+
+  // FIX:
+  #warning word-rotate/final-mix hash function only works on 32-bit architectures
+  #warning word-rotate/final-mix hash function still needs to be tested for randomness vs nelson
+
+  // Word-Rotate / Final-Mix hash function by Daniel Wilkerson; A
+  // slighly faster and likely more random hash function; Invented in
+  // collaboration with Simon Goldsmith.
+  //
+  // Supposedly gcc will sometimes recognize this and generate a
+  // single rotate instruction 'ROR'.  Thanks to Matt Harren for this.
+  // http://groups.google.com/groups?q=rorl+x86&start=10&hl=en&lr=&ie=UTF-8&oe=UTF-8&
+  // selm=359954C9.3B354F0%40cartsys.com&rnum=11
+  // http://www.privacy.nb.ca/cryptography/archives/coderpunks/new/1998-10/0096.html
+  #define ROTATE(n, b) (n >> b) | (n << (32 - b))
+
+  // Note that UINT_MAX        = 4294967295U;
+  // source of primes: http://www.utm.edu/research/primes/lists/small/small.html
+  static unsigned const primeA = 1500450271U;
+  static unsigned const primeB = 2860486313U;
+  // source of primes: http://www.utm.edu/research/primes/lists/2small/0bit.html
+  static unsigned const primeC = (1U<<31) - 99U;
+  static unsigned const primeD = (1U<<30) - 35U;
+
+  static int count = 0;
+  ++count;
+
+  unsigned h = primeA;
+
+  // Stride a word at a time.  Note that this works best (or works at
+  // all) if the string is 32-bit aligned.  This initial 'if' block is
+  // to prevent an extra unneeded rotate.
+  //
+  // FIX: this would be even faster if all strings were NUL-padded in
+  // length to a multiple of 4; we could then omit all but the last
+  // 'if' and the ragged end after the loop (it doesn't matter if you
+  // tile a few extra NULs into your value).
+  if (!key[0]) goto end0;
+  if (!key[1]) goto end1;
+  if (!key[2]) goto end2;
+  if (!key[3]) goto end3;
+  // No rotate here.
+  h += *( (unsigned *) key );
+  key += 4;
+  while (1) {
+    // invariant: when we get here, we are ready to rotate
+    if (!key[0]) {h = ROTATE(h, 5); goto end0;}
+    if (!key[1]) {h = ROTATE(h, 5); goto end1;}
+    if (!key[2]) {h = ROTATE(h, 5); goto end2;}
+    if (!key[3]) {h = ROTATE(h, 5); goto end3;}
+    h = ROTATE(h, 5);
+    // FIX: if the start of the string is not 4-byte aligned then this
+    // will be slower on x86 and I think even illegal on MIPS and
+    // perhaps others.  To be portable we should ensure this.
+    h += *( (unsigned *) key ); // on my machine plus is faster than xor
+    key += 4;
+  }
+  xfailure("shouldn't get here");
+
+  // deal with the ragged end
+  // invariant: when we get here we are ready to add
+end3:
+  h += *key; h = ROTATE(h, 5); key += 1;
+end2:
+  h += *key; h = ROTATE(h, 5); key += 1;
+end1:
+  h += *key;                    // No rotate nor increment here.
+  #ifndef NDEBUG
+    key += 1;                   // this is only needed for the assertion below
+  #endif
+end0:
+  xassertdb(*key=='\0');
+
+  // I will say for now that the property of hash functions that we
+  // want is that a change in any input bit has a 50% chance of
+  // inverting any output bit.
+  //
+  // At this point, compare this hash function to the Nelson hash
+  // function above.  In Nelson, everytime data is added, the
+  // accumulator, 'h', is "stirred" with a multiplication.  Since data
+  // is being added at the low byte and since multiplication
+  // propagates dependencies towards the high bytes and since after
+  // ever add there is at least one multiply, every byte has a chance
+  // to affect the value of every bit above the first byte.
+  //
+  // However, in this hash function we have saved time by simply
+  // "tiling" the data across the accumulator and at this point it
+  // hasn't been "stirred" at all.  Since most hashvalues are used by
+  // modding off some high bits, those bits have never had a chance to
+  // affect the final value, so some stirring is needed.  How much
+  // "stirring" do we need?
+  //
+  // Consider the 32-bit word in two halves, H and L.
+  //
+  // 1) With a single multiply, any bit of L "has a chance" to affect
+  // any bit in H.  The reverse is not true.
+  h *= primeB;
+
+  // 2) We therefore swap H and L and multiply again.  Now, any bit in
+  // H has had a chance to affect any bit in L.  We are not done
+  // though, since the high order bits in H have not had a chance to
+  // affect the low order bits of H (yes H).  Please note however,
+  // that since L affected H and H affected L, the high order bits of
+  // L *have* had a chance to affect the low order bits of L.
+  h = ROTATE(h, 16);
+  h *= primeC;
+
+  // 3) Therefore we swap H and L and multiply once again.  Now the
+  // high order bits of H have had a chance to affect L (in 2) which
+  // now can affect H again.  Any bit now has "had a chance" to affect
+  // any other bit.
+  h = ROTATE(h, 16);
+  h *= primeD;
+
+  return h;
+
+  #undef ROTATE
+
+
+  #else
+    #error You must pick a hash function
+  #endif // STRHASH_ALG multi-switch
+}
+
+
+STATICDEF bool StringHash::keyCompare(char const *key1, char const *key2)
+{
+  return 0==strcmp(key1, key2);
+}
+
+
+// ---------------------- test code --------------------
+#ifdef TEST_STRHASH
+
+#include <iostream.h>    // cout
+#include <stdlib.h>      // rand
+#include <iostream>      // istream
+#include <fstream>       // filebuf
+#include "trace.h"       // traceProgress
+#include "crc.h"         // crc32
+#include "nonport.h"     // getMilliseconds
+#include "array.h"       // GrowArray
+#include "str.h"         // string
+
+// pair a GrowArray with its size
+struct StringArray {
+  int tableSize;
+  GrowArray<char*> table;
+  bool appendable;
+
+  StringArray(int tableSize0)
+    : tableSize(tableSize0)
+    , table(tableSize)
+    , appendable(tableSize == 0)
+  {}
+  void append(char *str) {
+    xassert(appendable);
+    table.ensureIndexDoubler(tableSize);
+    table[tableSize] = str;
+    ++tableSize;
+  }
+};
+
+// data to hash
+StringArray *dataArray = NULL;
+
+
+char const *id(void *p)
+{
+  return (char const*)p;
+}
+
+char *randomString()
+{
+  char *ret = new char[11];
+  loopi(10) {
+    ret[i] = (rand()%26)+'a';
+  }
+  ret[10]=0;
+  return ret;
+}
+
+// fill a table with random strings
+void makeRandomData(int numRandStrs) {
+  dataArray = new StringArray(numRandStrs);
+  {loopi(dataArray->tableSize) {
+    dataArray->table[i] = randomString();
+  }}
+}
+
+
+// file the data array with whitespace-delimited strings from a file
+void readDataFromFile(char *inFileName) {
+  dataArray = new StringArray(0);
+  char *delim = " \t\n\r\v\f";
+  std::filebuf fb;
+  fb.open (inFileName, ios::in);
+  istream in(&fb);
+  while(true) {
+    stringBuilder s;
+    s.readdelim(in, delim);
+//      cout << ":" << s->pcharc() << ":" << endl;
+    if (in.eof()) break;
+//      // don't insert 0 length strings
+//      if (s->length() == 0) continue;
+    dataArray->append(strdup(s.c_str()));
+  }
+}
+
+void writeData(ostream &out) {
+  cout << "write data" << endl;
+  for(int i=0; i<dataArray->tableSize; ++i) {
+    out << dataArray->table[i] << endl;
+  }
+}
+
+// dsw: what is the point of this?
+// dealloc the test strings
+//  void deleteData() {
+//    {loopi(dataArray->tableSize) {
+//      delete[] dataArray->table[i];
+//    }}
+//  //    delete[] dataArray->table;
+//  }
+
+void correctnessTest() {
+  traceProgress() << "start of strhash correctness testing\n";
+
+  // insert them all into a hash table
+  StringHash hash(id);
+  {loopi(dataArray->tableSize) {
+    hash.add(dataArray->table[i], dataArray->table[i]);
+    hash.selfCheck();
+  }}
+  hash.selfCheck();
+  xassert(hash.getNumEntries() == dataArray->tableSize);
+
+  // verify that they are all mapped properly
+  {loopi(dataArray->tableSize) {
+    xassert(hash.get(dataArray->table[i]) == dataArray->table[i]);
+  }}
+  hash.selfCheck();
+
+  // remove every other one
+  {loopi(dataArray->tableSize) {
+    if (i%2 == 0) {
+      hash.remove(dataArray->table[i]);
+      hash.selfCheck();
+    }
+  }}
+  hash.selfCheck();
+  xassert(hash.getNumEntries() == dataArray->tableSize / 2);
+
+  // verify it
+  {loopi(dataArray->tableSize) {
+    if (i%2 == 0) {
+      xassert(hash.get(dataArray->table[i]) == NULL);
+    }
+    else {
+      xassert(hash.get(dataArray->table[i]) == dataArray->table[i]);
+    }
+  }}
+  hash.selfCheck();
+
+  // remove the rest
+  {loopi(dataArray->tableSize) {
+    if (i%2 == 1) {
+      hash.remove(dataArray->table[i]);
+      hash.selfCheck();
+    }
+  }}
+  hash.selfCheck();
+  xassert(hash.getNumEntries() == 0);
+
+  traceProgress() << "end of strhash correctness testing\n";
+}
+
+void performanceTest(int numPerfRuns) {
+  // test performance of the hash function
+  traceProgress() << "start of strhash performance testing\n";
+
+  long startTime = getMilliseconds();
+  loopj(numPerfRuns) {
+    loopi(dataArray->tableSize) {
+      StringHash::coreHash(dataArray->table[i]);
+      //crc32((unsigned char*)dataArray->table[i], strlen(dataArray->table[i]));
+      //crc32((unsigned char*)dataArray->table[i], 10);
+    }
+  }
+  long stopTime = getMilliseconds();
+  long duration = stopTime - startTime;
+  cout << "milliseconds to hash: " << duration << endl;
+
+  traceProgress() << "end of strhash performance testing\n";
+}
+
+// command-line state
+int numRandStrs = 0;
+char *inFileName = NULL;
+bool dump = false;
+bool testCor = true;
+bool testPerf = true;
+int numPerfRuns = 10000;
+
+void usage() {
+  cout << "Test the string hashing module strhash.cc\n"
+       << "  --help / -h     : print this message\n"
+       << "  --[no-]testCor  : run the correctness tests\n"
+       << "                    will fail if data has duplicate strings (?!)\n"
+       << "  --[no-]testPerf : run the performance tests\n"
+       << "  --numPerfRuns N : loop over data N times during performance run\n"
+       << "  --file FILE     : use the whitespace-delimited string contents of FILE\n"
+       << "  --random N      : use N internally generated random strings of length 10;\n"
+       << "                    N should be even\n"
+       << "  --dump          : dump out the data after generating/reading it\n"
+       << "The default is '--random 300 --testCor --testPerf --numPerfRuns 10000'."
+       << endl;
+}
+
+void initFromFlags(int &argc, char**&argv) {
+  --argc; ++argv;
+  for(;
+      *argv;
+      --argc, ++argv) {
+    if (strcmp(*argv, "--help")==0 || strcmp(*argv, "-h")==0) {
+      usage();
+      exit(0);
+    } else if (strcmp(*argv, "--testCor")==0) {
+      testCor = true;
+    } else if (strcmp(*argv, "--no-testCor")==0) {
+      testCor = false;
+    } else if (strcmp(*argv, "--testPerf")==0) {
+      testPerf = true;
+    } else if (strcmp(*argv, "--no-testPerf")==0) {
+      testPerf = false;
+    } else if (strcmp(*argv, "--random")==0) {
+      if (inFileName) {
+        cout << "do not use --random and --file together" << endl;
+        usage();
+        exit(1);
+      }
+      --argc; ++argv;
+      if (!*argv) {
+        cout << "supply an argument to --random" << endl;
+        usage();
+        exit(1);
+      }
+      numRandStrs = atoi(*argv);
+      if (!(numRandStrs > 0)) {
+        cout << "argument to --random must be > 0" << endl;
+        usage();
+        exit(1);
+      }
+    } else if (strcmp(*argv, "--file")==0) {
+      if (numRandStrs) {
+        cout << "do not use --random and --file together" << endl;
+        usage();
+        exit(1);
+      }
+      --argc; ++argv;
+      if (!*argv) {
+        cout << "supply an argument to --file" << endl;
+        usage();
+        exit(1);
+      }
+      inFileName = strdup(*argv);
+      xassert(inFileName);
+    } else if (strcmp(*argv, "--numPerfRuns")==0) {
+      --argc; ++argv;
+      if (!*argv) {
+        cout << "supply an argument to --numPerfRuns" << endl;
+        usage();
+        exit(1);
+      }
+      numPerfRuns = atoi(*argv);
+      if (!(numPerfRuns > 0)) {
+        cout << "argument to --numPerfRuns must be > 0" << endl;
+        usage();
+        exit(1);
+      }
+    } else if (strcmp(*argv, "--dump")==0) {
+      dump = true;
+    } else {
+      cout << "unrecognized flag " << *argv << endl;
+      usage();
+      exit(1);
+    }
+  }
+}
+
+int main(int argc, char **argv)
+{
+  traceAddSys("progress");
+
+  #if STRHASH_ALG == 1
+    cout << "hash function 1: Nelson" << endl;
+  #elif STRHASH_ALG == 2
+    cout << "hash function 2: word-rotate/final-mix" << endl;
+  #else
+    #error You must pick a hash function
+  #endif // STRHASH_ALG multi-switch
+
+  // read command line flags
+  initFromFlags(argc, argv);
+
+  // read data
+  if ((!inFileName) && (!numRandStrs)) {
+    numRandStrs = 300;          // default
+  }
+  if (numRandStrs % 2 != 0) {
+    cout << "use an even-number argument for --random" << endl;
+    usage();
+    exit(1);
+  }
+  if (numRandStrs) {
+    makeRandomData(numRandStrs);
+  } else if (inFileName) {
+    if (testCor) {
+      cout << "Warning: The correctness test fails if strings are duplicated "
+        "and you are reading data from a file." << endl;
+    }
+    readDataFromFile(inFileName);
+  } else {
+    xfailure("goink?");
+  }
+
+  // dump data
+  if (dump) {
+    writeData(cout);
+  }
+
+  // test
+  if (testCor) {
+    correctnessTest();
+  }
+  if (testPerf) {
+    performanceTest(numPerfRuns);
+  }
+
+  // delete data
+//    deleteData();
+
+  cout << "strhash tests finished\n";
+  return 0;
+}
+
+#endif // TEST_STRHASH

Added: vendor/elsa/current/smbase/strhash.h
===================================================================
--- vendor/elsa/current/smbase/strhash.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strhash.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,81 @@
+// strhash.h            see license.txt for copyright and terms of use
+// hash table mapping strings to arbitrary pointers, where
+// the stored pointers can be used to derive the key, and
+// cannot be NULL
+
+// This module uses 'char const *' instead of 'rostring', because
+// it is at the core of some performance-critical modules (such
+// as StringTable) that don't want extra allocation going on.
+
+#ifndef STRHASH_H
+#define STRHASH_H
+
+#include "hashtbl.h"      // HashTable
+
+class StringHash : private HashTable {
+public:     // types
+  // given a stored data pointer, retrieve the associated key
+  typedef char const* (*GetKeyFn)(void *data);
+
+private:    // funcs
+  // disallowed
+  StringHash(StringHash&);
+  void operator=(StringHash&);
+  void operator==(StringHash&);
+
+public:     // funcs
+  StringHash(GetKeyFn getKey);
+  ~StringHash();
+
+  // utilities
+  static unsigned coreHash(char const *key);
+  static bool keyCompare(char const *key1, char const *key2);
+
+  // return # of mapped entries
+  int getNumEntries() const
+    { return HashTable::getNumEntries(); }
+
+  // if this key has a mapping, return it; otherwise,
+  // return NULL
+  void *get(char const *key) const
+    { return HashTable::get(key); }
+
+  // add a mapping from 'key' to 'value'; there must not already
+  // be a mapping for this key
+  void add(char const *key, void *value)
+    { HashTable::add(key, value); }
+
+  // remove the mapping for 'key' -- it must exist
+  void remove(char const *key)
+    { HashTable::remove(key); }
+
+  // drop all entries
+  void empty() 
+    { HashTable::empty(); }  
+
+  // check the data structure's invariants, and throw an exception
+  // if there is a problem
+  void selfCheck() const
+    { HashTable::selfCheck(); }
+};
+
+
+// type-safe template wrapper          
+template <class T>
+class TStringHash : public StringHash {
+public:      // types
+  typedef char const* (*GetKeyFn)(T *data);
+
+public:
+  TStringHash(GetKeyFn fn)            : StringHash((StringHash::GetKeyFn)fn) {}
+  ~TStringHash()                      {}
+
+  int getNumEntries() const           { return StringHash::getNumEntries(); }
+  T *get(char const *key) const       { return (T*)StringHash::get(key); }
+  void add(char const *key, T *value) { StringHash::add(key, (void*)value); }
+  void remove(char const *key)        { StringHash::remove(key); }
+  void empty()                        { StringHash::empty(); }
+};
+
+
+#endif // STRHASH_H

Added: vendor/elsa/current/smbase/string.txt
===================================================================
--- vendor/elsa/current/smbase/string.txt	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/string.txt	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,294 @@
+string.txt
+This document describes handling of string classes in smbase.
+
+
+
+The 'string' class defined in str.h predates std::string by several
+years.  I find its interface quite satisfactory.
+
+However, as part of the goal of releasing Elsa (etc.) is to let others
+use it in their projects, and std::string is understandably becoming
+quite popular, it must at a minimum be possible to integrate
+smbase-based code with code that uses std::string.
+
+One option is to simply put my string class into its own namespace,
+say smbase::string, or maybe rename it to sm_string or something.  But
+it was never my intent to have more than one notion of 'string' in a
+given code base; I made my own simply because there was nothing else
+at the time.  The programmer should not be forced to choose among
+string classes for routine tasks; a string is a string.
+
+Therefore my plan is to evolve my string (hereafter: smbase::string,
+even though it is not actually in a namespace at the moment) towards
+interface compatibility with std::string.  The ideal end state is that
+one could simply choose at compile-time which implementation to use,
+and all the client code would work, and the only difference (if any)
+would be performance.
+
+In other words, make smbase::string a subset of std::string.
+
+
+Now, that is all well and good, but there is one major problem:
+std::string does not implicitly convert to 'char const *', whereas
+smbase::string does (or used to), and a great deal of my code relies
+on this conversion.
+
+My general approach had been to use parameters of type 'char const *'
+whenever a function was (1) not going to modify the string, and (2)
+not going to let the pointer escape (say, into the heap).  This worked
+well because it was both efficient and convenient; code that needed to
+store strings used 'string' and code that needed to temporarily use a
+string used 'char const *', and both could be passed to C library
+functions.
+
+But since std::string cannot be implicitly converted to char const *,
+this strategy will not work, as it would require lots of explicit
+conversions (calls to c_str) that would clutter up the code.
+
+The main alternative is to push 'string' into interfaces further down
+in the subsystem hierarchy, closer to the C library.  The main problem
+with that is it entails either making the parameter types be 'string',
+which incurs an extra pair of calls to malloc and free each time it is
+passed down, or make the type 'string const &', which is unwieldy.
+
+Actually, many implementations of std::string, including the one in
+gcc's C++ library, use a copy-on-write strategy that would avoid the
+calls to malloc and free.  But the price is a significant storage
+overhead for each string (4 extra words for gcc), plus potential
+problems in multithreaded code.  While in general I think
+copy-on-write is a good idea, I do not want to adopt a style of code
+that will force me to use copy-on-write to get decent performance.
+Moreover, the cost I am *really* concerned about is allocations when
+there previously were none; the gap between 1 allocation and 2 is
+small compared to the gap between 0 and 1; and copy-and-write is of
+no help for eliminating that first allocation.
+
+
+My (straightforward) idea is to use the following 'rostring':
+         
+  // str.h
+  typedef string const &rostring;
+  
+This type, normally used as a function parameter type, conveys both 
+(1) that the user promises not to modify the string, and also 
+(2) that the address of the object passed will *not* "escape", i.e.
+be stored in the heap or a global after the function returns.  These
+semantics have always been associated with my use of 'char const *'
+in parameters, but now they have their own name, and this name is
+much easier to type than 'string const &'.
+
+I think this approach provides a reasonable compromise.  It lets
+me pass strings down efficiently and soundly, and I can create
+string objects implicitly from char ptrs.  The only problem is
+I cannot implicitly convert *to* char ptrs, so some conversion
+is necessary.
+
+It is my hope that the conversion can be done in such a way that it
+would be possible to change the definition of 'rostring' *back* to
+'char const *', without breaking too much stuff.  The reason I want
+that property is to give me a path to undo the changes, or perhaps use
+yet another definition for 'rostring', should that become necessary.
+It is also consistent with the limited intended purposes of
+'rostring'.
+
+
+Transition guide for new string interface:
+
+  - Replace non-performance-critical uses of
+      char const *
+    as function parameters with
+      rostring
+    which is a typedef for 'string const &'.
+
+    What is performance critical?  Mainly, uses of strings as keys
+    in hash tables.  In that case, the string data is often coming
+    from a lexer, which must *not* be required to allocate a copy
+    just to talk to the hash table.
+
+    Non-performance-critical uses include debugging info, error
+    messages, etc.
+    
+    If an interface is both performance-critical and also heavily
+    used with constructed strings (obviously not on the same code
+    paths), then it is reasonable to overload the function to
+    accept both 'char const *' and 'rostring'.  However, I do not
+    want to do this for lots of functions; generally, any given
+    interface should either be classified as above or below the
+    boundary line between 'rostring' and 'char const *', and all
+    its functions should consistently use one or the other (with
+    only well-motivated exceptions).
+    
+    See also the discussion below.
+
+  - Be careful when converting code to use 'rostring':
+    - It is usually *not* a good idea to change the types of local 
+      variables to 'rostring'.
+    - It will certainly not work to change 'char const *&' to 
+      'rostring&', since the latter will be an invalid type.
+    - Watch out for return types; if the function is returning a
+      locally-constructed string, a return type of 'rostring' will
+      be death.
+    - If the 'char const *' was *nullable*, then you should not
+      convert it to rostring, since the latter cannot accept a NULL
+      pointer.  One solution is to overload the function to accept
+      either a nullable 'char const *' or an rostring.  Another is
+      to change call sites (or default args) to pass "" instead.
+
+  - To convert an rostring to a char const*, use
+      char const *toCStr(rostring s);
+    instead of
+      char const *string::c_str() const;
+    to maintain the vague hope that 'rostring' could at some point
+    be yet some other type (perhaps even 'char const *' again).
+    For example:
+    
+      void foo(rostring s)
+      {
+        FILE *fp = fopen(toCStr(s), "r");       // yes
+        FILE *fp = fopen(s.c_str(), "r");       // no
+        ...
+      }
+
+  - One exception to the above: if an 'rostring' is being converted
+    to 'char const *' because the former is a parameter of an overloaded
+    function that just calls into another version which accepts the
+    latter, then use c_str() instead.  This makes it clear that the
+    'rostring' is really being treated as 'string const &', not simply
+    "something vaguely similar to char const *".  For example:
+    
+      int foo(char const *s);                        // real function
+      int foo(rostring s) { return foo(s.c_str()); } // yes
+      int foo(rostring s) { return foo(toCStr(s)); } // no
+
+  - To convert a string (other than 'rostring') to a char const*, use
+      char const *string::c_str() const;
+    instead of
+      char const *string::pcharc() const;
+    as the latter is gratuitously nonstandard and has been deleted.
+
+  - Replace uses of
+      string::string(char const *src, int length);
+    with
+      string substring(char const *p, int n);
+    since the former has different semantics in smbase than in std.
+
+  - The old string class allowed code to create a string with
+      string::string(int length)
+    and then modify the string with
+      char *pchar();
+    and
+      char operator[] (int i) const;
+    If the latter function (operator[]) is all that is needed,
+    use stringBuilder instead.  If the former is needed, use
+    Array<char> instead, but remember to explicitly allocate
+    one extra byte for the NUL terminator.
+    
+  - To convert code that iteratively scans a 'char const *', such as
+      void foo(char const *src)
+      {
+        while (*src) {
+          // ... do work ...
+          src++;
+        }
+      }
+    use something like the following:
+      void foo(rostring origSrc)
+      {                      
+        char const *src = toCStr(origSrc);
+
+        while (*src) {
+          // ... do work ...
+          src++;
+        }
+      }
+    Rename the *parameter*, and bind a local variable to the pointer
+    under the original name, so preserve semantic equivalence.
+
+  - If the code is testing a previously 'char const *' value against
+    NULL, e.g.
+      if (name) { ... }
+    then, assuming the caller has been appropriately modified to
+    pass an empty ("") rostring instead, change the test to
+      if (name[0]) { ... }
+    as this is a little less verbose than name.empty(), and will
+    work even if name is changed back to 'char const *'.
+
+
+
+The question arises as to exactly where the line should be drawn
+between code that nominally uses 'rostring' and code that nominally
+uses 'char const *'.  As with most issues of language/API design, it
+is a matter of balancing convenience and performance.
+
+Basically, there are three sources of strings in a typical program:
+
+  - Static strings in the program text.
+
+    The transition to 'rostring' may cause some static strings to
+    be malloc'd where they were not malloc'd before.  However, there
+    are very few such strings (generally less than 10000), so if
+    malloc'ing such strings ever becomes a performance problem it
+    must be that some strings are being malloc'd multiple times.
+    But that is easy to fix, e.g., by changing
+
+      foo("hi there")
+      
+    to
+    
+      static const string hi_there("hi there");
+      foo(hi_there)
+      
+    unwieldy though it may be.  (This should not be needed often.)
+
+  - Constructed strings.
+  
+    Constructing strings, like
+
+      stringc << "hello" << ' ' << "world!"
+
+    requires lots of allocation, and the result is a 'string'.
+    Passing this to an 'rostring' won't incur any penalty.
+    
+  - Strings in program input data.
+  
+    These are the strings I am worried about.  In the 'char const *'
+    regime, these strings are typically first read into an I/O
+    buffer first.  From there, the strings are either processed
+    in-place and discarded, or else copied to a more permanent
+    storage location, but not copied again.
+    
+    It would be very bad for performance if the transition to
+    'rostring' caused processing of such strings (and there are
+    lots of them) to incur additional allocation.  That is why I
+    want to keep string table interfaces (etc.) capable of accepting
+    raw 'char const *' pointers: it ought to be possible to do all
+    the processing on input data strings without them taking any
+    trips through the allocator.
+    
+So the principles I advocate are:
+
+  (1) Make sure input data strings don't have to make extra trips
+      through the allocator.  This means exposing interfaces capable
+      of accepting 'char const *' in key places like hash tables.
+
+  (2) Make sure static strings and constructed strings can be used
+      as conveniently as possible; for the latter, that means accepting
+      'rostring' in most places.
+
+  (3) Avoid polluting interfaces with duplicates interfaces just to
+      meet (1) and (2); clutter is a big long-term problem.
+
+One more thing I have been doing is if the interface did not have any
+reason to #include str.h under the old 'char const *' regime, for
+example autofile.h, then it may be best to stick with 'char const *'
+in the interest of minimizing dependencies.  (This is debatable.)
+
+
+
+
+
+
+
+
+
+EOF

Added: vendor/elsa/current/smbase/stringset.cc
===================================================================
--- vendor/elsa/current/smbase/stringset.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/stringset.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,22 @@
+// stringset.cc            see license.txt for copyright and terms of use
+// code for stringset.h
+
+#include "stringset.h"        // this module
+
+StringSet::~StringSet()
+{}
+
+void StringSet::add(char const *elt)
+{
+  if (!contains(elt)) {
+    elts.add(elt, NULL);
+  }
+}
+
+void StringSet::remove(char const *elt)
+{
+  if (contains(elt)) {
+    elts.remove(elt);
+  }
+}
+

Added: vendor/elsa/current/smbase/stringset.h
===================================================================
--- vendor/elsa/current/smbase/stringset.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/stringset.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,83 @@
+// stringset.h            see license.txt for copyright and terms of use
+// set of character strings
+
+#ifndef STRINGSET_H
+#define STRINGSET_H
+
+#include "strsobjdict.h"       // StringSObjDict
+
+class StringSet {
+private:     // data        
+  // represent using a dictionary of pointers to nothing
+  StringSObjDict<int> elts;
+  
+public:      // funcs
+  StringSet() : elts() {}
+  ~StringSet();
+
+  // external iterator
+  class Iter {
+  private:
+    StringSObjDict<int>::Iter iter;
+
+  public:
+    Iter(StringSet &set) : iter(set.elts) {}
+    Iter(Iter const &obj) : DMEMB(iter) {}
+    Iter& operator= (Iter const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    Iter& next() { iter.next(); return *this; }
+
+    string const &data() const { return iter.key(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class Iter;
+
+  class IterC {
+  private:
+    StringSObjDict<int>::IterC iter;
+
+  public:
+    IterC(StringSet const &set) : iter(set.elts) {}
+    IterC(IterC const &obj) : DMEMB(iter) {}
+    IterC& operator= (IterC const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    IterC& next() { iter.next(); return *this; }
+
+    string const &data() const { return iter.key(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class IterC;
+
+  // # elts in the set
+  int size() const                        { return elts.size(); }
+
+  bool isEmpty() const                    { return elts.isEmpty(); }
+  bool isNotEmpty() const                 { return elts.isNotEmpty(); }
+
+  // true if elt is in the set
+  bool contains(char const *elt) const    { return elts.isMapped(elt); }
+  bool contains(rostring elt) const       { return contains(elt.c_str()); }
+
+  // add elt to the set; ok if it's already there
+  void add(char const *elt);
+  void add(rostring elt) { add(elt.c_str()); }
+
+  // remove elt from the set; ok if it's not there now
+  void remove(char const *elt);
+  void remove(rostring elt) { remove(elt.c_str()); }
+
+  // empty the set
+  void empty()                            { elts.empty(); }
+};
+
+#define FOREACH_STRINGSET(list, iter) \
+  for(StringSet::IterC iter(list); !iter.isDone(); iter.next())
+
+#define FOREACH_STRINGSET_NC(list, iter) \
+  for(StringSet::Iter iter(list); !iter.isDone(); iter.next())
+
+#endif // STRINGSET_H

Added: vendor/elsa/current/smbase/strintdict.h
===================================================================
--- vendor/elsa/current/smbase/strintdict.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strintdict.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,186 @@
+// strintlist.h            see license.txt for copyright and terms of use
+// dictionary of longs (integers that fit into void*), indexed by string
+// (case-sensitive)
+// (c) Scott McPeak, 2000
+// NOTE: automatically generated from xstrobjdict.h -- do not edit directly
+
+// quarl 2006-06-08
+//    created xstrobjdict.h to generate strobjdict.h, strsobjdict.h, and new
+//    file strintdict.h
+
+#ifndef STRINTDICT_H
+#define STRINTDICT_H
+
+#include "svdict.h"    // StringVoidDict
+
+void qsortStringArray(char const **strings, int size); // strutil.h
+
+// the dictionary object is considered to own all of the things
+// contained, so constness means constness of the contained objects
+// as well as the mapping from strings to them
+
+
+class StringIntDict {
+public:     // types
+  // 'foreach' iterator functions
+  typedef bool (*ForeachFn)(string const &key, long value, void *extra);
+
+  // external iterator
+  class Iter {
+  private:
+    StringVoidDict::Iter iter;
+
+  public:
+    Iter(StringIntDict &dict) : iter(dict.dict) {}
+    Iter(Iter const &obj) : DMEMB(iter) {}
+    Iter& operator= (Iter const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    Iter& next() { iter.next(); return *this; }
+
+    string const &key() const { return iter.key(); }
+    long &value() const { return (long &)iter.value(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class Iter;
+
+  class IterC {
+  private:
+    StringVoidDict::IterC iter;
+
+  public:
+    IterC(StringIntDict const &dict) : iter(dict.dict) {}
+    IterC(IterC const &obj) : DMEMB(iter) {}
+    IterC& operator= (IterC const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    IterC& next() { iter.next(); return *this; }
+
+    string const &key() const { return iter.key(); }
+    long value() const { return (long)iter.value(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class IterC;
+
+  class SortedKeyIter {
+  private:     // data
+    // underlying iterator state
+    StringIntDict const &map;
+    int keyIndex;
+    // dsw: I think it is a mistake to use getNumEntries() repeatedly
+    // instead of caching the value that it was at the time the
+    // iterator was constructed.  While we are still not thread-safe
+    // in the sense that an entry could be added or deleted, we could
+    // catch that, but we still do not want to separate the array of
+    // sortedKeys from its length as if these get out of synch this is
+    // an impossible bug to catch and a very low-level error.  Note
+    // that we still have a bit of a race condidition that numEntries
+    // is initialized before we iterate over the keys, but we are
+    // likely to catch that later.
+    int const numEntries;
+    char const **sortedKeys;    // array of strings
+
+  public:      // fucs
+    SortedKeyIter(StringIntDict const &map0)
+      : map(map0)
+      , keyIndex(0)
+      , numEntries(map.size())
+      , sortedKeys(new char const *[numEntries])
+    {
+      int i = 0;
+      // delegate to the other Iter class
+      for(IterC iter(map); !iter.isDone(); iter.next()) {
+//          xassert(i<numEntries);
+        sortedKeys[i++] = iter.key().c_str();
+      }
+      xassert(numEntries == i);
+      ::qsortStringArray(sortedKeys, numEntries);
+    }
+    ~SortedKeyIter() {
+      delete [] sortedKeys;
+    }
+
+    bool isDone() const   { return keyIndex == numEntries; }
+    SortedKeyIter &next() { ++keyIndex; return *this; }
+
+    // return information about the currently-referenced table entry
+
+    // dsw: I already have a char const* so I think it is a mistake to
+    // wrap a string around it
+    char const *key() const {
+      char const *key = sortedKeys[keyIndex];
+//        xassert(map.isMapped(key));
+      return key;
+    }
+    long value() const {
+      return (long )map.queryfC(key());
+    }
+  };
+
+private:    // data
+  // underlying dictionary functionality
+  StringVoidDict dict;
+
+public:     // funcs
+  StringIntDict() : dict() {}
+  ~StringIntDict() {}
+
+public:    // funcs
+  StringIntDict(StringIntDict const &obj) : dict(obj.dict) {}
+
+  // comparison and assignment use *pointer* comparison/assignment
+
+  StringIntDict& operator= (StringIntDict const &obj)    { dict = obj.dict; return *this; }
+
+  bool operator== (StringIntDict const &obj) const        { return dict == obj.dict; }
+  NOTEQUAL_OPERATOR(StringIntDict)
+
+  // due to similarity with StringVoidDict, see svdict.h for
+  // details on these functions' interfaces
+
+public:
+  // ------- selectors ---------
+  int size() const                                     { return dict.size(); }
+
+  bool isEmpty() const                                 { return dict.isEmpty(); }
+  bool isNotEmpty() const                              { return !isEmpty(); }
+
+  bool query(char const *key, long &value) const         { return dict.query(key, (void*&)value); }
+  long queryf(char const *key) const                     { return (long)dict.queryf(key); }
+  long queryif(char const *key) const                    { return (long)dict.queryif(key); }
+  
+  // parallel functions for API consistency
+  bool queryC(char const *key, long &value) const { return query(key, value); }
+  long queryfC(char const *key) const { return queryf(key); }
+
+  bool isMapped(char const *key) const                 { return dict.isMapped(key); }
+
+  // -------- mutators -----------
+  void add(char const *key, long value)                  { dict.add(key, (void*)value); }
+  long /*owner*/ remove(char const *key)                { return (long)dict.remove(key); }
+  long modify(char const *key, long newValue)              { return (long)dict.modify(key, (void*)newValue); }
+
+  void empty()                                         { dict.empty(); }
+
+  // -------- parallel interface for 'rostring' --------
+  bool query(rostring key, long &value) const { return query(key.c_str(), value); }
+  long queryf(rostring key) const             { return queryf(key.c_str()); }
+  long queryif(rostring key) const            { return queryif(key.c_str()); }
+  bool isMapped(rostring key) const         { return isMapped(key.c_str()); }
+  void add(rostring key, long value)          { dict.add(key, (void*)value); }
+  long modify(rostring key, long newValue)      { return modify(key.c_str(), newValue); }
+  long remove(rostring key)                   { return remove(key.c_str()); }
+
+  // --------- iters -------------
+  void foreach(ForeachFn func, void *extra=NULL) const
+    { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
+
+  // ------------ misc --------------
+  // debugging
+  int private_getTopAddr() const { return dict.private_getTopAddr(); }
+};
+
+
+#endif // STRINTDICT_H

Added: vendor/elsa/current/smbase/strobjdict.h
===================================================================
--- vendor/elsa/current/smbase/strobjdict.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strobjdict.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,172 @@
+// strobjdict.h            see license.txt for copyright and terms of use
+// dictionary of objects, indexed by string (case-sensitive)
+// (c) Scott McPeak, 2000
+// NOTE: automatically generated from xstrobjdict.h -- do not edit directly
+
+// quarl 2006-06-08
+//    created xstrobjdict.h to generate strobjdict.h, strsobjdict.h, and new
+//    file strintdict.h
+
+#ifndef STROBJDICT_H
+#define STROBJDICT_H
+
+#include "svdict.h"    // StringVoidDict
+
+void qsortStringArray(char const **strings, int size); // strutil.h
+
+// since the dictionary does not own the pointed-to objects,
+// it has the same constness model as StringVoidDict, namely
+// that const means the *mapping* is constant but not the
+// pointed-to objects
+
+template <class T>
+class StringObjDict {
+public:     // types
+  // 'foreach' iterator functions
+  typedef bool (*ForeachCFn)(string const &key, T const * value, void *extra);
+  typedef bool (*ForeachFn)(string const &key, T * /*serf*/ value, void *extra);
+
+  // external iterator
+  class Iter {
+  private:
+    StringVoidDict::IterC iter;
+
+  public:
+    Iter(StringObjDict const &dict) : iter(dict.dict) {}
+    Iter(Iter const &obj) : DMEMB(iter) {}
+    Iter& operator= (Iter const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    Iter& next() { iter.next(); return *this; }
+
+    string const &key() const { return iter.key(); }
+    T const * &value() const { return (T const * &)iter.value(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class Iter;
+  typedef Iter IterC;
+
+  class SortedKeyIter {
+  private:     // data
+    // underlying iterator state
+    StringObjDict<T> const &map;
+    int keyIndex;
+    // dsw: I think it is a mistake to use getNumEntries() repeatedly
+    // instead of caching the value that it was at the time the
+    // iterator was constructed.  While we are still not thread-safe
+    // in the sense that an entry could be added or deleted, we could
+    // catch that, but we still do not want to separate the array of
+    // sortedKeys from its length as if these get out of synch this is
+    // an impossible bug to catch and a very low-level error.  Note
+    // that we still have a bit of a race condidition that numEntries
+    // is initialized before we iterate over the keys, but we are
+    // likely to catch that later.
+    int const numEntries;
+    char const **sortedKeys;    // array of strings
+
+  public:      // fucs
+    SortedKeyIter(StringObjDict<T> const &map0)
+      : map(map0)
+      , keyIndex(0)
+      , numEntries(map.size())
+      , sortedKeys(new char const *[numEntries])
+    {
+      int i = 0;
+      // delegate to the other Iter class
+      for(IterC iter(map); !iter.isDone(); iter.next()) {
+//          xassert(i<numEntries);
+        sortedKeys[i++] = iter.key().c_str();
+      }
+      xassert(numEntries == i);
+      ::qsortStringArray(sortedKeys, numEntries);
+    }
+    ~SortedKeyIter() {
+      delete [] sortedKeys;
+    }
+
+    bool isDone() const   { return keyIndex == numEntries; }
+    SortedKeyIter &next() { ++keyIndex; return *this; }
+
+    // return information about the currently-referenced table entry
+
+    // dsw: I already have a char const* so I think it is a mistake to
+    // wrap a string around it
+    char const *key() const {
+      char const *key = sortedKeys[keyIndex];
+//        xassert(map.isMapped(key));
+      return key;
+    }
+    T const * value() const {
+      return (T const * )map.queryfC(key());
+    }
+  };
+
+private:    // data
+  // underlying dictionary functionality
+  StringVoidDict dict;
+
+public:     // funcs
+  StringObjDict() : dict() {}
+  ~StringObjDict() { empty(); }
+
+private:    // funcs
+  // disallowed
+  StringObjDict(StringObjDict const &obj);
+  StringObjDict& operator= (StringObjDict const &obj);
+  bool operator== (StringObjDict const &obj) const;
+
+  // due to similarity with StringVoidDict, see svdict.h for
+  // details on these functions' interfaces
+
+public:
+  // ------- selectors ---------
+  int size() const                                     { return dict.size(); }
+
+  bool isEmpty() const                                 { return dict.isEmpty(); }
+  bool isNotEmpty() const                              { return !isEmpty(); }
+
+  bool queryC(char const *key, T const * &value) const  { return dict.query(key, (void*&)value); }
+  bool query(char const *key, T * &value)               { return queryC(key, (T const * &)value); }
+
+  T const * queryfC(char const *key) const              { return (T const *)dict.queryf(key); }
+  T * /*serf*/ queryf(char const *key)                 { return (T *)dict.queryf(key); }
+  T * /*serf*/ queryif(char const *key)                { return (T *)dict.queryif(key); }
+
+  bool isMapped(char const *key) const                 { return dict.isMapped(key); }
+
+  // -------- mutators -----------
+  void add(char const *key, T * value)                  { dict.add(key, (void*)value); }
+  T * /*owner*/ remove(char const *key)                { return (T *)dict.remove(key); }
+  void deleteAt(char const *key)                       { deleteObject(remove(key)); }
+
+  void empty()               { dict.emptyAndDel((StringVoidDict::DelFn)deleteObject); }
+
+  // -------- parallel interface for 'rostring' --------
+  bool query(rostring key, T * &value) const { return query(key.c_str(), value); }
+  T * queryf(rostring key) const             { return queryf(key.c_str()); }
+  T * queryif(rostring key) const            { return queryif(key.c_str()); }
+  bool isMapped(rostring key) const         { return isMapped(key.c_str()); }
+  void add(rostring key, T * value)          { dict.add(key, (void*)value); }
+  T * modify(rostring key, T * newValue)      { return modify(key.c_str(), newValue); }
+  T * remove(rostring key)                   { return remove(key.c_str()); }
+
+  // --------- iters -------------
+  void foreachC(ForeachCFn func, void *extra=NULL) const
+    { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
+  void foreach(ForeachFn func, void *extra=NULL)
+    { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
+
+  // ------------ misc --------------
+  static void deleteObject(T * obj);
+  // debugging
+  int private_getTopAddr() const { return dict.private_getTopAddr(); }
+};
+
+template <class T>
+STATICDEF void StringObjDict<T>::deleteObject(T * obj)
+{
+  delete obj;
+}
+
+#endif // STROBJDICT_H

Added: vendor/elsa/current/smbase/strsobjdict.h
===================================================================
--- vendor/elsa/current/smbase/strsobjdict.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strsobjdict.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,185 @@
+// strsobjdict.h            see license.txt for copyright and terms of use
+// dictionary of *serf* pointers to objects, indexed by string (case-sensitive)
+// (c) Scott McPeak, 2000
+// NOTE: automatically generated from xstrobjdict.h -- do not edit directly
+
+// quarl 2006-06-08
+//    created xstrobjdict.h to generate strobjdict.h, strsobjdict.h, and new
+//    file strintdict.h
+
+#ifndef STRSOBJLIST_H
+#define STRSOBJLIST_H
+
+#include "svdict.h"    // StringVoidDict
+
+void qsortStringArray(char const **strings, int size); // strutil.h
+
+// the dictionary object is considered to own all of the things
+// contained, so constness means constness of the contained objects
+// as well as the mapping from strings to them
+
+template <class T>
+class StringSObjDict {
+public:     // types
+  // 'foreach' iterator functions
+  typedef bool (*ForeachFn)(string const &key, T * value, void *extra);
+
+  // external iterator
+  class Iter {
+  private:
+    StringVoidDict::Iter iter;
+
+  public:
+    Iter(StringSObjDict &dict) : iter(dict.dict) {}
+    Iter(Iter const &obj) : DMEMB(iter) {}
+    Iter& operator= (Iter const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    Iter& next() { iter.next(); return *this; }
+
+    string const &key() const { return iter.key(); }
+    T * &value() const { return (T * &)iter.value(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class Iter;
+
+  class IterC {
+  private:
+    StringVoidDict::IterC iter;
+
+  public:
+    IterC(StringSObjDict const &dict) : iter(dict.dict) {}
+    IterC(IterC const &obj) : DMEMB(iter) {}
+    IterC& operator= (IterC const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    IterC& next() { iter.next(); return *this; }
+
+    string const &key() const { return iter.key(); }
+    T * value() const { return (T *)iter.value(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class IterC;
+
+  class SortedKeyIter {
+  private:     // data
+    // underlying iterator state
+    StringSObjDict<T> const &map;
+    int keyIndex;
+    // dsw: I think it is a mistake to use getNumEntries() repeatedly
+    // instead of caching the value that it was at the time the
+    // iterator was constructed.  While we are still not thread-safe
+    // in the sense that an entry could be added or deleted, we could
+    // catch that, but we still do not want to separate the array of
+    // sortedKeys from its length as if these get out of synch this is
+    // an impossible bug to catch and a very low-level error.  Note
+    // that we still have a bit of a race condidition that numEntries
+    // is initialized before we iterate over the keys, but we are
+    // likely to catch that later.
+    int const numEntries;
+    char const **sortedKeys;    // array of strings
+
+  public:      // fucs
+    SortedKeyIter(StringSObjDict<T> const &map0)
+      : map(map0)
+      , keyIndex(0)
+      , numEntries(map.size())
+      , sortedKeys(new char const *[numEntries])
+    {
+      int i = 0;
+      // delegate to the other Iter class
+      for(IterC iter(map); !iter.isDone(); iter.next()) {
+//          xassert(i<numEntries);
+        sortedKeys[i++] = iter.key().c_str();
+      }
+      xassert(numEntries == i);
+      ::qsortStringArray(sortedKeys, numEntries);
+    }
+    ~SortedKeyIter() {
+      delete [] sortedKeys;
+    }
+
+    bool isDone() const   { return keyIndex == numEntries; }
+    SortedKeyIter &next() { ++keyIndex; return *this; }
+
+    // return information about the currently-referenced table entry
+
+    // dsw: I already have a char const* so I think it is a mistake to
+    // wrap a string around it
+    char const *key() const {
+      char const *key = sortedKeys[keyIndex];
+//        xassert(map.isMapped(key));
+      return key;
+    }
+    T const * value() const {
+      return (T const * )map.queryfC(key());
+    }
+  };
+
+private:    // data
+  // underlying dictionary functionality
+  StringVoidDict dict;
+
+public:     // funcs
+  StringSObjDict() : dict() {}
+  ~StringSObjDict() {}
+
+public:    // funcs
+  StringSObjDict(StringSObjDict const &obj) : dict(obj.dict) {}
+
+  // comparison and assignment use *pointer* comparison/assignment
+
+  StringSObjDict& operator= (StringSObjDict const &obj)    { dict = obj.dict; return *this; }
+
+  bool operator== (StringSObjDict const &obj) const        { return dict == obj.dict; }
+  NOTEQUAL_OPERATOR(StringSObjDict)
+
+  // due to similarity with StringVoidDict, see svdict.h for
+  // details on these functions' interfaces
+
+public:
+  // ------- selectors ---------
+  int size() const                                     { return dict.size(); }
+
+  bool isEmpty() const                                 { return dict.isEmpty(); }
+  bool isNotEmpty() const                              { return !isEmpty(); }
+
+  bool query(char const *key, T * &value) const         { return dict.query(key, (void*&)value); }
+  T * queryf(char const *key) const                     { return (T *)dict.queryf(key); }
+  T * queryif(char const *key) const                    { return (T *)dict.queryif(key); }
+  
+  // parallel functions for API consistency
+  bool queryC(char const *key, T * &value) const { return query(key, value); }
+  T * queryfC(char const *key) const { return queryf(key); }
+
+  bool isMapped(char const *key) const                 { return dict.isMapped(key); }
+
+  // -------- mutators -----------
+  void add(char const *key, T * value)                  { dict.add(key, (void*)value); }
+  T * /*owner*/ remove(char const *key)                { return (T *)dict.remove(key); }
+  T * modify(char const *key, T * newValue)              { return (T *)dict.modify(key, (void*)newValue); }
+
+  void empty()                                         { dict.empty(); }
+
+  // -------- parallel interface for 'rostring' --------
+  bool query(rostring key, T * &value) const { return query(key.c_str(), value); }
+  T * queryf(rostring key) const             { return queryf(key.c_str()); }
+  T * queryif(rostring key) const            { return queryif(key.c_str()); }
+  bool isMapped(rostring key) const         { return isMapped(key.c_str()); }
+  void add(rostring key, T * value)          { dict.add(key, (void*)value); }
+  T * modify(rostring key, T * newValue)      { return modify(key.c_str(), newValue); }
+  T * remove(rostring key)                   { return remove(key.c_str()); }
+
+  // --------- iters -------------
+  void foreach(ForeachFn func, void *extra=NULL) const
+    { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
+
+  // ------------ misc --------------
+  // debugging
+  int private_getTopAddr() const { return dict.private_getTopAddr(); }
+};
+
+
+#endif // STRSOBJLIST_H

Added: vendor/elsa/current/smbase/strtable.cc
===================================================================
--- vendor/elsa/current/smbase/strtable.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strtable.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,125 @@
+// strtable.cc            see license.txt for copyright and terms of use
+// code for strtable.h
+// quarl 2006-06-06 moved from ast; see there for prior version history.
+
+#include "strtable.h"    // this module
+#include "xassert.h"     // xassert
+#include "flatten.h"     // Flatten
+
+#include <string.h>      // strlen
+
+
+StringTable *flattenStrTable = NULL;
+
+
+STATICDEF char const *StringTable::identity(void *data)
+{
+  return (char const*)data;
+}
+
+
+StringTable::StringTable()
+  : hash(identity),
+    racks(NULL),
+    longStrings(NULL)
+{}
+
+
+StringTable::~StringTable()
+{
+  clear();
+}
+
+void StringTable::clear()
+{
+  hash.empty();
+
+  while (racks != NULL) {
+    Rack *temp = racks;
+    racks = racks->next;
+    delete temp;
+  }
+
+  while (longStrings != NULL) {
+    LongString *temp = longStrings;
+    longStrings = longStrings->next;
+    delete temp->data;
+    delete temp;
+  }
+}
+
+
+StringRef StringTable::add(char const *src)
+{
+  // see if it's already here
+  StringRef ret = get(src);
+  if (ret) {
+    return ret;
+  }
+
+  int len = strlen(src)+1;     // include null terminator
+
+  // is it a long string?
+  if (len >= longThreshold) {
+    char *d = new char[len];
+    ret = d;
+    memcpy(d, src, len);
+
+    // prepend a new long-string entry
+    longStrings = new LongString(longStrings, d);
+  }
+
+  else {
+    // see if we need a new rack
+    if (!racks || len > racks->availBytes()) {
+      // need a new rack
+      xassert(len <= rackSize);
+      racks = new Rack(racks);     // prepend new rack
+    }
+
+    // add the string to the last rack
+    ret = racks->nextByte();
+    memcpy(racks->nextByte(), src, len);
+    racks->usedBytes += len;
+  }
+
+  // enter the intended location into the indexing structures
+  hash.add(ret, (void*)ret);
+
+  return ret;
+}
+
+
+StringRef StringTable::get(char const *src) const
+{
+  return (StringRef)hash.get(src);
+}
+
+
+// for now, just store each instance separately ...
+void StringTable::xfer(Flatten &flat, StringRef &ref)
+{
+  if (flat.reading()) {
+    // read the string
+    char *str;
+    flat.xferCharString(str);
+
+    if (str) {
+      // add to table
+      ref = add(str);
+
+      // delete string's storage
+      delete str;
+    }
+    else {
+      // was NULL
+      ref = NULL;
+    }
+  }
+
+  else {
+    // copy it to disk
+    // since we're writing, the cast is ok
+    flat.xferCharString(const_cast<char*&>(ref));
+  }
+}

Added: vendor/elsa/current/smbase/strtable.h
===================================================================
--- vendor/elsa/current/smbase/strtable.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strtable.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,113 @@
+// strtable.h            see license.txt for copyright and terms of use
+// implements a collection of immutable strings with unique representatives
+// quarl 2006-06-06 moved from ast; see there for prior version history.
+
+#ifndef STRTABLE_H
+#define STRTABLE_H
+
+#include "strhash.h"     // StringHash
+#include "str.h"         // rostring
+
+// fwd
+class Flatten;
+
+// global string table for use during flattening/unflattening;
+// it's up to clients to manage this ptr, as this module doesn't
+// do anything besides define it into existence
+// (this isn't the ideal solution..)
+extern class StringTable *flattenStrTable;
+
+
+// the type of references to strings in a string table; the pointer
+// can be used directly in equality comparisons, because several calls
+// to 'add' return the same pointer; and it points to the represented
+// string (null-terminated), so it can be printed directly, etc.
+typedef char const *StringRef;
+
+
+class StringTable {
+public:      // constants
+  enum {
+    rackSize = 16000,      // size of one rack
+    longThreshold = 1000,  // minimum length of a "long" string
+  };
+
+private:     // types
+  // some of the strings stored in the table
+  struct Rack {
+    Rack *next;            // (owner) next rack, if any; for deallocation
+    int usedBytes;         // # of bytes of 'data' that are used
+    char data[rackSize];   // data where strings are stored
+
+  public:
+    Rack(Rack *n) : next(n), usedBytes(0) {}
+    int availBytes() const { return rackSize - usedBytes; }
+    char *nextByte() { return data + usedBytes; }
+  };
+
+  // stores long strings
+  struct LongString {
+    LongString *next;      // (owner) next long string
+    char *data;            // (owner) string data, any length (null terminated)
+
+  public:
+    LongString(LongString *n, char *d) : next(n), data(d) {}
+  };
+
+private:    // data
+  // hash table mapping strings to pointers into one
+  // of the string racks
+  StringHash hash;
+
+  // linked list of racks; only walked at dealloc time; we add new
+  // strings to the first rack, and prepend a new one if necessary;
+  // 'racks' is never null
+  Rack *racks;
+
+  // similar for long strings
+  LongString *longStrings;
+
+private:    // funcs
+  // not allowed
+  StringTable(StringTable&);
+  void operator=(StringTable&);
+  void operator==(StringTable&);
+
+  // for mapping data to keys, in the hashtable
+  static char const *identity(void *data);
+
+public:     // funcs
+  StringTable();
+  ~StringTable();
+
+  // throw away everything in this table
+  void clear();
+
+  // add 'src' to the table, if it isn't already there; return a
+  // unique representative, such that multiple calls to 'add' with
+  // the same string contents will always yield the same value
+  //
+  // note that this module does not retain a pointer or reference
+  // to the original 'src' (it makes a copy if needed)
+  StringRef add(char const *src);
+  StringRef add(rostring src) { return add(src.c_str()); }
+
+  // some syntactic sugar
+  StringRef operator() (char const *src) { return add(src); }
+  StringRef operator() (rostring src) { return add(src); }
+
+  // if 'src' is in the table, return its representative; if not,
+  // return NULL
+  StringRef get(char const *src) const;
+
+  // similar functions for strings with specified lengths
+  // this doesn't work because the underlying hash table interface needs null terminators..
+  //StringRef add(char const *src, int len);
+  //StringRef get(char const *src, int len) const;
+
+  // read/write binary
+  void xfer(Flatten &flat, StringRef &ref);
+};
+
+
+#endif // STRTABLE_H

Added: vendor/elsa/current/smbase/strtokp.cpp
===================================================================
--- vendor/elsa/current/smbase/strtokp.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strtokp.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,106 @@
+// strtokp.cc            see license.txt for copyright and terms of use
+// code for strtokp.h
+// Scott McPeak, 1997, 1999, 2000  This file is public domain.
+
+#include "strtokp.h"    // this module
+#include "exc.h"        // xassert
+#include <string.h>     // strtok
+
+
+StrtokParse::StrtokParse(rostring origStr, rostring origDelim)
+  : buf(strlen(origStr)+1)
+{
+  char const *str = toCStr(origStr);
+  char const *delim = toCStr(origDelim);
+
+  // make local copy
+  strcpy(buf, str);
+
+  // parse it first time to count # of tokens
+  int ct=0;
+  char *tok = strtok(buf.ptr(), delim);
+  while (tok) {
+    ct++;
+    tok = strtok(NULL, delim);
+  }
+
+  // restore buf
+  strcpy(buf, str);
+
+  // allocate storage
+  _tokc = ct;
+  if (ct) {
+    _tokv = new char*[ct+1];
+    _tokv[ct] = NULL;     // terminate argv[]-like list
+  }
+  else {
+    _tokv = NULL;
+  }
+
+  // parse it again, this time saving the values
+  ct=0;
+  tok = strtok(buf.ptr(), delim);
+  while (tok) {
+    _tokv[ct] = tok;
+    ct++;
+    tok = strtok(NULL, delim);
+  }
+
+  // simple check just because it's easy
+  xassert(ct == _tokc);
+}
+
+
+StrtokParse::~StrtokParse()
+{
+  // buf deletes itself
+
+  if (_tokv) {
+    delete[] _tokv;
+  }
+}
+
+
+void StrtokParse::validate(int which) const
+{
+  xassert((unsigned)which < (unsigned)_tokc);
+}
+
+
+char const *StrtokParse::tokv(int which) const
+{
+  validate(which);
+  return _tokv[which];
+}
+
+
+string StrtokParse::
+  reassemble(int firstTok, int lastTok, rostring original) const
+{
+  int left = offset(firstTok);
+  int right = offset(lastTok) + strlen(tokv(lastTok));
+
+  return substring(toCStr(original) + left, right-left);
+}
+
+
+string StrtokParse::
+  join(int firstTok, int lastTok, rostring separator) const
+{
+  stringBuilder sb;
+
+  for (int i=firstTok; i<=lastTok; i++) {
+    if (i > firstTok) {
+      sb << separator;
+    }
+    sb << tokv(i);
+  }
+
+  return sb;
+}
+
+
+int StrtokParse::offset(int which) const
+{
+  return tokv(which) - (char const*)buf;
+}

Added: vendor/elsa/current/smbase/strtokp.h
===================================================================
--- vendor/elsa/current/smbase/strtokp.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strtokp.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,72 @@
+// strtokp.h            see license.txt for copyright and terms of use
+// using strtok to parse an entire string at once
+// Scott McPeak, 1997  This file is public domain.
+
+// NOTE: This class should not be used for any high-performance
+// parsing tasks; i.e., it should not find itself in the inner loop of
+// anything.  Among other things, it allocates, which is always bad in
+// an inner loop.  This class makes certain common tasks convenient,
+// but that convenience is at the expense of performance.  That is why
+// the interfaces below accept 'rostring', not 'char const *'.  (See
+// string.txt.)
+
+#ifndef __STRTOKP_H
+#define __STRTOKP_H
+
+#include "str.h"       // string
+#include "array.h"     // Array
+#include <string.h>    // strlen
+
+class StrtokParse {
+  Array<char> buf;     // locally allocated storage; NUL terminated
+  int _tokc;           // # of tokens found
+  char **_tokv;        // array of tokens themselves; NULL terminated (owner)
+
+private:
+  void validate(int which) const;
+    // throw an exception if which is invalid token
+
+public:
+  StrtokParse(rostring str, rostring delim);
+    // parse 'str' into tokens delimited by chars from 'delim'; the
+    // use of 'rostring' is intentional (see above)
+
+  ~StrtokParse();
+    // clean up
+
+  int tokc() const { return _tokc; }
+  operator int () const { return tokc(); }
+    // simple count of available tokens
+
+  char const *tokv(int which) const;     // may throw xArrayBounds
+  char const* operator[] (int which) const { return tokv(which); }
+    // access to tokens; must make local copies to modify
+
+  string reassemble(int firstTok, int lastTok, rostring originalString) const;
+    // return the substring of the original string spanned by the
+    // given range of tokens; if firstTok==lastTok, only that token is
+    // returned (without any separators); must be that firstTok <=
+    // lastTok
+
+  string join(int firstTok, int lastTok, rostring separator) const;
+    // return a string created by concatenating the given range of tokens
+    // together with 'separator' in between them
+
+  int offset(int which) const;
+    // return a value that, when added to the original 'str' parameter,
+    // yields a pointer to where tokv(which) is, as a substring, in that string
+
+  int offsetAfter(int which) const
+    { return offset(which) + strlen(tokv(which)); }
+    // offset for character just beyond last one in tokv (should be either
+    // a delimiter character, or 0)
+
+  char **spawn_tokv_array() { return _tokv; }
+    // this is defined because it makes it convenient to generate
+    // spawn arguments, and should be limited to use for that purpose
+    // (because it exposes internal representation which is in
+    // principle subject to change)
+};
+
+#endif // __STRTOKP_H
+

Added: vendor/elsa/current/smbase/strtokpc.h
===================================================================
--- vendor/elsa/current/smbase/strtokpc.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strtokpc.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,55 @@
+// strtokpc.h
+
+// quarl 2006-05-24 initial version
+
+// String tokenizing class.  Modifies an input string in-place to
+// null-terminate individual tokens, and undoes modifications on destruction.
+// It does not allocate or copy strings, so suitable to be used in an inner
+// loop.
+
+// It only supports iterating linearly through the tokens (its functionality
+// is similar to strtok_r, but it undoes modifications).
+
+#ifndef STRTOKPC_H
+#define STRTOKPC_H
+
+class StrtokParseC {
+  char *str;
+  char save;
+
+public:
+  StrtokParseC(char const *str0) : str(const_cast<char*>(str0)), save('\0') {}
+  ~StrtokParseC() { if (save != '\0') { *str = save; } }
+
+  // Return a token, or NULL.  The token is only valid until the next call to
+  // nextToken() or until destruction.
+  char const *nextToken(char const delim) {
+    if (save != '\0') {
+      *str = save;
+      ++str;
+      save = '\0';
+    }
+
+    if (*str == '\0') return NULL;
+
+    char const *tok = str;
+
+    while (1) {
+      if (*str == '\0') {
+        save = '\0';
+        return tok;
+      }
+
+      if (*str == delim) {
+        save = delim;
+        *str = '\0';
+        return tok;
+      }
+
+      ++str;
+    }
+  }
+};
+
+#endif
+

Added: vendor/elsa/current/smbase/strutil.cc
===================================================================
--- vendor/elsa/current/smbase/strutil.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strutil.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,690 @@
+// strutil.cc            see license.txt for copyright and terms of use
+// code for strutil.h
+
+#include "strutil.h"     // this module
+#include "exc.h"         // xformat
+#include "autofile.h"    // AutoFILE
+#include "array.h"       // Array
+
+#include <ctype.h>       // isspace
+#include <string.h>      // strstr, memcmp
+#include <stdio.h>       // sprintf
+#include <stdlib.h>      // strtoul, qsort
+#include <time.h>        // time, asctime, localtime
+
+
+// replace all instances of oldstr in src with newstr, return result
+string replace(rostring origSrc, rostring oldstr, rostring newstr)
+{
+  stringBuilder ret;
+  char const *src = toCStr(origSrc);
+
+  while (*src) {
+    char const *next = strstr(src, toCStr(oldstr));
+    if (!next) {
+      ret << src;
+      break;
+    }
+
+    // add the characters between src and next
+    ret << substring(src, next-src);
+
+    // add the replace-with string
+    ret << newstr;
+
+    // move src to beyond replaced substring
+    src += (next-src) + strlen(oldstr);
+  }
+
+  return ret;
+}
+
+
+string expandRanges(char const *chars_)
+{
+  stringBuilder ret;
+
+  // Fix from Hendrik Tews: use unsigned chars to as not to fall over
+  // when ranges have values near 127 on compilers for which 'char' is
+  // signed by default (which is probably the common case)
+  unsigned char *chars = (unsigned char*)chars_;
+
+  while (*chars) {
+    if (chars[1] == '-' && chars[2] != 0) {
+      // range specification
+      if (chars[0] > chars[2]) {
+        xformat("range specification with wrong collation order");
+      }
+
+      // use 'int' so we can handle chars[2] == 255 (otherwise we get
+      // infinite loop)
+      for (int c = chars[0]; c <= chars[2]; c++) {
+        ret << (unsigned char)c;
+      }
+      chars += 3;
+    }
+    else {
+      // simple character specification
+      ret << chars[0];
+      chars++;
+    }
+  }
+
+  return ret;
+}
+
+
+string translate(rostring origSrc, rostring srcchars, rostring destchars)
+{
+  // first, expand range notation in the specification sequences
+  string srcSpec = expandRanges(toCStr(srcchars));
+  string destSpec = expandRanges(toCStr(destchars));
+
+  // build a translation map
+  char map[256];
+  string::size_type i;
+  for (i=0; i<256; i++) {
+    map[i] = i;
+  }
+
+  // excess characters from either string are ignored ("SysV" behavior)
+  for (i=0; i < srcSpec.length() && i < destSpec.length(); i++) {
+    map[(unsigned char)( srcSpec[i] )] = destSpec[i];
+  }
+
+  // run through 'src', applying 'map'
+  char const *src = toCStr(origSrc);
+  Array<char> ret(strlen(src)+1);
+  char *dest = ret.ptr();
+  while (*src) {
+    *dest = map[(unsigned char)*src];
+    dest++;
+    src++;
+  }
+  *dest = 0;    // final nul terminator
+
+  return string(ret);
+}
+
+
+// why is this necessary?
+string stringToupper(rostring src)
+  { return translate(src, "a-z", "A-Z"); }
+
+
+string trimWhitespace(rostring origStr)
+{
+  char const *str = toCStr(origStr);
+
+  // trim leading whitespace
+  while (isspace(*str)) {
+    str++;
+  }
+
+  // trim trailing whitespace
+  char const *end = str + strlen(str);
+  while (end > str &&
+         isspace(end[-1])) {
+    end--;
+  }
+
+  // return it
+  return substring(str, end-str);
+}
+
+
+string firstAlphanumToken(rostring origStr)
+{
+  char const *str = toCStr(origStr);
+
+  // find the first alpha-numeric; NOTE: if we hit the NUL at the end,
+  // that should not be alpha-numeric and we should stop
+  while(!isalnum(*str)) {
+    str++;
+  }
+
+  // keep going until we are not at an alpha-numeric
+  char const *end = str;
+  while(isalnum(*end)) {
+    end++;
+  }
+
+  // return it
+  return substring(str, end-str);
+}
+
+
+// table of escape codes
+static struct Escape {
+  char actual;      // actual character in string
+  char escape;      // char that follows backslash to produce 'actual'
+} const escapes[] = {
+  { '\0', '0' },  // nul
+  { '\a', 'a' },  // bell
+  { '\b', 'b' },  // backspace
+  { '\f', 'f' },  // form feed
+  { '\n', 'n' },  // newline
+  { '\r', 'r' },  // carriage return
+  { '\t', 't' },  // tab
+  { '\v', 'v' },  // vertical tab
+  { '\\', '\\'},  // backslash
+  { '"',  '"' },  // double-quote
+  { '\'', '\''},  // single-quote
+};
+
+
+string encodeWithEscapes(char const *p, int len)
+{
+  stringBuilder sb;
+
+  for (; len>0; len--, p++) {
+    // look for an escape code
+    unsigned i;
+    for (i=0; i<TABLESIZE(escapes); i++) {
+      if (escapes[i].actual == *p) {
+        sb << '\\' << escapes[i].escape;
+        break;
+      }
+    }
+    if (i<TABLESIZE(escapes)) {
+      continue;   // found it and printed it
+    }
+
+    // try itself
+    if (isprint(*p)) {
+      sb << *p;
+      continue;
+    }
+
+    // use the most general notation
+    char tmp[5];
+    sprintf(tmp, "\\x%02X", (unsigned char)(*p));
+    sb << tmp;
+  }
+
+  return sb;
+}
+
+
+string encodeWithEscapes(rostring p)
+{
+  return encodeWithEscapes(toCStr(p), strlen(p));
+}
+
+
+string quoted(rostring src)
+{
+  return stringc << "\""
+                 << encodeWithEscapes(src)
+                 << "\"";
+}
+
+
+void decodeEscapes(ArrayStack<char> &dest, rostring origSrc,
+                   char delim, bool allowNewlines)
+{
+  char const *src = toCStr(origSrc);
+
+  while (*src != '\0') {
+    if (*src == '\n' && !allowNewlines) {
+      xformat("unescaped newline (unterminated string)");
+    }
+    if (*src == delim) {
+      xformat(stringc << "unescaped delimiter (" << delim << ")");
+    }
+
+    if (*src != '\\') {
+      // easy case
+      dest.push(*src);
+      src++;
+      continue;
+    }
+
+    // advance past backslash
+    src++;
+
+    // see if it's a simple one-char backslash code;
+    // start at 1 so we do *not* use the '\0' code since
+    // that's actually a special case of \0123', and
+    // interferes with the latter
+    int i;
+    for (i=1; i<TABLESIZE(escapes); i++) {
+      if (escapes[i].escape == *src) {
+        dest.push(escapes[i].actual);
+        src++;
+        break;
+      }
+    }
+    if (i < TABLESIZE(escapes)) {
+      continue;
+    }
+
+    if (*src == '\0') {
+      xformat("backslash at end of string");
+    }
+
+    if (*src == '\n') {
+      // escaped newline; advance to first non-whitespace
+      src++;
+      while (*src==' ' || *src=='\t') {
+        src++;
+      }
+      continue;
+    }
+
+    if (*src == 'x' || isdigit(*src)) {
+      // hexadecimal or octal char (it's unclear to me exactly how to
+      // parse these since it's supposedly legal to have e.g. "\x1234"
+      // mean a one-char string.. whatever)
+      bool hex = (*src == 'x');
+      if (hex) {
+        src++;
+
+        // strtoul is willing to skip leading whitespace, so I need
+        // to catch it myself
+        if (isspace(*src)) {
+          xformat("whitespace following hex (\\x) escape");
+        }
+      }
+
+      char const *endptr;
+      unsigned long val = strtoul(src, (char**)&endptr, hex? 16 : 8);
+      if (src == endptr) {
+        // this can't happen with the octal escapes because
+        // there is always at least one valid digit
+        xformat("invalid hex (\\x) escape");
+      }
+
+      dest.push((char)(unsigned char)val);    // possible truncation..
+      src = endptr;
+      continue;
+    }
+
+    // everything not explicitly covered will be considered
+    // an error (for now), even though the C++ spec says
+    // it should be treated as if the backslash were not there
+    //
+    // 7/29/04: now making backslash the identity transformation in
+    // this case
+    //
+    // copy character as if it had not been backslashed
+    dest.push(*src);
+    src++;
+  }
+}
+
+
+string parseQuotedString(rostring text)
+{
+  if (!( text[0] == '"' &&
+         text[strlen(text)-1] == '"' )) {
+    xformat(stringc << "quoted string is missing quotes: " << text);
+  }
+
+  // strip the quotes
+  string noQuotes = substring(toCStr(text)+1, strlen(text)-2);
+
+  // decode escapes
+  ArrayStack<char> buf;
+  decodeEscapes(buf, noQuotes, '"');
+  buf.push(0 /*NUL*/);
+
+  // return string contents up to first NUL, which isn't necessarily
+  // the same as the one just pushed; by invoking this function, the
+  // caller is accepting responsibility for this condition
+  return string(buf.getArray());
+}
+
+
+string localTimeString()
+{
+  time_t t = time(NULL);
+  char const *p = asctime(localtime(&t));
+  return substring(p, strlen(p) - 1);     // strip final newline
+}
+
+
+string sm_basename(rostring origSrc)
+{
+  char const *src = toCStr(origSrc);
+
+  char const *sl = strrchr(src, '/');   // locate last slash
+  if (sl && sl[1] == 0) {
+    // there is a slash, but it is the last character; ignore it
+    // (this behavior is what /bin/basename does)
+    return sm_basename(substring(src, strlen(src)-1));
+  }
+
+  if (sl) {
+    return string(sl+1);     // everything after the slash
+  }
+  else {
+    return string(src);      // entire string if no slashes
+  }
+}
+
+string dirname(rostring origSrc)
+{
+  char const *src = toCStr(origSrc);
+
+  char const *sl = strrchr(src, '/');   // locate last slash
+  if (sl == src) {
+    // last slash is leading slash
+    return string("/");
+  }
+
+  if (sl && sl[1] == 0) {
+    // there is a slash, but it is the last character; ignore it
+    // (this behavior is what /bin/dirname does)
+    return dirname(substring(src, strlen(src)-1));
+  }
+
+  if (sl) {
+    return substring(src, sl-src);     // everything before slash
+  }
+  else {
+    return string(".");
+  }
+}
+
+
+// I will expand this definition to use more knowledge about English
+// irregularities as I need it
+string plural(int n, rostring prefix)
+{
+  if (n==1) {
+    return prefix;
+  }
+
+  if (0==strcmp(prefix, "was")) {
+    return string("were");
+  }
+  if (prefix[strlen(prefix)-1] == 'y') {
+    return stringc << substring(prefix, strlen(prefix)-1) << "ies";
+  }
+  else {
+    return stringc << prefix << "s";
+  }
+}
+
+string pluraln(int n, rostring prefix)
+{
+  return stringc << n << " " << plural(n, prefix);
+}
+
+
+string a_or_an(rostring noun)
+{
+  bool use_an = false;
+
+  if (strchr("aeiouAEIOU", noun[0])) {
+    use_an = true;
+  }
+
+  // special case: I pronounce "mvisitor" like "em-visitor"
+  if (noun[0]=='m' && noun[1]=='v') {
+    use_an = true;
+  }
+
+  if (use_an) {
+    return stringc << "an " << noun;
+  }
+  else {
+    return stringc << "a " << noun;
+  }
+}
+
+
+char *copyToStaticBuffer(char const *s)
+{
+  enum { SZ=200 };
+  static char buf[SZ+1];
+
+  int len = strlen(s);
+  if (len > SZ) len=SZ;
+  memcpy(buf, s, len);
+  buf[len] = 0;
+
+  return buf;
+}
+
+
+bool prefixEquals(rostring str, rostring prefix)
+{
+  int slen = strlen(str);
+  int plen = strlen(prefix);
+  return slen >= plen &&
+         0==memcmp(toCStr(str), toCStr(prefix), plen);
+}
+
+bool suffixEquals(rostring str, rostring suffix)
+{
+  int slen = strlen(str);
+  int ulen = strlen(suffix);    // sUffix
+  return slen >= ulen &&
+         0==memcmp(toCStr(str)+slen-ulen, toCStr(suffix), ulen);
+}
+
+
+void writeStringToFile(rostring str, rostring fname)
+{
+  AutoFILE fp(toCStr(fname), "w");
+
+  if (fputs(toCStr(str), fp) < 0) {
+    xbase("fputs: EOF");
+  }
+}
+
+
+string readStringFromFile(rostring fname)
+{
+  AutoFILE fp(toCStr(fname), "r");
+
+  stringBuilder sb;
+
+  char buf[4096];
+  for (;;) {
+    int len = fread(buf, 1, 4096, fp);
+    if (len < 0) {
+      xbase("fread failed");
+    }
+    if (len == 0) {
+      break;
+    }
+
+    sb.append(buf, len);
+  }
+
+  return sb;
+}
+
+
+bool readLine(string &dest, FILE *fp)
+{
+  char buf[80];
+
+  if (!fgets(buf, 80, fp)) {
+    return false;
+  }
+
+  if (buf[strlen(buf)-1] == '\n') {
+    // read a newline, we got the whole line
+    dest = buf;
+    return true;
+  }
+
+  // only got part of the string; need to iteratively construct
+  stringBuilder sb;
+  while (buf[strlen(buf)-1] != '\n') {
+    sb << buf;
+    if (!fgets(buf, 80, fp)) {
+      // found eof after partial; return partial *without* eof
+      // indication, since we did in fact read something
+      break;
+    }
+  }
+
+  dest = sb;
+  return true;
+}
+
+
+string chomp(rostring src)
+{
+  if (!src.empty() && src[strlen(src)-1] == '\n') {
+    return substring(src, strlen(src)-1);
+  }
+  else {
+    return src;
+  }
+}
+
+
+DelimStr::DelimStr(char delimiter0)
+  : delimiter(delimiter0)
+{}
+
+DelimStr& DelimStr::operator<< (char const *text) {
+  if (!sb.empty()) sb << delimiter;
+  sb << text;
+  return *this;
+}
+
+
+int compareStrings(const void *a, const void *b) {
+  char const **a1 = (char const **)a;
+  char const **b1 = (char const **)b;
+  return strcmp(*a1, *b1);
+}
+
+void qsortStringArray(char const **strings, int size) {
+  qsort(strings, size, sizeof strings[0], compareStrings);
+}
+
+
+// ----------------------- test code -----------------------------
+#ifdef TEST_STRUTIL
+
+#include "test.h"      // USUAL_MAIN
+
+#include <assert.h>    // assert
+#include <fstream.h>   // ofstream
+#include <stdlib.h>    // getenv
+#include <stdio.h>     // printf, remove
+
+void expRangeVector(char const *in, char const *out)
+{
+  printf("expRangeVector(%s, %s)\n", in, out);
+  string result = expandRanges(in);
+  xassert(result.equals(out));
+}
+
+void trVector(char const *in, char const *srcSpec, char const *destSpec, char const *out)
+{
+  printf("trVector(%s, %s, %s, %s)\n", in, srcSpec, destSpec, out);
+  string result = translate(in, srcSpec, destSpec);
+  xassert(result.equals(out));
+}
+
+void decodeVector(char const *in, char const *out, int outLen)
+{
+  printf("decodeVector: \"%s\"\n", in);
+  ArrayStack<char> dest;
+  decodeEscapes(dest, in, '\0' /*delim, ignored*/, false /*allowNewlines*/);
+  xassert(dest.length() == outLen);
+  xassert(0==memcmp(out, dest.getArray(), dest.length()));
+}
+
+void basenameVector(char const *in, char const *out)
+{
+  printf("basenameVector(%s, %s)\n", in, out);
+  string result = sm_basename(in);
+  xassert(result.equals(out));
+}
+
+void dirnameVector(char const *in, char const *out)
+{
+  printf("dirnameVector(%s, %s)\n", in, out);
+  string result = dirname(in);
+  xassert(result.equals(out));
+}
+
+void pluralVector(int n, char const *in, char const *out)
+{
+  printf("pluralVector(%d, %s, %s)\n", n, in, out);
+  string result = plural(n, in);
+  xassert(result.equals(out));
+}
+
+
+// testcase from Hendrik Tews
+void translateAscii()
+{
+  char ascii[256];
+  char underscore[256];
+
+  for(int i=0; i<=254; i++){
+    ascii[i] = i+1;
+    underscore[i] = '_';
+  }
+  ascii[255] = 0;
+  underscore[255] = 0;
+
+  {
+    ofstream file("strutil.out");
+    assert(file);
+    file << "Hallo" << endl
+         << ascii << endl
+         << "Hallo2" << endl
+         << translate(ascii, "\001-\057\072-\101\133-\140\173-\377", underscore)
+                                          // ^^^ probably should be 100, no biggie
+         << endl;
+  }
+
+  if (!getenv("SAVE_OUTPUT")) {
+    remove("strutil.out");
+  }
+}
+
+
+void entry()
+{
+  expRangeVector("abcd", "abcd");
+  expRangeVector("a", "a");
+  expRangeVector("a-k", "abcdefghijk");
+  expRangeVector("0-9E-Qz", "0123456789EFGHIJKLMNOPQz");
+
+  trVector("foo", "a-z", "A-Z", "FOO");
+  trVector("foo BaR", "a-z", "A-Z", "FOO BAR");
+  trVector("foo BaR", "m-z", "M-Z", "fOO BaR");
+
+  decodeVector("\\r\\n", "\r\n", 2);
+  decodeVector("abc\\0def", "abc\0def", 7);
+  decodeVector("\\033", "\033", 1);
+  decodeVector("\\x33", "\x33", 1);
+  decodeVector("\\?", "?", 1);
+
+  basenameVector("a/b/c", "c");
+  basenameVector("abc", "abc");
+  basenameVector("/", "");
+  basenameVector("a/b/c/", "c");
+
+  dirnameVector("a/b/c", "a/b");
+  dirnameVector("a/b/c/", "a/b");
+  dirnameVector("/a", "/");
+  dirnameVector("abc", ".");
+  dirnameVector("/", "/");
+
+  pluralVector(1, "path", "path");
+  pluralVector(2, "path", "paths");
+  pluralVector(1, "fly", "fly");
+  pluralVector(2, "fly", "flies");
+  pluralVector(2, "was", "were");
+
+  translateAscii();
+}
+
+
+USUAL_MAIN
+
+#endif // TEST_STRUTIL

Added: vendor/elsa/current/smbase/strutil.h
===================================================================
--- vendor/elsa/current/smbase/strutil.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/strutil.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,136 @@
+// strutil.h            see license.txt for copyright and terms of use
+// various string utilities built upon the 'str' module
+// Scott McPeak, July 2000
+
+#ifndef STRUTIL_H
+#define STRUTIL_H
+
+#include "str.h"      // string
+#include "array.h"    // ArrayStack
+
+#include <stdio.h>    // FILE
+
+
+// direct string replacement, replacing instances of oldstr with newstr
+// (newstr may be "")
+string replace(rostring src, rostring oldstr, rostring newstr);
+
+// works like unix "tr": the source string is translated character-by-character,
+// with occurrences of 'srcchars' replaced by corresponding characters from
+// 'destchars'; further, either set may use the "X-Y" notation to denote a
+// range of characters from X to Y
+string translate(rostring src, rostring srcchars, rostring destchars);
+
+// a simple example of using translate; it was originally inline, but a bug
+// in egcs made me move it out of line
+string stringToupper(rostring src);
+//  { return translate(src, "a-z", "A-Z"); }
+
+
+// remove any whitespace at the beginning or end of the string
+string trimWhitespace(rostring str);
+// dsw: get the first alphanum token in the string
+string firstAlphanumToken(rostring str);
+
+
+// encode a block of bytes as a string with C backslash escape
+// sequences (but without the opening or closing quotes)
+//
+// 'src' is *not* rostring, since it is not NUL terminated
+string encodeWithEscapes(char const *src, int len);
+
+// safe when the text has no NUL characters
+string encodeWithEscapes(rostring src);
+
+// adds the quotes too
+string quoted(rostring src);
+
+
+// decode an escaped string; throw xFormat if there is a problem
+// with the escape syntax; if 'delim' is specified, it will also
+// make sure there are no unescaped instances of that
+void decodeEscapes(ArrayStack<char> &dest, rostring src,
+                   char delim = 0, bool allowNewlines=false);
+
+// given a string with quotes and escapes, yield just the string;
+// works if there are no escaped NULs
+string parseQuotedString(rostring text);
+
+
+// this probably belongs in a dedicated module for time/date stuff..
+// returns asctime(localtime(time))
+string localTimeString();
+
+
+// given a directory name like "a/b/c", return "c"
+// renamed from 'basename' because of conflict with something in string.h
+string sm_basename(rostring src);
+
+// given a directory name like "a/b/c", return "a/b"; if 'src' contains
+// no slashes at all, return "."
+string dirname(rostring src);
+
+
+// return 'prefix', pluralized if n!=1; for example
+//   plural(1, "egg") yields "egg", but
+//   plural(2, "egg") yields "eggs";
+// it knows about a few irregular pluralizations (see the source),
+// and the expectation is I'll add more irregularities as I need them
+string plural(int n, rostring prefix);
+
+// same as 'plural', but with the stringized version of the number:
+//   pluraln(1, "egg") yields "1 egg", and
+//   pluraln(2, "egg") yields "2 eggs"
+string pluraln(int n, rostring prefix);
+
+// prepend with an indefinite article:
+//   a_or_an("foo") yields "a foo", and
+//   a_or_an("ogg") yields "an ogg"
+string a_or_an(rostring noun);
+
+
+// Sometimes it's useful to store a string value in a static buffer;
+// most often this is so 'gdb' can see the result.  This function just
+// copies its input into a static buffer (of unspecified length, but
+// it checks bounds internally), and returns a pointer to that buffer.
+char *copyToStaticBuffer(char const *src);
+
+
+// true if the first part of 'str' matches 'prefix'
+bool prefixEquals(rostring str, rostring prefix);
+
+// and similar for last part
+bool suffixEquals(rostring str, rostring suffix);
+
+
+// read/write strings <-> files
+void writeStringToFile(rostring str, rostring fname);
+string readStringFromFile(rostring fname);
+
+
+// read the next line from a FILE* (e.g. an AutoFILE); the
+// newline is returned if it is present (you can use 'chomp'
+// to remove it); returns false (and "") on EOF
+bool readLine(string &dest, FILE *fp);
+
+
+// like perl 'chomp': remove a final newline if there is one
+string chomp(rostring src);
+
+
+// dsw: build a string with delimiters between each appended string
+struct DelimStr {
+  char delimiter;               // this could be more general but I don't need it
+  stringBuilder sb;
+
+  explicit DelimStr(char delimiter0);
+  DelimStr& operator << (char const *text);
+};
+
+
+// compare function for strings; for use with qsort()
+int compareStrings(const void *a, const void *b);
+void qsortStringArray(char const **strings, int size);
+
+
+#endif // STRUTIL_H

Added: vendor/elsa/current/smbase/svdict.cc
===================================================================
--- vendor/elsa/current/smbase/svdict.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/svdict.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,547 @@
+// svdict.cc            see license.txt for copyright and terms of use
+// code for svdict.h
+
+#include "svdict.h"         // this module
+#include <string.h>         // strcmp
+
+
+#define FOREACH_NODE(itervar) \
+  for(Node *itervar = top; itervar != NULL; itervar = itervar->next)
+
+#define FOREACH_ITER(dict, itervar) \
+  for(Iter itervar = (dict).getIter(); !itervar.isDone(); itervar.next())
+
+#define FOREACH_ITERC(dict, itervar) \
+  for(IterC itervar = (dict).getIterC(); !itervar.isDone(); itervar.next())
+
+#define MUTABLE_SORT(obj) (const_cast<StringVoidDict&>(obj)).sort()
+
+
+STATICDEF char const *StringVoidDict::Node::getKey(StringVoidDict::Node const *n)
+{
+  return n->key.c_str();
+}
+
+
+StringVoidDict::StringVoidDict()
+  : top(NULL),
+    hash((StringHash::GetKeyFn)Node::getKey)
+{}
+
+
+StringVoidDict::StringVoidDict(StringVoidDict const &obj)
+  : top(NULL),
+    hash((StringHash::GetKeyFn)Node::getKey)
+{
+  *this = obj;
+}
+
+
+StringVoidDict::~StringVoidDict()
+{
+  SELFCHECK();
+  empty();
+}
+
+
+StringVoidDict& StringVoidDict::operator= (StringVoidDict const &obj)
+{
+  if (this == &obj) {
+    return *this;
+  }
+
+  empty();
+
+  Node *end = top;
+  FOREACH_ITERC(obj, src) {
+    // const_cast needed because the resulting dictionary can now access
+    // the data objects and modify them... hmm...
+    Node *newnode = new Node(src.key().c_str(), const_cast<void*>(src.value()));
+    if (!end) {
+      // first element of list
+      end = top = newnode;
+    }
+    else {
+      // adding to end of nonempty list
+      end = end->next = newnode;
+    }
+    hash.add(newnode->key.c_str(), newnode);
+  }
+
+  SELFCHECK();
+  return *this;
+}
+
+
+bool StringVoidDict::operator== (StringVoidDict const &obj) const
+{
+  // sort both lists
+  MUTABLE_SORT(*this);
+  MUTABLE_SORT(obj);
+
+  IterC ths(*this), other(obj);
+  while (!ths.isDone() && !other.isDone()) {
+    if (0!=strcmp(ths.key(), other.key()) ||
+        ths.value() != other.value()) {
+      return false;
+    }
+    ths.next();
+    other.next();
+  }
+
+  if (!ths.isDone() || !other.isDone()) {
+    // one finished first, so they can't be equal
+    return false;
+  }
+
+  return true;
+}
+
+
+bool StringVoidDict::isEmpty() const
+{
+  return top == NULL;
+}
+
+
+int StringVoidDict::size() const
+{
+  return hash.getNumEntries();
+}
+
+
+bool StringVoidDict::query(char const *key, void *&value) const
+{
+  Node *n = (Node*)hash.get(key);
+  if (!n) {
+    return false;
+  }
+
+  value = n->value;
+  return true;
+}
+
+
+void *StringVoidDict::queryf(char const *key) const
+{
+  void *ret;
+  bool ok = query(key, ret);
+  xassert(ok);
+  return ret;
+}
+
+
+void *StringVoidDict::queryif(char const *key) const
+{
+  void *ret;
+  if (query(key, ret)) {
+    return ret;
+  }
+  else {
+    return NULL;
+  }
+}
+
+
+bool StringVoidDict::isMapped(char const *key) const
+{
+  void *dummy;
+  return query(key, dummy);
+}
+
+
+void StringVoidDict::add(char const *key, void *value)
+{
+  xassert(!isMapped(key));
+
+  // just prepend; we'll sort later (when an iterator is retrieved)
+  top = new Node(key, value, top);
+  hash.add(key, top);
+
+  SELFCHECK();
+}
+
+// Another version of add() which takes a 'string const &'.  If we are using a
+// reference-counting implementation of 'string' then this is more efficient.
+// (The strdup inside this Node construction happens to be the bottleneck in
+// XML deserialization.)
+void StringVoidDict::add(string const &key, void *value)
+{
+  xassert(!isMapped(key.c_str()));
+
+  // just prepend; we'll sort later (when an iterator is retrieved)
+  top = new Node(key, value, top);
+  hash.add(key.c_str(), top);
+
+  SELFCHECK();
+}
+
+
+void *StringVoidDict::modify(char const *key, void *newValue)
+{
+  Iter entry = find(key);
+  xassert(!entry.isDone());
+
+  void *ret = entry.value();
+  entry.value() = newValue;
+
+  SELFCHECK();
+  return ret;
+}
+
+
+StringVoidDict::Iter StringVoidDict::find(char const *key)
+{
+  Node *n = (Node*)hash.get(key);
+  return Iter(n);
+}
+
+
+void *StringVoidDict::remove(char const *key)
+{
+  void *ret;     // will be previous value
+  xassert(top);
+
+  // check for removal of top element
+  if (0==strcmp(top->key, key)) {
+    Node *temp = top;
+    top = top->next;
+    ret = temp->value;
+    hash.remove(temp->key.c_str());
+    delete temp;
+  }
+
+  // find node to remove in tail of list
+  else {
+    Node *p = top;
+    while (p->next && 0!=strcmp(p->next->key, key)) {
+      p = p->next;
+    }
+
+    if (!p->next) {
+      // reached the end of the list without finding the key
+      xfailure("failed to find key");
+    }
+
+    // remove p->next from the list
+    Node *temp = p->next;
+    p->next = p->next->next;
+    ret = temp->value;
+    hash.remove(temp->key.c_str());
+    delete temp;
+  }
+
+  SELFCHECK();
+  return ret;
+}
+
+
+void StringVoidDict::empty()
+{
+  emptyAndDel(NULL);
+}
+
+void StringVoidDict::emptyAndDel(DelFn func)
+{
+  while (top) {
+    Node *temp = top;
+    top = top->next;
+
+    if (func != NULL) {
+      func(temp->value);
+    }
+    // hash.remove(temp->key.c_str());
+    delete temp;
+  }
+  hash.empty();
+
+  SELFCHECK();
+}
+
+
+StringVoidDict::Iter StringVoidDict::getIter()
+{
+  sort();        // must return items in sorted order
+  return Iter(top);
+}
+
+
+StringVoidDict::IterC StringVoidDict::getIterC() const
+{
+  //sort();
+  const_cast<StringVoidDict*>(this)->sort();    // mutable
+  return IterC(top);
+}
+
+
+void StringVoidDict::foreach(ForeachFn func, void *extra) const
+{
+  const_cast<StringVoidDict*>(this)->sort();    // mutable
+
+  for (Node *n = top; n != NULL; n = n->next) {
+    if (func(n->key, n->value, extra)) {
+      return;
+    }
+  }
+}
+
+
+// use simple insertion sort for now
+/*mutable*/ void StringVoidDict::sort()
+{
+  if (!top) {
+    return;
+  }
+
+  // invariant: sequence of nodes from 'top' to 'walker', inclusive,
+  //            is always sorted
+  Node *walker = top;
+  while (walker->next != NULL) {
+    // see if walker->next is out of order
+    if (0 <= strcmp(walker->key, walker->next->key)) {
+      // it's in order
+      walker = walker->next;
+      continue;
+    }
+
+    // remove walker->next from where it is (note that this has
+    // the effect of advancing walker, so below here we won't
+    // have another movement of walker)
+    Node *mover = walker->next;
+    walker->next = walker->next->next;
+    mover->next = NULL;       // (redundant because of (**) lines)
+
+    // insert at head?
+    if (0 < strcmp(mover->key, top->key)) {
+      mover->next = top;            // (**)
+      top = mover;
+      continue;
+    }
+
+    // must find correct place to insert mover (will find the place
+    // where we can insert mover just before searcher->next)
+    Node *searcher = top;
+    while (0 < strcmp(searcher->next->key, mover->key)) {
+      searcher = searcher->next;
+      xassert(searcher != walker);
+        // otherwise how could mover have been out of order to begin with?
+    }
+
+    // insert mover before searcher->next
+    mover->next = searcher->next;   // (**)
+    searcher->next = mover;
+  }
+
+  SELFCHECK();
+
+  #ifndef NDEBUG
+    verifySorted();
+  #endif
+}
+
+
+void StringVoidDict::verifySorted() const
+{
+  if (!top) {
+    return;
+  }
+
+  Node *p = top;
+  while (p->next) {
+    xassert(0 <= strcmp(p->key, p->next->key));
+    p = p->next;
+  }
+}
+
+
+// verify that the list is well structured
+void StringVoidDict::selfCheck() const
+{
+  {
+    Node *fast = top, *slow = top;
+    while (fast && fast->next) {
+      fast = fast->next->next;
+      slow = slow->next;
+
+      xassert(fast != slow);
+        // if these become equal, the list is circular
+    }
+  }
+
+  // check counts, mappings
+  int ct=0;
+  for (Node *n = top; n != NULL; n = n->next, ct++) {
+    xassert(hash.get(n->key.c_str()) == n);
+  }
+  xassert(hash.getNumEntries() == ct);
+}
+
+
+void StringVoidDict::insertOstream(ostream &os) const
+{
+  FOREACH_ITERC(*this, entry) {
+    os << entry.key() << " = " << entry.value() << endl;
+  }
+}
+
+
+string StringVoidDict::toString() const
+{
+  stringBuilder sb;
+  sb << "{";
+  int count=0;
+  FOREACH_ITERC(*this, entry) {
+    if (count++ > 0) {
+      sb << ",";
+    }
+    sb << " " << entry.key() << "=\"" << entry.value() << "\"";
+  }
+  sb << " }";
+  return sb;
+}
+
+
+// -------------------- test code ------------------------
+#ifdef TEST_SVDICT
+
+#include "test.h"      // USUAL_MAIN
+#include <stdlib.h>    // rand
+
+#define myrandom(n) (rand()%(n))
+
+char randChar()
+{
+  return (char)(myrandom(127-32+1)+32);
+}
+
+string randString(int len)
+{
+  stringBuilder str;
+  loopj(len) {
+    str << randChar();
+  }
+  return str;
+}
+
+string randStringRandLen(int maxlen)
+{
+  return randString(myrandom(maxlen)+1);
+}
+
+string randKey(StringVoidDict const &dict)
+{
+  int size = dict.size();
+  xassert(size > 0);
+
+  int nth = myrandom(size);
+  StringVoidDict::IterC entry(dict);
+  for (; nth > 0; entry.next(), nth--)
+    {}
+
+  return entry.key();
+}
+
+void *randVoidPtr()
+{
+  return (void*)(myrandom(100) * 8);
+}
+
+
+void entry()
+{
+  StringVoidDict dict;
+  int size=0, collisions=0;
+
+  int iters = 1000;
+  loopi(iters) {
+    switch (myrandom(6)) {
+      case 0: {
+        // insert a random element
+        string key = randStringRandLen(10);
+        void *value = randVoidPtr();
+
+        if (!dict.isMapped(key.c_str())) {
+          dict.add(key.c_str(), value);
+          size++;
+        }
+        else {
+          collisions++;
+        }
+        break;
+      }
+
+      case 1: {
+        // remove a random element
+        if (dict.isEmpty()) {
+          break;
+        }
+
+        string key = randKey(dict);
+        dict.remove(key.c_str());
+        size--;
+        break;
+      }
+
+      case 2: {
+        // check a random element that should not be there
+        string key = randStringRandLen(10);
+        if (dict.isMapped(key.c_str())) {
+          collisions++;
+        }
+        break;
+      }
+
+      case 3: {
+        // verify that computed length is right
+        xassert(size == dict.size());
+        break;
+      }
+
+      case 4: {
+        // test == and =
+        StringVoidDict dict2(dict);
+        xassert(dict2 == dict);
+        xassert(dict2.size() == dict.size());
+
+        // modify it, then verify inequality
+        if (!dict2.isEmpty()) {
+          string key = randKey(dict2);
+          void *value = dict2.queryf(key.c_str());
+
+          if (myrandom(2) == 0) {
+            dict2.remove(key.c_str());
+          }
+          else {
+            dict2.modify(key.c_str(), (void*)((char const *)value + 24));
+          }
+          xassert(dict2 != dict);
+        }
+
+        break;
+      }
+
+      case 5: {
+        // random modification
+        if (!dict.isEmpty()) {
+          string key = randKey(dict);
+          dict.modify(key.c_str(), randVoidPtr());
+        }
+        break;
+      }
+
+      default:
+        xfailure("huh?");
+        break;
+    }
+  }
+
+  cout << "final size: " << size
+       << "\ncollisions: " << collisions
+       << "\n";
+
+  cout << "all tests passed\n";
+}
+
+USUAL_MAIN
+
+#endif // TEST_STRDICT

Added: vendor/elsa/current/smbase/svdict.h
===================================================================
--- vendor/elsa/current/smbase/svdict.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/svdict.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,191 @@
+// svdict.h            see license.txt for copyright and terms of use
+// dictionary of void*, indexed by string (case-sensitive)
+// (c) Scott McPeak, 2000
+
+// created by modifying strdict; at some point strdict should
+// be rewritten to use this module
+
+#ifndef __SVDICT_H
+#define __SVDICT_H
+
+#include <iostream.h>   // ostream
+#include "str.h"        // string
+#include "macros.h"     // DMEMB
+#include "xassert.h"    // xassert
+#include "typ.h"        // MUTABLE
+#include "strhash.h"    // StringHash
+
+
+// constness: for this class, 'const' means the *mapping* from string
+// to void* won't change; but I don't prevent the thing pointed-at
+// by the void* from changing (would like multiple levels of constness..)
+
+class StringVoidDict {
+private:    // types
+  // 3/16/03: I believe the reason I stored the information both in a
+  // hash table and in a linked list is to be able to support efficient
+  // alphabetical iteration
+  class Node {
+  public:
+    Node *next;
+    string key;
+    void *value;
+
+  public:
+    Node(char const *k, void *v, Node *n = NULL)
+      : next(n), key(k), value(v) {}
+    Node(string const &k, void *v, Node *n = NULL)
+      : next(n), key(k), value(v) {}
+    ~Node() {}
+
+    static char const *getKey(Node const *n);
+  };
+
+public:     // types
+  // function for general foreach; return false to continue,
+  // true to stop iterating
+  typedef bool (*ForeachFn)(string const &key, void *value, void *extra);
+
+  // function type to delete void*s while emptying
+  typedef void (*DelFn)(void *value);
+
+  // Note: some care must be taken when dealing with Iters, because
+  //       they can be invalidated when held across modifications to
+  //       structure of the underlying dictionary
+  class Iter {
+  private:
+    Node *current;
+
+  public:
+    Iter(Node *n) : current(n) {}
+    Iter(StringVoidDict &dict) { operator=(dict.getIter()); }
+    Iter(Iter const &obj) : DMEMB(current) {}
+    Iter& operator= (Iter const &obj) { CMEMB(current); return *this; }
+
+    bool isDone() const { return current == NULL; }
+    void adv() { xassert(current); current = current->next; }
+    Iter& next() { xassert(current); current = current->next; return *this; }
+      // 'next' returns a value primarily to allow use in for-loop comma exprs
+
+    string &key() const { return current->key; }
+    void *&value() const { return current->value; }
+
+    long private_getCurrent() const { return (long)current; }
+  };
+  friend class Iter;
+
+  // iterator that can't modify the dictionary entries
+  class IterC : protected Iter {
+  public:
+    IterC(Node const *n) : Iter(const_cast<Node*>(n)) {}
+    IterC(StringVoidDict const &dict) : Iter(const_cast<StringVoidDict&>(dict)) {}
+    IterC(IterC const &obj) : Iter(obj) {}
+    IterC& operator= (IterC const &obj) { Iter::operator=(obj); return *this; }
+
+    // some operations can be made available unchanged
+    Iter::isDone;
+    Iter::next;
+    Iter::private_getCurrent;
+
+    // others must be const-ified
+    string const &key() const { return Iter::key(); }
+    void const *&value() const { return (void const *&)Iter::value(); }
+  };
+
+private:    // data
+  // first list node (possibly NULL)
+  Node *top;
+
+  // hash table to improve lookup performance
+  StringHash hash;
+
+  // invariants:
+  //   list is well-formed structurally
+  //   every node is in the hash table, and vice versa
+
+protected:  // funcs
+  void selfCheck() const;      // throw exception if invariants violated
+
+  void verifySorted() const;   // throw exception if list isn't sorted
+
+  void /*mutable*/ sort();     // arrange nodes in alphabetically sorted order
+    // (mutable because this isn't supposed to be visible from the outside)
+
+public:
+  StringVoidDict();          // initializes to empty dictionary
+  StringVoidDict(StringVoidDict const &obj);
+  ~StringVoidDict();
+
+  StringVoidDict& operator= (StringVoidDict const &obj);
+
+  // comparison is done by pointer equality of void*
+  bool operator== (StringVoidDict const &obj) const;
+  NOTEQUAL_OPERATOR(StringVoidDict)
+
+  // ------- selectors ---------
+  int size() const;
+    // retrieve # of mappings
+
+  bool isEmpty() const;
+    // returns true if size() is 0
+
+  bool isNotEmpty() const
+    { return !isEmpty(); }
+
+  bool query(char const *key, void *&value) const;
+    // if 'key' is mapped to a value, put it into 'value' and return true;
+    // otherwise, return false
+
+  void *queryf(char const *key) const;
+    // return the value corresponding to 'key', or throw an exception of it's
+    // not mapped
+
+  void *queryif(char const *key) const;
+    // return the value corresponding to 'key', or return NULL
+
+  bool isMapped(char const *key) const;
+    // return true if 'key' is mapped to a value
+
+  // -------- mutators -----------
+  void add(char const *key, void *value);
+  void add(string const &key, void *value);
+    // add a mapping from 'key' to 'value'; 'key' must initially be unmapped
+
+  void *modify(char const *key, void *newValue);
+    // change the existing value for 'key', which must exist, to 'newValue';
+    // the old value is returned
+
+  void *remove(char const *key);
+    // remove the mapping from 'key', which must exist; it is returned
+
+  void emptyAndDel(DelFn func);
+    // apply the deletion func to all values, during empty()
+
+  void empty();
+    // remove all mappings
+
+  // --------- iters -------------
+  Iter getIter();
+    // retrieve an iterator (the iterator remains valid only as long as
+    // the structure of the dictionary does not get modified);
+    // values will be iterated in *alphabetical* order
+
+  IterC getIterC() const;
+    // retrieve a const iterator
+
+  Iter find(char const *key);
+    // return an iterator pointing to 'key', or an iterator
+    // that isDone() if 'key' isn't mapped
+
+  void foreach(ForeachFn func, void *extra=NULL) const;
+    // apply 'func' to every mapping, in alphabetical order
+
+  // ------------ misc --------------
+  INSERT_OSTREAM(StringVoidDict)
+  string toString() const;
+
+  // debugging...
+  long private_getTopAddr() const { return (long)top; }
+};
+
+#endif // __SVDICT_H

Added: vendor/elsa/current/smbase/syserr.cpp
===================================================================
--- vendor/elsa/current/smbase/syserr.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/syserr.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,384 @@
+// syserr.cpp            see license.txt for copyright and terms of use
+// code for syserr.h
+// Scott McPeak, 1999-2000  This file is public domain.
+
+#include "syserr.h"       // this module
+
+// ---------------- portable code ----------------
+char const * const xSysError::reasonStrings[] = {
+  "No error occurred",
+  "File not found",
+  "Path not found",
+  "Access denied",
+  "Out of memory (maybe)",    // always a suspicious message
+  "Invalid pointer address",
+  "Invalid data format",
+  "Invalid argument",
+  "Attempt to modify read-only data",
+  "The object already exists",
+  "Resource is temporarily unavailable",
+  "Resource is busy",
+  "File name is invalid (too long, or bad chars, or ...)",
+  "Unknown or unrecognized error",
+  "(bug -- invalid reason code)"        // corresponds to NUM_REASONS
+};
+
+
+STATICDEF char const *xSysError::
+  getReasonString(xSysError::Reason r)
+{
+  // at compile-time, verify consistency between enumeration and string array
+  // (it's in here because, at least on Borland, the preprocessor respects
+  // the member access rules (strangely..))
+  #ifdef __BORLANDC__
+    #if TABLESIZE(reasonStrings) != NUM_REASONS+1
+      #error table and enumeration do not match
+    #endif
+  #endif
+
+  if ((unsigned)r < NUM_REASONS) {
+    return reasonStrings[r];
+  }
+  else {
+    return reasonStrings[NUM_REASONS];
+  }
+}
+
+
+xSysError::xSysError(xSysError::Reason r, int sysCode, rostring sysReason,
+                     rostring syscall, rostring ctx)
+  : xBase(constructWhyString(r, sysReason, syscall, ctx)),
+    reason(r),
+    reasonString(getReasonString(r)),
+    sysErrorCode(sysCode),
+    sysReasonString(sysReason),
+    syscallName(syscall),
+    context(ctx)
+{}
+
+
+STATICDEF string xSysError::
+  constructWhyString(xSysError::Reason r, rostring sysReason,
+                     rostring syscall, rostring ctx)
+{
+  // build string; start with syscall that failed
+  stringBuilder sb;
+  sb << syscall << ": ";
+
+  // now a failure reason string
+  if (r != R_UNKNOWN) {
+    sb << getReasonString(r);
+  }
+  else if ( /*(sysReason != NULL) &&*/ (sysReason[0] != 0)) {
+    sb << sysReason;
+  }
+  else {
+    // no useful info, use the R_UNKNOWN string
+    sb << getReasonString(r);
+  }
+
+  // finally, the context
+  if (!ctx.empty()) {
+    sb << ", " << ctx;
+  }
+
+  return sb;
+}
+
+
+xSysError::xSysError(xSysError const &obj)
+  : xBase(obj),
+    reason(obj.reason),
+    reasonString(obj.reasonString),
+    sysErrorCode(obj.sysErrorCode),
+    sysReasonString(obj.sysReasonString),
+    syscallName(obj.syscallName),
+    context(obj.context)
+{}
+
+
+xSysError::~xSysError()
+{}
+
+
+STATICDEF void xSysError::
+  xsyserror(rostring syscallName, rostring context)
+{
+  // retrieve system error code
+  int code = getSystemErrorCode();
+
+  // translate it into one of ours
+  string sysMsg;
+  Reason r = portablize(code, sysMsg);
+
+  // construct an object to throw
+  xSysError obj(r, code, sysMsg, syscallName, context);
+
+  // toss it
+  THROW(obj);
+}
+
+void xsyserror(char const *syscallName)
+{
+  xSysError::xsyserror(syscallName, string(""));
+}
+
+void xsyserror(rostring syscallName, rostring context)
+{
+  xSysError::xsyserror(syscallName, context);
+}
+
+
+string sysErrorCodeString(int systemErrorCode, rostring syscallName,
+                                               rostring context)
+{
+  string sysMsg;
+  xSysError::Reason r = xSysError::portablize(systemErrorCode, sysMsg);
+  return xSysError::constructWhyString(
+           r, sysMsg,
+           syscallName, context);
+}
+
+string sysErrorString(char const *syscallName, char const *context)
+{
+  return sysErrorCodeString(xSysError::getSystemErrorCode(),
+                            syscallName, context);
+}
+
+
+// ----------------------- Win32 code ------------------------------------
+#ifdef __WIN32__
+
+#ifdef USE_MINWIN_H
+#  include "minwin.h"   // api
+#else
+#  include <windows.h>  // api
+#endif
+#include <errno.h>      // errno
+
+STATICDEF int xSysError::getSystemErrorCode()
+{
+  int ret = GetLastError();
+
+  // update: The confusing behavior I observed was with the Borland 4.5
+  // runtime libraries.  When I linked with the non-multithreaded versions,
+  // GetLastError worked as expected.  But when I linked with the
+  // multithreaded versions, GetLastError always returned 0, and I had to
+  // consult errno instead.  Further, the errno values didn't coincide
+  // exactly with expected values.  Therefore, the solution (at least for
+  // now) is to link only with the non-multithreaded versions, and not
+  // look to errno for anything.
+  #ifdef MT
+  #  error something is fishy with multithreaded..
+  #endif
+
+  // I thought something was happening, but now it seems
+  // it's not..
+  #if 0     // ?
+  if (ret == ERROR_SUCCESS) {
+    // for some calls, like mkdir, GetLastError is not
+    // set, but errno is; fortunately, MS decided to
+    // (mostly) overlap GetLastError codes with errno codes,
+    // so let's try this:
+    return errno;
+  }
+  #endif // 0
+
+  return ret;
+}
+
+
+STATICDEF xSysError::Reason xSysError::portablize(int sysErrorCode, string &sysMsg)
+{
+  // I'd like to put this into a static class member, but then
+  // the table would have to prepend R_ constants with xSysError::,
+  // which is a pain.
+
+  // method to translate an error code into a string on win32; this
+  // code is copied+modified from the win32 SDK docs for FormatMessage
+  {
+    // get the string
+    LPVOID lpMsgBuf;
+    FormatMessage(
+        FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_FROM_SYSTEM |
+        FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL,
+        GetLastError(),
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+        (LPTSTR) &lpMsgBuf,
+        0,
+        NULL
+    );
+
+    // now the SDK says: "Process any inserts in lpMsgBuf."
+    //
+    // I think this means that lpMsgBuf might have "%" escape
+    // sequences in it... oh well, I'm just going to keep them
+
+    // make a copy of the string
+    sysMsg = (char*)lpMsgBuf;
+
+    // Free the buffer.
+    LocalFree( lpMsgBuf );
+  }
+
+  static struct S {
+    int code;
+    Reason reason;
+  } const arr[] = {
+    { ERROR_SUCCESS,           R_NO_ERROR          },
+    { ERROR_FILE_NOT_FOUND,    R_FILE_NOT_FOUND    },
+    { ERROR_PATH_NOT_FOUND,    R_PATH_NOT_FOUND    },
+    { ERROR_ACCESS_DENIED,     R_ACCESS_DENIED     },
+    { ERROR_NOT_ENOUGH_MEMORY, R_OUT_OF_MEMORY     },
+    { ERROR_OUTOFMEMORY,       R_OUT_OF_MEMORY     },
+    { ERROR_INVALID_BLOCK,     R_SEGFAULT          },
+    { ERROR_BAD_FORMAT,        R_FORMAT            },
+    { ERROR_INVALID_DATA,      R_INVALID_ARGUMENT  },
+    { ERROR_WRITE_PROTECT,     R_READ_ONLY         },
+    { ERROR_ALREADY_EXISTS,    R_ALREADY_EXISTS    },
+    // ???                     R_AGAIN
+    { ERROR_BUSY,              R_BUSY              },
+  };
+
+  loopi(TABLESIZE(arr)) {
+    if (arr[i].code == sysErrorCode) {
+      // found it
+      return arr[i].reason;
+    }
+  }
+
+  // I don't know
+  return R_UNKNOWN;
+}
+
+
+// ---------------------- unix ---------------------------
+#else      // unix
+
+#include <errno.h>       // errno
+#include <string.h>      // strerror
+
+// mappings to a set of error codes I can use below
+// (I am sure I've already done this somewhere else, but I
+// may have lost that file)
+#ifndef EZERO
+#  define EZERO 0
+#endif
+#ifndef ENOFILE
+#  define ENOFILE ENOENT
+#endif
+#ifndef ENOPATH
+#  define ENOPATH ENOENT
+#endif
+#ifndef EINVMEM
+#  define EINVMEM EFAULT
+#endif
+#ifndef EINVFMT
+#  define EINVFMT 0         // won't be seen because EZERO is first
+#endif
+
+
+STATICDEF int xSysError::getSystemErrorCode()
+{
+  return errno;          // why was this "errno()"??
+}
+
+
+STATICDEF xSysError::Reason xSysError::portablize(int sysErrorCode, string &sysMsg)
+{
+  sysMsg = strerror(sysErrorCode);
+    // operator= copies to local storage
+
+  static struct S {
+    int code;
+    Reason reason;
+  } const arr[] = {
+    { EZERO,        R_NO_ERROR          },
+    { ENOFILE,      R_FILE_NOT_FOUND    },
+    { ENOPATH,      R_PATH_NOT_FOUND    },
+    { EACCES,       R_ACCESS_DENIED     },
+    { ENOMEM,       R_OUT_OF_MEMORY     },
+    { EINVMEM,      R_SEGFAULT          },
+    { EINVFMT,      R_FORMAT            },
+    { EINVAL,       R_INVALID_ARGUMENT  },
+    { EROFS,        R_READ_ONLY         },
+    { EEXIST,       R_ALREADY_EXISTS    },
+    { EAGAIN,       R_AGAIN             },
+    { EBUSY,        R_BUSY              },
+    { ENAMETOOLONG, R_INVALID_FILENAME  },
+  };
+
+  loopi(TABLESIZE(arr)) {
+    if (arr[i].code == sysErrorCode) {
+      // found it
+      return arr[i].reason;
+    }
+  }
+
+  // I don't know
+  return R_UNKNOWN;
+}
+
+
+#endif  // unix
+
+
+// ------------------ test code ------------------------
+#ifdef TEST_SYSERR
+#include "test.h"       // various
+#include "nonport.h"    // changeDirectory
+
+// this is a macro because failingCall needs to be
+// call-by-name so I can wrap it in a try
+#define TRY_FAIL(failingCall, expectedCode)                       \
+  try {                                                           \
+    if (failingCall) {                                            \
+      cout << "ERROR: " #failingCall " should have failed\n";     \
+    }                                                             \
+    else {                                                        \
+      /* got an error to test */                                  \
+      xsyserror(#failingCall);                                    \
+    }                                                             \
+  }                                                               \
+  catch (xSysError &x) {                                          \
+    if (x.reason != xSysError::expectedCode) {                    \
+      cout << "ERROR: " #failingCall " returned '"                \
+           << x.reasonString << "' but '"                         \
+           << xSysError::getReasonString(xSysError::expectedCode) \
+           << "' was expected\n";                                 \
+      errors++;                                                   \
+    }                                                             \
+  }
+
+void entry()
+{
+  int errors = 0;
+  xBase::logExceptions = false;
+  //nonportFail = xSysError::xsyserror;
+
+  //TRY_FAIL(createDirectory("/tmp\\Scott\\"),
+  //         R_ALREADY_EXISTS);
+
+  TRY_FAIL(changeDirectory("some.strange.name/yadda"),
+           R_PATH_NOT_FOUND);
+
+  TRY_FAIL(createDirectory("/tmp"),
+           R_ALREADY_EXISTS);
+
+  TRY_FAIL(isDirectory("doesnt.exist"),
+           R_FILE_NOT_FOUND);
+
+  if (errors == 0) {
+    cout << "success!\n";
+  }
+  else {
+    cout << errors << " error(s)\n";
+  }
+}
+
+USUAL_MAIN
+
+#endif // TEST_SYSERR
+

Added: vendor/elsa/current/smbase/syserr.h
===================================================================
--- vendor/elsa/current/smbase/syserr.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/syserr.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,100 @@
+// syserr.h            see license.txt for copyright and terms of use
+// error-reporting exception for system calls that fail
+// Scott McPeak, 1999  This file is public domain.
+
+// The intent here is to provide a way for portable *handling* of errors
+// that are generated by nonportable code.
+
+#ifndef __SYSERR_H
+#define __SYSERR_H
+
+#include "exc.h"       // xBase
+
+class xSysError : public xBase {
+private:    // data
+  // error strings for Reasons
+  static char const * const reasonStrings[];
+
+public:     // data
+  // portable failure reasons (modelled loosely on errno.h)
+  // it is anticipated that, as certain errors become important on certain
+  //   platforms, that this list will be extended as necessary
+  enum Reason {
+    R_NO_ERROR,          // no error occurred
+    R_FILE_NOT_FOUND,
+    R_PATH_NOT_FOUND,
+    R_ACCESS_DENIED,
+    R_OUT_OF_MEMORY,
+    R_SEGFAULT,          // invalid address / pointer
+    R_FORMAT,            // bad data format
+    R_INVALID_ARGUMENT,
+    R_READ_ONLY,
+    R_ALREADY_EXISTS,
+    R_AGAIN,             // resource temporarily unavailable
+    R_BUSY,              // resource busy
+    R_INVALID_FILENAME,  // too long, bad chars, etc.
+    R_UNKNOWN,           // OS-specific, can't find out, just don't know, etc.
+    NUM_REASONS          // (must be last item in list)
+  } reason;
+
+  // reason string that corresponds to 'reason'
+  char const * const reasonString;
+
+  // nonportable error code (errno on Unix, GetLastError() on Windows)
+  // (value is 0 when we don't have this information)
+  int sysErrorCode;
+
+  // reason string given by the OS, if any (might be NULL)
+  string sysReasonString;
+
+  // name of syscall or API function name
+  string syscallName;
+
+  // error context; what was being done (e.g., "opening an.important.file")
+  string context;
+
+public:    // funcs
+  xSysError(Reason r, int sysCode, rostring sysReason,
+            rostring syscall, rostring ctx);
+  xSysError(xSysError const &obj);
+  ~xSysError();
+
+  // mapping functions used internally
+  static int getSystemErrorCode();
+    // retrieve the error code used by local convention
+    // [nonportable implementation]
+
+  static Reason portablize(int sysErrorCode, string &sysReason);
+    // return a portable equivalent of a system error code;
+    // returns R_UNKNOWN if the code is esoteric or invalid;
+    // sets 'sysmsg' to the system's message string, if possible
+    // [nonportable implementation]
+
+  static char const *getReasonString(Reason r);
+    // translate a Reason into a string (if r is invalid, a string
+    // saying to will be returned)
+
+  static string constructWhyString(Reason r, rostring sysReason,
+                                   rostring syscall, rostring ctx);
+    // construct the string we throw as the 'why' of xBase; if ctx is NULL,
+    // the string doesn't include it
+
+  static void xsyserror(rostring syscallName, rostring context);
+    // does the throw
+};
+
+
+// function that does the throw
+void xsyserror(char const *syscallName);
+void xsyserror(rostring syscallName, rostring context);
+
+
+// get a representative string, for logging etc.
+string sysErrorCodeString(int systemErrorCode, rostring syscallName,
+                                               rostring context);
+
+string sysErrorString(char const *syscallName, char const *context=NULL);
+
+
+#endif // __SYSERR_H
+

Added: vendor/elsa/current/smbase/taillist.h
===================================================================
--- vendor/elsa/current/smbase/taillist.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/taillist.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,134 @@
+// taillist.h; see license.txt for copyright and terms of use
+// list wrapper around VoidTailList in the spirit of ASTList, but doesn't own
+
+// taken almost verbatim from asttlist.h in smbase
+
+#ifndef TAILLIST_H
+#define TAILLIST_H
+
+#include "vdtllist.h"           // VoidTailList
+
+template <class T> class TailListIter;
+template <class T> class TailListIterNC;
+
+// a list which does not own the items in it (will NOT deallocate
+// them), and has constant-time access to the last element
+template <class T>
+class TailList {
+private:
+  friend class TailListIter<T>;
+  friend class TailListIterNC<T>;
+
+protected:
+  VoidTailList list;            // list itself
+
+private:
+  TailList(TailList const &obj); // not allowed
+
+public:
+  TailList()                             : list() {}
+  ~TailList()                            {  }
+
+  // ctor to make singleton list; often quite useful
+  TailList(T *elt)                       : list() { prepend((void*)elt); }
+
+  // stealing ctor; among other things, since &src->list is assumed to
+  // point at 'src', this class can't have virtual functions;
+  // these ctors delete 'src'
+  TailList(TailList<T> *src)              : list(&src->list) {}
+  void steal(TailList<T> *src)           { list.steal(&src->list); }
+
+  // selectors
+  int count() const                     { return list.count(); }
+  bool isEmpty() const                  { return list.isEmpty(); }
+  bool isNotEmpty() const               { return list.isNotEmpty(); }
+  T *nth(int which)                     { return (T*)list.nth(which); }
+  T const *nthC(int which) const        { return (T const*)list.nth(which); }
+  T *first()                            { return (T*)list.first(); }
+  T const *firstC() const               { return (T const*)list.first(); }
+  T *last()                             { return (T*)list.last(); }
+  T const *lastC() const                { return (T const*)list.last(); }
+
+  // insertion
+  void prepend(T *newitem)              { list.prepend((void*)newitem); }
+  void append(T *newitem)               { list.append((void*)newitem); }
+  void appendAll(TailList<T> &tail)     { list.appendAll(tail.list); }
+  void insertAt(T *newitem, int index)  { list.insertAt((void*)newitem, index); }
+  void concat(TailList<T> &tail)         { list.concat(tail.list); }
+
+  // removal
+  T *removeFirst()                      { return (T*)list.removeFirst(); }
+  T *removeLast()                       { return (T*)list.removeLast(); }
+  T *removeAt(int index)                { return (T*)list.removeAt(index); }
+  void removeItem(T *item)              { list.removeItem((void*)item); }
+
+  // list-as-set: selectors
+  int indexOf(T const *item) const      { return list.indexOf((void*)item); }
+  int indexOfF(T const *item) const     { return list.indexOfF((void*)item); }
+  bool contains(T const *item) const    { return list.contains((void*)item); }
+
+  // list-as-set: mutators
+  bool prependUnique(T *newitem)        { return list.prependUnique((void*)newitem); }
+  bool appendUnique(T *newitem)         { return list.appendUnique((void*)newitem); }
+
+  // debugging: two additional invariants
+  void selfCheck() const                { list.selfCheck(); }
+};
+
+
+template <class T>
+class TailListIter {
+protected:
+  VoidTailListIter iter;        // underlying iterator
+
+public:
+  TailListIter() {}      // initially done
+  TailListIter(TailList<T> const &list) : iter(list.list) {}
+  ~TailListIter()                       {}
+
+  void reset(TailList<T> const &list)   { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  TailListIter(TailListIter const &obj)             : iter(obj.iter) {}
+  TailListIter& operator=(TailListIter const &obj)  { iter = obj.iter;  return *this; }
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T const *data() const                 { return (T const*)iter.data(); }
+};
+
+#define FOREACH_TAILLIST(T, list, iter) \
+  for(TailListIter<T> iter(list); !iter.isDone(); iter.adv())
+
+
+// version of the above, but for non-const-element traversal
+template <class T>
+class TailListIterNC {
+protected:
+  VoidTailListIter iter;        // underlying iterator
+
+public:
+  TailListIterNC() {}      // initially done
+  TailListIterNC(TailList<T> &list)      : iter(list.list) {}
+  ~TailListIterNC()                     {}
+
+  void reset(TailList<T> &list)         { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  TailListIterNC(TailListIterNC const &obj)             : iter(obj.iter) {}
+  TailListIterNC& operator=(TailListIterNC const &obj)  { iter = obj.iter;  return *this; }
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T *data() const                       { return (T*)iter.data(); }
+
+  // iterator mutation; use with caution
+  void setDataLink(T *newData)          { iter.setDataLink((void*)newData); }
+};
+
+#define FOREACH_TAILLIST_NC(T, list, iter) \
+  for(TailListIterNC<T> iter(list); !iter.isDone(); iter.adv())
+
+#endif // TailLIST_H

Added: vendor/elsa/current/smbase/taillist_test.cc
===================================================================
--- vendor/elsa/current/smbase/taillist_test.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/taillist_test.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,44 @@
+// taillist_test.cc; see License.txt for copyright and terms of use
+
+// test code for taillist
+#include "taillist.h"
+#include "test.h" // USUAL_MAIN
+
+void entry()
+{
+  int a = 2,b = 4,c = 8,d = 16, e = 42;
+
+  TailList<int> list;
+
+  list.append(&d);
+  list.prepend(&b);		// 4, 16
+  list.insertAt(&c,1); 		// 4, 8, 16
+  list.append(&e); 		// 4, 8, 16, 42
+  
+  list.removeLast();		// 4, 8, 16
+
+  xassert( list.count() == 3 &&
+	   !list.isEmpty() &&
+	   list.nth(0) == &b &&
+	   list.nth(1) == &c &&
+	   list.nth(2) == &d &&
+	   list.indexOf(&b) == 0 &&
+	   list.indexOf(&c) == 1 &&
+	   list.indexOf(&e) == -1 &&
+	   list.indexOf(&d) == 2
+	   );
+  
+  // FIX: the selfCheck routine in the VoidTailList superclass is broken. 
+  // list.selfCheck();
+  
+  list.prepend(&a);		// 2, 4, 8, 16
+  
+  int count = 2;
+  FOREACH_TAILLIST_NC(int,list, iter) {
+    xassert( *(iter.data()) == count);
+    count *= 2;
+  }
+
+}
+
+USUAL_MAIN

Added: vendor/elsa/current/smbase/tarrayqueue.cc
===================================================================
--- vendor/elsa/current/smbase/tarrayqueue.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/tarrayqueue.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,81 @@
+// tarrayqueue.cc
+// test arrayqueue.h module
+
+#include "arrayqueue.h"      // module to test
+#include "objlist.h"         // ObjList
+#include "ckheap.h"          // malloc_stats
+
+#include <stdio.h>           // printf
+#include <stdlib.h>          // exit
+
+
+int maxLength = 0;
+
+// one round of testing
+void round(int ops)
+{
+  // implementation to test
+  ArrayQueue<int> arrayQueue;
+
+  // "trusted" implementation to compare with
+  ObjList<int> listQueue;
+
+  while (ops--) {
+    // check that the array and list agree
+    {
+      int index = 0;
+      FOREACH_OBJLIST(int, listQueue, iter) {
+        xassert(iter.data()[0] == arrayQueue[index]);
+        index++;
+      }
+      xassert(index == arrayQueue.length());
+      xassert(arrayQueue.isEmpty() == listQueue.isEmpty());
+      xassert(arrayQueue.isNotEmpty() == listQueue.isNotEmpty());
+      
+      if (index > maxLength) {
+        maxLength = index;
+      }
+    }
+
+    // do a random operation
+    int op = rand() % 100;
+    if (op == 0) {
+      // empty the queues
+      arrayQueue.empty();
+      listQueue.deleteAll();
+    }
+    else if (op < 5) {
+      // reverse them
+      arrayQueue.reverse();
+      listQueue.reverse();
+    }
+    else if (op < 40 && arrayQueue.isNotEmpty()) {
+      // dequeue
+      int i = arrayQueue.dequeue();
+      int *j = listQueue.removeFirst();
+      xassert(i == *j);
+      delete j;
+    }
+    else {
+      // enqueue
+      int elt = rand() % 100;
+      arrayQueue.enqueue(elt);
+      listQueue.append(new int(elt));
+    }
+  }
+}
+
+
+int main()
+{
+  for (int i=0; i<20; i++) {
+    round(1000);
+  }
+
+  malloc_stats();
+  printf("arrayqueue appears to work; maxLength=%d\n", maxLength);
+  return 0;
+}
+
+
+// EOF

Added: vendor/elsa/current/smbase/test.h
===================================================================
--- vendor/elsa/current/smbase/test.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/test.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,69 @@
+// test.h            see license.txt for copyright and terms of use
+// utilities for test code
+// Scott McPeak, 1999  This file is public domain.
+
+#ifndef __TEST_H
+#define __TEST_H
+
+#include <iostream.h>      // cout
+#include <stdio.h>         // printf
+#include "exc.h"           // xBase
+#include "nonport.h"       // getMilliseconds
+
+
+// reports uncaught exceptions
+//
+// 12/30/02: I used to print "uncaught exception: " before
+// printing the exception, but this is meaningless to the
+// user and the message usually has enough info anyway
+#define USUAL_MAIN                              \
+void entry();                                   \
+int main()                                      \
+{                                               \
+  try {                                         \
+    entry();                                    \
+    return 0;                                   \
+  }                                             \
+  catch (xBase &x) {                            \
+    cout << x << endl;                          \
+    return 4;                                   \
+  }                                             \
+}
+
+// same as above, but with command-line args
+#define ARGS_MAIN                               \
+void entry(int argc, char *argv[]);             \
+int main(int argc, char *argv[])                \
+{                                               \
+  try {                                         \
+    entry(argc, argv);                          \
+    return 0;                                   \
+  }                                             \
+  catch (xBase &x) {                            \
+    cout << x << endl;                          \
+    return 4;                                   \
+  }                                             \
+}
+
+
+// convenient for printing the value of a variable or expression
+#define PVAL(val) cout << #val << " = " << (val) << endl
+
+
+// easy way to time a section of code
+class TimedSection {
+  char const *name;
+  long start;
+
+public:
+  TimedSection(char const *n) : name(n) {
+    start = getMilliseconds();
+  }
+  ~TimedSection() {
+    cout << name << ": " << (getMilliseconds() - start) << " msecs\n";
+  }
+};
+
+
+#endif // __TEST_H
+

Added: vendor/elsa/current/smbase/test.input
===================================================================
(Binary files differ)


Property changes on: vendor/elsa/current/smbase/test.input
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: vendor/elsa/current/smbase/testarray.cc
===================================================================
--- vendor/elsa/current/smbase/testarray.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/testarray.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,87 @@
+// testarray.cc
+// test the array.h module
+// based on tarrayqueue.cc
+
+#include "array.h"     // module to test
+#include "objlist.h"         // ObjList
+#include "ckheap.h"          // malloc_stats
+
+#include <stdio.h>           // printf
+#include <stdlib.h>          // exit
+
+
+int maxLength = 0;
+
+// one round of testing
+void round(int ops)
+{
+  // implementations to test
+  ArrayStack<int> arrayStack;
+  ArrayStackEmbed<int, 10> arrayStackEmbed;
+
+  // "trusted" implementation to compare with
+  ObjList<int> listStack;
+
+  while (ops--) {
+    // check that the arrays and list agree
+    {
+      int length = listStack.count();
+      if (length > 0) {
+        xassert(listStack.first()[0] == arrayStack.top());
+        xassert(listStack.first()[0] == arrayStackEmbed.top());
+      }
+
+      int index = length-1;
+      FOREACH_OBJLIST(int, listStack, iter) {
+        xassert(iter.data()[0] == arrayStack[index]);
+        xassert(iter.data()[0] == arrayStackEmbed[index]);
+        index--;
+      }
+      xassert(index == -1);
+      xassert(length == arrayStack.length());
+      xassert(length == arrayStackEmbed.length());
+      xassert(arrayStack.isEmpty() == listStack.isEmpty());
+      xassert(arrayStackEmbed.isEmpty() == listStack.isEmpty());
+      xassert(arrayStack.isNotEmpty() == listStack.isNotEmpty());
+      xassert(arrayStackEmbed.isNotEmpty() == listStack.isNotEmpty());
+
+      if (length > maxLength) {
+        maxLength = length;
+      }
+    }
+
+    // do a random operation
+    int op = rand() % 100;
+    if (op < 40 && arrayStack.isNotEmpty()) {
+      // pop
+      int i = arrayStack.pop();
+      int j = arrayStackEmbed.pop();
+      int *k = listStack.removeFirst();
+      xassert(i == *k);
+      xassert(j == *k);
+      delete k;
+    }
+    else {
+      // push
+      int elt = rand() % 100;
+      arrayStack.push(elt);
+      arrayStackEmbed.push(elt);
+      listStack.prepend(new int(elt));
+    }
+  }
+}
+
+
+int main()
+{
+  for (int i=0; i<20; i++) {
+    round(1000);
+  }
+
+  malloc_stats();
+  printf("arrayStack appears to work; maxLength=%d\n", maxLength);
+  return 0;
+}
+
+
+// EOF

Added: vendor/elsa/current/smbase/testcout.cc
===================================================================
--- vendor/elsa/current/smbase/testcout.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/testcout.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,10 @@
+// testcout.cc
+// very simple test of the C++ compiler and runtime
+
+#include <iostream.h>     // cout
+
+int main()
+{
+  cout << "testcout: works\n";
+  return 0;
+}

Added: vendor/elsa/current/smbase/testmalloc.cc
===================================================================
--- vendor/elsa/current/smbase/testmalloc.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/testmalloc.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,130 @@
+// testmalloc.cc            see license.txt for copyright and terms of use
+// test malloc, test heap walk, etc.
+  
+#include <stdio.h>     // printf
+#include <unistd.h>    // write
+#include <string.h>    // strlen
+#include <stdlib.h>    // malloc
+
+#include "ckheap.h"    // malloc functions
+
+
+HeapWalkOpts myWalker(void *block, int size)
+{
+  printf("  block at %p, size %d\n", block, size);
+  return HW_GO;
+}
+
+
+void *toDealloc;
+HeapWalkOpts deallocWalker(void *block, int size)
+{
+  if (block == toDealloc) {
+    printf("deallocating block at %p, size %d\n", block, size);
+    return HW_FREE;
+  }
+  return HW_GO;
+}
+
+
+#define MSGOUT(str) write(1, str, strlen(str))
+
+void heapWalk(char const *context)
+{
+  printf("%s: heap contents:\n", context);
+  walkMallocHeap(myWalker);
+}
+
+#define TRACERET(expr)                      \
+  printf("%s returned %p\n", #expr, expr);  \
+  heapWalk(#expr);                          \
+  malloc_stats()
+
+#define TRACE(expr)                         \
+  expr;                                     \
+  heapWalk(#expr);                          \
+  malloc_stats()
+
+
+void test1()
+{
+  printf("--------- test1 ---------\n");
+  
+  void *p1, *p2, *p3, *p4, *p5, *p6;
+
+  heapWalk("start");
+
+  TRACERET(p1 = malloc(5));
+  TRACERET(p2 = malloc(70));
+  TRACERET(p3 = malloc(1000));
+  TRACERET(p4 = malloc(10000));
+  TRACERET(p5 = malloc(100000));
+  
+  // this last size is potentially interesting because it's
+  // beyond the 128k default threshold for when dlmalloc
+  // uses mmap() instead of sbrk() to get memory from the OS
+  TRACERET(p6 = malloc(1000000));
+
+  toDealloc = p3;
+  TRACE(walkMallocHeap(deallocWalker));
+
+  TRACE(free(p1));
+  TRACE(free(p5));
+  //TRACE(free(p3));   // done by above
+  TRACE(free(p6));
+  TRACE(free(p2));
+  TRACE(free(p4));
+}
+
+
+void test2()
+{
+  printf("--------- test2 ---------\n");
+
+  void *arr[100];
+  memset(arr, 0, sizeof(arr));
+
+  for (int i=0; i < 10000; i++) {
+    // pick a random slot
+    int slot = random() % 100;
+
+    if (arr[slot] == NULL) {
+      // allocate something
+      arr[slot] = malloc(random() % 1000);
+    }
+
+    else if (random()%4 != 0) {
+      // dealloc directly
+      free(arr[slot]);
+      arr[slot] = NULL;
+    }
+
+    else {
+      // dealloc by walk
+      toDealloc = arr[slot];
+      walkMallocHeap(deallocWalker);
+      arr[slot] = NULL;
+    }
+  }
+
+  // snapshot now
+  heapWalk("snapshot after test2");  
+
+  // free the rest
+  for (int j=0; j<100; j++) {
+    if (arr[j]) {
+      free(arr[j]);
+    }
+  }
+}
+
+
+int main()
+{
+  test1();
+  test2();
+
+  MSGOUT("testmalloc finished\n");
+  return 0;
+}
+

Added: vendor/elsa/current/smbase/thashtbl.h
===================================================================
--- vendor/elsa/current/smbase/thashtbl.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/thashtbl.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,95 @@
+// thashtbl.h            see license.txt for copyright and terms of use
+// type-safe version of HashTable
+
+#ifndef THASHTBL_H
+#define THASHTBL_H
+
+#include "hashtbl.h"     // HashTable, HashTableIter
+
+template <class KEY, class DATA> class THashTableIter;
+
+template <class KEY, class DATA>
+class THashTable {
+private:    // types
+  friend class THashTableIter<KEY, DATA>;
+
+public:     // types
+  // given a stored data pointer, retrieve the associated key
+  typedef KEY const* (*GetKeyFn)(DATA *data);
+
+  // given a key, retrieve the associated hash value;
+  // this should be a 32-bit integer ready to be mod'd by the table size
+  typedef unsigned (*HashFn)(KEY const *key);
+
+  // compare two keys; this is needed so we can handle collisions
+  // in the hash function; return true if they are equal
+  typedef bool (*EqualKeyFn)(KEY const *key1, KEY const *key2);
+
+private:    // data
+  // underlying table
+  HashTable table;
+
+private:    // funcs
+  // disallowed
+  THashTable(THashTable&);
+  void operator=(THashTable&);
+  void operator==(THashTable&);
+
+public:     // funcs
+  THashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek,
+             int initSize = HashTable::defaultSize)
+    : table((HashTable::GetKeyFn)gk,
+            (HashTable::HashFn)hf,
+            (HashTable::EqualKeyFn)ek,
+            initSize)
+  {}
+  ~THashTable() {}
+
+  // return # of mapped entries
+  int getNumEntries() const                 { return table.getNumEntries(); }
+
+  // if this hash value has a mapping, return it; otherwise,
+  // return NULL
+  DATA *get(KEY const *key) const           { return (DATA*)table.get(key); }
+
+  // add a mapping from 'key' to 'value'; there must not already
+  // be a mapping for this key
+  void add(KEY const *key, DATA *value)     { table.add(key, value); }
+
+  // remove the mapping for 'key' -- it must exist;
+  // returns the removed item
+  DATA *remove(KEY const *key)              { return (DATA*)table.remove(key); }
+
+  // remove all mappings
+  void empty(int initSize = HashTable::defaultSize)   { table.empty(initSize); }
+
+  // set whether shrinkage is allowed; it's useful to be able to
+  // disable this to avoid any allocation in certain situations
+  void setEnableShrink(bool en)             { table.setEnableShrink(en); }
+
+  // allow external access to an accessor function
+  KEY const *callGetKeyFn(DATA *data)       { return (KEY const*)table.getKey(data); }
+
+  // check the data structure's invariants, and throw an exception
+  // if there is a problem
+  void selfCheck() const                    { table.selfCheck(); }
+};
+
+
+// iterate over all stored values in a THashTable
+// NOTE: you can't change the table while an iter exists
+template <class KEY, class DATA>
+class THashTableIter {
+private:      // data         
+  HashTableIter iter;            // underlying iter
+
+public:       // funcs
+  THashTableIter(THashTable<KEY,DATA> &table) : iter(table.table) {}
+
+  bool isDone() const          { return iter.isDone(); }
+  void adv()                   { return iter.adv(); }
+  DATA *data() const           { return (DATA*)iter.data(); }
+};
+
+
+#endif // THASHTBL_H

Added: vendor/elsa/current/smbase/tmalloc.c
===================================================================
--- vendor/elsa/current/smbase/tmalloc.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/tmalloc.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,108 @@
+// tmalloc.c            see license.txt for copyright and terms of use
+// test malloc implementation in DEBUG_HEAP configuration
+
+#include <stdlib.h>     // malloc
+#include <stdio.h>      // printf
+
+#include "mysig.h"      // setHandler
+#include "ckheap.h"     // checkHeap
+                
+
+typedef void (*Fn)(void);
+
+
+void expectFail(Fn f)
+{
+  if (setjmp(sane_state) == 0) {
+    setHandler(SIGABRT, jmpHandler);
+    setHandler(SIGSEGV, jmpHandler);
+    f();
+    printf("should have caught that\n");
+    exit(2);
+  }
+  else {
+    printf("caught error ok\n");
+  }
+}
+
+
+void offEnd()
+{
+  char *p = malloc(10);
+  p[10] = 7;    // oops
+  free(p);
+}
+
+void offEndCheck()
+{
+  char *p = malloc(10);
+  p[10] = 7;    // oops
+  
+  // instead of using free() to find the error,
+  // find it with checkHeap
+  checkHeap();
+}
+
+void offBeg()
+{
+  char *p = malloc(15);
+  p[-2] = 8;
+  free(p);
+}
+
+void ok()
+{
+  char *p = malloc(20);
+  p[0] = 5;
+  p[19] = 9;
+  free(p);
+}
+
+void dangle()
+{
+  char **p = malloc(20);
+  *p = (char*)(p+4);    // *p is a pointer to 4 bytes later
+  **p = 8;              // should work ok
+  free(p);
+  **p = 7;              // should hit the 0xBB trap
+}
+
+void doubleFree()
+{
+  char *p = malloc(10);
+  free(p);
+  free(p);
+}
+
+int main()
+{   
+  // do some benign things
+  int i;
+  for (i=0; i<10; i++) {
+    int size = rand() % 100;
+    char *p;
+    
+    checkHeap();
+    p = malloc(size);
+    p[0] = i;
+    p[size-1] = i;
+    checkHeap();
+    free(p);
+  }
+
+  // this one will detect a trashed a zone, so do it first
+  checkHeap();
+  expectFail(offEndCheck);
+  printf("after offEndCheck\n");
+
+  // now, don't do checkHeap anymore, since it would fail
+
+  expectFail(offEnd);
+  expectFail(offBeg);
+  ok();
+  expectFail(dangle);
+  expectFail(doubleFree);
+
+  printf("tmalloc works\n");
+  return 0;
+}

Added: vendor/elsa/current/smbase/tobjlist.cc
===================================================================
--- vendor/elsa/current/smbase/tobjlist.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/tobjlist.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,213 @@
+// tobjlist.cc            see license.txt for copyright and terms of use
+// test code for objlist.h
+
+#include "objlist.h"    // this module
+#include "breaker.h"    // breaker
+#include "test.h"       // USUAL_MAIN
+
+#include <stdlib.h>     // rand()
+#include <stdio.h>      // printf()
+
+
+// ------------ object class --------------------
+// class of objects to hold in the list
+class Integer {
+public:
+  static int ctorcount;     // # of calls to ctor
+  static int dtorcount;     // # of calls to dtor
+  int i;                    // data this class holds
+
+public:
+  Integer(int ii);
+  ~Integer();
+};
+
+int Integer::ctorcount = 0;
+int Integer::dtorcount = 0;
+
+Integer::Integer(int ii)
+  : i(ii)
+{
+  ctorcount++;
+}
+
+Integer::~Integer()
+{
+  dtorcount++;
+}
+
+
+// ----------- testing ObjList -----------
+int intDiff(Integer const *left, Integer const *right, void*)
+{
+  return left->i - right->i;
+}
+
+
+// assumes we're using ptrvaldiff as the comparison fn
+void verifySorted(ObjList<Integer> const &list)
+{
+  int prev = 0;
+  ObjListIter<Integer> iter(list);
+  for (; !iter.isDone(); iter.adv()) {
+    int current = iter.data()->i;
+    xassert(prev <= current);
+    prev = current;
+  }
+}
+
+
+void print(ObjList<Integer> const &list)
+{   
+  printf("{ ");
+  ObjListIter<Integer> iter(list);
+  for (; !iter.isDone(); iter.adv()) {
+    printf("%d ", iter.data()->i);
+  }
+  printf("} ");
+}
+
+#define PRINT(lst) print(lst); printf("\n") /* user ; */
+
+
+void testSorting()
+{
+  enum { ITERS=100, ITEMS=20 };
+
+  loopi(ITERS) {
+    // construct a list
+    ObjList<Integer> list1;
+    ObjList<Integer> list2;
+    int items = rand()%ITEMS;
+    loopj(items) {
+      int it = rand()%ITEMS;
+      list1.prepend(new Integer(it));
+      list2.prepend(new Integer(it));     // two lists with identical contents
+    }
+    //PRINT(list1);
+
+    // sort them
+    list1.insertionSort(intDiff);
+    list2.mergeSort(intDiff);
+    //PRINT(list1);
+
+    // verify structure
+    list1.selfCheck();
+    list2.selfCheck();
+
+    // verify length
+    xassert(list1.count() == items && list2.count() == items);
+
+    // verify sortedness
+    verifySorted(list1);
+    verifySorted(list2);
+
+    // verify equality
+    ObjListIter<Integer> iter1(list1);
+    ObjListIter<Integer> iter2(list2);
+    for (; !iter1.isDone(); iter1.adv(), iter2.adv()) {
+      xassert(iter1.data()->i == iter2.data()->i);
+    }
+    xassert(iter2.isDone());    // another length check
+
+    // it's still conceivable the lists are not correct,
+    // but highly unlikely, in my judgment
+  }
+}
+
+
+void entry()
+{
+  // first set of tests
+  {
+    // some sample items
+    Integer *a = new Integer(1);
+    Integer *b = new Integer(2);
+    Integer *c = new Integer(3);
+    Integer *d = new Integer(4);
+
+    ObjList<Integer> list;
+
+    // test simple modifiers and info
+    list.append(c);     PRINT(list);   // c
+    list.prepend(b);   	PRINT(list);   // b c
+    list.append(d);	PRINT(list);   // b c d
+    list.prepend(a);	PRINT(list);   // a b c d
+    list.deleteAt(2);	PRINT(list);   // a b d
+
+    xassert( list.count() == 3 &&
+             !list.isEmpty() &&
+             list.nth(0) == a &&
+             list.nth(1) == b &&
+             list.nth(2) == d
+           );
+    list.selfCheck();
+             
+    // 'list' will delete the integers
+  }
+
+  // test that we can detect accidental duplication
+  {
+    Integer *x = new Integer(1);
+    ObjList<Integer> list;
+    list.prepend(x);
+    bool bad = false;
+    try {
+      // unspecified at interface level which of the
+      // following two will detect the problem
+      list.prepend(x);
+      list.selfCheck();
+      bad = true;
+    }
+    catch (...) {
+      printf("successfully detected duplicate insertion\n");
+
+      // repair list otherwise it will die during dtor!
+      list.removeAt(0);
+    }
+
+    if (bad) {
+      xfailure("FAILED to detect duplicate insertion\n");
+    }
+  }
+
+  #if 0     // the problem is dlmalloc uses regular assert, not xassert..
+  // test that we can detect insertion of bad ptrs
+  {
+    Integer *x = new Integer(1);
+    ObjList<Integer> list;
+    list.prepend(x);
+    bool bad = false;
+    try {
+      delete x;             // creates dangling reference
+      list.selfCheck();     // should detect it here
+      bad = true;
+    }
+    catch (...) {
+      printf("successfully detected bad-ptr insertion\n");
+
+      // repair list otherwise it will die during dtor!
+      list.removeAt(0);
+    }
+
+    if (bad) {
+      xfailure("FAILED to detect bad-ptr insertion\n");
+    }
+  }
+  #endif // 0
+
+  printf("Integer ctorcount=%d dtorcount=%d\n",
+         Integer::ctorcount, Integer::dtorcount);
+
+  // this hits most of the remaining code
+  // (a decent code coverage tool for C++ would be nice!)
+  testSorting();
+
+  printf("Integer ctorcount=%d dtorcount=%d\n",
+         Integer::ctorcount, Integer::dtorcount);
+
+  printf("ObjList<Integer> ok\n");
+}
+
+USUAL_MAIN
+

Added: vendor/elsa/current/smbase/tobjpool.cc
===================================================================
--- vendor/elsa/current/smbase/tobjpool.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/tobjpool.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,101 @@
+// tobjpool.cc            see license.txt for copyright and terms of use
+// test ObjectPool
+
+#include "objpool.h"     // ObjectPool
+
+#include <stdlib.h>      // rand
+#include <iostream.h>    // cout
+
+
+// class we're going to make a pool of
+class Foo {
+public:
+  union {
+    Foo *nextInFreeList;    // for ObjectPool
+    int x;
+  };
+  int y;
+  int z;
+
+public:
+  void establishInvariant(int index);
+  void checkInvariant(int index) const;
+  void deinit() {}
+};
+
+void Foo::establishInvariant(int index)
+{
+  x = index;
+  y = x+1;
+  z = y+1;
+}
+
+void Foo::checkInvariant(int index) const
+{
+  xassert(x == index);
+  xassert(y == x+1);
+  xassert(z == y+1);
+}
+                             
+
+enum { SMALL=30, BIG=100, ITERS=10000 };
+
+int main()
+{
+  ObjectPool<Foo> pool(SMALL);
+  int i;    
+  int numAllocated=0;
+
+  // keep track of what I've allocated
+  Foo **allocated = new Foo*[BIG];
+  for (i=0; i<BIG; i++) {
+    allocated[i] = NULL;
+  }
+
+  // start allocating at random
+  cout << "allocating/deallocating " << ITERS << " times..\n";
+  for (i=0; i<ITERS; i++) {
+    int index = rand()%BIG;
+    Foo *&f = allocated[index];
+
+    if (f) {
+      // deallocate
+      f->checkInvariant(index);
+      pool.dealloc(f);
+      f = NULL;
+      numAllocated--;
+    }
+    else {
+      // allocate
+      f = pool.alloc();
+      f->establishInvariant(index);
+      numAllocated++;
+    }
+  }
+
+  // query pool size before cleaning up
+  int startSize = pool.freeObjectsInPool();
+  int finalNumAllocd = numAllocated;
+
+  // deallocate all that remain
+  cout << "freeing remaining " << numAllocated << " stragglers\n";
+  for (i=0; i<BIG; i++) {
+    if (allocated[i]) {
+      Foo *&f = allocated[i];
+      f->checkInvariant(i);
+      pool.dealloc(f);
+      f = NULL;
+      numAllocated--;
+    }
+  }
+  xassert(numAllocated==0);
+
+  // verify that the # of objects freed is the # that became available
+  xassert(finalNumAllocd == (pool.freeObjectsInPool() - startSize));
+
+  cout << "pool capacity at end: " << pool.freeObjectsInPool() << endl;
+  cout << "tobjpool works!\n";
+
+  return 0;
+}
+

Added: vendor/elsa/current/smbase/trace.cc
===================================================================
--- vendor/elsa/current/smbase/trace.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/trace.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,186 @@
+// trace.cc            see license.txt for copyright and terms of use
+// code for trace.h
+
+#include "trace.h"     // this module
+#include "objlist.h"   // List
+#include "str.h"       // string
+#include "strtokp.h"   // StrtokParse
+#include "nonport.h"   // getMilliseconds()
+
+#include <fstream.h>   // ofstream
+#include <stdlib.h>    // getenv
+
+
+// auto-init
+static bool inited = false;
+
+// list of active tracers, initially empty
+static ObjList<string> tracers;
+
+// stream connected to /dev/null
+ofstream devNullObj("/dev/null");
+static ostream *devNull = &devNullObj;
+
+
+// initialize
+static void init()
+{
+  if (inited) {
+    return;
+  }
+
+  // there's a more efficient way to do this, but I don't care to dig
+  // around and find out how
+  // this leaks, and now that I'm checking for them, it's a little
+  // annoying...
+  //devNull = new ofstream("/dev/null");
+
+  inited = true;
+}
+
+
+void traceAddSys(char const *sysName)
+{
+  init();
+
+  tracers.prepend(new string(sysName));
+}
+
+
+void traceRemoveSys(char const *sysName)
+{
+  init();
+
+  MUTATE_EACH_OBJLIST(string, tracers, mut) {
+    if (mut.data()->compareTo(sysName) == 0) {
+      mut.deleteIt();
+      return;
+    }
+  }
+  xfailure("traceRemoveSys: tried to remove system that isn't there");
+}
+
+
+bool tracingSys(char const *sysName)
+{
+  init();
+
+  FOREACH_OBJLIST(string, tracers, iter) {
+    if (iter.data()->compareTo(sysName) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+void traceRemoveAll()
+{
+  tracers.deleteAll();
+}  
+
+
+ostream &trace(char const *sysName)
+{
+  init();
+
+  if (tracingSys(sysName)) {
+    cout << "%%% " << sysName << ": ";
+    return cout;
+  }
+  else {
+    return *devNull;
+  }
+}
+
+
+void trstr(char const *sysName, char const *traceString)
+{
+  trace(sysName) << traceString << endl;
+}
+
+
+ostream &traceProgress(int level)
+{
+  if ( (level == 1) ||
+       (level == 2 && tracingSys("progress2")) ) {
+    static long progStart = getMilliseconds();
+
+    return trace("progress") << (getMilliseconds() - progStart) << "ms: ";
+  }
+  else {
+    return *devNull;
+  }
+}
+
+
+void traceAddMultiSys(char const *systemNames)
+{
+  StrtokParse tok(systemNames, ",");
+  loopi(tok) {
+    if (tok[i][0] == '-') {
+      // treat a leading '-' as a signal to *remove*
+      // a tracing flag, e.g. from some defaults specified
+      // statically      
+      char const *name = tok[i]+1;
+      if (tracingSys(name)) {      // be forgiving here
+        traceRemoveSys(name);
+      }
+      else {
+        cout << "Currently, `" << name << "' is not being traced.\n";
+      }
+    }
+    
+    else {
+      // normal behavior: add things to the trace list
+      traceAddSys(tok[i]);
+    }
+  }
+}
+
+
+bool traceProcessArg(int &argc, char **&argv)
+{
+  traceAddFromEnvVar();
+
+  if (argc >= 3  &&  0==strcmp(argv[1], "-tr")) {
+    traceAddMultiSys(argv[2]);
+    argc -= 2;
+    argv += 2;
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+
+bool ignoreTraceEnvVar = false;
+
+void traceAddFromEnvVar()
+{
+  if (ignoreTraceEnvVar) {
+    return;
+  }
+
+  char const *var = getenv("TRACE");
+  if (var) {
+    traceAddMultiSys(var);
+  }
+
+  ignoreTraceEnvVar = true;
+}
+
+
+void printTracers(ostream &out, char *delim)
+{
+  bool first = true;
+  FOREACH_OBJLIST(string, tracers, iter) {
+    if (first) first = false;
+    else out << delim;
+    out << iter.data()->c_str();
+  }
+}
+
+
+// EOF

Added: vendor/elsa/current/smbase/trace.h
===================================================================
--- vendor/elsa/current/smbase/trace.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/trace.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,87 @@
+// trace.h            see license.txt for copyright and terms of use
+// module for diagnostic tracing
+// see trace.html
+
+#ifndef TRACE_H
+#define TRACE_H
+
+#include <iostream.h>     // ostream
+
+
+// add a subsystem to the list of those being traced
+void traceAddSys(char const *sysName);
+
+// remove a subsystem; must have been there
+void traceRemoveSys(char const *sysName);
+
+// see if a subsystem is among those to trace
+bool tracingSys(char const *sysName);
+
+// clear all tracing flags
+void traceRemoveAll();
+
+
+// trace; if the named system is active, this yields cout (after
+// sending a little output to identify the system); if not, it
+// yields an ostream attached to /dev/null; when using this
+// method, it is up to you to put the newline
+ostream &trace(char const *sysName);
+
+// give an entire string to trace; do *not* put a newline in it
+// (the tracer will do that)
+void trstr(char const *sysName, char const *traceString);
+
+// trace macro which disables itself when NDEBUG is true,
+// and automatically supplies 'endl' when it's not true
+//
+// dsw: debugging *weakly* implies tracing: if we are debugging, do
+// tracing unless otherwise specified
+#ifndef NDEBUG
+  #ifndef DO_TRACE
+    #define DO_TRACE 1
+  #endif
+#endif
+// dsw: tracing *bidirectionally* configurable from the command line:
+// it may be turned on *or* off: any definition other than '0' counts
+// as true, such as -DDO_TRACE=1 or just -DDO_TRACE
+#ifndef DO_TRACE
+  #define DO_TRACE 0
+#endif
+#if DO_TRACE != 0
+  #define TRACE(tag, exp) trace(tag) << exp << endl /* user ; */
+#else
+  #define TRACE(tag, exp) ((void)0)
+#endif
+
+
+// special for "progress" tracing; prints time too;
+// 'level' is level of detail -- 1 is highest level, 2 is
+// more refined (and therefore usually not printed), etc.
+ostream &traceProgress(int level=1);
+
+
+// add one or more subsystems, separated by commas
+void traceAddMultiSys(char const *systemNames);
+
+// if the first argument is a tracing directive, handle it, modify
+// argc and argv modified to effectively remove it, and return true
+// (argv[0] is assumed to be ignored by everything); this calls
+// 'traceAddFromEnvVar' too
+bool traceProcessArg(int &argc, char **&argv);
+
+// so here's a simple loop that will consume any leading
+// trace arguments
+#define TRACE_ARGS() while (traceProcessArg(argc, argv)) {}
+
+
+// add tracing flags from the environment variable "TRACE",
+// unless 'ignoreTraceEnvVar' is true; this sets it to true,
+// so it's idempotent
+void traceAddFromEnvVar();
+extern bool ignoreTraceEnvVar;    // initially false
+
+
+// render the tracers as a string for examination
+void printTracers(ostream &out, char *delim = ", ");
+
+#endif // TRACE_H

Added: vendor/elsa/current/smbase/trace.html
===================================================================
--- vendor/elsa/current/smbase/trace.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/trace.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,154 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<!-- tweak to test a commit; again -->
+
+<HTML>
+
+<HEAD>
+  <TITLE>Trace Module</TITLE>
+  <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+  <style type="text/css">
+    H1 { font-size: 125% }
+    H2 { font-size: 110% }
+    H3 { font-size: 100% }
+    P.title { font-size: 175% }
+  </style>
+</HEAD>
+
+<body>
+
+<center>
+<p class="title"><b>The Trace Module</b></p>
+</center>
+
+<h1>Introduction</h1>
+
+<p>
+The trace (<a href="trace.h">trace.h</a>, <a href="trace.cc">trace.cc</a>) 
+module is designed to support a refinement of printf-style 
+debugging.  While I do not use printf-style debugging exclusively,
+it is nevertheless an important and often effective technique.  
+
+<p>
+The main difficulty with traditional <tt>printf</tt> is that you
+can't easily turn the output on and off.  Hence, the central feature
+of the trace module is a set of <i>tracing flags</i>, set at run-time,
+that control tracing output.  There is also a compile-time flag,
+<TT>NDEBUG</TT>, to disable them completely.
+
+<h1>Basic Use</h1>
+
+<p>
+An example tracing directive is the following:
+<pre>
+  TRACE("weapons", "about to fire proton torpedo " << torpNum);
+</pre>
+If <TT>NDEBUG</TT> is #defined, this expands to nothing.  But if it
+is not, then this expands to something like:
+<pre>
+  if (tracingSys("weapons")) {
+    cout &lt;&lt; "%%% weapons: " &lt;&lt; "about to fire proton torpedo " &lt;&lt; torpNum &lt;&lt; endl;
+  }
+</pre>
+
+<p>
+Several things are noteworthy about the expansion:
+<ul>
+<li>The output is going to stdout.  I prefer it that way, but feel free to
+    add a global variable that sends it to stderr if you really want.
+<li>It is prefixed by "<tt>%%% weapons</tt>" (or whatever) so you can easily 
+    recognize it amongst other output, grep it in/out, etc.
+<li>Since it's using the C++ iostreams to do output, you can add extra
+    information, like <tt>torpNum</tt> above.  If you need <tt>printf</tt>-style
+    formatting, use the <tt>stringf</tt> function in the 
+    <a href="str.h">str</a> module.
+<li>Since it ends with <tt>endl</tt>, it prints the newline automatically,
+    <em>and</em> flushes the output stream.  That way you'll see the output
+    even if the program crashes on the next line.
+<li>The <tt>tracingSys</tt> function can be used to explicitly query whether
+    a given tracing flag is active.
+</ul>
+
+<p>
+Now, the above is a slight simplification.  In fact, the second argument
+to <TT>TRACE</TT> is actually evaluated <em>regardless</em> of whether
+the flag is turned on.  This is so that if the evaluation itself has a
+bug (e.g. it segfaults), it will be found quickly, rather than waiting 
+to bite someone who is trying to debug something else.
+
+<h1>Enabling Flags</h1>
+
+<p>
+There are several ways to turn on a tracing flag.
+<ul>
+<li>The <tt>traceAddSys</tt> function adds a flag explicitly.
+<li>The <TT>TRACE_ARGS</TT> macro will search for occurrences of
+    "<tt>-tr </tt><i>flag</i>" at the beginning of the command line
+    (argc, argv), and add the named flag.  You can specify more than
+    one flag if they are separated by commas (e.g "<tt>-tr a,b,c</tt>")
+    or with multiple <tt>-tr</tt> options.  Note that this is a
+    fairly clunky API, and should only be used in test programs.  A
+    real program should do its own command-line argument processing
+    and call <tt>traceAddSys</tt> directly.
+<li>The <tt>traceAddFromEnvVar</tt> function will grab a comma-separated
+    list of flags from the <tt>TRACE</tt> environment variable.
+    Note that <TT>TRACE_ARGS</TT> calls <tt>traceAddFromEnvVar</tt>.
+</ul>
+
+<h1>Trace Flag Naming Convention</h1>
+
+<p>
+In my projects, most of my tracing flags are given the name of the
+module they are in (e.g. <tt>TRACE("foo", ...)</tt> in <tt>foo.cc</tt>).
+Module-level tracing is to report events likely to be relevant to users
+and casual maintainers of the module.  For more detail, I typically
+add another word to name the task at hand, e.g. <tt>TRACE("fooInit").</tt>
+
+<h1>Debugging, Testing and the Trace Module</h1>
+
+<p>
+How should this module be used in the larger process context?  First,
+some terminology:
+<ul>
+<li><b>Testing</b> is the process of determining if software has defects,
+    and adequately characterizing those defects so they can be debugged,
+    ideally by producing a reproducible testcase.  The input to testing
+    is a program and a specification, and the output is a set of bug reports.
+<li><b>Debugging</b> is the process of finding out the cause of a defect.
+    The input is a bug report, and the output is
+    a detailed explanation of what is wrong with the program, which
+    characterizes the defect in sufficient detail to allow someone to fix
+    the code.
+</ul>
+
+<p>
+I advocate using the tracing module for <em>debugging</em> only.  Since
+the tracing activity (even when no output is produced) is typically 
+prohibitively expensive, one cannot ship to users an executable that
+has them in.  And, since it is a good idea to "ship what you test",
+testing should be done with <tt>NDEBUG</tt> turned on, and
+hence tracing disabled.  (See also the note about this in
+<a href="xassert.h">xassert.h</a>.)
+
+<p>
+Of course, there is nothing wrong with doing some testing with tracing
+enabled.  In fact, when I am the one developing the code, I do most of
+my testing with it enabled.  But the program <em>must</em> also be tested
+with tracing disabled if that's how users will use it, and to the 
+extent there is dedicated QA activities in your project I recommend
+they be performed on the <TT>NDEBUG</TT> build.
+
+<hr>
+<p>
+Back to <a href="index.html">smbase</a>.
+
+<p>
+  <a href="http://validator.w3.org/check/referer"><img border="0"
+      src="http://www.w3.org/Icons/valid-html401"
+      alt="Valid HTML 4.01!" height="31" width="88"></a>
+</p>
+
+
+</body>
+
+</html>

Added: vendor/elsa/current/smbase/trdelete.cc
===================================================================
--- vendor/elsa/current/smbase/trdelete.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/trdelete.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,116 @@
+// trdelete.cc            see license.txt for copyright and terms of use
+// code for trdelete.h
+
+#include <stdlib.h>       // abs
+#include "trdelete.h"     // this module
+#include "string.h"       // memset
+#include "breaker.h"      // breaker
+
+
+// There is a surprising twist to our story.  When an object is created with
+// 'new' on the dynamic heap, and it throws an exception, its destructor is not
+// called, because the object is not fully constructed yet.  However, the
+// storage allocated for that object should be freed; the exception runtimes
+// do this.
+
+// But, there is a bug (under Borland C++ 4.5) when operator delete is called
+// under these circumstances, the size argument is wrong.  I've been getting
+// values like 0x12fc14, which are pointers to objects on the stack.  After
+// quite a bit of dump tracing, I can't find an easy way to turn this pointer
+// into the desired value.
+
+// However, the dynamic heap node format for the Borland runtimes is pretty
+// simple, and an estimate of the heap size can readily be determined; the
+// dword just before the passed block pointer has such an estimate.  Therefore,
+// my strategy is to compare the given size with the dword at offset -4, and if
+// they are within 64 of each other (I've never seen differences greater than
+// 16), the size argument is considered valid.  If they aren't there isn't a
+// reliable way to convert the estimate into a precise size, so I just skip
+// trashing the memory altogether.
+
+
+static void trash(void *blk, size_t size)
+{
+  #ifdef __BORLANDC__
+  long guess = ((long*)blk)[-1];
+  if (abs(guess - (long)size) > 64) {
+    // assume the size is bogus
+    breaker();     // I want to know about it, for now
+    return;
+  }
+  #endif
+
+  // assume the size is ok
+  memset(blk, 0xAA, size);
+    // the choice of AA is made as it is easily recognizable,
+    // and 0xAAAAAAAA is pretty much always a bad pointer
+}
+
+
+void trashingDelete(void *blk, size_t size)
+{
+  trash(blk, size);
+
+  // use the global delete operator to free the memory;
+  // gratuitous cast to char* to silence gcc warning 
+  // "not a pointer-to-object type"
+  ::delete((char*)blk);
+}
+
+
+void trashingDeleteArr(void *blk, size_t size)
+{
+  trash(blk, size);
+
+  // use the global delete operator to free the memory;
+  // (see comment about gratuitious cast, above)
+  ::delete[]((char*)blk);
+}
+
+
+// ------------------------ test code ---------------------
+#ifdef TEST_TRDELETE
+
+#include <stdio.h>      // printf
+
+class Foo {
+public:
+  TRASHINGDELETE
+  int junk[10];         // stay away from malloc's data structures
+  int x;
+  int moreJunk[10];     // more padding
+};
+
+class Bar {
+public:
+  int junk[10];         // stay away from malloc's data structures
+  int x;
+  int moreJunk[10];     // more padding
+};
+
+
+int main()
+{
+  printf("malloc: %p\n", malloc(10));
+
+  Foo *f = new Foo;
+  f->x = 5;
+  delete f;
+  if (f->x == 5) {
+    printf("trashing-delete failed\n");
+    return 2;
+  }
+
+  Bar *b = new Bar;
+  b->x = 7;
+  delete b;
+  if ((unsigned)b->x == 0xAAAAAAAAu) {    // did it trash it anyway?
+    printf("non-trashing-delete failed\n");
+    return 2;
+  }
+
+  printf("trashing delete works\n");
+  return 0;
+}
+
+#endif // TEST_TRDELETE

Added: vendor/elsa/current/smbase/trdelete.h
===================================================================
--- vendor/elsa/current/smbase/trdelete.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/trdelete.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// trdelete.h            see license.txt for copyright and terms of use
+// objects which trash their contents upon deletion
+// I would love to have implemented this as a base class and simply derive
+//   things from it, but a poor implementation choice by Borland makes this
+//   too costly in terms of performance
+
+#ifdef _MSC_VER
+  // this module doesn't work under msvc, I don't care to figure out why
+  #define TRDELETE_H      // make it omit this file
+  #define TRASHINGDELETE  // and all references to it a no-op
+#endif
+
+#ifndef TRDELETE_H
+#define TRDELETE_H
+
+#include <stddef.h>      // size_t
+
+void trashingDelete(void *blk, size_t size);
+void trashingDeleteArr(void *blk, size_t size);
+
+// to use, include the TRASHINGDELETE macro in the public section of a class
+
+#define TRASHINGDELETE                                                              \
+  void operator delete(void *blk, size_t size) { trashingDelete(blk, size); }       \
+  void operator delete[](void *blk, size_t size) { trashingDeleteArr(blk, size); }
+
+#endif // TRDELETE_H

Added: vendor/elsa/current/smbase/tsobjlist.cc
===================================================================
--- vendor/elsa/current/smbase/tsobjlist.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/tsobjlist.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,38 @@
+// tsobjlist.cc            see license.txt for copyright and terms of use
+// test of sobjlist.h
+
+#include "sobjlist.h"    // SObjList
+#include <stdio.h>       // printf
+
+int main()
+{
+  char const *hi = "hi there";
+  char const *what = "what's up?";
+
+  // the real purpose of this test is to make sure it's ok to
+  // add a 'const' qualifier inside the angle brackets, and get
+  // the effect I'm after
+  SObjList<char const> list;
+  
+  // 'prepend' accepts a T*, which should become a char const *;
+  // if it only becomes (e.g.) a char*, then this call should
+  // trigger a compile error
+  list.prepend(hi);
+
+  list.append(what);
+  
+  // 'indexOf' accepts a T const *, so here I'm essentially verifying
+  // the compiler doesn't mind seeing 'const' twice
+  int i = list.indexOf(hi);
+  printf("index of 'hi' is %d\n", i);
+
+  i = list.indexOf(what);
+  printf("index of 'what' is %d\n", i);
+
+  // random test of extra 'const' outside the template context
+  // (gcc-2.95.3 doesn't like it, interesting..)
+  int const /*const*/ x = 5;
+  printf("x is %d\n", x);
+
+  return 0;
+}

Added: vendor/elsa/current/smbase/typ.h
===================================================================
--- vendor/elsa/current/smbase/typ.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/typ.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,154 @@
+// typ.h            see license.txt for copyright and terms of use
+// various types and definitions, some for portability, others for convenience
+// Scott McPeak, 1996-2000  This file is public domain.
+
+#ifndef __TYP_H
+#define __TYP_H
+
+// byte
+typedef unsigned char byte;
+typedef signed char signed_byte;
+
+
+// int32 used to be here, but defined nonportably, and I don't use
+// it anyway, so I ripped it out
+
+
+// NULL
+#ifndef NULL
+#  define NULL 0
+#endif // NULL
+
+
+// bool
+#ifdef LACKS_BOOL
+  typedef int bool;
+  bool const false=0;
+  bool const true=1;
+#endif // LACKS_BOOL
+
+
+// This used when I want to cast a pointer to an integer for something
+// like hashing the address.  It need not be injective.
+inline long pointerToInteger(void const *p)
+  { return (long)p; }
+
+  
+// This can be used to compare two pointers, even when they do not point
+// into the same object.
+inline int comparePointerAddresses(void const *p, void const *q)
+{
+  // John Skaller points out that comparing addresses directly is
+  // nonportable, and that std::less<> provides a solution (cppstd
+  // 20.3.3p8).  But, I'm concerned about the portability of std::less
+  // more than I am about the portability of address comparison.  The
+  // existence of this function at least ensures I only have to change
+  // one place.
+  return p==q?               0 :
+         (long)p < (long)q? -1 :      // would use std::less<> here
+                            +1 ;
+}
+
+
+// min, max
+#undef min
+#undef max
+       
+template <class T>
+inline T min(T const &a, T const &b)
+{
+  return a<b? a:b;
+}
+
+template <class T>
+inline T max(T const &a, T const &b)
+{
+  return a>b? a:b;
+}
+
+
+#if 0   // old
+  #ifndef __MINMAX_DEFINED
+  # ifndef min
+  #  define min(a,b) ((a)<(b)?(a):(b))
+  # endif
+  # ifndef max
+  #  define max(a,b) ((a)>(b)?(a):(b))
+  # endif
+  # define __MINMAX_DEFINED
+  #endif // __MINMAX_DEFINED
+#endif // 0
+
+
+// tag for definitions of static member functions; there is no
+// compiler in existence for which this is useful, but I like
+// to see *something* next to implementations of static members
+// saying that they are static, and this seems slightly more
+// formal than just a comment
+#define STATICDEF /*static*/
+
+
+// often-useful number-of-entries function
+#define TABLESIZE(tbl) ((int)(sizeof(tbl)/sizeof((tbl)[0])))
+
+
+// concise way to loop on an integer range
+#define loopi(end) for(int i=0; i<(int)(end); i++)
+#define loopj(end) for(int j=0; j<(int)(end); j++)
+#define loopk(end) for(int k=0; k<(int)(end); k++)
+
+
+// for using selfCheck methods
+// to explicitly check invariants in debug mode
+//
+// dsw: debugging *weakly* implies selfchecking: if we are debugging,
+// do selfcheck unless otherwise specified
+#ifndef NDEBUG
+  #ifndef DO_SELFCHECK
+    #define DO_SELFCHECK 1
+  #endif
+#endif
+// dsw: selfcheck *bidirectionally* configurable from the command line: it
+// may be turned on *or* off: any definition other than '0' counts as
+// true, such as -DDO_SELFCHECK=1 or just -DDO_SELFCHECK
+#ifndef DO_SELFCHECK
+  #define DO_SELFCHECK 0
+#endif
+#if DO_SELFCHECK != 0
+  #define SELFCHECK() selfCheck()
+#else
+  #define SELFCHECK() ((void)0)
+#endif
+
+
+// division with rounding towards +inf
+// (when operands are positive)
+template <class T>
+inline T div_up(T const &x, T const &y)
+{ return (x + y - 1) / y; }
+
+
+// mutable
+#ifdef __BORLANDC__
+#  define MUTABLE
+#  define EXPLICIT
+#else
+#  define MUTABLE mutable
+#  define EXPLICIT explicit
+#endif
+
+
+#define SWAP(a,b) \
+  temp = a;       \
+  a = b;          \
+  b = temp /*user supplies semicolon*/
+
+  
+// verify something is true at compile time (will produce
+// a compile error if it isn't)
+// update: use STATIC_ASSERT defined in macros.h instead
+//#define staticAssert(cond) extern int dummyArray[cond? 1 : 0]
+
+
+#endif // __TYP_H
+

Added: vendor/elsa/current/smbase/unixutil.c
===================================================================
--- vendor/elsa/current/smbase/unixutil.c	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/unixutil.c	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,94 @@
+// unixutil.c            see license.txt for copyright and terms of use
+// code for unixutil.h
+
+#include "unixutil.h"   // this module
+
+#include <unistd.h>     // write
+#include <assert.h>     // assert
+#include <sys/time.h>   // struct timeval
+#include <sys/types.h>  // select
+#include <unistd.h>     // select
+#include <stdio.h>      // perror
+
+// 12/13/04: according to rfistman at hotmail, this is required to get
+// FD_ZERO to work on OS X; or should I just #include sys/select.h?
+// how portable is that?
+//
+// A little googling reveals this page documenting sys/select.h:
+//
+//   http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/select.h.html
+//
+// It says it was introduced to POSIX in 2000, which I interpret to mean
+// older systems are likely to not have it.  Indeed, I see messages from
+// people reporting that this file is missing, e.g.,
+//
+//   http://curl.haxx.se/mail/archive-2003-05/0161.html
+//   http://archives.postgresql.org/pgsql-hackers/1997-01/msg00878.php
+//
+// So I will just stick with string.h until I see a problem with it.
+#include <string.h>     // bzero via FD_ZERO on OS X
+
+#ifdef __MINGW32__
+  // on mingw32, fd_set lives in winsock.h
+  #include <winsock.h>
+#endif
+
+
+int writeAll(int fd, void const *buf, int len)
+{
+  int written = 0;
+  while (written < len) {
+    int result = write(fd, ((char const*)buf)+written, len-written);
+    if (result < 0) {
+      return 0;    // failure
+    }
+    written += result;
+  }
+  assert(written == len);
+  return 1;        // success
+}
+
+
+int readString(int fd, char *str, int len)
+{ 
+  int count = read(fd, str, len-1);
+  if (count < 0) {
+    return 0;      // failure
+  }
+  str[count]=0;
+
+  // remove trailing newlines (or NULs), if any
+  while (count>0 && (str[count-1] == '\n' || str[count-1] == 0)) {
+    count--;
+    str[count] = 0;
+  }
+
+  return 1;
+}
+
+
+int canRead(int fd)
+{
+  fd_set set;
+  struct timeval tv;
+  int res;
+
+  // check only 'fd'
+  FD_ZERO(&set);
+  FD_SET(fd, &set);
+
+  // do not block at all
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  res = select(fd+1, &set, NULL, NULL, &tv);
+  if (res == -1) {
+    perror("select");     // not ideal...
+    return 0;
+  }
+  
+  return res;             // 0 or 1
+}
+
+
+// EOF

Added: vendor/elsa/current/smbase/unixutil.h
===================================================================
--- vendor/elsa/current/smbase/unixutil.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/unixutil.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,27 @@
+// unixutil.h            see license.txt for copyright and terms of use
+// some utilities on top of unix functions
+
+#ifndef UNIXUTIL_H
+#define UNIXUTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// write entire contents of buffer to 'fd', returning 0 on failure
+int writeAll(int fd, void const *buf, int len);
+                                           
+// read(2) some data into a buffer of 'len' bytes; null-terminate
+// those bytes, and strip any trailing newline; return 0 on failure
+int readString(int fd, char *str, int len);
+
+// test if there are bytes available to be read from a file descriptor,
+// returning nonzero if so
+int canRead(int fd);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // UNIXUTIL_H

Added: vendor/elsa/current/smbase/vdtllist.cc
===================================================================
--- vendor/elsa/current/smbase/vdtllist.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/vdtllist.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,327 @@
+// vdtllist.cc            see license.txt for copyright and terms of use
+// code for vdtllist.h
+
+#include "vdtllist.h"      // this module
+
+void VoidTailList::steal(VoidTailList *src)
+{
+  if (src) {
+    top = src->top;
+    tail = src->tail;
+    src->top = NULL;    // paranoia
+    delete src;
+  }
+  else {
+    top = NULL;
+    tail = NULL;
+  }
+}
+
+void VoidTailList::prepend(void *newitem)
+{
+  VoidList::prepend(newitem);
+  if (!tail) {
+    tail = top;
+  }
+}
+
+void VoidTailList::append(void *newitem)
+{
+  if (isEmpty()) {
+    prepend(newitem);
+  }
+  else {
+    // payoff: constant-time append
+    tail->next = new VoidNode(newitem, NULL);
+    tail = tail->next;
+  }
+}
+
+void VoidTailList::appendAll(VoidTailList &tail)
+{
+  for (VoidTailListIter iter(tail); !iter.isDone(); iter.adv()) {
+    this->append(iter.data());
+  }
+}
+
+void VoidTailList::insertAt(void *newitem, int index)
+{
+  VoidList::insertAt(newitem, index);
+  adjustTail();
+}
+
+void VoidTailList::concat(VoidTailList &srcList)
+{
+#if 1
+  // quarl 2006-06-01: alter representation directly; VoidList::concat() would
+  // take O(N) to find the tail.
+  if (srcList.top) {
+    if (top) {
+      tail->next = srcList.top;
+    } else {
+      top = srcList.top;
+    }
+
+    tail = srcList.tail; xassert(tail);
+    srcList.top = NULL;
+    srcList.tail = NULL;
+  } else {
+    // nothing to do
+  }
+#else
+  // grab what will be the tail of the concatenated list
+  VoidNode *catTail = srcList.top? srcList.tail : tail;
+
+  // build proper backbone structure
+  VoidList::concat(srcList);
+
+  // fix tails
+  tail = catTail;
+  srcList.tail = NULL;
+#endif
+}
+
+void VoidTailList::adjustTail()
+{
+  if (!tail) {
+    tail = top;
+  }
+  else if (tail->next) {
+    tail = tail->next;
+  }
+  xassert(tail->next == NULL);
+}
+
+void *VoidTailList::removeFirst()
+{
+  xassert(top);
+  if (top == tail) {
+    tail = NULL;
+  }
+  void *retval = top->data;
+  VoidNode *tmp = top;
+  top = top->next;
+  delete tmp;
+  return retval;
+}
+
+void *VoidTailList::removeLast()
+{
+  xassert(top);
+  if (top == tail) {
+    return removeFirst();
+  }
+
+  VoidNode *before = top;
+  while (before->next != tail) {
+    before = before->next;
+  }
+  void *retval = tail->data;
+  delete tail;
+  tail = before;
+  tail->next = NULL;
+  return retval;
+}
+
+void *VoidTailList::removeAt(int index)
+{
+  xassert(top);
+  if (index == 0) {
+    // NOTE: removeFirst fixes the 'tail' pointer.
+    return removeFirst();
+  }
+
+  VoidNode *before = top;    // will point to node before one to be removed
+  index--;
+  while (index > 0) {
+    before = before->next;
+    index--;
+  }
+  xassert(index == 0);
+
+  // fix 'tail' if necessary
+  if (tail == before->next) {
+    tail = before;
+  }
+
+  // patch around before->next
+  VoidNode *toDelete = before->next;
+  void *retval = toDelete->data;
+  before->next = toDelete->next;
+  delete toDelete;
+
+  return retval;
+}
+
+// for now, copy of VoidList::removeIfPresent, since the functions it calls
+// are not virtual.
+bool VoidTailList::removeIfPresent(void *item)
+{
+  // for now, not a real fast implementation
+  int index = indexOf(item);
+  if (index == -1) {
+    return false;   // not there
+  }
+  else {
+    removeAt(index);
+    return true;
+  }
+}
+
+// for now, copy of VoidList::removeItem, since the functions it calls are not
+// virtual.
+void VoidTailList::removeItem(void *item)
+{
+  bool wasThere = removeIfPresent(item);
+  xassert(wasThere);
+}
+
+void VoidTailList::removeAll()
+{
+  VoidList::removeAll();
+  tail = NULL;
+}
+
+bool VoidTailList::prependUnique(void *newitem)
+{
+  bool retval = VoidList::prependUnique(newitem);
+  adjustTail();
+  return retval;
+}
+
+bool VoidTailList::appendUnique(void *newitem)
+{
+  bool retval = VoidList::appendUnique(newitem);
+  adjustTail();
+  return retval;
+}
+
+void VoidTailList::selfCheck() const
+{
+  VoidList::selfCheck();
+
+  if (isNotEmpty()) {
+    // get last node
+    VoidNode *n = top;
+    while (n->next) {
+      n = n->next;
+    }
+
+    // 'tail' should be the last one
+    xassert(tail == n);
+  }
+  else {
+    xassert(tail == NULL);
+  }
+}
+
+
+// --------------- VoidTailListMutator ------------------
+VoidTailListMutator&
+  VoidTailListMutator::operator=(VoidTailListMutator const &obj)
+{
+  // we require that the underlying lists be the same
+  // because we can't reset the 'list' reference if they
+  // aren't
+  xassert(&list == &obj.list);
+
+  prev = obj.prev;
+  current = obj.current;
+
+  return *this;
+}
+
+
+void VoidTailListMutator::insertBefore(void *item)
+{
+  if (prev == NULL) {
+    // insert at start of list
+    list.prepend(item);
+    reset();
+  }
+  else {
+    current = new VoidNode(item, current);
+    if (list.tail == current)
+      list.tail = current;
+    prev->next = current;
+  }
+}
+
+
+void VoidTailListMutator::insertAfter(void *item)
+{
+  xassert(!isDone());
+  current->next = new VoidNode(item, current->next);
+  if (list.tail == current) {
+    list.tail = current->next;
+  }
+}
+
+
+void VoidTailListMutator::append(void *item)
+{
+  xassert(isDone());
+  insertBefore(item);
+  adv();
+}
+
+
+void *VoidTailListMutator::remove()
+{
+  xassert(!isDone());
+  void *retval = data();
+  if (prev == NULL) {
+    // removing first node
+    list.top = current->next;
+    delete current;
+    current = list.top;
+    if (current == NULL) {
+      list.tail = NULL;
+    }
+  }
+  else {
+    current = current->next;
+    delete prev->next;   // old 'current'
+    prev->next = current;
+    if (current == NULL) {
+      list.tail = prev;
+    }
+  }
+  return retval;
+}
+
+
+// --------------------- test code ------------------
+#ifdef TEST_VDTLLIST
+
+#include <stdio.h>    // printf
+
+int main()
+{
+  VoidTailList list;
+  int zero, one, two, three;
+
+  // This isn't a very exhaustive test; it's mainly to check that
+  // selfCheck doesn't do anything really stupid (it used to).
+
+  list.selfCheck();
+
+  list.append(&two);     list.selfCheck();
+  list.prepend(&one);    list.selfCheck();
+  list.append(&three);   list.selfCheck();
+  list.prepend(&zero);   list.selfCheck();
+
+  xassert(list.nth(0) == &zero);
+  xassert(list.nth(1) == &one);
+  xassert(list.nth(2) == &two);
+  xassert(list.nth(3) == &three);
+
+  list.removeAll();
+  list.selfCheck();
+
+  printf("vdtllist works\n");
+
+  return 0;
+}
+
+#endif // TEST_VDTLLIST

Added: vendor/elsa/current/smbase/vdtllist.h
===================================================================
--- vendor/elsa/current/smbase/vdtllist.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/vdtllist.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,170 @@
+// vdtllist.h            see license.txt for copyright and terms of use
+// list of void*, with a pointer maintained to the last (tail)
+// element, for constant-time append
+
+#ifndef VDTLLIST_H
+#define VDTLLIST_H
+
+#include "voidlist.h"      // VoidList
+
+// inherit privately so I can choose what to expose
+class VoidTailList : private VoidList {
+private:
+  // by making this a friend, it should see VoidList as a
+  // base class, and thus simply work
+  // but it doesn't..
+  //friend VoidListIter;
+
+  friend class VoidTailListIter;
+  friend class VoidTailListMutator;
+
+protected:
+  VoidNode *tail;       // (serf) last element of list, or NULL if list is empty
+  VoidNode *getTop() const { return VoidList::getTop(); }
+
+private:
+  VoidTailList(VoidTailList const &obj);    // not allowed
+
+  void adjustTail();
+
+public:
+  VoidTailList()                     { tail = NULL; }
+  ~VoidTailList()                    {}
+
+  // special ctor which steals the list and then deallocates the header
+  VoidTailList(VoidTailList *src)    { tail = NULL; steal(src); }
+  void steal(VoidTailList *src);     // deletes 'src'
+
+  // this syntax just makes the implementation inherited from
+  // 'VoidList' public, whereas it would default to private,
+  // since it was inherited privately
+  VoidList::count;
+
+  // see voidlist.h for documentation of each of these functions
+  VoidList::isEmpty;
+  VoidList::isNotEmpty;
+  VoidList::nth;
+  VoidList::first;
+  void *last() const                 { xassert(tail); return tail->data; }
+
+  // insertion
+  void prepend(void *newitem);
+  void append(void *newitem);
+  void appendAll(VoidTailList &tail);
+  void insertAt(void *newitem, int index);
+  void concat(VoidTailList &tail);
+
+  // removal
+  void *removeFirst();               // remove first, return data; must exist
+  void *removeLast();
+  void *removeAt(int index);
+  bool removeIfPresent(void *item);
+  void removeItem(void *item);
+  void removeAll();
+
+  // list-as-set: selectors
+  VoidList::indexOf;
+  VoidList::indexOfF;
+  VoidList::contains;
+
+  // list-as-set: mutators
+  bool prependUnique(void *newitem);
+  bool appendUnique(void *newitem);
+  //void removeItem(void *item);
+  //bool removeIfPresent(void *item);
+
+  // debugging
+  void selfCheck() const;
+  VoidList::debugPrint;
+};
+
+
+// for traversing the list and modifying it
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists, and only one such iterator should exist for
+//       any given list
+class VoidTailListMutator {
+  friend class VoidTailListIter;
+
+protected:
+  VoidTailList &list; 	  // underlying list
+  VoidNode *prev;         // (serf) previous node; NULL if at list's head
+  VoidNode *current;      // (serf) node we're considered to be pointing at
+
+public:
+  VoidTailListMutator(VoidTailList &lst)   : list(lst) { reset(); }
+  ~VoidTailListMutator()               {}
+
+  void reset()                     { prev = NULL;  current = list.top; }
+
+  // iterator copying; safe *only* until one of the mutators modifies
+  // the list structure (by inserting or removing), at which time all
+  // other iterators might be in limbo
+  VoidTailListMutator(VoidTailListMutator const &obj)
+    : list(obj.list), prev(obj.prev), current(obj.current) {}
+  VoidTailListMutator& operator=(VoidTailListMutator const &obj);
+    // requires that 'this' and 'obj' already refer to the same 'list'
+
+  // iterator actions
+  bool isDone() const              { return current == NULL; }
+  void adv()                       { prev = current;  current = current->next; }
+  void *data()                     { return current->data; }
+  void *&dataRef()                 { return current->data; }
+
+  // insertion
+  void insertBefore(void *item);
+    // 'item' becomes the new 'current', and the current 'current' is
+    // pushed forward (so the next adv() will make it current again)
+
+  void insertAfter(void *item);
+    // 'item' becomes what we reach with the next adv();
+    // isDone() must be false
+
+  void append(void *item);
+    // only valid while isDone() is true, it inserts 'item' at the end of
+    // the list, and advances such that isDone() remains true; equivalent
+    // to { xassert(isDone()); insertBefore(item); adv(); }
+
+  // removal
+  void *remove();
+    // 'current' is removed from the list and returned, and whatever was
+    // next becomes the new 'current'
+
+  // debugging
+  void selfCheck() const
+    { xassert((prev->next == current  &&  current != list.top) ||
+              (prev==NULL && current==list.top)); }
+};
+
+// copied from voidlist.h because g++ won't do what I want..
+class VoidTailListIter {
+protected:
+  VoidNode *p;                        // (serf) current item
+
+public:
+  VoidTailListIter(VoidTailList const &list)  { reset(list); }
+  VoidTailListIter()                          { p = NULL; }
+  ~VoidTailListIter()                         {}
+
+  void reset(VoidTailList const &list)        { p = list.getTop(); }
+
+  // iterator copying; generally safe
+  VoidTailListIter(VoidTailListIter const &obj)             { p = obj.p; }
+  VoidTailListIter& operator=(VoidTailListIter const &obj)  { p = obj.p; return *this; }
+
+  // but copying from a mutator is less safe; see above
+  //VoidTailListIter(VoidListMutator &obj)      { p = obj.current; }
+
+  // iterator actions
+  bool isDone() const                         { return p == NULL; }
+  void adv()                                  { p = p->next; }
+  void *data() const                          { return p->data; }
+  void *&dataRef()                            { return p->data; }
+
+  // iterator mutation; use with caution
+  void setDataLink(void *newData)             { p->data = newData; }
+};
+
+
+
+#endif // VDTLLIST_H

Added: vendor/elsa/current/smbase/voidlist.cc
===================================================================
--- vendor/elsa/current/smbase/voidlist.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/voidlist.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,955 @@
+// voidlist.cc            see license.txt for copyright and terms of use
+// code for voidlist.h
+
+#include "voidlist.h"   // this module
+#include "breaker.h"    // breaker
+#include "str.h"        // stringc
+#include "ckheap.h"     // checkHeap
+
+#include <stdlib.h>     // rand()
+#include <stdio.h>      // printf()
+
+
+VoidList::VoidList(VoidList const &obj)
+  : top(NULL)
+{
+  *this = obj;
+}
+
+
+// # of items in list
+int VoidList::count() const
+{
+  int ct=0;
+  for(VoidNode *p = top; p; p = p->next) {
+    ct++;
+  }
+  return ct;
+}
+
+
+// get particular item, 0 is first (item must exist)
+void *VoidList::nth(int which) const
+{
+  return const_cast<VoidList*>(this)->nthRef(which);
+}
+
+
+// get particular item, 0 is first (item must exist)
+void *&VoidList::nthRef(int which)
+{
+  VoidNode *p;
+  xassert(which>=0);
+  for (p = top; which > 0; which--) {
+    xassert(p);
+    p = p->next;
+  }
+  if (p == NULL) {
+    xfailure(stringc << "asked for list element "
+                     << (count()+which) << " (0-based) but list only has "
+                     << count() << " elements");
+  }
+  return p->data;
+}
+
+
+// fail assertion if list fails integrity check
+void VoidList::selfCheck() const
+{
+  if (!top) {
+    return;
+  }
+
+  // The technique here is the fast/slow list traversal to find loops (which
+  // are the only way a singly-linked list can be bad). Basically, if there
+  // is a loop then the fast ptr will catch up to and equal the slow one; if
+  // not, the fast will simply find the terminating null. It is the only way
+  // I know of to find loops in O(1) space and O(n) time.
+
+  VoidNode *slow=top, *fast=top->next;
+  while (fast && fast != slow) {
+    // check heap properties
+    checkHeapNode(fast);
+
+    slow = slow->next;
+    fast = fast->next;
+    if (fast) {
+      checkHeapNode(fast);
+      fast = fast->next;      // usually, fast jumps 2 spots per slow's 1
+    }
+  }
+
+  if (fast == slow) {
+    xfailure("linked list has a cycle");
+  }
+  else {
+    return;         // no loop
+  }
+}
+
+
+void VoidList::checkHeapDataPtrs() const
+{
+  for (VoidNode *p=top; p!=NULL; p=p->next) {
+    checkHeapNode(p->data);
+  }
+}
+
+
+void VoidList::checkUniqueDataPtrs() const
+{
+  for (VoidNode *p=top; p!=NULL; p=p->next) {
+    // run 'q' from 'top' to 'p', looking for any
+    // collisions with 'p->data'
+    for (VoidNode *q=top; q!=p; q=q->next) {
+      if (q->data == p->data) {
+        xfailure("linked list with duplicate element");
+      }
+    }
+  }
+}
+
+
+// insert at front
+void VoidList::prepend(void *newitem)
+{
+  top = new VoidNode(newitem, top);
+}
+
+
+// insert at rear
+void VoidList::append(void *newitem)
+{
+  if (!top) {
+    prepend(newitem);
+  }
+  else {
+    VoidNode *p;
+    for (p = top; p->next; p = p->next)
+      {}
+    p->next = new VoidNode(newitem);
+  }
+}
+
+
+// insert at particular point, index of new node becomes 'index'
+void VoidList::insertAt(void *newitem, int index)
+{
+  if (index == 0 || isEmpty()) {
+    // special case prepending or an empty list
+    xassert(index == 0);     // if it's empty, index should be 0
+    prepend(newitem);
+  }
+
+  else {
+    // Looking at the loop below, the key things to note are:
+    //  1. If index started as 1, the loop isn't executed, and the new
+    //     node goes directly after the top node.
+    //  2. p is never allowed to become NULL, so we can't walk off the
+    //     end of the list.
+
+    index--;
+    VoidNode *p;
+    for (p = top; p->next && index; p = p->next) {
+      index--;
+    }
+    xassert(index == 0);
+      // if index isn't 0, then index was greater than count()
+
+    // put a node after p
+    VoidNode *n = new VoidNode(newitem);
+    n->next = p->next;
+    p->next = n;
+  }
+}
+
+
+void VoidList::insertSorted(void *newitem, VoidDiff diff, void *extra)
+{
+  // put it first?
+  if (!top ||
+      diff(newitem, top->data, extra) <= 0) {                // newitem <= top
+    prepend(newitem);
+    return;
+  }
+
+  // we will be considering adding 'newitem' *after* cursor, as we go
+  VoidNode *cursor = top;
+  while (cursor->next != NULL &&
+         diff(cursor->next->data, newitem, extra) < 0) {     // cursor->next < newitem
+    cursor = cursor->next;
+  }
+
+  // insert 'newitem' after 'cursor'
+  VoidNode *newNode = new VoidNode(newitem);
+  newNode->next = cursor->next;
+  cursor->next = newNode;
+}
+
+
+// ----------------- list-as-set stuff -------------------
+// get the index of an item's first occurrance
+int VoidList::indexOf(void *item) const
+{
+  int index = 0;
+  for (VoidNode *p = top; p != NULL; p = p->next, index++) {
+    if (p->data == item) {
+      return index;
+    }
+  }
+  return -1;
+}
+
+
+int VoidList::indexOfF(void *item) const
+{
+  int ret = indexOf(item);
+  xassert(ret >= 0);
+  return ret;
+}
+
+
+bool VoidList::prependUnique(void *newitem)
+{
+  if (!contains(newitem)) {
+    prepend(newitem);
+    return true;
+  }
+  else {
+    return false;   // no change
+  }
+}
+
+
+bool VoidList::appendUnique(void *newitem)
+{
+  if (!top) {
+    prepend(newitem);
+    return true;
+  }
+
+  // walk to the end of list, while checking to
+  // see if 'newitem' is already in the list
+  VoidNode *p;
+  for (p = top; p->next; p = p->next) {
+    if (p->data == newitem) {
+      return false;      // item is already on list; no change
+    }
+  }
+  if (p->data == newitem) {
+    return false;
+  }
+
+  p->next = new VoidNode(newitem);
+  return true;
+}
+
+
+bool VoidList::removeIfPresent(void *item)
+{
+  // for now, not a real fast implementation
+  int index = indexOf(item);
+  if (index == -1) {
+    return false;   // not there
+  }
+  else {
+    removeAt(index);
+    return true;
+  }
+}
+
+
+void VoidList::removeItem(void *item)
+{
+  bool wasThere = removeIfPresent(item);
+  xassert(wasThere);
+}
+
+// ----------------- end of list-as-set stuff -------------------
+
+
+void *VoidList::removeAt(int index)
+{
+  if (index == 0) {
+    xassert(top != NULL);   // element must exist to remove
+    VoidNode *temp = top;
+    void *retval = temp->data;
+    top = top->next;
+    delete temp;
+    return retval;
+  }
+
+  // will look for the node just before the one to delete
+  index--;
+
+  VoidNode *p;
+  for (p = top; p->next && index>0;
+       p = p->next, index--)
+    {}
+
+  if (p->next) {
+    // index==0, so p->next is node to remove
+    VoidNode *temp = p->next;
+    void *retval = temp->data;
+    p->next = p->next->next;
+    delete temp;
+    return retval;
+  }
+  else {
+    // p->next==NULL, so index was too large
+    xfailure("Tried to remove an element not on the list");
+    return NULL;    // silence warning
+  }
+}
+
+
+void VoidList::removeAll()
+{
+  while (top != NULL) {
+    VoidNode *temp = top;
+    top = top->next;
+    delete temp;
+  }
+}
+
+
+void VoidList::reverse()
+{
+  // transfer list to a temporary
+  VoidNode *oldlist = top;
+  top = NULL;
+
+  // prepend all nodes
+  while (oldlist != NULL) {
+    // take first node from oldlist
+    VoidNode *node = oldlist;
+    oldlist = oldlist->next;
+
+    // prepend it to new list
+    node->next = top;
+    top = node;
+  }
+}
+
+
+//   The difference function should return <0 if left should come before
+// right, 0 if they are equivalent, and >0 if right should come before
+// left. For example, if we are sorting numbers into ascending order,
+// then 'diff' would simply be subtraction.
+//   The 'extra' parameter passed to sort is passed to diff each time it
+// is called.
+//   O(n^2) time, O(1) space
+void VoidList::insertionSort(VoidDiff diff, void *extra)
+{
+  VoidNode *primary = top;                   // primary sorting pointer
+  while (primary && primary->next) {
+    if (diff(primary->data, primary->next->data, extra) > 0) {   // must move next node?
+      VoidNode *tomove = primary->next;
+      primary->next = primary->next->next;    // patch around moving node
+
+      if (diff(tomove->data, top->data, extra) < 0) {           // new node goes at top?
+        tomove->next = top;
+        top = tomove;
+      }
+
+      else {                                  // new node *not* at top
+        VoidNode *searcher = top;
+        while (diff(tomove->data, searcher->next->data, extra) > 0) {
+          searcher = searcher->next;
+        }
+
+        tomove->next = searcher->next;        // insert new node into list
+        searcher->next = tomove;
+      }
+    }
+
+    else {
+      primary = primary->next;              // go on if no changes
+    }
+  }
+}
+
+
+// O(n log n) time, O(log n) space
+void VoidList::mergeSort(VoidDiff diff, void *extra)
+{
+  if (top == NULL || top->next == NULL) {
+    return;   // base case: 0 or 1 elements, already sorted
+  }
+
+  // half-lists
+  VoidList leftHalf;
+  VoidList rightHalf;
+
+  // divide the list
+  {
+    // to find the halfway point, we use the slow/fast
+    // technique; to get the right node for short lists
+    // (like 2-4 nodes), we start fast off one ahead
+
+    VoidNode *slow = top;
+    VoidNode *fast = top->next;
+
+    while (fast && fast->next) {
+      slow = slow->next;
+      fast = fast->next;
+      fast = fast->next;
+    }
+
+    // at this point, 'slow' points to the node
+    // we want to be the last of the 'left' half;
+    // the left half will either be the same length
+    // as the right half, or one node longer
+
+    // division itself
+    rightHalf.top = slow->next;	 // top half to right
+    leftHalf.top = this->top;    // bottom half to left
+    slow->next = NULL; 	       	 // cut the link between the halves
+  }
+
+  // recursively sort the halves
+  leftHalf.mergeSort(diff, extra);
+  rightHalf.mergeSort(diff, extra);
+
+  // merge the halves into a single, sorted list
+  VoidNode *merged = NULL;     	 // tail of merged list
+  while (leftHalf.top != NULL &&
+         rightHalf.top != NULL) {
+    // see which first element to select, and remove it
+    VoidNode *selected;
+    if (diff(leftHalf.top->data, rightHalf.top->data, extra) < 0) {
+      selected = leftHalf.top;
+      leftHalf.top = leftHalf.top->next;
+    }
+    else {
+      selected = rightHalf.top;
+      rightHalf.top = rightHalf.top->next;
+    }
+
+    // append it to the merged list
+    if (merged == NULL) {
+      // first time; special case
+      merged = this->top = selected;
+    }
+    else {
+      // 2nd and later; normal case
+      merged = merged->next = selected;
+    }
+  }
+
+  // one of the halves is exhausted; concat the
+  // remaining elements of the other one
+  if (leftHalf.top != NULL) {
+    merged->next = leftHalf.top;
+    leftHalf.top = NULL;
+  }
+  else {
+    merged->next = rightHalf.top;
+    rightHalf.top = NULL;
+  }
+
+  // verify both halves are now exhausted
+  xassert(leftHalf.top == NULL &&
+          rightHalf.top == NULL);
+
+  // list is sorted
+}
+
+
+bool VoidList::isSorted(VoidDiff diff, void *extra) const
+{
+  if (isEmpty()) {
+    return true;
+  }
+
+  void *prev = top->data;
+  VoidListIter iter(*this);
+  iter.adv();
+  for (; !iter.isDone(); iter.adv()) {
+    void *current = iter.data();
+
+    if (diff(prev, current, extra) <= 0) {
+      // ok: prev <= current
+    }
+    else {
+      return false;
+    }
+
+    prev = current;
+  }
+
+  return true;
+}
+
+
+// attach tail's nodes to this; empty the tail
+void VoidList::concat(VoidList &tail)
+{
+  if (!top) {
+    top = tail.top;
+  }
+  else {
+    VoidNode *n = top;
+    for(; n->next; n = n->next)
+      {}
+    n->next = tail.top;
+  }
+
+  tail.top = NULL;
+}
+
+
+// attach some of source's nodes to this, removing them from 'source'
+void VoidList::stealTailAt(int index, VoidList &source)
+{
+  if (index == 0) {
+    concat(source);
+    return;
+  }
+
+  // find the node in 'source' just before the first one that
+  // will be transferred
+  VoidNode *beforeTransfer = source.top;
+  index--;
+  while (index--) {
+    beforeTransfer = beforeTransfer->next;
+  }
+
+  // break off the tail
+  VoidNode *tailStart = beforeTransfer->next;
+  beforeTransfer->next = NULL;
+
+  // transfer 'tailStart' and beyond to 'this'
+  if (!top) {
+    top = tailStart;
+  }
+  else {
+    // find the end of 'this' list
+    VoidNode *n = top;
+    for(; n->next; n = n->next)
+      {}
+    n->next = tailStart;
+  }
+}
+
+
+void VoidList::appendAll(VoidList const &tail)
+{
+  // make a dest iter and move it to the end
+  VoidListMutator destIter(*this);
+  while (!destIter.isDone()) {
+    destIter.adv();
+  }
+
+  VoidListIter srcIter(tail);
+  for (; !srcIter.isDone(); srcIter.adv()) {
+    destIter.append(srcIter.data());
+  }
+}
+
+
+void VoidList::prependAll(VoidList const &tail)
+{
+  VoidListMutator destIter(*this);
+  VoidListIter srcIter(tail);
+  for (; !srcIter.isDone(); srcIter.adv()) {
+    destIter.insertBefore(srcIter.data());
+    destIter.adv();
+  }
+}
+
+
+VoidList& VoidList::operator= (VoidList const &src)
+{
+  if (this != &src) {
+    removeAll();
+    appendAll(src);
+  }
+  return *this;
+}
+
+
+bool VoidList::equalAsLists(VoidList const &otherList, VoidDiff diff, void *extra) const
+{
+  return 0==compareAsLists(otherList, diff, extra);
+}
+
+int VoidList::compareAsLists(VoidList const &otherList, VoidDiff diff, void *extra) const
+{
+  VoidListIter mine(*this);
+  VoidListIter his(otherList);
+
+  while (!mine.isDone() && !his.isDone()) {
+    int cmp = diff(mine.data(), his.data(), extra);
+    if (cmp == 0) {
+      // they are equal; keep going
+    }
+    else {
+      // unequal, return which way comparison went
+      return cmp;
+    }
+
+    mine.adv();
+    his.adv();
+  }
+
+  if (!mine.isDone() || !his.isDone()) {
+    // unequal lengths: shorter compares as less
+    return mine.isDone()? -1 : +1;
+  }
+
+  return 0;        // everything matches
+}
+
+
+bool VoidList::equalAsSets(VoidList const &otherList, VoidDiff diff, void *extra) const
+{
+  return this->isSubsetOf(otherList, diff, extra) &&
+         otherList.isSubsetOf(*this, diff, extra);
+}
+
+
+bool VoidList::isSubsetOf(VoidList const &otherList, VoidDiff diff, void *extra) const
+{
+  for (VoidListIter iter(*this); !iter.isDone(); iter.adv()) {
+    if (!otherList.containsByDiff(iter.data(), diff, extra)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+bool VoidList::containsByDiff(void *item, VoidDiff diff, void *extra) const
+{
+  for (VoidListIter iter(*this); !iter.isDone(); iter.adv()) {
+    if (0==diff(item, iter.data(), extra)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+void VoidList::removeDuplicatesAsMultiset(VoidDiff diff, void *extra)
+{
+  if (isEmpty()) {
+    return;
+  }
+
+  mergeSort(diff, extra);
+
+  VoidListMutator mut(*this);
+
+  void *prevItem = mut.data();
+  mut.adv();
+
+  while (!mut.isDone()) {
+    if (0==diff(prevItem, mut.data(), extra)) {
+      // this element is identical to the previous one, so remove
+      // it from the list
+      mut.remove();
+    }
+    else {
+      prevItem = mut.data();
+      mut.adv();
+    }
+  }
+}
+
+
+STATICDEF int VoidList::pointerAddressDiff(void *left, void *right, void*)
+{
+  return comparePointerAddresses(left, right);
+}
+
+
+void VoidList::debugPrint() const
+{
+  printf("{ ");
+  for (VoidListIter iter(*this); !iter.isDone(); iter.adv()) {
+    printf("%p ", iter.data());
+  }
+  printf("}");
+}
+
+
+// --------------- VoidListMutator ------------------
+VoidListMutator&
+  VoidListMutator::operator=(VoidListMutator const &obj)
+{
+  // we require that the underlying lists be the same
+  // because we can't reset the 'list' reference if they
+  // aren't
+  xassert(&list == &obj.list);
+
+  prev = obj.prev;
+  current = obj.current;
+
+  return *this;
+}
+
+
+void VoidListMutator::insertBefore(void *item)
+{
+  if (prev == NULL) {
+    // insert at start of list
+    list.prepend(item);
+    reset();
+  }
+  else {
+    current = prev->next = new VoidNode(item, current);
+  }
+}
+
+
+void VoidListMutator::insertAfter(void *item)
+{
+  xassert(!isDone());
+  current->next = new VoidNode(item, current->next);
+}
+
+
+void VoidListMutator::append(void *item)
+{
+  xassert(isDone());
+  insertBefore(item);
+  adv();
+}
+
+
+void *VoidListMutator::remove()
+{
+  xassert(!isDone());
+  void *retval = data();
+  if (prev == NULL) {
+    // removing first node
+    list.top = current->next;
+    delete current;
+    current = list.top;
+  }
+  else {
+    current = current->next;
+    delete prev->next;   // old 'current'
+    prev->next = current;
+  }
+  return retval;
+}
+
+
+// --------------- VoidListIter --------------------
+VoidListIter::VoidListIter(VoidList const &list, int pos)
+{
+  reset(list);
+  while (pos--) {
+    adv();
+  }
+}
+
+
+// -------------- testing --------------
+#ifdef TEST_VOIDLIST
+#include "test.h"     // USUAL_MAIN
+
+// assumes we're using pointerAddressDiff as the comparison fn
+// (I don't use isSorted because this fn will throw at the disequality,
+// whereas isSorted would forget that info)
+void verifySorted(VoidList const &list)
+{
+  const void* prev = 0;
+  VoidListIter iter(list);
+  for (; !iter.isDone(); iter.adv()) {
+    const void *current = (const void *)iter.data();
+    xassert(prev <= current);    // numeric address test
+    prev = current;
+  }
+}
+
+
+#define PRINT(lst) printf("%s: ", #lst); lst.debugPrint(); printf("\n") /* user ; */
+
+void testSorting()
+{
+  enum { ITERS=100, ITEMS=20 };
+
+  loopi(ITERS) {
+    // construct a list (and do it again if it ends up already sorted)
+    VoidList list1;
+    VoidList list3;     // this one will be constructed sorted one at a time
+    int numItems;
+    do {
+      list1.removeAll();    // clear them in case we have to build it more than once
+      list3.removeAll();
+      numItems = rand()%ITEMS;
+      loopj(numItems) {
+        void *toInsert = (void*)( (rand()%ITEMS) * 4 );
+	list1.prepend(toInsert);
+        list3.insertSorted(toInsert, VoidList::pointerAddressDiff);
+      }
+    } while (list1.isSorted(VoidList::pointerAddressDiff));
+
+    // list3 should be sorted already
+    //PRINT(list3);
+    verifySorted(list3);
+
+    // duplicate it for use with other algorithm
+    VoidList list2;
+    list2 = list1;
+
+    // sort them
+    list1.insertionSort(VoidList::pointerAddressDiff);
+    xassert(list1.equalAsPointerSets(list2));      // verify intermediate equality
+    xassert(!list1.equalAsPointerLists(list2));    // but not elementwise
+    list2.mergeSort(VoidList::pointerAddressDiff);
+    //PRINT(list1);
+
+    // verify structure
+    list1.selfCheck();
+    list2.selfCheck();
+
+    // verify length
+    xassert(list1.count() == numItems && list2.count() == numItems);
+
+    // verify sortedness
+    verifySorted(list1);
+    verifySorted(list2);
+
+    // verify equality
+    xassert(list1.equalAsPointerLists(list2));
+    xassert(list1.equalAsPointerLists(list3));
+
+    // to test as-sets equality
+    void *first = list1.first();
+    while (list1.removeIfPresent(first))
+      {}     // remove all occurrances of 'first'
+    xassert(!list1.equalAsPointerSets(list2));
+  }
+}
+
+
+void entry()
+{
+  // first set of tests
+  {
+    // some sample items
+    void *a=(void*)4, *b=(void*)8, *c=(void*)12, *d=(void*)16;
+
+    VoidList list;
+
+    // test simple modifiers and info
+    list.append(c);     PRINT(list);   // c
+    list.prepend(b);   	PRINT(list);   // b c
+    list.append(d);	PRINT(list);   // b c d
+    list.prepend(a);	PRINT(list);   // a b c d
+    list.removeAt(2);	PRINT(list);   // a b d
+
+    xassert( list.count() == 3 &&
+             !list.isEmpty() &&
+             list.nth(0) == a &&
+             list.nth(1) == b &&
+             list.nth(2) == d &&
+             list.indexOf(a) == 0 &&
+             list.indexOf(b) == 1 &&
+             list.indexOf(c) == -1 &&
+             list.indexOf(d) == 2
+           );
+    list.selfCheck();
+
+    // test mutator s
+    {
+      VoidListMutator mut(list);
+      mut.adv();
+	// now it's pointing at b
+      mut.insertAfter(c);
+	// now list is (a b c d) and mut points at b still
+      verifySorted(list);
+      mut.remove();
+	// now list is (a c d) and mut points at c
+      xassert(mut.data() == c);
+
+      // copy the mutator
+      VoidListMutator mut2(mut);
+      mut2.adv();
+      xassert(mut.data() == c  &&  mut2.data() == d);
+
+      // copy to a normal iterator
+      VoidListIter iter(mut);
+      iter.adv();
+      xassert(iter.data() == d);
+      iter.adv();
+      xassert(iter.isDone()  &&  mut.data() == c);
+
+      PRINT(list);
+    }
+
+    // test appendUnique and prependUnique
+    // list starts as (a c d)
+    xassert(list.appendUnique(c) == false &&
+            list.prependUnique(d) == false &&
+            list.prependUnique(b) == true);
+      // now it is (b a c d)
+    list.removeItem(a);
+    xassert(list.removeIfPresent(a) == false);
+      // now it is (b c d)
+    verifySorted(list);
+    PRINT(list);
+
+    // test reverse
+    list.reverse();
+      // list is now (d c b)
+    xassert(list.indexOf(d) == 0 &&
+            list.indexOf(c) == 1 &&
+            list.indexOf(b) == 2);
+    PRINT(list);
+
+    // test stealTailAt
+    VoidList thief;
+    thief.stealTailAt(1, list);
+      // list is now (d)
+      // thief is now (c b)
+    xassert(list.count() == 1 &&
+            list.indexOf(d) == 0 &&
+            thief.count() == 2 &&
+            thief.indexOf(c) == 0 &&
+            thief.indexOf(b) == 1);
+
+    // test appendAll
+    list.appendAll(thief);      // list: (d c b)
+    PRINT(list);
+    xassert(list.count() == 3 &&
+            list.indexOf(d) == 0 &&
+            list.indexOf(c) == 1 &&
+            list.indexOf(b) == 2);
+
+    // test prependAll
+    list.prependAll(thief);     // list: (c b d c b)
+    PRINT(list);
+    xassert(list.count() == 5 &&
+            list.nth(0) == c &&
+            list.nth(1) == b &&
+            list.nth(2) == d &&
+            list.nth(3) == c &&
+            list.nth(4) == b);
+
+    xassert(thief.count() == 2);    // not modified
+
+    // test removeDuplicatesAsMultiset
+    list.removeDuplicatesAsPointerMultiset();     // list: (b c d)
+    PRINT(list);
+    xassert(list.count() == 3 &&
+            list.nth(0) == b &&
+            list.nth(1) == c &&
+            list.nth(2) == d);
+  }
+
+  // this hits most of the remaining code
+  // (a decent code coverage tool for C++ would be nice!)
+  testSorting();
+
+  printf("voidlist ok\n");
+}
+
+USUAL_MAIN
+
+#endif // NDEBUG
+

Added: vendor/elsa/current/smbase/voidlist.h
===================================================================
--- vendor/elsa/current/smbase/voidlist.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/voidlist.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,230 @@
+// voidlist.h            see license.txt for copyright and terms of use
+// list of void*
+
+// Author: Scott McPeak, 2000
+
+#ifndef __VOIDLIST_H
+#define __VOIDLIST_H
+
+#include "xassert.h"     // xassert
+#include "typ.h"         // bool
+#include "trdelete.h"    // TRASHINGDELETE
+
+// -------------------------- non-typesafe core -----------------------------
+// non-typesafe list node
+class VoidNode {
+public:
+  TRASHINGDELETE
+
+  VoidNode *next;           // (owner) next item in list, or NULL if last item
+  void *data;               // whatever it is the list is holding
+
+  VoidNode(void *aData=NULL, VoidNode *aNext=NULL) { data=aData; next=aNext; }
+};
+
+
+// forward decls for 'friend' decls
+class VoidListIter;
+class VoidListMutator;
+
+
+// The difference function should return <0 if left should come before
+// right, 0 if they are equivalent, and >0 if right should come before
+// left.  For example, if we are sorting numbers into ascending order,
+// then 'diff' could simply be subtraction.
+typedef int (*VoidDiff)(void *left, void *right, void *extra);
+
+
+// list of void*; at this level, the void* are completely opaque;
+// the list won't attempt to delete(), compare them, or anything else
+// (well, some comparison has creeped in now... but only via VoidDiff)
+class VoidList {
+private:
+  friend class VoidListIter;
+  friend class VoidListMutator;
+
+protected:
+  VoidNode *top;                     // (owner) first node, or NULL if list is empty
+  VoidNode *getTop() const { return top; } // for iterator, below
+
+public:
+  VoidList()                         { top=NULL; }
+  VoidList(VoidList const &obj);     // makes a (shallow) copy of the contents
+  ~VoidList()                        { removeAll(); }
+
+  // selectors
+  int count() const;                 // # of items in list
+  bool isEmpty() const               { return top == NULL; }
+  bool isNotEmpty() const            { return top != NULL; }
+  void *nth(int which) const;        // get particular item, 0 is first (item must exist)
+  void *&nthRef(int which);
+  void *first() const { return nth(0); }
+  void *last() const { return nth(count()-1); }
+
+  // insertion
+  void prepend(void *newitem);       // insert at front
+  void append(void *newitem);        // insert at rear
+  void insertAt(void *newitem, int index);
+    // new item is inserted such that its index becomdes 'index'
+  void insertSorted(void *newitem, VoidDiff diff, void *extra=NULL);
+    // insert into an already-sorted list so that the list is sorted afterwards
+
+  // removal
+  void *removeAt(int index);         // remove from list (must exist), and return removed item
+  void *removeFirst()                { return removeAt(0); }
+  void removeAll();
+
+  // list-as-set: selectors
+  int indexOf(void *item) const;     // returns index of *first* occurrance, or -1 if not present
+  int indexOfF(void *item) const;    // same as indexOf, but throws exception if not present
+  bool contains(void *item) const    // true if the item appears in the list
+    { return indexOf(item) >= 0; }
+
+  // list-as-set: mutators
+  bool prependUnique(void *newitem); // prepend only if not already there
+  bool appendUnique(void *newitem);  // append   "            "
+  void removeItem(void *item);       // remove first occurrance -- must exist
+  bool removeIfPresent(void *item);  // remove first occurrance; return true if changed
+
+  // complex modifiers
+  void reverse();
+  void insertionSort(VoidDiff diff, void *extra=NULL);
+  void mergeSort(VoidDiff diff, void *extra=NULL);
+
+  // and a related test
+  bool isSorted(VoidDiff diff, void *extra=NULL) const;
+
+  // multiple lists
+  void concat(VoidList &tail);           // tail is emptied, nodes appended to this
+  void appendAll(VoidList const &tail);  // tail is untouched.. but its contents are now exposed to non-constness... ug... oh well
+  void prependAll(VoidList const &head);
+  VoidList& operator= (VoidList const &src);  // afterwards, 'this' and 'src' have same contents
+
+  // steal (become the container for) the tail of a source list at any
+  // point; if 'index' is 0, the entire 'source' is stolen (i.e.
+  // index=0 is equivalent to 'concat', above); stolen items appended
+  // to 'this'
+  void stealTailAt(int index, VoidList &source);
+
+  // equal items in equal positions
+  bool equalAsLists(VoidList const &otherList, VoidDiff diff, void *extra=NULL) const;
+
+  // if equal, returns 0; otherwise, return order (-1/+1) according to
+  // the first differing pair of elements; a shorter (but otherwise
+  // idential list) will compare as being less
+  int compareAsLists(VoidList const &otherList, VoidDiff diff, void *extra=NULL) const;
+
+  // last-as-set: comparisons (NOT efficient)
+  bool equalAsSets(VoidList const &otherList, VoidDiff diff, void *extra=NULL) const;
+    // A subset of B, and vice-versa
+  bool isSubsetOf(VoidList const &otherList, VoidDiff diff, void *extra=NULL) const;
+    // uses slow elementwise containment
+  bool containsByDiff(void *item, VoidDiff diff, void *extra=NULL) const;
+
+  // use 'diff' to mergesort the list, then remove duplicate entries
+  void removeDuplicatesAsMultiset(VoidDiff diff, void *extra=NULL);
+
+  // treating the pointer values themselves as the basis for comparison
+  static int pointerAddressDiff(void *left, void *right, void*);
+  bool equalAsPointerLists(VoidList const &otherList) const
+    { return equalAsLists(otherList, pointerAddressDiff); }
+  bool equalAsPointerSets(VoidList const &otherList) const
+    { return equalAsSets(otherList, pointerAddressDiff); }
+  void removeDuplicatesAsPointerMultiset()
+    { removeDuplicatesAsMultiset(pointerAddressDiff); }
+
+  // debugging
+  void selfCheck() const;            // test this list; fail assertion if malformed
+  void debugPrint() const;           // print list contents to stdout
+  void checkHeapDataPtrs() const;    // fail assertion if any 'data' ptr isn't valid heap ptr
+  void checkUniqueDataPtrs() const;  // fail assertion if any 'data' ptr matches any other in this list
+};
+
+
+// for traversing the list and modifying it
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists, and only one such iterator should exist for
+//       any given list
+class VoidListMutator {
+  friend class VoidListIter;
+
+protected:
+  VoidList &list; 	  // underlying list
+  VoidNode *prev;         // (serf) previous node; NULL if at list's head
+  VoidNode *current;      // (serf) node we're considered to be pointing at
+
+public:
+  VoidListMutator(VoidList &lst)   : list(lst) { reset(); }
+  ~VoidListMutator()               {}
+
+  void reset()                     { prev = NULL;  current = list.top; }
+
+  // iterator copying; safe *only* until one of the mutators modifies
+  // the list structure (by inserting or removing), at which time all
+  // other iterators might be in limbo
+  VoidListMutator(VoidListMutator const &obj)
+    : list(obj.list), prev(obj.prev), current(obj.current) {}
+  VoidListMutator& operator=(VoidListMutator const &obj);
+    // requires that 'this' and 'obj' already refer to the same 'list'
+
+  // iterator actions
+  bool isDone() const              { return current == NULL; }
+  void adv()                       { prev = current;  current = current->next; }
+  void *data()                     { return current->data; }
+  void *&dataRef()                 { return current->data; }
+
+  // insertion
+  void insertBefore(void *item);
+    // 'item' becomes the new 'current', and the current 'current' is
+    // pushed forward (so the next adv() will make it current again)
+
+  void insertAfter(void *item);
+    // 'item' becomes what we reach with the next adv();
+    // isDone() must be false
+
+  void append(void *item);
+    // only valid while isDone() is true, it inserts 'item' at the end of
+    // the list, and advances such that isDone() remains true; equivalent
+    // to { xassert(isDone()); insertBefore(item); adv(); }
+
+  // removal
+  void *remove();
+    // 'current' is removed from the list and returned, and whatever was
+    // next becomes the new 'current'
+
+  // debugging
+  void selfCheck() const
+    { xassert((prev->next == current  &&  current != list.top) ||
+              (prev==NULL && current==list.top)); }
+};
+
+
+// for traversing the list without modifying it
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists
+class VoidListIter {
+protected:
+  VoidNode *p;                        // (serf) current item
+
+public:
+  VoidListIter(VoidList const &list)  { reset(list); }
+  VoidListIter(VoidList const &list, int pos);    // advance 'pos' times
+  ~VoidListIter()                     {}
+
+  void reset(VoidList const &list)    { p = list.getTop(); }
+
+  // iterator copying; generally safe
+  VoidListIter(VoidListIter const &obj)             { p = obj.p; }
+  VoidListIter& operator=(VoidListIter const &obj)  { p = obj.p;  return *this; }
+
+  // but copying from a mutator is less safe; see above
+  VoidListIter(VoidListMutator &obj)  { p = obj.current; }
+
+  // iterator actions
+  bool isDone() const                 { return p == NULL; }
+  void adv()                          { p = p->next; }
+  void *data() const                  { return p->data; }
+};
+
+
+#endif // __VOIDLIST_H

Added: vendor/elsa/current/smbase/vptrmap.cc
===================================================================
--- vendor/elsa/current/smbase/vptrmap.cc	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/vptrmap.cc	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,395 @@
+// vptrmap.cc
+// code for vptrmap.h
+
+#include "vptrmap.h"     // this module
+#include "xassert.h"     // xfailure
+
+#include <stddef.h>      // NULL
+#include <string.h>      // memset
+
+
+// ------------------ VoidPtrMap -------------------
+int VoidPtrMap::lookups = 0;
+int VoidPtrMap::probes = 0;
+
+
+VoidPtrMap::VoidPtrMap()
+  : hashTable(NULL),
+    tableSize(0),
+    tableSizeBits(0),
+    numEntries(0),
+    iterators(0)
+{
+  alloc(4);    // 16 entries initially
+  empty();
+}
+
+VoidPtrMap::~VoidPtrMap()
+{
+  delete[] hashTable;
+}
+
+
+void VoidPtrMap::alloc(int bits)
+{
+  tableSizeBits = bits;
+  tableSize = 1 << bits;
+  hashTable = new Entry[tableSize];
+}
+
+
+inline unsigned VoidPtrMap::hashFunc(unsigned multiplier, unsigned key) const
+{
+  // see Cormen/Leiserson/Rivest (CLR), section 12.3.2
+
+  // multiply, throwing away the overflow high bits
+  unsigned ret = key * multiplier;
+
+  // we want to extract the 'tableSizeBits' most sigificant bits
+  ret = ret >> ((sizeof(unsigned)*8) - tableSizeBits);
+  ret = ret & (tableSize-1);
+  
+  return ret;
+}
+
+
+VoidPtrMap::Entry &VoidPtrMap::findEntry(void const *key) const
+{
+  xassert(key != NULL);
+  lookups++;
+
+  // constants used in the hash functions
+  enum {
+    // value is  floor(  (sqrt(5)-1)/2 * 2^32  )
+    //
+    // This is the golden ratio.  CLR says Knuth says it's good.
+    CONST1 = 0x9E3779B9U,
+
+    // value is  floor(  (sqrt(3)-1)/2 * 2^32  )
+    //
+    // Some random website claims irrational constants are good,
+    // and I can't find any source (I don't have Knuth..) for
+    // another constant, so I just decided to substitute 3 for
+    // 5 in the golden ratio formula.  Since I trust this one
+    // less, I use it for the less important role (stride).
+    CONST2 = 0x5DB3D742U
+  };
+
+  // compute first hash function, which gives the starting index
+  // for the probe sequence
+  unsigned index = hashFunc(CONST1, (unsigned)pointerToInteger(key));
+
+  // analyze the first entry now, before computing the second
+  // hash function (stride) value
+  {
+    probes++;
+    Entry &e = hashTable[index];
+    if (e.key == NULL ||
+        e.key == key) {
+      return e;
+    }
+  }
+
+  // compute stride; it has to be odd so that it is relatively
+  // prime to the table size (which is a power of 2), so I just
+  // turn on the least significant bit
+  unsigned stride = hashFunc(CONST2, (unsigned)pointerToInteger(key)) | 1;
+
+  // uncomment this to experiment with linear hashing; when ITERS2MAX
+  // is 10000, I see a small increase in avgprobes when using linear
+  // hashing over double hashing
+  //unsigned stride = 1;
+
+  // collision; stride over the entries
+  for (int i=0; i<tableSize; i++) {
+    index = (index + stride) & (tableSize-1);
+
+    probes++;
+    Entry &e = hashTable[index];
+    if (e.key == NULL ||
+        e.key == key) {
+      return e;
+    }
+  }
+
+  // searched all entries with no success; but if this happens,
+  // then our load factor must be 1, which violates the invariant
+  // that numEntries < tableSize
+  xfailure("findEntry traversed all entries");
+  return *((Entry*)NULL);     // silence warning
+}
+
+
+void VoidPtrMap::add(void *key, void *value)
+{
+  xassert(iterators == 0);
+
+  // if load factor would exceed 3/4, expand
+  if (numEntries+1 > (tableSize/2 + tableSize/4)) {
+    expand();
+  }
+
+  Entry &e = findEntry(key);
+  if (e.key == NULL) {
+    e.key = key;              // new mapping
+    numEntries++;
+  }
+  else {
+    xassert(e.key == key);    // update existing mapping
+  }
+  e.value = value;
+}
+
+
+void VoidPtrMap::expand()
+{
+  Entry *oldHashTable = hashTable;
+  int oldTableSize = tableSize;
+
+  alloc(tableSizeBits + 1);
+  empty();
+
+  // re-insert all of the old elements
+  for (int i=0; i < oldTableSize; i++) {
+    Entry &e = oldHashTable[i];
+    if (e.key) {
+      add(e.key, e.value);
+    }
+  }
+
+  delete[] oldHashTable;
+}
+
+
+void VoidPtrMap::empty()
+{
+  xassert(iterators == 0);
+
+  // establishes invariant that NULL keys have NULL values
+  memset(hashTable, 0, sizeof(*hashTable) * tableSize);
+  numEntries = 0;
+}
+
+
+// ------------------- VoidPtrMap::Iter ------------------
+VoidPtrMap::Iter::Iter(VoidPtrMap const &m)
+  : map(m),
+    index(map.tableSize)
+{
+  map.iterators++;
+  adv();
+}
+
+VoidPtrMap::Iter::~Iter()
+{
+  map.iterators--;
+}
+
+
+void VoidPtrMap::Iter::adv()
+{
+  xassert(index >= 0);
+  index--;
+  while (index >= 0 &&
+         map.hashTable[index].key == NULL) {
+    index--;
+  }
+}
+
+
+// ------------------- test code ---------------------
+#ifdef TEST_VPTRMAP
+
+#include "test.h"      // USUAL_MAIN
+#include "array.h"     // ObjArrayStack
+#include "ckheap.h"    // malloc_stats
+#include "ptrmap.h"    // PtrMap
+
+#include <stdlib.h>    // rand, qsort
+#include <stdio.h>     // printf
+
+
+class Node {
+public:
+  int *value;
+  bool found;
+
+public:
+  Node() {
+    value = new int(0);
+    found = false;
+  }
+  ~Node() {
+    delete value;
+  }
+};
+
+
+int doubleCompar(void const *dp1, void const *dp2)
+{
+  double d1 = *((double*)dp1);
+  double d2 = *((double*)dp2);
+  if (d1 < d2) return -1;
+  if (d1 > d2) return +1;
+  return 0;    // almost never happens
+}
+
+
+void test1()
+{
+  printf("test1: testing PtrMap\n");
+
+  enum { ITERS1=10, ITERS2MAX=2000 };
+
+  double avgprobes[ITERS1];
+
+  printf("  iter  iters  entries  lookups  probes  avgprobes\n");
+  printf("  ----  -----  -------  -------  ------  ---------\n");
+
+  for (int i=0; i < ITERS1; i++) {
+    // I actually test PtrMap, the type-safe wrapper on top
+    // of VoidPtrMap, so I can test that class too; the casts
+    // that I used to need for VoidPtrMap are now protected by
+    // this CAST macro
+    //#define CAST(something) (something)
+    #define CAST(something) /*nothing*/
+
+    PtrMap<Node,int> map;
+    ObjArrayStack<Node> stack;
+
+    int iters2 = rand() % ITERS2MAX;
+    for (int j=0; j < iters2; j++) {
+      int op = rand() % 100;
+
+      if (op <= 40) {         // insert
+        Node *n = new Node;
+        stack.push(n);
+        map.add(n, n->value);
+      }
+
+      else if (op <= 80) {    // find exist
+        if (stack.isNotEmpty()) {
+          Node *n = stack[rand() % stack.length()];
+          int *v = CAST(int*)map.get(n);
+          xassert(v && v == n->value);
+
+          if (rand() % 10 == 0) {
+            // reassign
+            delete n->value;
+            n->value = new int(0);
+            map.add(n, n->value);
+          }
+        }
+      }
+
+      else if (op <= 90) {    // find non-exist
+        Node *n = new Node;
+        int *v = CAST(int*)map.get(n);
+        xassert(!v);
+        delete n;
+      }
+
+      else if (op <= 100) {   // traverse
+        // clear all 'found'
+        int k;
+        for (k=0; k < stack.length(); k++) {
+          stack[k]->found = false;
+        }
+
+        // walk via map; should find each one exactly once
+        int numFound = 0;
+        //VoidPtrMap::Iter iter(map);
+        PtrMap<Node,int>::Iter iter(map);
+        for (; !iter.isDone(); iter.adv()) {
+          Node *n = CAST(Node*)iter.key();
+          int *v = CAST(int*)iter.value();
+
+          xassert(v == n->value);
+          xassert(n->found == false);
+          n->found = true;
+          numFound++;
+        }
+
+        // check all 'found' (launch all 'zig')
+        for (k=0; k < stack.length(); k++) {
+          xassert(stack[k]->found == true);
+        }
+        xassert(numFound == stack.length());
+      }
+    }
+
+    xassert(map.getNumEntries() == stack.length());
+    //     "  iter  iters  entries  lookups  probes  avgprobes"
+    avgprobes[i] = ((double)VoidPtrMap::probes) / ((double)VoidPtrMap::lookups);
+    printf("  %4d  %5d  %7d  %7d  %6d    %g\n",
+           i,
+           iters2,
+           map.getNumEntries(),
+           VoidPtrMap::lookups,
+           VoidPtrMap::probes,
+           avgprobes[i]);
+
+    VoidPtrMap::probes = 0;
+    VoidPtrMap::lookups = 0;
+  }
+
+  // compute median of avgprobes
+  qsort(avgprobes, ITERS1, sizeof(avgprobes[0]), doubleCompar);
+  printf("median avgprobe: %g\n", avgprobes[ITERS1/2]);
+
+  //malloc_stats();
+}
+
+
+struct A {
+  int x;
+  A(int x0) : x(x0) {}
+};
+
+void test2()
+{
+  printf("test2: testing PtrSet\n");
+
+  PtrSet<A> s;
+  xassert(s.isEmpty());
+  xassert(s.getNumEntries() == 0);
+
+  A *a1 = new A(1);
+  s.add(a1);
+  xassert(s.isNotEmpty());
+  xassert(s.getNumEntries() == 1);
+
+  A *a2 = new A(2);
+  s.add(a2);
+  xassert(s.isNotEmpty());
+  xassert(s.getNumEntries() == 2);
+
+  xassert(s.contains(a1));
+  xassert(s.contains(a2));
+
+  s.empty();                    // make empty
+
+  xassert(!s.contains(a1));
+  xassert(!s.contains(a2));
+  xassert(s.isEmpty());
+  xassert(s.getNumEntries() == 0);
+
+  A *a3 = new A(3);
+  s.add(a3);
+  xassert(s.isNotEmpty());
+  xassert(s.getNumEntries() == 1);
+}
+
+
+void entry()
+{
+  printf("testing vptrmap\n");
+  test1();
+  test2();
+  printf("vptrmap is ok\n");
+}
+
+
+USUAL_MAIN
+
+#endif // TEST_VPTRMAP

Added: vendor/elsa/current/smbase/vptrmap.h
===================================================================
--- vendor/elsa/current/smbase/vptrmap.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/vptrmap.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,119 @@
+// vptrmap.h
+// map from void* to void*
+// interface based partly on hashtbl.h
+
+// Design considerations:
+//
+// Keys are pointers to objects.  They are likely to have the same
+// high bits (page) and low bits (alignment), and thus be
+// distinguished primarily by the bits in the middle.  No key is NULL.
+//
+// Deletion of a single mapping is not supported.  To delete some
+// mappings you have to rebuild the table.
+//
+// No adversary is present; hash function is fixed in advance.
+
+
+#ifndef VPTRMAP_H
+#define VPTRMAP_H
+
+
+class VoidPtrMap {
+private:     // types
+  // single entry in the hash table
+  struct Entry {
+    void *key;               // NULL only for unused entries
+    void *value;             // NULL if key is NULL
+  };
+
+private:     // data
+  // hash table itself; collision is resolved with double hashing,
+  // which is why efficient deletion is impossible
+  Entry *hashTable;
+
+  // number of (allocated) slots in the hash table; this is always a
+  // power of 2
+  int tableSize;
+  
+  // tableSize always equals 1 << tableSizeBits
+  int tableSizeBits;
+
+  // number of mappings (i.e. key!=NULL); always numEntries < tableSize
+  int numEntries;
+
+  // number of outstanding iterators; used to check that we don't
+  // modify the table while one is active (experimental)
+  mutable int iterators;
+
+public:      // data
+  // total # of lookups
+  static int lookups;
+  
+  // total # of entries examined during lookups; perfect hashing
+  // would yield lookups==probes
+  static int probes;
+
+private:     // funcs
+  // 'bits' becomes tableSizeBits; also set hashTable and tableSize
+  void alloc(int bits);
+
+  // multiplicative hash function
+  inline unsigned hashFunc(unsigned multiplier, unsigned key) const;
+
+  // return the first entry in key's probe sequence that has either
+  // a NULL key or a key equal to 'key'
+  Entry &findEntry(void const *key) const;
+
+  // make the table twice as big, and move all the entries into
+  // that new table
+  void expand();
+
+  // disallowed
+  VoidPtrMap(VoidPtrMap &obj);
+  void operator=(VoidPtrMap &obj);
+  void operator==(VoidPtrMap &obj);
+
+public:      // funcs
+  VoidPtrMap();              // empty map
+  ~VoidPtrMap();
+
+  // return # of mapped entries
+  int getNumEntries() const { return numEntries; }
+
+  // if this key has a mapping, return it; otherwise, return NULL
+  void *get(void const *key) const { return findEntry(key).value; }
+
+  // add a mapping from 'key' to 'value'; replaces existing
+  // mapping, if any
+  void add(void *key, void *value);
+
+  // remove all mappings
+  void empty();
+  
+  
+public:      // iterators
+  // iterate over all stored values in a VoidPtrMap
+  // NOTE: you can't change the table while an iter exists
+  class Iter {
+  private:      // data
+    VoidPtrMap const &map;       // table we're iterating over
+    int index;                   // current slot to return in adv(); -1 when done
+
+  public:       // funcs
+    Iter(VoidPtrMap const &map);
+    ~Iter();
+
+    bool isDone() const { return index < 0; }
+    void adv();            // must not be isDone()
+
+    // return information about the currently-referenced table entry
+    void *key() const      // key (never NULL)
+      { return map.hashTable[index].key; }
+    void *value() const    // associated value
+      { return map.hashTable[index].value; }
+  };
+  friend class Iter;
+};
+
+
+#endif // VPTRMAP_H

Added: vendor/elsa/current/smbase/warn.cpp
===================================================================
--- vendor/elsa/current/smbase/warn.cpp	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/warn.cpp	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,89 @@
+// warn.cc            see license.txt for copyright and terms of use
+// code for warn.h
+// Scott McPeak, 1999  This file is public domain.
+
+#include "warn.h"       // this module
+#include "typ.h"        // bool
+#include "breaker.h"    // breaker
+#include <stdio.h>      // fopen, stderr, etc.
+#include <time.h>       // time, ctime
+
+// globals
+WarningHandler warningHandler = defaultWarningHandler;
+#ifdef NDEBUG
+  WarnLevel logWarnLevel = (WarnLevel)(WARN_ALL - WARN_DEBUG);
+  WarnLevel displayWarnLevel = WARN_NONE;
+#else
+  WarnLevel logWarnLevel = WARN_ALL;
+  WarnLevel displayWarnLevel = WARN_ALL;
+#endif
+
+
+void warning(WarnLevel level, char const *message)
+{
+  warningHandler(level, message);
+}
+
+
+void defaultWarningHandler(WarnLevel level, char const *message)
+{
+  if (level & WARN_DEBUG) {
+    // hit a breakpoint if the debugger is attached
+    breaker();
+  }
+
+  if (level & logWarnLevel) {
+    defaultWarningLogger(level, message);
+  }
+
+  if (level & logWarnLevel) {
+    defaultWarningPrinter(level, message);
+  }
+}
+
+
+void defaultWarningLogger(WarnLevel /*level*/, char const *message)
+{
+  static FILE *logfile = NULL;
+  static bool failedToOpen = false;
+
+  if (!logfile && !failedToOpen) {
+    logfile = fopen("warning.log", "a");
+    if (!logfile) {
+      // don't keep trying
+      failedToOpen = true;
+    }
+    else {
+      // start with a timestamp
+      time_t t;
+      time(&t);
+      int len = fprintf(logfile, "\nLog started at %s", ctime(&t));
+        // note: astonishingly (bad), the string returned by ctime() has
+        //       a newline at the end!
+
+      while (len--) {
+        fprintf(logfile, "-");
+      }
+      fprintf(logfile, "\n");
+    }
+  }
+
+  if (logfile) {
+    // append the message to the logfile
+    fprintf(logfile, "warning: %s\n", message);
+    fflush(logfile);
+  }
+}
+
+
+void defaultWarningPrinter(WarnLevel /*level*/, char const *message)
+{
+  fprintf(stderr, "warning: %s\n", message);
+  fflush(stderr);
+}
+
+
+// no test code because it is my judgment that bugs in this
+// module will be easily evident, and it is a very simple
+// module, so it isn't worth it to separately test
+

Added: vendor/elsa/current/smbase/warn.h
===================================================================
--- vendor/elsa/current/smbase/warn.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/warn.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,74 @@
+// warn.h            see license.txt for copyright and terms of use
+// module to facilitate providing operational warnings to the user
+// Scott McPeak, 1999  This file is public domain.
+
+#ifndef __WARN_H
+#define __WARN_H
+
+// note: In retrospect, this module was either a bad idea, or I didn't
+//       implement it well.  Either way, don't use it for anything new.
+
+// non-disjoint warning classification scheme
+// (add more classes as necessary)
+enum WarnLevel {
+  WARN_PERFORMANCE     = 0x01,
+    // may cause suboptimal performance
+
+  WARN_SECURITY        = 0x02,
+    // possible compromise of private data, unauthrorized
+    // access, authentication warning, etc.
+
+  WARN_COMPATIBILITY   = 0x04,
+    // interoperability with other software (including
+    // different versions of this software) may be
+    // adversely affected
+
+  WARN_DEBUG           = 0x08,
+    // of use during debugging only; setting this flag means
+    // the warning handler should alert an attached debugger
+
+  WARN_INFORMATION     = 0x10,
+    // I'm not sure when/why this would be used...
+    // Note: This is *not* to be used as a diagnostic 'printf'. 
+
+  WARN_ALL             = 0x1F,
+    // logical-or of all flags
+
+  WARN_NONE            = 0x0,
+    // no warnings
+};
+
+
+// user interface
+// --------------
+// call this to report a warning
+//   level   - logical-or of applicable conditions
+//   message - user-intelligible message (should *not* contain a newline)
+void warning(WarnLevel level, char const *message);
+
+
+// handler interface
+// -----------------
+// the warning() function calls warningHandler(), so new
+// handlers are installed by changing that value
+typedef void (*WarningHandler)(WarnLevel level, char const *message);
+extern WarningHandler warningHandler;
+
+
+// default handler
+// ---------------
+// the default warning handler masks the input level with two
+// global variables:
+//   logWarnLevel - messages are written to a log file, "warning.log"
+//   displayWarnLevel - messages are written to stderr via stdio 'stderr'
+extern WarnLevel logWarnLevel;       // default: WARN_ALL, minus WARN_DEBUG ifdef NDEBUG
+extern WarnLevel displayWarnLevel;   // default: ifdef NDEBUG, WARN_NONE, else WARN_ALL
+
+// handler functions (handler dispatches to logger and printer)
+void defaultWarningHandler(WarnLevel level, char const *message);
+void defaultWarningLogger(WarnLevel level, char const *message);
+void defaultWarningPrinter(WarnLevel level, char const *message);
+
+
+#endif // __WARN_H
+

Added: vendor/elsa/current/smbase/xassert.h
===================================================================
--- vendor/elsa/current/smbase/xassert.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/xassert.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,85 @@
+// xassert.h            see license.txt for copyright and terms of use
+// replacement for assert that throws an exception on failure
+// (x_assert_fail is defined in exc.cpp)
+// Scott McPeak, 1997-1998  This file is public domain.
+
+#ifndef XASSERT_H
+#define XASSERT_H
+
+#include "macros.h"     // NORETURN
+
+// linkdepend: exc.cpp
+
+// this functions accepts raw 'char const *' instead of 'rostring'
+// because I do not want this interface to depend on str.h, and also
+// because I do not want the many call sites to have the overhead
+// of constructing and destructing temporary objects
+void x_assert_fail(char const *cond, char const *file, int line) NORETURN;
+
+// Ordinary 'xassert' *can* be turned off, but the nominal intent
+// is that it be left on, under the "ship what you test" theory.
+// I advocate using NDEBUG_NO_ASSERTIONS only as a way to gauge the
+// performance impact of the existing assertions.
+#if !defined(NDEBUG_NO_ASSERTIONS)
+  #define xassert(cond) \
+    ((cond)? (void)0 : x_assert_fail(#cond, __FILE__, __LINE__))
+#else
+  #define xassert(cond) ((void)0)
+#endif
+
+// Here's a version which will turn off with ordinary NDEBUG.  It
+// is for more expensive checks that need not ship.
+#if !defined(NDEBUG) && !defined(NDEBUG_NO_ASSERTIONS)
+  #define xassertdb(cond) xassert(cond)
+#else
+  #define xassertdb(cond) ((void)0)
+#endif
+
+// call when state is known to be bad; will *not* return
+#define xfailure(why) x_assert_fail(why, __FILE__, __LINE__)
+
+
+// Quick note: one prominent book on writing code recommends that
+// assertions *not* include the failure condition, since the file
+// and line number are sufficient, and the condition string uses
+// memory.  The problem is that sometimes a compiled binary is
+// out of date w/respect to the code, and line numbers move, so
+// the condition string provides a good way to find the right
+// assertion.
+
+
+/*
+  Why throw an exception after an assertion?
+
+  The standard assert() calls abort() after printing its message.
+  This is like throwing an exception all the way to the calling
+  process.  This is fine if programs are small.
+
+  But when a program is large enough, it may contain subsystems at
+  several layers, such that a higher level module is capable of
+  recovering from the failure of a lower level module.  Using abort(),
+  one would have to resort to catching signals, which is messy.
+
+  An exception is much nicer to catch, and has the added benefit that
+  intermediate layers can catch and rethrow, appending little bits of
+  context, if they want to make the message more informative.
+
+  In most of my programs, the 'x_assert' exception is only caught in
+  main() (implicitly, by catching 'xBase'), and hence 'xassert' acts
+  very much like 'assert'.  But by using 'xassert' consistenty, any
+  time I *do* have a large program with recovery, all the lower-level
+  modules are all ready to cooperate.
+
+  Speaking of recovery: Be aware that when a module fails an
+  assertion, its internal state is most likely inconsistent.  Recovery
+  actions need to be fairly conservative about what code gets
+  re-entered and state re-used after a failure.  This is no different
+  than with 'assert', as a program could have inconsistent state *on
+  disk* that gets reactivated upon being restarted, but persistent
+  (across process boundaries) inconsistent state is simply less
+  common.
+
+*/
+
+#endif // XASSERT_H
+

Added: vendor/elsa/current/smbase/xobjlist.h
===================================================================
--- vendor/elsa/current/smbase/xobjlist.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/xobjlist.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,388 @@
+m4_dnl // xobjlist.h            see license.txt for copyright and terms of use
+m4_dnl // template file to be processed with m4 to generate one
+m4_dnl // of the wrappers around VoidList
+m4_dnl
+m4_changequote([, ])m4_dnl      // for this section
+m4_changecom[]m4_dnl            // no m4 "comments"
+m4_ifelse(m4_output, sobjlist.h, [m4_dnl
+// sobjlist.h
+// serf list of arbitrary objects
+m4_define(makeName, S[$1])m4_dnl
+m4_define(outputCond, [$1])m4_dnl       // select 1st arg
+m4_define(SPC, [])m4_dnl
+], [m4_dnl
+// objlist.h
+// owner list of arbitrary dynamically-allocated objects
+m4_define(makeName, [$1])m4_dnl
+m4_define(outputCond, [$2])m4_dnl       // select 2nd arg
+m4_define(SPC, [ ])m4_dnl               // for balancing lined-up comments
+])m4_dnl
+m4_define(includeLatch, makeName(OBJLIST_H))m4_dnl
+m4_define(className, makeName(ObjList))m4_dnl
+m4_define(iterName, makeName(ObjListIter))m4_dnl
+m4_define(mutatorName, makeName(ObjListMutator))m4_dnl
+m4_define(iterNameNC, makeName(ObjListIterNC))m4_dnl
+m4_define(multiIterName, makeName(ObjListMultiIter))m4_dnl
+m4_changequote(, )m4_dnl              // so quotes are not quoted..
+m4_changequote([[[, ]]])m4_dnl        // reduce likelihood of confusion
+// NOTE: automatically generated from xobjlist.h -- do not edit directly
+
+// Author: Scott McPeak, 2000
+
+#ifndef includeLatch
+#define includeLatch
+
+#include "voidlist.h"    // VoidList
+
+
+// forward declarations of template classes, so we can befriend them in className
+// (not required by Borland C++ 4.5, but GNU wants it...)
+template <class T> class iterName;
+template <class T> class mutatorName;
+template <class T> class iterNameNC;
+
+
+outputCond([[[m4_dnl      // sobjlist
+// the list is considered to not own any of the items; it's ok to
+// insert items multiple times or into multiple lists
+]]], [[[m4_dnl            // objlist
+// the list is considered to own all of the items; it is an error to insert
+// an item into more than one such list, or to insert an item more than once
+// into any such list
+]]])m4_dnl
+template <class T>
+class className {
+private:
+  friend class iterName<T>;
+  friend class mutatorName<T>;
+  friend class iterNameNC<T>;
+
+protected:
+  VoidList list;                        // list itself
+
+outputCond([[[m4_dnl    // sobjlist
+public:
+  // make shallow copies
+  className[[[]]](className const &obj)         : list(obj.list) {}
+  className& operator= (className const &src)         { list = src.list; return *this; }
+]]], [[[m4_dnl          // objlist
+private:
+  // this is an owner list; these are not allowed
+  className[[[]]](className const &obj);
+  className& operator= (className const &src);
+]]])m4_dnl
+
+public:
+  className[[[]]]()                            : list() {}
+  ~className[[[]]]()                      m4_dnl
+     outputCond({}    /* all items removed */, { deleteAll(); })
+
+  // The difference function should return <0 if left should come before
+  // right, 0 if they are equivalent, and >0 if right should come before
+  // left.  For example, if we are sorting numbers into ascending order,
+  // then 'diff' would simply be subtraction.
+  typedef int (*Diff)(T const *left, T const *right, void *extra);
+
+  // selectors
+  int count() const                     { return list.count(); }
+  bool isEmpty() const                  { return list.isEmpty(); }
+  bool isNotEmpty() const               { return list.isNotEmpty(); }
+  T *&nthRef(int which)                 { return (T*&)list.nthRef(which); }
+  T *nth(int which)                     { return (T*)list.nth(which); }
+  T const *nthC(int which) const        { return (T const*)list.nth(which); }
+  T *first()                            { return (T*)list.first(); }
+  T const *firstC() const               { return (T const*)list.first(); }
+  T *last()                             { return (T*)list.last(); }
+  T const *lastC() const                { return (T const*)list.last(); }
+
+  // insertion
+  void prepend(T *newitem)              { list.prepend((void*)newitem); }
+  void append(T *newitem)               { list.append((void*)newitem); }
+  void insertAt(T *newitem, int index)  { list.insertAt((void*)newitem, index); }
+  void insertSorted(T *newitem, Diff diff, void *extra=NULL)
+    { list.insertSorted((void*)newitem, (VoidDiff)diff, extra); }
+
+  // removal
+  T *removeAt(int index)                { return (T*)list.removeAt(index); }
+  T *removeFirst()                      { return (T*)list.removeFirst(); }
+outputCond([[[m4_dnl     // sobjlist
+  void removeAll()                      { list.removeAll(); }
+]]], [[[m4_dnl           // objlist
+  void deleteAt(int index)              { delete (T*)list.removeAt(index); }
+  void deleteAll();
+]]])m4_dnl
+
+  // list-as-set: selectors
+  int indexOf(T const *item) const      { return list.indexOf((void*)item); }
+  int indexOfF(T const *item) const     { return list.indexOfF((void*)item); }
+  bool contains(T const *item) const    { return list.contains((void*)item); }
+
+  // list-as-set: mutators
+  bool prependUnique(T *newitem)        { return list.prependUnique((void*)newitem); }
+  bool appendUnique(T *newitem)         { return list.appendUnique((void*)newitem); }
+  void removeItem(T const *item)        { list.removeItem((void*)item); }    // whether the arg should be const is debatable..
+  bool removeIfPresent(T const *item)   { return list.removeIfPresent((void*)item); }
+
+  // complex modifiers
+  void reverse()                                    { list.reverse(); }
+  void insertionSort(Diff diff, void *extra=NULL)   { list.insertionSort((VoidDiff)diff, extra); }
+  void mergeSort(Diff diff, void *extra=NULL)       { list.mergeSort((VoidDiff)diff, extra); }
+
+  // and a related test
+  bool isSorted(Diff diff, void *extra=NULL) const  { return list.isSorted((VoidDiff)diff, extra); }
+
+  // multiple lists
+  void concat(className &tail)                       { list.concat(tail.list); }
+outputCond([[[m4_dnl    // sobjlist
+  void appendAll(className const &tail)              { list.appendAll(tail.list); }
+  void prependAll(className const &head)             { list.prependAll(head.list); }
+]]], [[[m4_dnl          // objlist
+  // (we do *not* have appendAll, since these are supposed to be owner lists)
+]]])m4_dnl
+
+  // steal
+  void stealTailAt(int index, className &tail)       { list.stealTailAt(index, tail.list); }
+
+  // equal items in equal positions
+  bool equalAsLists(className const &otherList, Diff diff, void *extra=NULL) const
+    { return list.equalAsLists(otherList.list, (VoidDiff)diff, extra); }
+  int compareAsLists(className const &otherList, Diff diff, void *extra=NULL) const
+    { return list.compareAsLists(otherList.list, (VoidDiff)diff, extra); }
+
+  // last-as-set: comparisons (NOT efficient)
+  bool equalAsSets(className const &otherList, Diff diff, void *extra=NULL) const
+    { return list.equalAsSets(otherList.list, (VoidDiff)diff, extra); }
+  bool isSubsetOf(className const &otherList, Diff diff, void *extra=NULL) const
+    { return list.isSubsetOf(otherList.list, (VoidDiff)diff, extra); }
+  bool containsByDiff(T const *item, Diff diff, void *extra=NULL) const
+    { return list.containsByDiff((void*)item, (VoidDiff)diff, extra); }
+
+  // treating the pointer values themselves as the basis for comparison
+  bool equalAsPointerLists(className const &otherList) const
+    { return list.equalAsPointerLists(otherList.list); }
+  bool equalAsPointerSets(className const &otherList) const
+    { return list.equalAsPointerSets(otherList.list); }
+
+outputCond([[[m4_dnl    // sobjlist
+  // removing duplicates
+  void removeDuplicatesAsMultiset(Diff diff, void *extra=NULL)
+    { list.removeDuplicatesAsMultiset((VoidDiff)diff, extra); }
+  void removeDuplicatesAsPointerMultiset()
+    { list.removeDuplicatesAsPointerMultiset(); }
+
+  // debugging: no invariants beyond VoidList
+  void selfCheck() const                { list.selfCheck(); }
+  
+  // but export the additional checks for cases where they apply anyway
+  void checkHeapDataPtrs() const        { list.checkHeapDataPtrs(); }
+  void checkUniqueDataPtrs() const      { list.checkUniqueDataPtrs(); }
+]]], [[[m4_dnl          // objlist
+  // debugging: two additional invariants
+  void selfCheck() const { 
+    list.selfCheck();
+    list.checkHeapDataPtrs();
+    list.checkUniqueDataPtrs();
+  }
+]]])m4_dnl
+};
+
+
+outputCond(, [[[m4_dnl      // objlist
+template <class T>
+void ObjList<T>::deleteAll()
+{
+  while (!list.isEmpty()) {
+    deleteAt(0);
+  }
+}
+
+
+]]])m4_dnl
+// for traversing the list and modifying it (nodes and/or structure)
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists, and only one such iterator should exist for
+//       any given list
+template <class T>
+class mutatorName {
+  friend class iterName<T>;
+
+protected:
+  VoidListMutator mut;       // underlying mutator
+
+public:
+  mutatorName[[[]]](className<T> &lst)     : mut(lst.list) { reset(); }
+  ~mutatorName[[[]]]()                    {}
+
+  void reset()                          { mut.reset(); }
+
+  // iterator copying; safe *only* until one of the mutators modifies
+  // the list structure (by inserting or removing), at which time all
+  // other iterators might be in limbo
+  mutatorName[[[]]](mutatorName const &obj)             : mut(obj.mut) {}
+  mutatorName& operator=(mutatorName const &obj)  { mut = obj.mut;  return *this; }
+    // requires that 'this' and 'obj' already refer to the same 'list'
+
+  // iterator actions
+  bool isDone() const                   { return mut.isDone(); }
+  void adv()                            { mut.adv(); }
+  T *data()                             { return (T*)mut.data(); }
+  T *&dataRef()                         { return (T*&)mut.dataRef(); }
+
+  // insertion
+  void insertBefore(T *item)            { mut.insertBefore((void*)item); }
+    // 'item' becomes the new 'current', and the current 'current' is
+    // pushed forward (so the next adv() will make it current again)
+
+  void insertAfter(T *item)             { mut.insertAfter((void*)item); }
+    // 'item' becomes what we reach with the next adv();
+    // isDone() must be false
+
+  void append(T *item)                  { mut.append((void*)item); }
+    // only valid while isDone() is true, it inserts 'item' at the end of
+    // the list, and advances such that isDone() remains true; equivalent
+    // to { xassert(isDone()); insertBefore(item); adv(); }
+
+  // removal
+  T *remove()                           { return (T*)mut.remove(); }
+    // 'current' is removed from the list and returned, and whatever was
+    // next becomes the new 'current'
+
+outputCond(, [[[m4_dnl    // sobjlist
+  void deleteIt()                       { delete (T*)mut.remove(); }
+    // same as remove(), except item is deleted also
+
+]]])m4_dnl
+  // debugging
+  void selfCheck() const                { mut.selfCheck(); }
+};
+
+#define makeName(MUTATE_EACH_OBJLIST)(T, list, iter) \
+  for(mutatorName< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// for traversing the list without modifying it (neither nodes nor structure)
+// NOTE: no list-modification fns should be called on 'list' while this
+//       iterator exists
+template <class T>
+class iterName {
+protected:
+  VoidListIter iter;      // underlying iterator
+
+public:
+  iterName[[[]]](className<T> const &list) : iter(list.list) {}
+  iterName[[[]]](className<T> const &list, int pos) : iter(list.list, pos) {}
+  ~iterName[[[]]]()                       {}
+
+  void reset(className<T> const &list)   { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  iterName[[[]]](iterName const &obj)             : iter(obj.iter) {}
+  iterName& operator=(iterName const &obj)  { iter = obj.iter;  return *this; }
+
+  // but copying from a mutator is less safe; see above
+  iterName[[[]]](mutatorName<T> &obj)             : iter(obj.mut) {}
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T const *data() const                 { return (T const*)iter.data(); }
+};
+
+#define makeName(FOREACH_OBJLIST)(T, list, iter) \
+  for(iterName< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// intermediate to the above two, this allows modification of the
+// objects stored on the list, but not the identity or order of
+// the objects in the list
+template <class T>
+class iterNameNC {
+protected:
+  VoidListIter iter;      // underlying iterator
+
+public:
+  iterNameNC[[[]]](className<T> &list) : iter(list.list) {}
+  iterNameNC[[[]]](className<T> &list, int pos) : iter(list.list, pos) {}
+  ~iterNameNC[[[]]]()                     {}
+
+  void reset(className<T> &list)         { iter.reset(list.list); }
+
+  // iterator copying; generally safe
+  iterNameNC[[[]]](iterNameNC const &obj)             : iter(obj.iter) {}
+  iterNameNC& operator=(iterNameNC const &obj)  { iter = obj.iter;  return *this; }
+
+  // but copying from a mutator is less safe; see above
+  iterNameNC[[[]]](mutatorName<T> &obj)               : iter(obj.mut) {}
+
+  // iterator actions
+  bool isDone() const                   { return iter.isDone(); }
+  void adv()                            { iter.adv(); }
+  T *data() const                       { return (T*)iter.data(); }
+};
+
+#define makeName(FOREACH_OBJLIST_NC)(T, list, iter) \
+  for(iterNameNC< T > iter(list); !iter.isDone(); iter.adv())
+
+
+// iterate over the combined elements of two or more lists
+template <class T>
+class multiIterName {
+private:
+  // all the lists
+  className<T> **lists;               SPC// serf array of serf list pointers
+  int numLists;                      // length of this array
+
+  // current element
+  int curList;                       // which list we're working on
+  iterName<T> iter;              SPC// current element of that list
+
+  // invariant:
+  //   either curList==numLists, or
+  //   iter is not 'done'
+
+public:
+  multiIterName[[[]]](className<T> **L, int n)
+    : lists(L),
+      numLists(n),
+      curList(0),
+      iter(*(lists[0]))
+  {
+    xassert(n > 0);
+    normalize();
+  }
+
+  // advance the iterator to the next element of the next non-empty list;
+  // establishes invariant above
+  void normalize();
+
+  bool isDone() const {
+    return curList == numLists;
+  }
+
+  T const *data() const {
+    return iter.data();
+  }
+
+  void adv() {
+    iter.adv();
+    normalize();
+  }
+};
+
+// this was originally inline, but that was causing some strange
+// problems (compiler bug?)
+template <class T>
+void multiIterName<T>::normalize()
+{
+  while (iter.isDone() && curList < numLists) {
+    curList++;
+    if (curList < numLists) {
+      iter.reset(*(lists[curList]));
+    }
+  }
+}
+
+
+// (tweak to ensure objlist.h and sobjlist.h both change)
+
+#endif // includeLatch

Added: vendor/elsa/current/smbase/xstrobjdict.h
===================================================================
--- vendor/elsa/current/smbase/xstrobjdict.h	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/smbase/xstrobjdict.h	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,312 @@
+m4_dnl // xstrobjdict.h            see license.txt for copyright and terms of use
+m4_dnl // template file to be processed with m4 to generate one
+m4_dnl // of the wrappers around VoidList
+m4_dnl
+m4_changequote([, ])m4_dnl      // for this section
+m4_changecom[]m4_dnl            // no m4 "comments"
+m4_ifelse(m4_output, strsobjdict.h, [m4_dnl
+// strsobjdict.h            see license.txt for copyright and terms of use
+// dictionary of *serf* pointers to objects, indexed by string (case-sensitive)
+m4_define(makeName, S[$1])m4_dnl
+m4_define(outputCond, [$1])m4_dnl       // select 1st arg
+m4_define(SPC, [])m4_dnl
+m4_define(XSTROBJDICT, [StringSObjDict])m4_dnl
+m4_define(includeLatch, [STRSOBJLIST_H])m4_dnl
+m4_define(TPTR, [T *])m4_dnl
+m4_define(TCPTR, [T const *])m4_dnl
+m4_define(outputCondTemplate, [$1])m4_dnl
+], [m4_dnl
+m4_ifelse(m4_output, strintdict.h, [m4_dnl
+// strintlist.h            see license.txt for copyright and terms of use
+// dictionary of longs (integers that fit into void*), indexed by string
+// (case-sensitive)
+m4_define(makeName, S[$1])m4_dnl
+m4_define(outputCond, [$1])m4_dnl       // select 1st arg
+m4_define(SPC, [ ])m4_dnl
+m4_define(XSTROBJDICT, [StringIntDict])m4_dnl
+m4_define(includeLatch, [STRINTDICT_H])m4_dnl
+m4_define(TPTR, [long])m4_dnl
+m4_define(TCPTR, [long])m4_dnl
+m4_define(outputCondTemplate, [$2])m4_dnl
+], [m4_dnl
+// strobjdict.h            see license.txt for copyright and terms of use
+// dictionary of objects, indexed by string (case-sensitive)
+m4_define(makeName, [$1])m4_dnl
+m4_define(outputCond, [$2])m4_dnl       // select 2nd arg
+m4_define(SPC, [ ])m4_dnl               // for balancing lined-up comments
+m4_define(XSTROBJDICT, [StringObjDict])m4_dnl
+m4_define(includeLatch, [STROBJDICT_H])m4_dnl
+m4_define(TPTR, [T *])m4_dnl
+m4_define(TCPTR, [T const *])m4_dnl
+m4_define(outputCondTemplate, [$1])m4_dnl
+])m4_dnl
+])m4_dnl
+m4_dnl m4_define(XSTROBJDICT_type, XSTROBJDICT[]_type)m4_dnl
+m4_define(XSTROBJDICT_type, outputCondTemplate(XSTROBJDICT<T>, XSTROBJDICT))m4_dnl
+m4_changequote(, )m4_dnl              // so quotes are not quoted..
+m4_changequote([[[, ]]])m4_dnl        // reduce likelihood of confusion
+// (c) Scott McPeak, 2000
+// NOTE: automatically generated from xstrobjdict.h -- do not edit directly
+
+// quarl 2006-06-08
+//    created xstrobjdict.h to generate strobjdict.h, strsobjdict.h, and new
+//    file strintdict.h
+
+#ifndef includeLatch
+#define includeLatch
+
+#include "svdict.h"    // StringVoidDict
+
+void qsortStringArray(char const **strings, int size); // strutil.h
+
+outputCond([[[m4_dnl
+// the dictionary object is considered to own all of the things
+// contained, so constness means constness of the contained objects
+// as well as the mapping from strings to them
+]]],[[[m4_dnl
+// since the dictionary does not own the pointed-to objects,
+// it has the same constness model as StringVoidDict, namely
+// that const means the *mapping* is constant but not the
+// pointed-to objects
+]]])m4_dnl
+
+outputCondTemplate([[[template <class T>]]])
+class XSTROBJDICT {
+public:     // types
+m4_dnl  typedef outputCondTemplate([[[XSTROBJDICT<T>]]], [[[XSTROBJDICT]]]) [[[XSTROBJDICT_type]]];
+  // 'foreach' iterator functions
+outputCond([[[m4_dnl
+  typedef bool (*ForeachFn)(string const &key, TPTR value, void *extra);
+]]],[[[m4_dnl
+  typedef bool (*ForeachCFn)(string const &key, TCPTR value, void *extra);
+  typedef bool (*ForeachFn)(string const &key, TPTR /*serf*/ value, void *extra);
+]]])m4_dnl
+
+outputCond([[[m4_dnl
+  // external iterator
+  class Iter {
+  private:
+    StringVoidDict::Iter iter;
+
+  public:
+    Iter(XSTROBJDICT &dict) : iter(dict.dict) {}
+    Iter(Iter const &obj) : DMEMB(iter) {}
+    Iter& operator= (Iter const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    Iter& next() { iter.next(); return *this; }
+
+    string const &key() const { return iter.key(); }
+    TPTR &value() const { return (TPTR &)iter.value(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class Iter;
+
+  class IterC {
+  private:
+    StringVoidDict::IterC iter;
+
+  public:
+    IterC(XSTROBJDICT const &dict) : iter(dict.dict) {}
+    IterC(IterC const &obj) : DMEMB(iter) {}
+    IterC& operator= (IterC const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    IterC& next() { iter.next(); return *this; }
+
+    string const &key() const { return iter.key(); }
+    TPTR value() const { return (TPTR)iter.value(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class IterC;
+]]],[[[m4_dnl
+  // external iterator
+  class Iter {
+  private:
+    StringVoidDict::IterC iter;
+
+  public:
+    Iter(XSTROBJDICT const &dict) : iter(dict.dict) {}
+    Iter(Iter const &obj) : DMEMB(iter) {}
+    Iter& operator= (Iter const &obj) { CMEMB(iter); return *this; }
+
+    bool isDone() const { return iter.isDone(); }
+    Iter& next() { iter.next(); return *this; }
+
+    string const &key() const { return iter.key(); }
+    TCPTR &value() const { return (TCPTR &)iter.value(); }
+
+    int private_getCurrent() const { return iter.private_getCurrent(); }
+  };
+  friend class Iter;
+  typedef Iter IterC;
+]]])m4_dnl
+
+  class SortedKeyIter {
+  private:     // data
+    // underlying iterator state
+    XSTROBJDICT_type const &map;
+    int keyIndex;
+    // dsw: I think it is a mistake to use getNumEntries() repeatedly
+    // instead of caching the value that it was at the time the
+    // iterator was constructed.  While we are still not thread-safe
+    // in the sense that an entry could be added or deleted, we could
+    // catch that, but we still do not want to separate the array of
+    // sortedKeys from its length as if these get out of synch this is
+    // an impossible bug to catch and a very low-level error.  Note
+    // that we still have a bit of a race condidition that numEntries
+    // is initialized before we iterate over the keys, but we are
+    // likely to catch that later.
+    int const numEntries;
+    char const **sortedKeys;    // array of strings
+
+  public:      // fucs
+    SortedKeyIter(XSTROBJDICT_type const &map0)
+      : map(map0)
+      , keyIndex(0)
+      , numEntries(map.size())
+      , sortedKeys(new char const *[numEntries])
+    {
+      int i = 0;
+      // delegate to the other Iter class
+      for(IterC iter(map); !iter.isDone(); iter.next()) {
+//          xassert(i<numEntries);
+        sortedKeys[i++] = iter.key().c_str();
+      }
+      xassert(numEntries == i);
+      ::qsortStringArray(sortedKeys, numEntries);
+    }
+    ~SortedKeyIter() {
+      delete [] sortedKeys;
+    }
+
+    bool isDone() const   { return keyIndex == numEntries; }
+    SortedKeyIter &next() { ++keyIndex; return *this; }
+
+    // return information about the currently-referenced table entry
+
+    // dsw: I already have a char const* so I think it is a mistake to
+    // wrap a string around it
+    char const *key() const {
+      char const *key = sortedKeys[keyIndex];
+//        xassert(map.isMapped(key));
+      return key;
+    }
+    TCPTR value() const {
+      return (TCPTR )map.queryfC(key());
+    }
+  };
+
+private:    // data
+  // underlying dictionary functionality
+  StringVoidDict dict;
+
+public:     // funcs
+  XSTROBJDICT[[[]]]() : dict() {}
+outputCond([[[m4_dnl
+  ~XSTROBJDICT[[[]]]() {}
+]]],[[[m4_dnl
+  ~XSTROBJDICT[[[]]]() { empty(); }
+]]])m4_dnl
+
+outputCond([[[m4_dnl
+public:    // funcs
+  XSTROBJDICT[[[]]](XSTROBJDICT const &obj) : dict(obj.dict) {}
+
+  // comparison and assignment use *pointer* comparison/assignment
+
+  XSTROBJDICT& operator= (XSTROBJDICT const &obj)    { dict = obj.dict; return *this; }
+
+  bool operator== (XSTROBJDICT const &obj) const        { return dict == obj.dict; }
+  NOTEQUAL_OPERATOR(XSTROBJDICT)
+]]],[[[m4_dnl
+private:    // funcs
+  // disallowed
+  XSTROBJDICT[[[]]](XSTROBJDICT const &obj);
+  XSTROBJDICT& operator= (XSTROBJDICT const &obj);
+  bool operator== (XSTROBJDICT const &obj) const;
+]]])m4_dnl
+
+  // due to similarity with StringVoidDict, see svdict.h for
+  // details on these functions' interfaces
+
+public:
+  // ------- selectors ---------
+  int size() const                                     { return dict.size(); }
+
+  bool isEmpty() const                                 { return dict.isEmpty(); }
+  bool isNotEmpty() const                              { return !isEmpty(); }
+
+outputCond([[[m4_dnl
+  bool query(char const *key, TPTR &value) const         { return dict.query(key, (void*&)value); }
+  TPTR queryf(char const *key) const                     { return (TPTR)dict.queryf(key); }
+  TPTR queryif(char const *key) const                    { return (TPTR)dict.queryif(key); }
+  
+  // parallel functions for API consistency
+  bool queryC(char const *key, TPTR &value) const { return query(key, value); }
+  TPTR queryfC(char const *key) const { return queryf(key); }
+]]],[[[m4_dnl
+  bool queryC(char const *key, TCPTR &value) const  { return dict.query(key, (void*&)value); }
+  bool query(char const *key, TPTR &value)               { return queryC(key, (TCPTR &)value); }
+
+  TCPTR queryfC(char const *key) const              { return (TCPTR)dict.queryf(key); }
+  TPTR /*serf*/ queryf(char const *key)                 { return (TPTR)dict.queryf(key); }
+  TPTR /*serf*/ queryif(char const *key)                { return (TPTR)dict.queryif(key); }
+]]])m4_dnl
+
+  bool isMapped(char const *key) const                 { return dict.isMapped(key); }
+
+  // -------- mutators -----------
+  void add(char const *key, TPTR value)                  { dict.add(key, (void*)value); }
+  TPTR /*owner*/ remove(char const *key)                { return (TPTR)dict.remove(key); }
+outputCond([[[m4_dnl
+  TPTR modify(char const *key, TPTR newValue)              { return (TPTR)dict.modify(key, (void*)newValue); }
+
+  void empty()                                         { dict.empty(); }
+]]],[[[m4_dnl
+  void deleteAt(char const *key)                       { deleteObject(remove(key)); }
+
+  void empty()               { dict.emptyAndDel((StringVoidDict::DelFn)deleteObject); }
+]]])m4_dnl
+
+  // -------- parallel interface for 'rostring' --------
+  bool query(rostring key, TPTR &value) const { return query(key.c_str(), value); }
+  TPTR queryf(rostring key) const             { return queryf(key.c_str()); }
+  TPTR queryif(rostring key) const            { return queryif(key.c_str()); }
+  bool isMapped(rostring key) const         { return isMapped(key.c_str()); }
+  void add(rostring key, TPTR value)          { dict.add(key, (void*)value); }
+  TPTR modify(rostring key, TPTR newValue)      { return modify(key.c_str(), newValue); }
+  TPTR remove(rostring key)                   { return remove(key.c_str()); }
+
+  // --------- iters -------------
+outputCond([[[m4_dnl
+  void foreach(ForeachFn func, void *extra=NULL) const
+    { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
+]]],[[[m4_dnl
+  void foreachC(ForeachCFn func, void *extra=NULL) const
+    { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
+  void foreach(ForeachFn func, void *extra=NULL)
+    { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
+]]])m4_dnl
+
+  // ------------ misc --------------
+outputCond([[[m4_dnl
+]]],[[[m4_dnl
+  static void deleteObject(TPTR obj);
+]]])m4_dnl
+  // debugging
+  int private_getTopAddr() const { return dict.private_getTopAddr(); }
+};
+
+outputCond([[[m4_dnl
+]]],[[[m4_dnl
+template <class T>
+STATICDEF void XSTROBJDICT_type::deleteObject(TPTR obj)
+{
+  delete obj;
+}
+]]])m4_dnl
+
+#endif // includeLatch

Added: vendor/elsa/current/www/index.html
===================================================================
--- vendor/elsa/current/www/index.html	2007-05-22 21:47:04 UTC (rev 6938)
+++ vendor/elsa/current/www/index.html	2007-05-22 22:09:08 UTC (rev 6939)
@@ -0,0 +1,74 @@
+<html>
+  <head>
+    <title>Elsa-Stack</title>
+  </head>
+
+  <body>
+    <h1>Elsa-Stack</h1>
+
+    <p>Welcome!  This is the homepage for Elsa-Stack.  Elsa-stack is the
+      minimum collection of software necessary to build and run Elsa.
+      Elsa-stack contains the repositories:
+    </p>
+    <ul>
+      <li>smbase</li>
+      <li>ast</li>
+      <li><a href="http://www.cs.berkeley.edu/~smcpeak/elkhound/">Elkhound</a>
+      <li><a href="http://www.cs.berkeley.edu/~smcpeak/elkhound/sources/elsa/">Elsa</a>
+    </ul>
+
+    <p>
+      This repository is what we call a "software stack": it is a collection of
+      repositories that together form one large project of composable parts.  The
+      name is reminiscent of the TCP/IP networking stack, which we think of as being
+      organized this way.
+    </p>
+
+    <p>
+      If you want to use Elsa you should create your own stack that uses the same
+      components that Elsa-stack uses: smbase ast elkhound elsa, plus your
+      own.
+    </p>
+
+    <h2>Author</h2>
+    <p>
+      The author and maintainer of smbase, ast, elkhound, and elsa is Scott
+      McPeak
+<pre>
+  smcpeak cs berkeley edu
+         @  .        .
+</pre>
+
+      Homepage: <a href="http://www.cs.berkeley.edu/~smcpeak/">http://www.cs.berkeley.edu/~smcpeak/</a>.
+    </p>
+
+    <h2>Getting the code</h2>
+    <p>To check out elsa, install Subversion, then type:
+
+      <blockquote>
+        <tt>svn checkout https://svn.cubewano.org/repos/elsa-stack/trunk elsa-stack</tt>
+      </blockquote>
+    </p>
+
+    <p>To install Subversion with SSL enabled from source:
+      <blockquote>
+        <tt>
+          wget http://subversion.tigris.org/tarballs/subversion-1.3.0.tar.gz<br/>
+          tar xzf subversion-1.3.0.tar.gz<br/>
+          cd subversion-1.3.0<br/>
+          ./configure --with-ssl<br/>
+          make all<br/>
+          sudo make install
+        </tt>
+      </blockquote>
+
+    </p>
+
+    <h2>Documentation</h2>
+    <p>
+      See the <tt>README.txt</tt> for how to build.
+      Please see documentation for Elsa in <tt>elsa-stack/elsa/doc/</tt> .
+    </p>
+
+  </body>
+</html>



More information about the cig-commits mailing list